I have come across a problem with a spurious external interrupt on a BL2600 processor board (RCM3200). I have Int0 configured to trigger on the falling edge of an input pulse on PE4 with a priority of 2.
WrPortI( I0CR, &I0CRShadow, 0x10 + 0x2 );
The input signal is normally high (5.0V) and pulses low for 7us to generate the interrupt. A counter in the ISR shows two counts for each input pulse where there should only be one.
I added some code at the start of the ISR to toggle an output bit each time it fires. Actually that was the only code in the ISR for this test. When I scope out the pulse input and toggle output signals, I can see that the ISR usually fires on both the falling and rising edges of the input when it crosses the 2.0V threshold. Sometimes the ISR fires twice on the rising edge alone. The external input signal has about 1us fall time and 500us rise time.
I added an external 2K2 pull up resistor to 5.0V for the PE4 input which reduced the input signal rise time from 500us to 50us. This eliminated most of the spurious triggers but it still happens fairly regularly, maybe once in 10-20 interrupts compared to practically every one.
We already have a number of boards in the field so adding an external resistor as a fix is less than ideal. Spurious interrupts are still occurring anyway and I need to eliminate them. This seems more like a hardware glitch on the R3000 processor input pin (no hysteresis?). Is there some way to prevent the interrupt from firing on a slow rising edge as it crosses the input switching threshold? I’m looking for a software solution here rather than any hardware changes.
I recommend making your ISR routine as short as possible and if possible in assembly only. You could be running into latency issues.
From an Ask Larry article on ISR’s:
The main design goal of most ISRs should be to execute as quickly as possible. Usually this means that they should have a minimum of instructions. An ISR written in C, in most cases, will violate this goal. In general, you have very little idea as to how long C statements take to execute. This is mainly due to the compiler inserting function calls into the compiled C code. I usually tell customers that there is roughly a 5 to 1 ratio in execution time between C and assembly language.
Here are a few guidelines for writing ISRs:
•Write the ISR in assembly language.
•Do not have any looping constructions.
•Determine the clock cycles for each instruction and add them so you know how long the ISR takes – don’t forget to take into account the interrupt latency time! Worst case interrupt latency for the Rabbit® processors is 30 clocks.
•Set the Interrupt Priority Level (IPL) appropriately – in most cases the lowest active level.
•Determine the percentage of CPU time the ISR is going to take. This may not be easy but is worthwhile. This will give you an idea of what percentage of processor time is going to be used by the USR.
We once received code from a customer who had a “very short ISR written in C” only to find that the ISR called a library function that included thousands of lines of C code. It certainly looked short on the screen, but the code he was running was anything but.
One solution to this issue may be to disable the interrupt in the ISR and re enable it a set time later. It will really depend on the frequency of the pulses you are triggering on. If the time between pulses is relatively long then you can avoid the glitches by triggering on the first instance and not re enabling the interrupt until the you are sure the pulse is finished.
Alternatively, you can trigger on the first event and record the trigger time, then only fully service events which occur after the minimum time has elapsed and exit the ISR early if an interrupt is triggered before the minimum time.
Thanks for the suggestions. I currently set a flag when the interrupt is entered and clear it later when an external task is complete. Any interrupt that occurs while the flag is still set is an error and I ignore it.
I might try disabling the interrupt when the ISR is fired and setting it again when the flag gets cleared but just ignoring it for now seems to be working.