Minor issue with Interrupts

27 Sep 2010

I've recently come across a few situations where I've seen some "unexpected behaviour" with the Mbed libraries. I'll show one that is probably the easiest to highlight.

Given the code below, the Mbed InterruptIn is used to attach a function to falling edges on P16. However, also defined and the same functionality on P15 but not using an InterruptIn but doing it via one's own method (yes, I know, please don't say "just use an InterruptIn for p15 aswell". This is a demo program to illustrate a point).

#include "mbed.h"

DigitalOut myled1(LED1);
DigitalOut myled2(LED2);
DigitalOut myled3(LED3);
DigitalOut myled4(LED4);

InterruptIn p16irq(p16);

Serial pc(USBTX, USBRX);

uint32_t oldVector = NULL;

typedef void (*FN)(void);

extern "C" void p15_IRQHandler (void) __irq {
    
    /* Test for IRQ on Port0. */
    if (LPC_GPIOINT->IntStatus & 0x1) {
        
        /* p15 (Port0.23) falling interrupt? */
        if (LPC_GPIOINT->IO0IntStatF & (1 << 23)) {
            myled2 = !myled2;
            LPC_GPIOINT->IO0IntClr = (1 << 23);
        }
        else {
            /* If it's an unexpected IRQ then chain
               onto the old interrupt handler and hope
               it will deal with it. */
            if (oldVector) {
                ((FN)oldVector)();
            }    
        }
    }
}
 
void p15irq_init(void) {

    /* Enable a falling IRQ for p15 */
    LPC_GPIOINT->IO0IntEnF |= ( (1UL << 23) );
    
    /* Store the old interrupt vector to chain to. */    
    oldVector = NVIC_GetVector(EINT3_IRQn);
    
    NVIC_SetVector(EINT3_IRQn, (uint32_t)p15_IRQHandler);
    NVIC_EnableIRQ(EINT3_IRQn);
}

void flip1(void) {
    myled1 = !myled1;
}

int main() {
    int i;
    
    /* Don't call this here, see comments below. */
    // p15irq_init();
       
    p16irq.mode(PullUp);
    p16irq.fall(&flip1);   
    
    /* It's ok to call this AFTER the p16 setup above
       because we chain the interrupt. But not BEFORE
       because the InterruptIn library doesn't chain
       to the previous vector if it cannot handle the 
       interrupt. */
    p15irq_init();

    while(1) {
        myled4 = 1;
        wait(0.2);
        myled4 = 0;
        wait(0.2);
    }
}

 

It should be fairly obvious what the problem is from the comments but basically the Mbed InterruptIn library takes control of the interrupt vector in a "total fashion". It doesn't respect the previous contents of the vector and use it if it fails to handle the irq. In the above example, dabbing p15 or p16 will flip the leds as shown. However, if you move the call to p15_init() before the p16 setup, then you're in trouble. First, the Mbed interrupt handler isn't expecting p15 to generate an interrupt, quite right to, it's never been told or setup to handle it.

But then it fails in two respects. First, it doesn't call the old irq vector it replaced. But second, in not doing so, it fails to provide a "default" handler that clears the interrupt. So, if you hit p15 then you basically get stuck in an infinite interrupt loop.

Can the libraries ensure they chain interrupts so as to "play nice" with code that may lie outside of what it's expecting but has a;ready been setup to handle it? Otherwise, we'll have a "use the Mbed libraries, or homebrew, but not both" situation arising. Also, people writing libraries that use low level code my well come unstuck also and find their libraries won't be compat with Mbed libraries.

--Andy

 

 

28 Sep 2010

Hi Andy,

Seems like a good idea to me! As you say, at the moment we simply assume we own it or not, and the chaining example you suggest seems a good solution to try and get more flexible behaviour.

In the meantime, it also shows a workaround if anyone else wants to do this by your custom handler doing the chaining.

Thanks,

Simon

28 Sep 2010

Hi Simon,

Thanks for the confirmation. I'm intending to do a lot of documentation and code sample/snippets in both "native" and Mbed so this is useful information. Also in another thread there's discussion regarding advanced topics so I'm thinking how best to go down that route having gathered information like this and a other things I've found.

On a side note, I'm currently working on SD cards and see you've had some fun already. You can expect me to join those threads at some point. Btw, have you and your Mbed team bought Atmel's entire output of AT45DB161s until next March? Can't get them for love nor money, had to settle on a plentyful but inferior product!

regards,

--Andy

 

 

31 Jan 2017

hi, in mbed testing with MBED_SDK 5.2, test case MBED_28 (interrupt Chaining ) is Failing ,the same is passed with Mbed 2.0 SDK.

interrupt handler is not removing properly in mbed sdk 5.2.

Could you please enplane is this behavior is expected or its bug?

Regards, Arun KR