Forum Rule: Always post complete source code & details to reproduce any issue!
Results 1 to 13 of 13

Thread: Internal pull up and pull down resistors on teensy 3

  1. #1

    Internal pull up and pull down resistors on teensy 3

    I'm simply trying to drive buttons off digital pins. I have the buttons wired to 3.3V through a 1k resistor and then each button leads to a different pin. I'm then trying to use the internal pulldown to pull the pin down to ground when the button is open (to avoid artifacts as described here). I'm basically doing:

    Code:
    static const uint8_t buttonPins[MAX_BUTTONS] =  {2, 3, 4, 16, 17, 18};
    for (int i = 0; i < MAX_BUTTONS; ++i) {
        uint8_t pin = buttonPins[i];
        pinMode(pin, INPUT);
        *portConfigRegister(pin) = PORT_PCR_MUX(1) | PORT_PCR_PE;
        attachInterrupt(pin, CHANGE);
    }
    Pins 4,16,17,18 work as I expect. Pins 2 and 3 do not. When I attach a meter between pin 2 and ground with the button open, I see ~ 1V. Between 4 and ground, I see low millivolts. With the buttons closed I always see 3.3 V. I've tried a number of different combinations of pins, and always see the same behavior: a few of the lower number pins don't work as expected.

    My understanding is that enabling the internal pulldown should act exactly like connecting a ~20k resistor between that pin and ground. Is this correct?

    I'm not at all an electronics person so it's quite possible something else is going on. I know it's not the buttons because I've tested them with a multimeter and they read no connection open and ~ 1 ohm closed.

    The complete code is here (it's more complex, involving analog read on a slider pot), etc.

    I'm sure this is something really stupid I'm doing. Makes me feel dumb. Any help would be most appreciated.

    -c

  2. #2
    Senior Member Jp3141's Avatar
    Join Date
    Nov 2012
    Posts
    455
    I don't think there is an internal pulldown on the I/Os on Teensy 3, but there is an internal pull-up. This is in fact easier to use because one end of each button can be grounded.

    So, do in setup() {...
    pinMode(15, INPUT_PULLUP);
    digitalWrite(15, HIGH);

    and connect the button from 15 (in this example) to ground. You don't need a 1 k resistor, but if the buttons go off board it may be useful as protection for the CPU -- just put the R in series with the pin15 connection. You don't need a pullup (the pin provides it).

    The internal pullup is about 33 kohm (100 uA).

  3. #3
    Yeah, this had nothing to do with pull up or pull down. Just a stupid bug.

    For posterity: the teensy 3 does indeed have both internal pull up and pull down resistors. Both seem to work ok. Put another way: you can either

    • connect the button between ground and the pin and use the internal pull up
      Code:
      pinMode(n, INPUT_PULLUP);
      or
    • connect the button between 3.3V and the pin and use the internal pull down
      Code:
      *portConfigRegister(pin) = PORT_PCR_MUX(1) | PORT_PCR_PE;.


    This latter felt more natural to me (why would an input pin source voltage?) but I understand that they're basically equivalent.

    -c

  4. #4
    Paul,

    Is there any plan to have INPUT_PULLDOWN functionality similar to the INPUT_PULLUP?

    Keith

  5. #5
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    15,924
    I'll probably add INPUT_PULLDOWN. Right now I'm focused on compatibility, fixing bugs, and porting libraries.

  6. #6
    Junior Member
    Join Date
    Jan 2013
    Posts
    3
    Quote Originally Posted by PaulStoffregen View Post
    I'll probably add INPUT_PULLDOWN. Right now I'm focused on compatibility, fixing bugs, and porting libraries.
    Paul, any ETA on the INPUT_PULLDOWN functionality?

    Thanks!

  7. #7
    You can just use the code I posted above:

    Code:
    *portConfigRegister(pin) = PORT_PCR_MUX(1) | PORT_PCR_PE;
    -c

  8. #8
    Junior Member
    Join Date
    Jan 2013
    Posts
    3
    I was trying to get that set up last night but I was running into issues with Windows saying the USB device couldn't be recognized anymore.

    It still seems to recognize it in that I can reflash Blink back to it and it works but a very simple app with just your code above builds but Windows doesn't like it after my Teensy 3.0 reboots. Any ideas there?

    Also, do I need this bit?
    Code:
    pinMode(pin, INPUT);
    Also, this part didn't compile...
    Code:
    attachInterrupt(pin, CHANGE);
    I changed it to:
    Code:
    attachInterrupt(pin, changed, CHANGE);
    // ...
    void changed() {
        // TODO: Implement this. How to know which pin changed though?
    }
    For reference, this is what I see the moment I build and upload with that portConfigRegister snippet:
    Click image for larger version. 

Name:	N6WdVj7.png 
Views:	256 
Size:	3.7 KB 
ID:	245
    USB device not recognized
    The last USB device you connected to this computer malfunctioned, and Windows does not recognize it.
    Last edited by Olson.dev; 02-14-2013 at 12:56 AM.

  9. #9
    Senior Member
    Join Date
    Jan 2015
    Location
    SF Bay Area
    Posts
    255
    Quote Originally Posted by cmason View Post
    You can just use the code I posted above:

    Code:
    *portConfigRegister(pin) = PORT_PCR_MUX(1) | PORT_PCR_PE;
    -c
    FWIW, the above is bad code, as it will overwrite other bits in the register.
    The proper way is
    Code:
        *portConfigRegister(pin) |= PORT_PCR_PE; //pull enable
        *portConfigRegister(pin) &= ~PORT_PCR_PS; //pull down
    This is an old thread, but I do not see INPUT_PULLDOWN implemented (at least in my 1.20 teensyduino install).
    To implement pulldown
    add this define to core_pins.h, around line 43
    Code:
    #define INPUT_PULLDOWN 3
    change pinMode function in pins_teensy.c to
    Code:
    void pinMode(uint8_t pin, uint8_t mode)
    {
    	volatile uint32_t *config;
    
    	if (pin >= CORE_NUM_DIGITAL) return;
    	config = portConfigRegister(pin);
    
    	if (mode == OUTPUT) {
    		*portModeRegister(pin) = 1;
    		*config = PORT_PCR_SRE | PORT_PCR_DSE | PORT_PCR_MUX(1);
    	} else {
    		*portModeRegister(pin) = 0;
    		if (mode == INPUT) {
    			*config = PORT_PCR_MUX(1);
    		} else if (mode == INPUT_PULLUP) {
    			*config = PORT_PCR_MUX(1) | PORT_PCR_PE | PORT_PCR_PS; // pullup
    		} else {
    			*config = PORT_PCR_MUX(1) | PORT_PCR_PE; // pulldown
    		}
    	}
    }
    Last edited by doughboy; 02-05-2015 at 06:44 PM.

  10. #10
    Senior Member
    Join Date
    Jan 2015
    Location
    SF Bay Area
    Posts
    255
    another variation that does not override pullup and open drain setting.

    change in core_pins.h
    Code:
    #define INPUT            0
    #define OUTPUT           1
    #define INPUT_PULLUP	 2
    #define INPUT_PULLDOWN   3
    #define OUTPUT_OPENDRAIN 4
    change in pinmode in pins_teensy.c
    Code:
    void pinMode(uint8_t pin, uint8_t mode)
    {
    	volatile uint32_t *config;
    
    	if (pin >= CORE_NUM_DIGITAL) return;
    	config = portConfigRegister(pin);
    
            if (mode == OUTPUT || mode == OUTPUT_OPENDRAIN) {
    		*portModeRegister(pin) = 1;
    		__disable_irq();
    		*config &= ~PORT_PCR_MUX_MASK;
    		*config |= (PORT_PCR_SRE | PORT_PCR_DSE | PORT_PCR_MUX(1));
                    if (mode == OUTPUT_OPENDRAIN) {
    		    *config |= PORT_PCR_ODE;
    		} else {
    		    *config &= ~PORT_PCR_ODE;
                    }
    		__enable_irq();
    	} else if (mode == INPUT || mode == INPUT_PULLUP || mode == INPUT_PULLDOWN){
    		*portModeRegister(pin) = 0;
    		__disable_irq();
    		*config &= ~PORT_PCR_MUX_MASK;
                    *config |= PORT_PCR_MUX(1);
    		if (mode == INPUT_PULLUP) {
    		    *config |= (PORT_PCR_PE | PORT_PCR_PS); // pullup
    		} else if (mode == INPUT_PULLDOWN) {
    		    *config |= (PORT_PCR_PE); // pulldown
    		    *config &= ~(PORT_PCR_PS);
    		}
                    __enable_irq()
    	}
    }
    Last edited by doughboy; 02-06-2015 at 01:53 AM.

  11. #11

    Would be very nice to have in Teensyduino

    Quote Originally Posted by PaulStoffregen View Post
    I'll probably add INPUT_PULLDOWN. Right now I'm focused on compatibility, fixing bugs, and porting libraries.
    Quote Originally Posted by doughboy View Post
    another variation that does not override pullup and open drain setting.

    change in core_pins.h
    Code:
    #define INPUT            0
    #define OUTPUT           1
    #define INPUT_PULLUP	 2
    #define INPUT_PULLDOWN   3
    #define OUTPUT_OPENDRAIN 4
    change in pinmode in pins_teensy.c
    Code:
    void pinMode(uint8_t pin, uint8_t mode)
    {
    	volatile uint32_t *config;
    
    	if (pin >= CORE_NUM_DIGITAL) return;
    	config = portConfigRegister(pin);
    
            if (mode == OUTPUT || mode == OUTPUT_OPENDRAIN) {
    		*portModeRegister(pin) = 1;
    		__disable_irq();
    		*config &= ~PORT_PCR_MUX_MASK;
    		*config |= (PORT_PCR_SRE | PORT_PCR_DSE | PORT_PCR_MUX(1));
                    if (mode == OUTPUT_OPENDRAIN) {
    		    *config |= PORT_PCR_ODE;
    		} else {
    		    *config &= ~PORT_PCR_ODE;
                    }
    		__enable_irq();
    	} else if (mode == INPUT || mode == INPUT_PULLUP || mode == INPUT_PULLDOWN){
    		*portModeRegister(pin) = 0;
    		__disable_irq();
    		*config &= ~PORT_PCR_MUX_MASK;
                    *config |= PORT_PCR_MUX(1);
    		if (mode == INPUT_PULLUP) {
    		    *config |= (PORT_PCR_PE | PORT_PCR_PS); // pullup
    		} else if (mode == INPUT_PULLDOWN) {
    		    *config |= (PORT_PCR_PE); // pulldown
    		    *config &= ~(PORT_PCR_PS);
    		}
                    __enable_irq()
    	}
    }
    Something like that would be very nice to have in Teensyduino!

    _Markk

  12. #12
    Anything new on this functionality? The pins_teensy.c has become a bit more complicated in the last year and I am unsure of how to implement this.. Can Paul add this? Is there a reason it is not added?

    Keithg

  13. #13
    Senior Member
    Join Date
    Nov 2015
    Location
    Wales
    Posts
    579
    It's basically not changed.

    Do Markk's change to the core_pins.h

    And change pinMode() in pins_teensy.c to:
    Code:
    void pinMode(uint8_t pin, uint8_t mode)
    {
    	volatile uint32_t *config;
    
    	if (pin >= CORE_NUM_DIGITAL) return;
    	config = portConfigRegister(pin);
    
    	if (mode == OUTPUT) {
    #ifdef KINETISK
    		*portModeRegister(pin) = 1;
    #else
    		*portModeRegister(pin) |= digitalPinToBitMask(pin); // TODO: atomic
    #endif
    		*config = PORT_PCR_SRE | PORT_PCR_DSE | PORT_PCR_MUX(1);
    	} else {
    #ifdef KINETISK
    		*portModeRegister(pin) = 0;
    #else
    		*portModeRegister(pin) &= ~digitalPinToBitMask(pin);
    #endif
    		if (mode == INPUT || mode == INPUT_PULLUP || mode == INPUT_PULLDOWN) {
    			*config = PORT_PCR_MUX(1);
    			if (mode == INPUT_PULLUP) {
    		    	*config |= (PORT_PCR_PE | PORT_PCR_PS); // pullup
    			} else if (mode == INPUT_PULLDOWN) {
    			    *config |= (PORT_PCR_PE); // pulldown
    			    *config &= ~(PORT_PCR_PS);
    			}
    		} else {
    			*config = PORT_PCR_MUX(1) | PORT_PCR_PE | PORT_PCR_PS; // pullup
    		}
    	}
    }
    Perhaps one of us should make a pull request so Paul can update this easily?

    EDIT -
    I have done so
    Last edited by Xenoamor; 02-10-2016 at 10:47 AM.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •