The Nested Vectored Interrupt Controller (NVIC) is the interrupt controller used in ARM Cortex-M series processors. It provides low latency exception and interrupt handling, and manages interrupts in a hierarchical priority-based scheme. The NVIC allows for fast, deterministic interrupt processing and reduced interrupt latency compared to traditional interrupt controllers.
What is an Interrupt Controller?
An interrupt controller is hardware that manages interrupt requests in a microcontroller or microprocessor system. It prioritizes incoming interrupts, determines which ones need to be handled at a given time, and dispatches them to the processor for handling. This allows the processor to focus on its main tasks while the interrupt controller deals with managing and coordinating external events that require the processor’s attention.
Some key responsibilities of an interrupt controller include:
- Receiving interrupt requests from peripheral devices or internal sources
- Prioritizing interrupts based on programmable priority levels
- Deciding which interrupt should be handled when multiple requests are pending
- Signaling the processor that an interrupt is pending
- Passing interrupt vectors to the processor so it can run the associated interrupt service routine (ISR)
- Masking lower priority interrupts while a higher priority one is being serviced
- Keeping track of interrupt status and handling nested interrupts
Having a dedicated interrupt controller offloads these responsibilities from the main processor, allowing it to focus on main program execution unless an event requires its attention via an interrupt.
Key Features of the NVIC
The NVIC has several key features that enable deterministic, low latency interrupt handling in Cortex-M processors:
- Prioritized Interrupts – Each interrupt source can be assigned a priority level, allowing higher priority interrupts to preempt lower priority ones. The NVIC handles priority resolution, interrupting the current ISR to service a higher priority interrupt.
- Nested Interrupts – The NVIC allows interrupts to nest and preempt each other. For example, a very high priority interrupt can preempt a lower priority ISR without waiting for it to finish.
- Tail-chaining – The NVIC can chain interrupt service routines back-to-back for low latency processing.
- Vector Table Relocation – The interrupt vector table can be placed in RAM instead of flash, allowing dynamic reconfiguration.
- Power Management – The NVIC monitors interrupts and can wake up the processor from low power mode when service is required.
- Flexibility – NVIC offers extensive flexibility in programming interrupt priority levels, power management options, and interrupt gating.
These capabilities allow the NVIC to enable real-time, latency-sensitive application development. The prioritized, nested interrupt handling minimizes delay and jitter when handling peripheral events and interrupts.
The NVIC consists of the following key hardware components:
- Interrupt Grouping Logic – Groups and gates interrupts to prevent overwhelm.
- State Registers – Track interrupt status, masking, and priority configurations.
- Priority Encoder – Encodes the highest pending interrupt for processing.
- Interrupt Distributor – Routes interrupts from peripheral to the NVIC.
- Processor Interface – Signals the processor to handle an interrupt.
The interrupt distributor receives interrupt requests from the various peripherals and sources. It gates or masks interrupts based on configurations before passing them to the interrupt grouping logic. Here, related interrupts can be grouped to prevent duplicate handling.
The state registers contain status information for each interrupt and configurable settings like priority level and masking. The priority encoder analyzes pending interrupts and encodes the highest priority one for handling. It signals the processor interface to notify the core processor.
The processor interface contains the vector table, which holds the addresses of the ISRs. It fetches the appropriate ISR address based on the encoded interrupt and passes it to the processor along with the interrupt request signal. This architecture allows fast determination and low latency dispatching of pending interrupts.
Vector Table and Interrupt Handling
The NVIC makes use of a vector table containing the memory addresses of interrupt service routines. The vector table is usually placed in flash memory. However, the NVIC also allows you to relocate the vector table to SRAM at runtime for flexibility.
When an interrupt occurs, the NVIC determines the highest priority pending interrupt. It uses this interrupt number as an index into the vector table to retrieve the address of the corresponding ISR. This address is sent to the processor core, which will branch to the ISR to handle the interrupt.
When the ISR completes, program flow returns to the main application where it left off. The NVIC takes care of stacking register context to resume execution after the ISR. This approach of using a vector table for fast ISR lookup reduces interrupt latency compared to polling schemes.
The vector table approach also enables tailored handling of different interrupt sources by assigning a specific ISR to each. The number of vectors in the table matches the number of available interrupts in the Cortex-M device. For example, a Cortex-M4 supports up to 240 interrupt sources.
A key feature of the NVIC is support for nested interrupts. This means that a higher priority interrupt can preempt a currently running ISR immediately, without having to wait for it to finish. When the higher priority ISR completes, the NVIC returns to the original preempted routine.
Nested interrupts are made possible by automatic stacking of register context by the NVIC. When an ISR is first invoked, the NVIC pushes processor registers to the stack to save state. If a higher priority interrupt arrives, it will push the current stack pointer to save the preempted ISR state. This stacking allows arbitrary levels of nesting while maintaining the ability to return to the correct ISR once servicing completes.
Without support for nesting, interrupts would have to be serviced sequentially based on priority, even if critical events arise during lower priority ISR execution. This would increase worst-case interrupt latency and jitter, making real-time response more difficult.
Tail-chaining is another technique supported by the NVIC to reduce interrupt latency. It allows back-to-back interrupt servicing without needing to return from the ISR.
When an ISR completes handling an interrupt, instead of returning to the main program, it can chain directly into the next pending ISR. This saves the overhead of pushing and popping stack frames when context switching between ISRs.
To utilize tail-chaining, the ISR must end with a special instruction to chain to the next vector address rather than returning normally. When chaining, the NVIC also passes key register contents like LR and PC between ISRs so execution state is maintained.
Tail-chaining is useful in reducing worst-case latency and improving determinism when handling streams of high frequency interrupts.
The NVIC allows configuring interrupt priorities to dictate the handling order when multiple interrupts are pending simultaneously. This helps ensure critical interrupts get serviced first.
Each interrupt source can be assigned a priority from 0 (highest) to 255 (lowest) in steps of 16. The NVIC hardware internally maps these priority levels to the following priority bits:
- 0 to 3 for priority levels 0 to 15
- 4 to 7 for priority levels 16 to 255
Setting an interrupt priority to level 0 assigns it the highest preemptive priority. Level 1-15 are for critical interrupts that still need low latency servicing. Levels 16-255 are for more general interrupts that can tolerate some additional latency if needed.
The application developer is responsible for setting the NVIC priorities appropriately so that time-critical interrupts are handled faster. This prevents less important interrupts from delaying critical tasks and helps meet real-time requirements.
Interrupt Masking and Pending Status
The NVIC provides masking and pending status registers to allow flexibility in interrupt handling:
- Interrupt Mask Registers – Used to mask/unmask interrupts. Setting a mask bit disables that interrupt source.
- Interrupt Pending Registers – Indicate interrupts that are pending but may be masked.
- Active Bit Registers – Indicate which interrupts are actively being serviced.
Masking allows you to ignore interrupts from a peripheral temporarily if you do not want to handle them. Pending bits let you check for interrupts that arrived but may have been masked. You can then unmask and handle them later when convenient.
These registers give software flexibility in managing interrupt sources beyond just priority. Peripheral interrupts can be gated on and off based on the current application needs.
In addition to peripheral interrupts, the NVIC handles exception handling for events like faults and traps. These include system errors like undefined instructions, divide by zero, hard faults, and debug events.
Exceptions are handled similarly to interrupts. The NVIC receives each exception type from the processor and vectors to the corresponding fault handler routine based on the vector table. Effective exception handling helps identify system and software bugs and prevent crashes.
Low Power Modes
The NVIC supports low power modes in Cortex-M processors by intelligently managing interrupts. It can monitor activity and determine when to allow the processor to enter sleep mode.
By aggregating interrupt signals, the NVIC can wake up the processor on any interrupt event while still reducing power when idle. This coordination of power modes and fast wakeup helps balance power savings and interrupt latency.
The NVIC provides flexibility in selective interrupt wake up from sleep mode to further optimize power usage in inactive periods.
In summary, the Nested Vectored Interrupt Controller provides a fast and efficient way to handle interrupts in Cortex-M processors. Its prioritized approach focuses on low latency servicing of critical interrupts in real-time applications.
Features like nesting, tail-chaining, flexible priority assignments, and vector tables enable deterministic, fast response to events. This improves responsiveness and makes the NVIC well suited for embedded systems with real-time requirements.