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)
Powered by vBulletin® Version 4.2.2 Copyright © 2021 vBulletin Solutions, Inc. All rights reserved.