|
||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
|
|
Catching the Overrun Sometimes the hardest problems to find in a design are the problems that happen once in a great while and don't seem to repeat with any regularity. I have experienced such problems before because of overtaxing a processor. Most of my projects calculate all their timing off a single timing interrupt
that is divided into different time slots for different processes in the design. If all my processes don't complete in the time allotted to them, I will
see problems in feedback calculations and control calculations, and I will have communication problems.
Since there are many elements to a design, I first need to have a way to determine what type of problem exists and then see how to fix the problem. I may have had some suspicion that I was running into interrupt overruns, but I had to devise a plan on how to catch the problem. I've since taken a closer
look at my current designs to see if they are on the verge of running into similar problems, and have found that I need to be more aware of how much free
processing time I have to spare.
Interrupt processing involves stopping normal code execution and taking time to execute another section of code before continuing. This section of code
is called the interrupt service routine (ISR). During the execution of the ISR, other interrupts are often disabled. An interrupt causes a problem if its
service routine's execution time exceeds the time allotted before another interrupt is pending. For example, you might have a timer that triggers an interrupt once every 100 µs. If it takes 150 µs to service the interrupt (execute its ISR), you will have the next interrupt due 50 µs
before you have finished the routine. Since interrupts are disabled until you finish the ISR, the next execution of the ISR will be 50 µs late. That
might be acceptable. If subsequent interrupts don't take as long to execute, then the processor might have a chance to catch up without a serious problem.
However, if the ISR continues to take longer than 100 µs to execute, then the interrupt lag will continue to grow.
Depending on the design, when a lag in the execution of the ISR continues to grow, it can present another potentially nasty situation. Once the interrupt
lag grows to more than 100 µs, or if any individual interrupt takes longer than 200 µs to execute, then an interrupt isn't executed at all. The
timer will set the pending flag for the interrupt sometime during the ISR, and then set it again sometime before the ISR execution has completed. Once you
return from the interrupt, your processor recognizes that the pending flag has been set, but doesn't know that it was actually set twice. Therefore, it
executes the interrupt only once and you have missed executing the other interrupt. If you are basing all your timing off this interrupt, this can spawn a
plethora of hard-to-find problems.
There are various ways to catch a problem such as an interrupt overrun. I would like to mention a few that I've used to see when the problem exists. Adding
up machine cycles for every instruction in a design that has several hundred lines of code and various paths of execution is impractical. I have often used a
spare output pin temporally to toggle high upon starting the interrupt routine and then toggle low when I exit the routine. A scope on that pin will show you
the approximate execution time of the routine. Watching the scope for a while can build your confidence of whether or not your routine is experiencing any
overrun conditions. I would recommend, if possible, setting your scope to trigger on the positive width of the pulse being greater than the allotted time for
the interrupt to execute.
If your interrupt is extremely fast, or if you are having a hard time seeing the wide pulse on the scope, then you could use a counter to look at ISR jitter.
ISR jitter is my term for how the ISR execution time varies from one interrupt to the next. A software PWM is great at showing ISR jitter. What you have is code
that sets up a counter at the same time that it sets an output pin high. The counter decrements once every interrupt until it reaches zero, whereupon the output
pin is set low. The ratio of the counter value to the number of counts before the pin is set high again forms the PWM ratio. Here's a quick example using National
COP8 code embedded within the ISR of a timing interrupt that trips every 100 µs.
;This section takes care of turning on the The code above sets up an output pin to have a pulse-width ratio of 80% with a frequency of 100 Hz. If you set up your scope to trigger on the rising edge
of this output pin, then you will see the ISR jitter. The falling edge of the PWM will bounce back and forth, manifesting the variance in ISR execution time.
What you need to watch for is jitter that exceeds 100 µs. If you see excessive jumps like this, then the interrupt has overrun and problems can be
around the corner. There is a 20% chance that a problem could fall in the 20% low time and be missed in this capture, but you can improve those odds by
increasing the pulse width.
If your design doesn't allow you to stare at the scope for hours on end and you have some spare code space and a byte of RAM, you might consider putting a
section of code in your interrupt section to detect overrun conditions. If your design includes some outside communication to read locations or have a debug
display that can show a counter, you can also get an idea of how repetitious the problem is. Here's an example, again in National code.
int_overrun: The overrun counter increments each time that interrupt is in danger of being late in subsequent executions of the ISR pointing you to danger areas.
Enjoy!
Guides and Experts Analog
Avenue EDA Tools PLD DSP EDA Embedded
Systems Power Test
|
|||||||||||||||||||||||||||||||||
|
Copyright © 2003 ChipCenter-QuestLink About ChipCenter-Questlink |
||||||||||||||||||||||||||||||||||