I am writing a GPIO input object that reads the pinstate of GPIO port 0. I am putting in a feature where the different pull resistor states can be specified. They are done so with an enum type in the header. One problem, the code has no effect. The default state of the pin does not change. I am almost certain the values in the pinmodes are right as I checked them with the debugger. I have a feeling there is something simple I am overlooking.
switch(GetPullType()) // Connect specified pull resistor. { case PULLDOWN: LPC_PINCON->PINMODE0 |= (1 << gPinNumber); LPC_PINCON->PINMODE0 |= (1 << gPinNumber + 1); break; case PULLUP: LPC_PINCON->PINMODE0 &= ~(1 << gPinNumber); LPC_PINCON->PINMODE0 &= ~(1 << gPinNumber + 1); break; default: LPC_PINCON->PINMODE0 &= ~(1 << gPinNumber); LPC_PINCON->PINMODE0 |= (1 << gPinNumber + 1); break; }
I checked the inputs with a volt meter. Here is what I read in each mode for any specified pin:
PULLDOWN = 4.3 volts PULLUP = 4.36 volts PULLNONE = 4.35 volts
According to these voltages, the default pullup mode is not changing. I am using the LPC1768 controller with an MCB1700 development board.
Could there be something wrong with the board + chip? 3 something volts seems a little high.
I did some more playing around by breaking the program down to its simplest form. What I am trying to do is read the state of a momentary push button connected from VCC to the pin. The pin is supposed to be pulled down. The problem is when I attempt to enable the pull down resistor, the input behaves is if it were pulled up (the led turns off when the input is grounded). What is going on? Here is the code I am running:
#include <stdio.h> #include <LPC17XX.h> int main(void) { LPC_GPIO1->FIODIR |= 1 << 28; // Make P1.28 an output. LPC_GPIO0->FIODIR &= ~(1 << 0); // Make P0.0 an input. LPC_PINCON->PINMODE0 = 0x03; // Pull P0.0 down. while (1) { if (LPC_GPIO0->FIOPIN & (1 << 0)) // Read state of P0.0. { LPC_GPIO1->FIOSET |= 1 << 28; // Make P1.28 high. LPC_GPIO1->FIOCLR &= ~(1 << 28); } else { LPC_GPIO1->FIOCLR |= 1 << 28; // Make P1.28 low. LPC_GPIO1->FIOSET &= ~(1 << 28); } }
LPC_PINCON->PINMODE0 |= (1 << gPinNumber); LPC_PINCON->PINMODE0 |= (1 << gPinNumber + 1);
Shouldn't you have written:
LPC_PINCON->PINMODE0 |= (1 << (2*gPinNumber)); LPC_PINCON->PINMODE0 |= (1 << (2*gPinNumber+1));
Obviously only working fpr P0.0..P0.15.
Thanks, I was using the wrong formula all along! Still, there are only pulldown resistors work for P0.0 through P0.3. Is this because they have I2C on them as well as the A to D? I cannot seem to find where it says this in the manual. Probably just a footnote somewhere. Where does it say this so I can compensate in my program?
Thanks, Ben
Almost all GPIO have the same options. An exception is I2C signals with open-drain and a need for external pull-up/down.
Thanks, all working now.
I guess you did realize that my rewritten code (where I showed you that you need to multiply bit number with two) can be further optimized from:
into:
LPC_PINCON->PINMODE0 |= (3 << (2*gPinNumber));
And the magic value 3 could be changed into a constant named INPUT_MODE_PULLDOWN, to make it easier to see what the statement is intended to do. Of course, INPUT_MODE_PULLDOWN (3) is the only mode setting possible with just an bit-or operation. The other modes needs bit-not-and to clear one or both bits.