Forums

LPC177x GPIO interrupt

Started by geo255 4 years ago11 replieslatest reply 4 years ago825 views

I am struggling to get a #GPIO interrupt (port 0.3) working on an LPC1778 (#LPC1700).  I've checked online, including here, and I seem to be doing everything correctly, but I'm missing something.

I have a signal on P0[3] which pulses low for 12ms every 500ms.  My test code (below) has an interrupt which should count the edges and also polls the pin to verify that the input is actually changing.  The result is that the poll count increments, but the interrupt count doesn't.  I have tested that the interrupt function is correctly defined by adding an NVIC_SetPendingIRQ(EINT3_IRQn) to force it.  I've also tried explicitly setting the GPIO power at the start, but it didn't make a difference (it's powered on at reset anyway).

The IO0IntStat registers all get set, indicating that there's an interrupt pending.

#include <CMSIS/LPC177x_8x.h>

#define INTERRUPT_PIN 3 // P0[3]

volatile static unsigned int uInterrupt = 0;
volatile static unsigned int uPoll = 0;
unsigned int uPinState = 0;
unsigned int uPrevPinState = 0;

void EINT3_IRQHandler(void)
{
    if ((LPC_GPIOINT->IO0IntStatR & (1 << INTERRUPT_PIN)) || (LPC_GPIOINT->IO0IntStatF & (1 << INTERRUPT_PIN)))
    {
        LPC_GPIOINT->IO0IntClr = (1 << INTERRUPT_PIN);
    }
    uInterrupt++;
}


int main(void)
{
    __enable_irq();

    LPC_GPIO0->DIR &= ~(1 << INTERRUPT_PIN);
    LPC_GPIOINT->IO0IntEnR |= (1 << INTERRUPT_PIN);
    LPC_GPIOINT->IO0IntEnF |= (1 << INTERRUPT_PIN);
    
    NVIC_SetPriority(EINT3_IRQn, 0x80);
    NVIC_EnableIRQ(EINT3_IRQn);

    while (1)
    {
        uPinState = (LPC_GPIO0->PIN & (1 << INTERRUPT_PIN));
        if (uPinState != uPrevPinState)
        {
            uPoll++;
            uPrevPinState = uPinState;
        }
    }
    return 0;
}
[ - ]
Reply by geo255October 5, 2016

Thank you to everyone who replied.

I found the problem...

The 1778 doesn't route the GPIO interrupts through the EINT3 vector, but has a dedicated GPIO vector.  In case anyone else makes the same mistake as me, this code works...


#include <CMSIS/LPC177x_8x.h>

#define INTERRUPT_PIN 3 /* P0[3] */

volatile static unsigned int uInterrupt = 0;
volatile static unsigned int uPoll = 0;
unsigned int uPinState = 0;
unsigned int uPrevPinState = 0;

void GPIO_IRQHandler(void)
{
    if ((LPC_GPIOINT->IO0IntStatR & (1 << INTERRUPT_PIN)) || 
        (LPC_GPIOINT->IO0IntStatF & (1 << INTERRUPT_PIN)))
    {
        LPC_GPIOINT->IO0IntClr = (1 << INTERRUPT_PIN);
        uInterrupt++;
    }
}


int main(void)
{
    __enable_irq();

    // Power on the GPIO block - just sets them to the default reset values.
    LPC_SC->PCLKSEL = 4;
    LPC_SC->PCONP |= (1 << 15);

    // Configure P0[3] as a GPIO input.
    LPC_IOCON->P0_3 = 0x00000020;
    LPC_GPIO0->DIR &= ~(1 << INTERRUPT_PIN);
    
    // Enable P0[3] interrupt on both rising and falling edges.
    LPC_GPIOINT->IO0IntEnR |= (1 << INTERRUPT_PIN);
    LPC_GPIOINT->IO0IntEnF |= (1 << INTERRUPT_PIN);
    
    // Enable the GPIO interrupt vector.
    NVIC_EnableIRQ(GPIO_IRQn);

    // Clear any pending interrupt.
    LPC_GPIOINT->IO0IntClr = (1 << INTERRUPT_PIN);
    
    // Poll loop used to test - it increments uPoll if the GPIO input changes
    // state.  The two counters should stay in sync if everything is working ok.
    while (1)
    {
        uPinState = (LPC_GPIO0->PIN & (1 << INTERRUPT_PIN));
        if (uPinState != uPrevPinState)
        {
            uPoll++;
            uPrevPinState = uPinState;
        }
    }
    return 0;
}




[ - ]
Reply by jorickOctober 5, 2016

I have a complete LPC17xx/40xx library that I wrote, so I'm posting the links to the GPIO module.  You may find the information useful.  The module has the following features:

  • Processor family aware.  Works with both the LPC175x/6x and LPC177x/8x families.
  • Complete support for GPIO interrupts including registering a function as an interrupt handler.
  • Bit Banding is used to access individual bits in the GPIO device control registers, so this is a good example of its use.
  • Doxygen style comments.  Lots of comments!

http://jorick.us/nxp/hardware/GPIO.c

http://jorick.us/nxp/hardware/GPIO.h

http://jorick.us/nxp/header_files/Types.h

This module makes some external calls but it should be obvious what the calls do if you want to replace them.

[ - ]
Reply by jkvasanOctober 5, 2016

Hi

For the interrupt to work, you need to configure it as an edge triggered interrupt.Also you need to select raising or falling edge depending upon your application.Also you need to clear any interrupt associated bit inside the interrupt callback function if it is necessary.

[ - ]
Reply by geo255October 5, 2016

Hi,

Thanks for the reply.  I think I did all that:

Configure the interrupt on both rising and falling edges:

LPC_GPIOINT->IO0IntEnR |= (1 << INTERRUPT_PIN);
LPC_GPIOINT->IO0IntEnF |= (1 << INTERRUPT_PIN);

Clear the interrupt bit in the callback funstion:

LPC_GPIOINT->IO0IntClr = (1 << INTERRUPT_PIN);

Have I done this incorrectly?

[ - ]
Reply by pawelkOctober 5, 2016

I do not know this uC of the top of my head, but you should check with the datasheet if you need to enable GPIO clock. With ARM its usually the case that you need to enable peripheral clock first. And I do not see any clock being initialized in your main().

[ - ]
Reply by geo255October 5, 2016

Hi,

Thanks for the reply.  In one test, I explicitly set these:

LPC_SC->PCLKSEL = 4;        // The input clock is divided by 4 to produce the APB peripheral clock.
LPC_SC->PCONP |= (1 << 15); // PCGPIO Power/clock control bit for IOCON, GPIO, and GPIO interrupts.

Although the datasheet said these are the reset values.  Is there any more that I need to do?

[ - ]
Reply by DNadlerOctober 5, 2016

IIRC, you need to do this to enable GPIO:

  LPC_SYSCON->SYSAHBCLKCTRL |= (1<<6); // power on GPIO: Enable AHB clock to the GPIO domain.


Hope that helps,
Best Regards, Dave

[ - ]
Reply by mjbcswitzerlandOctober 5, 2016

Hi

You are setting up the port for a "port interrupt" but enabling the "external" interrupt on IRQ3. There are two different things on the LPC17xx devices.

If you want to use the IRQ3 "external interrupt" you need to configure the pin for its IRQ3 function (in PINSEL4 register), and enable the interrupt with edge sensitivity in the System Control's EXTMODE and EXTPOLAR registers.

You might do well to look at using the uTasker LPC17xx project as reference because it includes a simple interface for port and external interrupt, as well as an LPC17xx simulator which allows it to be tested in real-time in VisualStudio - it makes it simple to use the interfaces and/or test your own to see why it is not working.

Regards

Mark

http://www.utasker.com/

[ - ]
Reply by jorickOctober 5, 2016

The GPIO interrupts are shared with External Interrupt 3 (EINT3) in the LPC175x/6x family, but has its own interrupt in the LPC177x/8x family.  Perhaps the OP is using the wrong data sheet? 

[ - ]
Reply by geo255October 5, 2016

This was the problem!

[ - ]
Reply by DNadlerOctober 5, 2016

IIRC, you need to do this to enable GPIO:

  LPC_SYSCON->SYSAHBCLKCTRL |= (1<<6); // power on GPIO: Enable AHB clock to the GPIO domain.


Hope that helps,
Best Regards, Dave