7 years, 11 months ago.

Why won't this LPC1768 GPIO interrupt trigger?

*Updated: answered my own question, see below.

I'm using the LPC1768 on the mbed application board. I'm trying to get a handle on using low level interrupts on this platform, ie. instead of using:

InterruptIn centre(p14)
centre.rise(whatever);

...I'm trying to write and enable the interrupts like so:

extern "C" void EINT3_IRQHandler(void)
{
  // ...
}

I can't seem to get the GPIO interrupts to work. I'd like to trigger an interrupt when the joystick centre button is pressed. The schematics show that this comes in on port 14 of the LPC board, which is P0.16 as far as the chip itself is concerned. According to the LPC manual, the GPIO interrupts come through on the EINT3 interrupt vector. I've enabled the interrupt, I've written the handler (which turns one of the LPC board LEDs on), but when I push the button, the LED remains off.

Here's the simplest example I could make:

#include "LPC17xx.h"

extern "C" void EINT3_IRQHandler(void)
{  
    // Toggle the LED.
    LPC_GPIO1->FIOPIN ^= 1 << 18;

    // Clear the interrupt.
    LPC_GPIOINT->IO0IntClr = ~((uint32_t) 0);
}

int main()
{
    __disable_irq();

    NVIC_DisableIRQ(EINT3_IRQn);

    // Power up GPIO.
    LPC_SC->PCONP |= ( 1 << 15 );

    // P1.18 as output.
    LPC_GPIO1->FIODIR |= 1 << 18;

    // GPIO P0.16 as input.
    LPC_PINCON->PINSEL1 &= ~(0x3 << 0);
    LPC_PINCON->PINMODE1 &= ~(0x3 << 0);
    LPC_PINCON->PINMODE1 |= (0x3 << 0);
    LPC_GPIO0->FIODIR   &= ~(0x1 << 16);

    LPC_GPIOINT->IO0IntEnR |= (0x1 << 16);

    LPC_SC->EXTINT = 1;

    NVIC_EnableIRQ(EINT3_IRQn);

    __enable_irq();

    while(1);

    return 0;
}

In real code I would, of course, check the interrupt flags inside the handler. But at this point, I just want to prove that the handler can be triggered at all.

If I rewrite this example using a timer-based interrupt instead, the LED blinks as fast as I like. So what have I missed with the GPIO interrupt?

Update #1: I tried replacing the interrupt with a busy-wait that just polled the button and updated the LED with the pin reading. I found that I needed to set the pin mode to use a pull-down resistor to get that to work. But putting this in the interrupt-based code didn't make it work.

Update #2: After posting, I found the solution in a linked question. Clear the interrupt at the start of the ISR, not at the end. The working ISR looks like:

extern "C" void EINT3_IRQHandler(void)
{  
    // Clear the interrupt.
    LPC_GPIOINT->IO0IntClr = (1 << 16);
    
    // Toggle the LED.
    LPC_GPIO1->FIOPIN ^= (1 << 18);
}
Be the first to answer this question.