Article: Writing An ISR
Interrupt Service Routines(ISR) are important and often critical pieces of code in any Embedded Design. An ISR basically executes when an Interrupt is generated. Now an Interrupt can be generated due to the occurance of a specific event. The event is usually asynchronous in nature (can occur anytime) as far as the microcontroller is concerned. The event can be anything- a timer expiring or an ADC input etc. To truly understand the critical nature of an ISR, it is important to understand that when an interrupt occurs, the microcontrollers stops executing normal code and enters the ISR code. Now the normal code being executed could be performing a trivial task or a critical time sensitive task.So basically an Interrupt is like a shock to the system. It is the job of a good designer to make sure the shock is as small as possible, while at the same time responding to the event which causes an Interrupt to be generated.Keeping this important fact in mind, the article below lists some points to be taken care of while writing an ISR.
1. Small Code Size
Keep ISR code size as small as possible.It is important to avoid large sections of code within an ISR. For e.g:- avoid lengthy computations at all costs.In most cases ISRs should just set or clear a couple of flags and exit. Changing the state of these flags, should indicate to the main code that an event has ocurred. It is important that the main code is able to acknowledge change in state of flags before the next ISR occurs. If this does not happen, an event can be missed, with sometimes catastrophic consequences.So frequency of ISR related flag checking in main code should depend on how often the Interrupt is expected.
2. Avoid waiting for state changes
ISR should not contain any code which is waiting indefinitely for an event to occur. A typical instance of this happens when it becomes necessary to reset certain hardware registers once an Interrupt ocuurs. This is done in order to rearm or re-activate the interrupt. Such code sometimes sets a certain mode and then checks a flag to see if the mode is correctly set. E.g. of such code is while(!REG1[Bit5]);Such code is a potential Hang waiting to happen and should be avoided at all cost in an ISR.
3. Decide Priority of all ISRs
Priority table must be created in order to decide the priority of all ISRs. The question to be asked while deciding priority is which interrupt should be served first, in case two or more arrive simultaneously.In case there is an Interrupt which cannot be delayed, then Nested Interrupt must be allowed. Nesting basically means that when one ISR is being executed, another high priority Interrupt can occur and in that case ISR of that interrupt will be serviced immediately. To allow nesting or not is a design call and depends on microcontroller capability as well as nature of the Interrupt in question.
4. Protect critical sections of code
While writing ISRs it is important that critical sections of code within the main flow are protected. Critical sections are those code snippets in main code which cannot be interrupted if an ISR occurs. Since ISRs occur at any time, it is important that these sections are protected from interruption. Interrupting critical sections may cause Hang or may cause permanent disabling of certain peripherals or features of a controller.
5. Watchdog within an ISR
It is important not to forget the watchdog, whether internal or external within an ISR. It is important to note that ISRs can occur one after the other and so even if one ISR code is small enough not to cause watchdog reset, if ISRs occur one after the other, watchdog timer may expire. So it is important that the dog is tickled at least once during an ISR.