Setting up GPIOs for the LPC1227

As you already know, NXP crue doesn’t provide libraries for this chip, and in their own words, they won’t ever (More info  here).

That’s sad ‘cause this is a milestone chip for the low-end industrial market. I loved it since the first time I saw it :). But this post is not about hate-love story; it’s about setting the GPIOs up.

Although at first glance it may seem to be a seally topic, in fact it is not. For example, no one tell you that the IOCON bit in the SYSAHBCLKCTRL register must be set in order to enable the clock that will allow you to configure the GPIOs. If you don’t, then you can’t configure any GPIO block (as input or output, for example). As usual, I learned it the hard way.

Most online examples include this line

/* Enable all three GPIO blocks and IOCON */
 LPC_SYSCON->SYSAHBCLKCTRL |= 0xE001001FUL;

Can you tell what is this about? It hides some important stuff. Please refer to Table 21, pp. 23, UM10441. It enables clocks for the core, the IOCON and GPIOs. So in order we can see what’s going on I’ve splitted this line up into some more human readable format:

void System_Init()
{
  LPC_SYSCON->SYSAHBCLKCTRL = 0x01F;
  // Turn all clocks off, except the core ones.
  // Any single other must be turned on separately, according to the
  // user needs.
  // See UM10441 - 4.5.14.

  LPC_SYSCON->SYSAHBCLKCTRL |= 1 << 16;   // We turn the IOCON clock on, so we can configure each GPIO.   // This must be done before any other action that involves GPIOs!!   // See UM10441 - 4.5.14.   LPC_SYSCON->SYSAHBCLKCTRL |= 1 << 29;   LPC_SYSCON->SYSAHBCLKCTRL |= 1 << 30;   LPC_SYSCON->SYSAHBCLKCTRL |= 1 << 31;
  // We turn on the clocks for each of the available ports.

  // More code (not related with enabling clocks) ...
}

Besides the comments, now it’s posible to see what we are doing. And following this same fashion we configure the other chip peripherals: I2C, SPI, RTC, CMP, UARTx, DMA, WDT, ADC, CTxxBy, CRC. As a rule of thumb, don’t forget to turn the peripheral clock on before you use it. If you fail to do so, you’ll end up frustrated and upset =).

After GPIOs block’s clocks have been enabled, it’s time to configure each chip’s pin to be GPIO. There are tons of registers that need to be touched in order to accomplish this task. First of all remember that each chip’s pin shares functionality with other modules. Besides, and as GPIO, each pin can have it’s internal pull-up resistor enabled or not, to have input inverted or not, to be digital or analog, to be high or low current, to be open-drain or not, to have its input filter enabled or not, including a clock divider for this filter.

Each one of these funcionalities can be set or reset through a dedicated register. Each chip’s pin has its own configuration register. Please refer from Table 63 to Table 117, pp. 161, UM10441 to see the details.

We haven’t ended yet. In this chip any GPIO pin can act as an interrupt source. But (for now) interrupts are out of this discussion, however I’ll take this important topic as soon as I got some other free time.

Fot the most basic purposes, it’s enough to set or reset the pin (as output), or read it (as input). For that we only need six registers (yes, I said “only”).

  • DIR  – Set the pin as input or output.
  • PIN – We can read the logic level present in an input pin.
  • OUT – Set (3.3V) or reset (0V) the logic level of an output pin.
  • SET – Set the logic level of an output pin.
  • CLR – Reset the logic level of an output pin.
  • NOT – Toggle the pin’s state of an output pin.

Please refer to Table 122, pp. 134, UM10441 to see the details. Each of these registers (among the other ones with regard to interrupts) are 32 bits sized. There is a one to one correspondence between bit number in these register and chip’s pin. Of course, we shouldn’t touch those bits that correspond to terminals that are not present in the chip.

For ending this post, let give some examples of using those last registers:

void System_Init()
{
  // More code (related with enabling clocks) ...

  LPC_GPIO0->DIR |= 1 << 12;   // We set PIO0.12 as output   LPC_GPIO2->DIR |= 1 << 7;   // We set PIO2.7 as output   // Probably more code ... } int main() {   System_Init();   // Enable peripherals and configure GPIOs   LPC_GPIO0->SET |= 1 << 12;   // We turn PIO0.12 on   LPC_GPIO2->NOT |= 1 << 7;
  // We toggle PIO2.7

  while( 1 )
  {
    ;
    // Do nothing
  }

  return 0;
}

For now that’s all, I need to go back to work. ASAP I’ll post a tutorial on regarding other interesting GPIOs stuff.

10-march-15 update

If you thought this procedure is a bit complicated, things get worse when dealing with the so called “Reserved pins”. As I was using pins which first option is as GPIO I haven’t had the need to touch the SYSCON register. But that won’t be the case with the reserved pins. Please keep reading.

Some pins, say PIO0_30, PIO0_31, PIO1_0 and PIO1_1 for example, have their first option labeled as “reserved”. So we need to choose a different option. The procedure is the same as when we want to configure a pin with functionality other than GPIO (e.g. I2C, Timer, etc.)
For the project I’m working on right now I did this:

    LPC_SYSCON->SYSAHBCLKCTRL |= 1 << 16;     
    // LPC_SYSAHBCTRL.IOCON = TRUE     
    
    LPC_SYSCON->SYSAHBCLKCTRL |= 1 << 31;     
    // LPC_SYSAHBCTRL.GPIO0 = TRUE     

    LPC_IOCON->R_PIO0_30 = 0xb8;
    // state after reset

    LPC_IOCON->R_PIO0_30 |= 0x01;
    // as PIO0_30

    LPC_IOCON->R_PIO0_31 = 0xb8;
    // state after reset

    LPC_IOCON->R_PIO0_31 |= 0x01;
    // as PIO0_31

    LPC_IOCON->R_PIO1_0 = 0xb8;
    LPC_IOCON->R_PIO1_0 = 0x01;
    LPC_IOCON->R_PIO1_1 = 0xb8;
    LPC_IOCON->R_PIO1_1 = 0x01;

Comments under expression are a short explanation for me for when I forget what I did.

After these changes I was able to use such pins as GPIOs.

Anuncios

3 comentarios sobre “Setting up GPIOs for the LPC1227

  1. Hello,
    thank’s for the example.

    i would like set pull up resistor for my LPC1227 but I can’t, how I set?

    And I have a problem with 1.30 pin this is my initialization:

    LPC_SYSCON->SYSAHBCLKCTRL |= 1 <SYSAHBCLKCTRL |= 1 < R_PIO1_0 = 0xb8;
    LPC_IOCON->R_PIO1_0 = 0x01;

    GPIOSetDir(1, 0, OUTPUT);
    GPIOSetValue(1, 0, HIGH);

    But no working, I have no idea why?

    1. Hi

      1.- Pull-up resistor is selected by default after reset, so you don’t need to do anything after this instruction:

      LPC_IOCON->R_PIO0_31 = 0xb8;
      // state after reset

      2.- The first argument of the GPIOSetXXX() library functions is the port number, which in turns IT IS NOT 1, but a well define constant:

      LPC_GPIO1

      so, you need to change those instructions for these others:

      GPIOSetDir(GPIO1, 0, OUTPUT);
      GPIOSetValue(GPIO1, 0, HIGH);

      Let me know if that works for you.

      Finally, ASAP I got some spare time I’ll write a little tutorial about using raw instructions (but no assembler) for the GPIOs.

      Greetings!

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s