PDA

View Full Version : Internal pull up and pull down resistors on teensy 3



cmason
12-14-2012, 08:22 AM
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 (http://www.ladyada.net/learn/arduino/lesson5.html)). I'm basically doing:


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 (https://bitbucket.org/cmason/teensy3/src/tip/teensy/main_pedal.cpp) (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

Jp3141
12-14-2012, 01:58 PM
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).

cmason
12-16-2012, 04:08 AM
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
pinMode(n, INPUT_PULLUP); or
connect the button between 3.3V and the pin and use the internal pull down
*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

keithg
12-17-2012, 04:16 AM
Paul,

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

Keith

PaulStoffregen
12-17-2012, 10:58 AM
I'll probably add INPUT_PULLDOWN. Right now I'm focused on compatibility, fixing bugs, and porting libraries.

Olson.dev
02-13-2013, 01:51 AM
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!

cmason
02-13-2013, 04:57 PM
You can just use the code I posted above:



*portConfigRegister(pin) = PORT_PCR_MUX(1) | PORT_PCR_PE;


-c

Olson.dev
02-13-2013, 10:19 PM
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?

pinMode(pin, INPUT);

Also, this part didn't compile...

attachInterrupt(pin, CHANGE);

I changed it to:


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:
245


USB device not recognized
The last USB device you connected to this computer malfunctioned, and Windows does not recognize it.

doughboy
02-05-2015, 05:30 PM
You can just use the code I posted above:



*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


*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


#define INPUT_PULLDOWN 3

change pinMode function in pins_teensy.c to


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
}
}
}

doughboy
02-05-2015, 07:42 PM
another variation that does not override pullup and open drain setting.

change in core_pins.h


#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


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()
}
}

Markk
11-13-2015, 02:25 PM
I'll probably add INPUT_PULLDOWN. Right now I'm focused on compatibility, fixing bugs, and porting libraries.


another variation that does not override pullup and open drain setting.

change in core_pins.h


#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


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

keithg
02-10-2016, 03:59 AM
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

Xenoamor
02-10-2016, 10:16 AM
It's basically not changed.

Do Markk's change to the core_pins.h

And change pinMode() in pins_teensy.c to:

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 (https://github.com/PaulStoffregen/cores/pull/114/files)