Embedded Systems: Interrupts
Explaining the hecklers of embedded systems
What is an interrupt?
The literal meaning of interrupt according to the Oxford Dictionary is “stop the continuous progress of (an activity or process)”.
Imagine, you are performing a stand-up comedy set and everything is going smoothly. The setups, punch-lines, everything is landing perfectly and then suddenly, someone from the audience heckles you. It breaks your flow and you have to deal with the heckler in between your set. Once dealt, you can move forward with your set.
That is exactly what an interrupt does in an embedded system also. In a microcontroller, an interrupt will stop the normal program from executing and allow the microcontroller to service that interrupt using special code before it can resume executing the normal code.
What is an interrupt service routine?
An interrupt service routine or better known by it’s abbreviation an “ISR” is code that is written on your microcontroller to service a particular interrupt. It can also be called an interrupt handler.
What is interrupt latency?
The time taken between the generation of the interrupt and the servicing of the particular interrupt is called interrupt latency.
What is an interrupt request?
The hardware signal that is sent to the microcontroller which would stop the executing of the normal code so that the interrupt can be serviced is called an interrupt request. The interrupt request is also better known by it’s abbreviation “IRQ”.
What is the flow of events related to interrupts?
The events that occur are:
- Interrupt request is sent by the peripheral to the microcontroller
- The microcontroller is executing the normal code and will get interrupted by this hardware signal (IRQ)
- The microcontroller will stop executing it’s normal code and jump into a special function called an interrupt service routine (ISR) to service the particular interrupt
- Once the interrupt has been serviced, the interrupt request will be set to low so that the next interrupt can come in. This is particularly done by an operation in the ISR code.
- The ISR code is exited and control is given back to the normal code and the normal execution is resumed.
The diagram below will explain the entire flow of events right from the generation to the servicing of the interrupt.
What are the different types of interrupts?
There are different types of interrupts. They are:
- Hardware Interrupts — A hardware interrupt is one where the interrupt request (IRQ) comes from an external device as an input to the microcontroller. The hardware interrupts can happen asynchronously at any given point during the execution of the program.
Example: A temperature sensor has been programmed such that when the temperature becomes greater than 30 degrees celsius, it should inform the main microcontroller. Now, when the temperature sensor will detect 30 degrees celsius, it will interrupt the microcontroller via an interrupt request and the microcontroller will then service the interrupt from the temperature sensor and perform whatever needs to be done in the ISR before clearing the IRQ line. - Software Interrupts — A software interrupt is one that is called upon by the microcontroller itself when it executes special instructions or when certain conditions are met while executing the code. The most common form of software interrupts are traps and exceptions. Similarly to hardware interrupts, there are special subroutines that are called when software interrupts occur which take care of the certain interrupt.
Example: A divide by zero math error is found while executing the code. The microcontroller will catch this error and throw a divide by zero exception and the code will get interrupted.
What are the different types of triggers for interrupts?
There are two types of triggers based on which interrupts can get generated. They are:
- Level triggered interrupts — The interrupt is detected when the interrupt line is held at a particular level (either high or low level). The hardware signal changes it’s level (goes from high to low or low to high) and this level is held on the interrupt line so that the microcontroller can detect the interrupt. When the microcontroller finishes servicing of the particular interrupt, it commands the interrupt signal to go back to it’s inactive state. The diagram above shows a level triggered interrupt.
- Edge triggered interrupts — The interrupt is detected by the rising or the falling edge of the interrupt line. The hardware signal is driven to the particular edge and after a period of time it is released and goes back to the inactive state. The controller getting this interrupt signal should be able to detect the rising or falling edge of the interrupt signal for edge triggered interrupts to work.
What is interrupt masking?
Interrupt masking is the selective enabling/disabling of certain interrupts. Each interrupt is represented by a bit in the interrupt mask register.
If the corresponding bit is set, then the interrupt is ignored by the host microcontroller, hence the interrupt gets disabled. If the bit is cleared, then the interrupt is enabled and will be serviced by the host microcontroller.
These interrupts which can be masked by using the interrupt mask register are called maskable interrupts. The interrupts which cannot be masked are called non-maskable interrupts (NMIs). The non-maskable interrupts are generally the higher priority interrupts which cannot be ignored by the host microcontroller.
In a way, interrupt masking helps to put the hecklers who will disturb your comedy set on mute, so that you don’t have to spend time dealing with them.
What is interrupt priority?
Certain processors like the ARM cortex processors allow the user to assign software based priority levels to different interrupts. Interrupt priorities can be assigned an 8 bit value and so it will have a range from 0 to 255. The interrupt priority decreases as the interrupt priority number increases.
If two interrupts have the same priority level associated with it, then the pending interrupt with the lower interrupt number, will get serviced first. Example: If IRQ[0] and IRQ[1] have the same priority level of 2, the interrupt IRQ[0] will get serviced first, since it’s interrupt number is lower.
An important point to note is that the software priority levels do not affect the reset, non-maskable interrupts (NMIs) and hard fault. These events will always have the highest priority, higher than the software based interrupt priorities.
What are the main points to remember while writing an ISR?
There need to be some points that need to be kept in mind while writing an ISR. They are:
- Keep the ISR as short as possible
- Do not perform print and logging operations inside the ISR
- Do not re-enable interrupts in the ISR
- Do not use long/large loops inside the ISR
- Do not use semaphores or mutexes inside the ISR
- Make sure to account for the interrupt source as early as possible in the ISR
- If dealing with timestamped interrupt based data, timestamp the interrupt source at the start of the ISR
The main point to remember always is to try and manage to keep the heckling interaction as short as possible.
When an RTOS is running, how do you service the interrupt?
When using an RTOS, you can handle the interrupt in many ways. One thing to remember is that if a lot of time is spent in the ISR, the threads/tasks are being starved from CPU time and hence that can cause problems in your system.
Thus, the ISR should be as short as possible since the rest of the system is halted when the hardware interrupt is being serviced.
In an RTOS environment, you can make use of RTOS features to help the handling of the interrupt. Generally, the ISR is kept very short because of the RTOS features present.
As soon as the interrupt occurs, the ISR basically records the source/timestamp of the interrupt and will just put the interrupt event into a queue and send it to the respective task. The queue can be any type of messaging system that the RTOS is using, like a pipe, mailbox, queue, etc. After posting the interrupt event to the correct task, the ISR is exited and the RTOS resumes running it’s tasks.
The corresponding task on receiving the interrupt event will then have a separate event handler to handle the interrupt event. Based on the priority of the interrupt, the priority of the task should also be decided so that there is not a lot of latency between the interrupt source and the handling of the interrupt.