One might think that statement is facetious but on more than one occasion in the last year the author has worked with an organisation whose coding standard strictly said something like “Interrupts are to be avoided at all costs and manager approval must be obtained before their use”. This seems absolutely silly! Interrupts are an important instrument for designing embedded software so what is all this fuss about?
It is undoubtedly true that in the past some developer disobeyed the design rules and patterns for writing good interrupt service routines and a costly and chaotic debug session occur. The result was that the company swore off using interrupts unless it was absolutely necessary and decided that polling was a better solution. There are of course many problems with this decision. Polling is very inefficient. Rather than putting a processor to sleep to conserve energy the processor must always be awake looking to see if an event has just occurred. Even worse, without interrupts, the real-time response of the system could be compromised!
Strange things can certainly happen to a system if proper interrupt implementation is not followed. It is absolutely guaranteed thanks to Murphy that this strange behaviour will happen at the most inopportune time. So what can be done to ensure that interrupts are implemented properly and utilised as they were meant to be?
Tip #1 – Create an ISR Table
An interrupt service routine table is an array that contains a list of every possible interrupts that can occur on the microcontroller. Each interrupt is populated with the function (pointer to a function) that is executed when the interrupt occurs. There are many advantages to doing this. The first is that it becomes very easy to assign a function call to an interrupt. Simply change the function name in the table, recompile and now that function is called when the interrupt occurs.
Next, the programmer is forced to include a function for every interrupt. This is a good practice because every interrupt gets initialised with code! During debugging if an errant interrupt occurs rather than jumping off and executing unknown code, a “DummyISR” could be executed instead. This allows for that errant interrupt to be trapped and debugged. Finally, using an interrupt table in this manner forces the interrupt code to take on an organised structure that is easy to understand and configure.
There are many different ways in which the table can be implemented. The most common is through the use of #pragma. This allows the table to be placed at a specific memory location in flash. The two implementations that are most common are to allow the starting address of the flash location to be specified or a linker memory label to be defined. Using #pragma is something that a developer should try to avoid but if this is the only method available to implement the interrupt table then this would be a good exception to the rule. An example of such a table can be found in Figure 1.
Figure 1 – Interrupt service routine table