I was recently working on an interrupt that was asserted, but the system didn’t respond by handling the interrupt. The interrupt that wasn’t being handled came from a CPLD into a GPIO pin. The CPLD asserts the interrupt in response to several external events. I thought that this would make a good example of what not to do in an ISR.
If only one of the external events was triggering, then the interrupt seemed to work well.   If more than one triggered, not necessarily at the same time, then eventually the interrupt stopped being serviced. Seemed like the system never saw the interrupt, but of course it is handled in hardware so that seemed unlikely.
I reviewed the code. Here is what it did in response to this interrupt:
In the ISR:
1.       Clear the GPIO interrupt from the CPLD
2.       Mask off the interrupt in the CPLD, so that other interrupts to the CPLD can cause the interrupt when they arrive
3.       Clear the interrupt in the CPLD
In the IST:
1.       Handle the source of the interrupt
2.       Call InterruptDone
In InterruptDone
1.       Mask all interrupts to avoid read/modify/write errors from the ISR
2.       Re-enable the interrupt in the CPLD
3.       Clear the GPIO interrupt from the CPLD
4.       Re-enable the interrupt from the CPLD, which was never disabled
5.       Re-enable all interrupts
Do you see where the problem is? Neither did I for a couple of days. I poked around the system, when this failed the interrupts where all enabled, but not asserted. Not asserted? Well that turned out to be my test application detecting the problem and “fixing” it by reinitializing the external hardware so it actually made sense.
Actually if you read through what it is doing and only think about one signal into the CPLD, it does work. Well, sort of but only if the external interrupts are spaced apart, which they were.
The real problem is step #3 of handling InterruptDone. To understand, realize that we can only execute step #1 if the interrupt is not asserted, if it was asserted we would be in the ISR not in InterruptDone. After step #1, the interrupt can assert without going to the ISR. If it does assert before completing step #3, then the interrupt is cleared and the interrupt controller will not signal the ISR to run.
Copyright © 2008 – Bruce Eitman
All Rights Reserved