|
|
View previous topic :: View next topic |
Author |
Message |
Hans Wedemeyer
Joined: 15 Sep 2003 Posts: 226
|
When Interrupts collide |
Posted: Sat Jan 06, 2007 11:18 am |
|
|
I have to do a project which requires two asynchronous signals to be accumulated with no lost counts.
Luckily the signals are not high frequency about 500mS and 100mS
Initially I'm planning to use EXT_INT for the slower signal and INT_TIMER1 for the slightly fast signal.
I anticipate there will be times when interrupts collide.
So I’m trying to figure out the best or preferred or correct way to ensure no counts are missed.
Is there a "sure fire way" to handle the situation when an interrupt collisions occurs ?
Is it OK to do code for the un-handled interrupt in the other ISR or is it best to handle it outside in main ?
Will this work ?
#BYTE PIR1 = 0XF9E
#BIT TMR1IF = PIR1.0
#byte INTCON = 0XFF2
#bit INT0IF = INTCON.1
int32 ExtCounter;
int32 T1Counter;
////////////////////////////////////////////////////////////////
//
#INT_EXT
EXT_isr()
{
ExtCounter++;
if (TMR1IF) // is set then INT_TIMER1 has not been handled
{
T1Counter++;
clear_Interrupt(INT_TIMER1);
}
}
////////////////////////////////////////////////////////////////
//
#INT_TIMER1
TIMER1_isr()
{
T1Counter++; // totalizer finer resolution is in the 16 bit counter registers
if (INT0IF) // is set then INT_EXT has not been handled
{
ExtCounter++;
clear_Interrupt(INT_EXT);
}
} |
|
|
Mark
Joined: 07 Sep 2003 Posts: 2838 Location: Atlanta, GA
|
|
Posted: Sat Jan 06, 2007 12:52 pm |
|
|
You wouldn't lose the interrupt. Instead you would just get back to back interrupts. You can use the #int_global to create a global interrupt handler and then check for the 2 interrupts inside of it. This would probably be the cleanest method. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Sat Jan 06, 2007 1:29 pm |
|
|
I did the same thing that you're doing, the code shown in this thread:
http://www.ccsinfo.com/forum/viewtopic.php?t=906
Using #int_global means you have to write your own interrupt dispatcher.
That seems like a more high risk approach. |
|
|
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
|
Posted: Sat Jan 06, 2007 2:16 pm |
|
|
I don't like the given examples where an interrupt handler also checks for another interrupt to be active. These examples will give the shortest response time possible, but reponse time was not mentioned as a requirement. Problem with the given examples is that they are more difficult in maintenance, for the current two interrupts it will do but imagine how more complicated it will become when a third interrupt will be added in a later stage.
I suggest to use the standard interrupt dispatcher. No simultaneous interrupts will be lost, they will be handled 'back to back' as Mark already mentioned. Only disadvantage is about an extra 100 instruction cycles overhead, but who cares for this very rare case at these low frequencies? The small but rare overhead you can save is not worth the added complexity of the given examples. |
|
|
Hans Wedemeyer
Joined: 15 Sep 2003 Posts: 226
|
|
Posted: Sat Jan 06, 2007 2:23 pm |
|
|
PCM programmer wrote: | I did the same thing that you're doing, the code shown in this thread:
http://www.ccsinfo.com/forum/viewtopic.php?t=906
Using #int_global means you have to write your own interrupt dispatcher.
That seems like a more high risk approach. |
Thanks for reminding me about that thread.... Yes this is a similar issue and perhaps I can do something with this. |
|
|
Mark
Joined: 07 Sep 2003 Posts: 2838 Location: Atlanta, GA
|
|
Posted: Sat Jan 06, 2007 2:31 pm |
|
|
PCM programmer wrote: | I did the same thing that you're doing, the code shown in this thread:
http://www.ccsinfo.com/forum/viewtopic.php?t=906
Using #int_global means you have to write your own interrupt dispatcher.
That seems like a more high risk approach. |
I was thinking about the #int_default. It will generate the code to save and restore the registers. |
|
|
Hans Wedemeyer
Joined: 15 Sep 2003 Posts: 226
|
Based upon experience I'm not sure this is corret ! |
Posted: Sat Jan 06, 2007 3:11 pm |
|
|
ckielstra wrote: | I don't like the given examples where an interrupt handler also checks for another interrupt to be active. These examples will give the shortest response time possible, but reponse time was not mentioned as a requirement. Problem with the given examples is that they are more difficult in maintenance, for the current two interrupts it will do but imagine how more complicated it will become when a third interrupt will be added in a later stage.
I suggest to use the standard interrupt dispatcher. No simultaneous interrupts will be lost, they will be handled 'back to back' as Mark already mentioned. Only disadvantage is about an extra 100 instruction cycles overhead, but who cares for this very rare case at these low frequencies? The small but rare overhead you can save is not worth the added complexity of the given examples. |
I think there is still a chance that two signals can cause one of the interrupts to be masked or lost...
About a year ago I was doing a simple project where a GPS 1PPS was connected to the INT_EXT and there was also a TIMER_1 running at about 250 mS.
The entire code was driven by the 1PPS .
Occasionally the program would stop, and upon investigation I found the INT_EXT IF was set and never got serviced. !
Adding a simple check in the main() code for the EXT_INT flag and my own flag allowed me to call clear_interrupt(INT_EXT); and the problem was solved.
Yet you are telling me if my code just waited long enough it would service the INT_EXT some time in the future...... Well when the code stopped I can assure you the INT_EXT IF remained set and never got serviced for hours.... !
That experience led me to ask this question today....
Please explain what I'm missing here... |
|
|
Hans Wedemeyer
Joined: 15 Sep 2003 Posts: 226
|
|
Posted: Sat Jan 06, 2007 3:18 pm |
|
|
Mark wrote: | You wouldn't lose the interrupt. Instead you would just get back to back interrupts. You can use the #int_global to create a global interrupt handler and then check for the 2 interrupts inside of it. This would probably be the cleanest method. |
As I replied to another post. I never have trusted the hardware/CCS to do what you suggest.
I have experienced lost (i.e unserviced) interrupts as I explained.
This project needs to count pulses and be sure nothing is missed.
Perhaps I should rig up a test with controlled signals and test the code.
Pump in known number of pulses for each signal and see what the results are. |
|
|
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
|
Posted: Sat Jan 06, 2007 3:38 pm |
|
|
Quote: | Occasionally the program would stop, and upon investigation I found the INT_EXT IF was set and never got serviced. ! | This sounds like a PIC internal hardware error. With INT_EXT set and unmasked there should be nothing able to stop the interrupt occurring.
Just curious, which PIC with which wafer stepping were you using? |
|
|
Ttelmah Guest
|
|
Posted: Sat Jan 06, 2007 3:48 pm |
|
|
It is basically impossible to miss interrupts, _except_ if the total time taken in any handler, plus the time needed for the global handler code, is longer than the interval between any interrupt, or the input signal, does not last long enough. This varies with the PIC, and the interrupt involved. For example, the 'port changed' interrupt, must be held for four entire clock cycles, while the INT pin typically only needs 25nSec.
I have hundreds of systems, some of which have been servicing typically 15000000+ interrupts a day, from multiple sources, and have never seen even one missed (Usually 100 clock counts per second, plus about thirty received, and similar number of transmitted characters - both handled with interrupts, plus SPI comms, plus keypad operation).
The interrupt flag, is standard logic. A simple hardware flip flop. If this is not being triggered, it is because the signal does not meet the signal/timing requirements.
Best Wishes |
|
|
Hans Wedemeyer
Joined: 15 Sep 2003 Posts: 226
|
|
Posted: Sat Jan 06, 2007 4:14 pm |
|
|
Ttelmah wrote: | It is basically impossible to miss interrupts, _except_ if the total time taken in any handler, plus the time needed for the global handler code, is longer than the interval between any interrupt, or the input signal, does not last long enough. This varies with the PIC, and the interrupt involved. For example, the 'port changed' interrupt, must be held for four entire clock cycles, while the INT pin typically only needs 25nSec.
I have hundreds of systems, some of which have been servicing typically 15000000+ interrupts a day, from multiple sources, and have never seen even one missed (Usually 100 clock counts per second, plus about thirty received, and similar number of transmitted characters - both handled with interrupts, plus SPI comms, plus keypad operation).
The interrupt flag, is standard logic. A simple hardware flip flop. If this is not being triggered, it is because the signal does not meet the signal/timing requirements.
Best Wishes |
I respect your opinion, but the GPS RX that was used had a (correction not 100mS ) 4uS low pulse. The ISR simply set a flag and nothing else. The flag is monitored in the main() and when set would trigger the rest of the code.
That program did not do very much, and when it "stopped" I was the firts to be amazed...
I added code to flip flop a spare pin and monitored it with my scope. When the code stopped the pin remained at either 1 or 0 and never changed state even though the second channel of the scope showed a clean (correction not 100mS ) 4uS 1PPS at the PIC pin.
After that experience I got defensive about PIC interrupts
The pin had a 10K pull-up resistor.
GPS was a Trimble Lassen IQ and PIC was PIC18LF6720 @ 16MHz The PIC was far more horse power than the project needed, I tend to stick with few chips... Better work with the devil I know....
Just checked that old project and it was before I added the 2 NOP offset for the reset vector as called for by an earlier Errata sheet and still recommend by Microchip tech support.
If I ever get back to that project I could add the 2 NOP offset and see if it fixes the problem.
That was also the time I had PWM outputs dying and Microchip tech-support offered no solution. Again one of those problem I was told could never happen.... !
For a while I tested each chip.... then found (stumbled onto) a fix that was so simple.
Each time I found a chip with the PWM problem I applied the fix and it cured it each time... In the end I stopped testing the chip and made the fix permanent. |
|
|
Ttelmah Guest
|
|
Posted: Sat Jan 06, 2007 4:23 pm |
|
|
The problem here, is that if there is a hardware problem in the PIC, no amount of fiddling with the code is going to help, unless (as with the NOP), it is not a problem with triggering the reset flag, but the actual code jump that is triggered. Hence 'being defensive', is really pointless.
Get a really good logic logging system, set a system up, and test it for real. You can program the logger to trigger on the interrupt event, and see if the handler does respond with total reliability or not. Even cruder, get a simple up/down counter module (the little LCD ones). Have the event that is meant to trigger the interrupt trigger the 'up' counter input, and have the handler toggle a pin on the down counter input. Leave it running for a day or two, and see if the counter is anything but 0/1. If it is, there is a problem, otherwise leave well alone, and get on with the other parts of the project...
Best Wishes |
|
|
Hans Wedemeyer
Joined: 15 Sep 2003 Posts: 226
|
|
Posted: Sat Jan 06, 2007 4:31 pm |
|
|
Ttelmah wrote: | The problem here, is that if there is a hardware problem in the PIC, no amount of fiddling with the code is going to help, unless (as with the NOP), it is not a problem with triggering the reset flag, but the actual code jump that is triggered. Hence 'being defensive', is really pointless.
Get a really good logic logging system, set a system up, and test it for real. You can program the logger to trigger on the interrupt event, and see if the handler does respond with total reliability or not. Even cruder, get a simple up/down counter module (the little LCD ones). Have the event that is meant to trigger the interrupt trigger the 'up' counter input, and have the handler toggle a pin on the down counter input. Leave it running for a day or two, and see if the counter is anything but 0/1. If it is, there is a problem, otherwise leave well alone, and get on with the other parts of the project...
Best Wishes |
Well that clear_interrupt() call in main() fixed that gps project problem...
I agree with this one I need serious testing as I posted earlier.
Thanks |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|