Difference between revisions of "Embedded System Tutorial Interrupts"
(→Setup ISR on SJ-One) |
(→ISR Procedure) |
||
Line 12: | Line 12: | ||
The following steps demonstrate what happens when an interrupt occurs : | The following steps demonstrate what happens when an interrupt occurs : | ||
* CPU manipulates the PC (program counter) to jump to the ISR | * CPU manipulates the PC (program counter) to jump to the ISR | ||
+ | * IMPORTANT: CPU will disable interrupts (or that priority level's interrupts until end of ISR) | ||
* Registers are saved before running the ISR (pushed onto the stack) | * Registers are saved before running the ISR (pushed onto the stack) | ||
* ISR is run | * ISR is run | ||
* Registers are restored (popped from stack) | * Registers are restored (popped from stack) | ||
+ | * Interrupts are re-enabled (or that priority level's interrupt is re-enabled) | ||
On some processors, the savings and restoring of registers is a manual step and the compiler would help you do it. You can google "GCC isr attribute" to study this topic further. On SJ-One board, which uses LPC17xx (ARM Cortex M3), this step is automatically taken care of by the CPU hardware. | On some processors, the savings and restoring of registers is a manual step and the compiler would help you do it. You can google "GCC isr attribute" to study this topic further. On SJ-One board, which uses LPC17xx (ARM Cortex M3), this step is automatically taken care of by the CPU hardware. |
Revision as of 21:08, 2 December 2013
Contents
Introduction
This tutorial demonstrates how to use interrupts on a processor. In general, you will understand the concept behind interrupts on any processor, but we will use the SJ-One board as an example.
What is an interrupt?
- Hardware capability to break normal software flow to attend an urgent request
- "An event that needs immediate attention"
Science
The science behind interrupts lies in the hardware that allows the CPU to be interrupted. Each peripheral in a microcontroller may be able to assert an interrupt to the CPU core, and then the CPU core would jump to the corresponding interrupt service routine (ISR) to service the interrupt.
ISR Procedure
The following steps demonstrate what happens when an interrupt occurs :
- CPU manipulates the PC (program counter) to jump to the ISR
- IMPORTANT: CPU will disable interrupts (or that priority level's interrupts until end of ISR)
- Registers are saved before running the ISR (pushed onto the stack)
- ISR is run
- Registers are restored (popped from stack)
- Interrupts are re-enabled (or that priority level's interrupt is re-enabled)
On some processors, the savings and restoring of registers is a manual step and the compiler would help you do it. You can google "GCC isr attribute" to study this topic further. On SJ-One board, which uses LPC17xx (ARM Cortex M3), this step is automatically taken care of by the CPU hardware.
The SW to HW Connection
Now that we understand how the CPU hardware services interrupts, we need to define how we inform the CPU WHERE our ISR function is located at. There is something called an Interrupt Vector Table. This table is nothing but addresses of functions that correspond to the microcontroller interrupts. Specific interrupts use specific "slots" in this table, and we have to populate these spots with our software functions that service the interrupts.
SJ-One (LPC17xx) Example
Through some magic of the compiler, and the linker script, the compiler is able to place the software interrupt vector table at a specific location that the CPU expects the interrupt vector table to be located at. This connects the dots about how the CPU is able to determine WHERE your interrupt service routines are located at. From there on, anytime a specific interrupt occurs, the CPU is able to fetch the address and make the JUMP.
GCC Magic
In the SJ-One sample project, each ISR is named, but is labeled as a "weak" function. What this means in the land of GCC (compiler) is that unless the same function name is defined somewhere else, the weak function serves as the ISR function. If you do define the function name somewhere else, it will override the "weak" function and the compiler will place the address of your new function into the interrupt vector table.
Setup ISR on SJ-One
The first step is to be able to locate the real-name of the "weak" ISR function. For example, you can locate a UART0 ISR function that is weak, and we will override with our new function. The only thing to keep in mind is that due to "C++ Mangling" of function names, if your ISR is located in a *.cpp file, you will need to enclose it into extern "C" tags. See below for examples:
/***************/
/* my_file.cpp */
extern "C"
{
void UART0_IRQHandler()
{
/* Your ISR */
}
}
/*************/
/* my_file.c */
/* extern tag not needed for a C file */
void UART0_IRQHandler()
{
/* Your ISR */
}
What to do inside an ISR
Do very little inside an ISR. When you are inside an ISR, the whole system is blocked (other than higher priority interrupts). If you spend too much time inside the ISR, then you are destroying the realtime operating system principle and everything gets clogged because of you :(
With that said, here is the general guideline
- Spend as little time as possible. DO NOT POLL FOR ANYTHING.
- If you are using FreeRTOS API, you must use FromISR functions only!
- Most important: Clear the source of the interrupt
- For example, if interrupt was for rising edge of a pin, clear the "rising edge" bit such that you will not re-enter into the same interrupt function.