This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

Output of an LED set using a pull-up resistor

I just started working with the NXP LPC1768 in class and I'm struggling to understand how the internal pullup/down resistors are utilized. We have a program that changes the status(on/off) of one of the LEDs at the push of a button. My question is why does the following line of code cause the LED to light up:

LPC_PINCON->PINMODE3 = LPC_PINCON->PINMODE3 & 0xFFFFFFCF;
LPC_GPIO1->FIOSET |= (1<<18);

When the program starts, the LED is on. However, since this pin is set to pull up, I expected it to be off. If setting the 18th bit to 1 is equivalent to closing the switch, then that means that this line:

LPC_GPIO1->FIOSET |= (1<<18);

would cause the current to flow to ground, turning the LED off. I must be misunderstanding something, since the LED is obviously on with the current code. Any insights?

Parents
  • You haven't told us how the LED is connected.

    It makes a difference if the LED is connected between VCC and the I/O pin, or between the I/O pin and GND.

    When you set the I/O pin with your command, the pin will go high and try to output 3.3V. So a LED connected between the I/O pin and ground will be lit (assuming the correct polarity of the LED).

    The internal pull-up or pull-down of the PIN is weak. And only applies when the pin is configured for input.

    What you don't show us is if your code will set the pin as output. The default is input, in which case the internal pull-up or pull-down will apply.

    The pull-up or pull-down isn't strong enough to get a LED to light up fully, but can get some LED to give a dimmer light. Many modern LED doesn't need much current until they glow enough that you can see them.

Reply
  • You haven't told us how the LED is connected.

    It makes a difference if the LED is connected between VCC and the I/O pin, or between the I/O pin and GND.

    When you set the I/O pin with your command, the pin will go high and try to output 3.3V. So a LED connected between the I/O pin and ground will be lit (assuming the correct polarity of the LED).

    The internal pull-up or pull-down of the PIN is weak. And only applies when the pin is configured for input.

    What you don't show us is if your code will set the pin as output. The default is input, in which case the internal pull-up or pull-down will apply.

    The pull-up or pull-down isn't strong enough to get a LED to light up fully, but can get some LED to give a dimmer light. Many modern LED doesn't need much current until they glow enough that you can see them.

Children
  • We're using the internal pullup/down resistors.
    The whole code looks like this:

    LPC_PINCON->PINSEL3 = LPC_PINCON->PINSEL3 & 0xFFFFFCF;
    LPC_GPIO1->FIODIR = LPC_GPIO1->FIODIR |(1<<18);
    LPC_PINCON->PINMODE3 = LPC_PINCON->PINMODE3 & 0xFFFFFFCF;
    LPC_GPIO1->FIOCLR = LPC_GPIO1->FIOCLR | (1<<18); //I feel that this line is redundant
    LPC_GPIO1->FIOSET = LPC_GPIO1->FIOSET| (1<<18);
    

    So the pin is set as output. All I can tell about how the LED is connected is that we aren't using any external resistors or components other than what's already pre-set on the chip. Everything we are setting/changing is using code. PS: sorry for the lack of information.

  • LPC_GPIO1->FIOCLR = LPC_GPIO1->FIOCLR | (1<<18); //I feel that this line is redundant
    


    Yes - this line is redundant.

    And no - you aren't using any internal pull-up or pull-down. As I mentioned earlier, they do not apply if you make the pin an output.

    Note the paragraph about the mode register in the processor user manual - my emphasis on "input mode":
    "The PINMODE registers control the input mode of all ports."

    The line:

    LPC_GPIO1->FIOSET = LPC_GPIO1->FIOSET| (1<<18);
    


    will (since your LPC_PINCON->PINSEL3 line makes it into GPIO and your LPC_GPIO1->FIODIR line makes it an output) make the processor fight all it can to hold the pin high. There will be no internal pull-up. There will be no internal pull-down. There will just be a transistor connecting the GPIO pin to VCC.

    I expect you have a series resistor for the LED, because most LED operates at lower voltages than the VCC of the LPC17xx chips. So without external series resistor, the LED will consume all current it can until the processor pin can't supply more. The processor can handle this as long as it doesn't happen on too many pins at the same time - but the LED may get too high current and be destroyed.

    Anyway - if the LED is connected between I/O pin and GND, then you turn off the LED with

    LPC_GPIO1->FIOCLR = (1<<18); //I feel that this line is redundant
    


    Clear means you make the output pin go to ground. So there is no longer any voltage over the LED.

    and you turn it on with:

    LPC_GPIO1->FIOSET = (1<<18); //I feel that this line is redundant
    


    Set means you make the output pin go to VCC. So there will be 3.3V between the GPIO pin and GND.

    Note that the FI0CLR and FI0SET registers are designed for you to assign directly. No |= should be used. This is to make it fast to set and clear a GPIO pin without the need to know what state it had before - or what state any other pin has. This is different from the PINSEL or MODE or FI0DIR, where you need to preserve the state of all other bits of the registers.

    FI0CLR and FI0SET do not have any state to preserve - they are just simply write-only registers.

  • In regards to your last NOTE, would it be better, then, to change FIOSET/CLR registers like this:

    LPC_GPIO1->FIOSET = (1<<18);
    

    would that be equivalent to this:

    LPC_GPIO1->FIOSET = LPC_GPIO1->FIOSET| (1<<18);
    

    ?

  • This is how you are expected to use the registers:

    LPC_GPIO1->FIOSET = (1<<18);
    

    This is how you waste CPU time and code size by using register explicitly designed for write-only use as if they needed read-modify-write code:

    LPC_GPIO1->FIOSET = LPC_GPIO1->FIOSET | (1<<18);
    


    which can be shortened to (but still representes a not needed read-modify-write):

    LPC_GPIO1->FIOSET |= (1<<18);
    

    So yes - you should modify all your use of FIxSET and FIxCLR to just assign bits - never any read/modify/write. That's the whole purpose of the processor getting dedicated registers for set and clear. Else the processor could have managed with the FIxPIN register. The FIxPIN register do require the use of "reg |= bit" and "reg &= ~bit", while the FIxSET and FIxCLR only requires "reg = bit".