The interrupt vector table is a key component in ARM Cortex microcontrollers and processors that allows them to respond quickly and efficiently to events. It provides the processor with the memory addresses of handler or interrupt service routines for different interrupts. When an interrupt occurs, the processor can immediately fetch the corresponding handler address from the vector table and jump to the handler code to service the interrupt.
What is an Interrupt?
An interrupt is a signal to the processor that some event has occurred that requires immediate attention. Examples include a timer reaching its count value, data received on a serial port, a key pressed on a keyboard, etc. When such events occur, the associated hardware triggers an interrupt request signal to the processor. If interrupts are enabled, the processor suspends current program execution and invokes an interrupt handler to service the event before resuming normal execution.
Need for Fast Interrupt Handling
Quick interrupt handling is critical in embedded systems and microcontrollers to ensure real-time response. Any delay in servicing high priority interrupts can cause problems such as data loss, motor stalls, etc. Hardware interrupts must have very low latency. The processor should be able to detect the interrupt, identify the source and invoke the corresponding handler code as fast as possible.
Role of Interrupt Vector Table
The interrupt vector table contains predefined addresses of all possible interrupt handlers in a microcontroller. It provides a lookup table for the processor to quickly find the appropriate handler for any interrupt. Typical steps when an interrupt occurs are:
- The interrupt request signal along with the interrupt number is sent to the processor by the interrupt-generating hardware.
- The processor finishes executing current instruction, suspends main program execution, and jumps to the interrupt vector table.
- It looks up the address corresponding to the interrupt number.
- The handler address is loaded and the processor jumps to that location in code memory.
- The corresponding interrupt service routine code executes.
- After handling the interrupt, the handler executes a return instruction to resume main program execution.
Interrupt Vector Table Structure
The interrupt vector table resides in code memory which is often flash memory in microcontrollers. Its location is predefined for each processor family. For Cortex-M CPUs, it starts at memory address 0x0000_0000.
Each entry in the vector table is 4 bytes – the memory address of an interrupt handler function. The order of entries corresponds to the interrupt request numbers. For example, the first entry holds the address of Stack Pointer initialization code. The second entry is address of the Non-Maskable Interrupt handler and so on.
A sample vector table structure for a Cortex M3 processor with 5 interrupts would be: 0x0000_0000: Stack Pointer Value 0x0000_0004: NMI Handler Address 0x0000_0008: HardFault Handler Address 0x0000_000C: Interrupt Handler 1 Address 0x0000_0010: Interrupt Handler 2 Address 0x0000_0014: Interrupt Handler 3 Address
Thus the vector table directly maps interrupt requests to the memory address of corresponding handler code. The processor simply uses the interrupt number as an index and jumps to the retrieved address.
Initializing the Interrupt Vector Table
The vector table is normally initialized during microcontroller startup code. The startup code executes on first power on and performs chip initialization. This includes:
- Configuring Stack Pointer
- Setting up vector table entries with handler addresses
- Enabling exceptions and interrupts
For each expected interrupt, the startup code must populate the table with address of its handler function. These addresses are resolved by the linker at build time. Developers writing handler functions in C/assembly need not worry about addresses, but must ensure the function name matches.
Advantages of Interrupt Vector Table
- Fast interrupt response – Direct table lookup eliminates any software overhead to dispatch interrupts.
- Easy to manage multiple interrupts – Adding new interrupts just needs adding a new entry without any code modifications.
- Facilitates prioritization – Higher priority interrupts can appear earlier reducing response time.
- Flexible associations – Interrupts can be freely associated with any handler function.
- Hardware agnostic – Software doesn’t need to know interrupt sources. Code works across device families.
Interrupt Latency
The use of an interrupt vector table ensures minimum interrupt latency, which is the time from interrupt assertion to start of handler execution. This is because:
- No instruction decoding or fetching is needed to determine the handler.
- Jumping to table entry is a single-cycle operation.
- Table fetch and jump overhead is same for all interrupts resulting in fixed worst-case latency.
Overall latency depends on the underlying hardware but ranges from under 10 clock cycles to few tens of cycles. This ultra low latency enables Cortex-M cores to deliver real-time performance.
Modifying Interrupt Vector Table at Runtime
Though the vector table is initialized at startup, its contents can be modified during runtime by software. This allows changing interrupt associations dynamically.
For example, a common use case is switching stack memory region for an interrupt. This just requires modifying the corresponding vector table entry to point to a function that sets up the alternative stack. The system call to change the interrupt stack would:
- Disable Interrupts
- Read the current handler address from the vector table
- Write the address of stack switching function instead
- Re-enable Interrupts
Now when the interrupt occurs, the switching function will execute first followed by the original handler.
Similar approaches can be used by an RTOS to dynamically insert hook functions, change priorities or reroute handlers at runtime as needed.
Linked List Structure
Some microcontrollers allow chaining vector table entries to linked lists instead of fixed handler addresses. Each entry then holds the address of a stub function which loads the next handler address from a data structure and jumps to it. This allows completely dynamic interrupt handling.
Weak Linking of Handlers
To facilitate modifying the vector table, the interrupt service routines are often declared as weak functions rather than standard functions. Weak linking means that if the startup code contains an alternative function address for that vector slot, it will override the weak routine and link to the new function. void __attribute__ ((weak)) NMI_Handler() { // NMI Handler Code }
This approach is used by various IDEs and chip vendors to allow easy remapping of interrupts to user functions.
Customizing Interrupt Handler
Users can customize interrupt handling in various ways by manipulating the vector table:
- Change handler priorities by reordering table entries.
- Map unused interrupts to a dummy handler to catch errors.
- Map multiple sources to a shared handler for consolidated handling.
- Insert an execution profiler or statistics routine for interrupts.
- Remap specific interrupts dynamically at runtime.
This flexibility enables software to tailor interrupt management as per application needs.
Conclusion
The interrupt vector table is a key hardware acceleration feature for fast interrupt response in Cortex-M processors. It enables each interrupt to be directed to its handler function with minimal latency through direct table lookup. The ability to remap handlers dynamically provides flexibility to optimize interrupt handling as per usage context. Proper utilization of the vector table is essential to building responsive real-time embedded systems using ARM processors.