A non-maskable interrupt (NMI) in ARM is a hardware interrupt that cannot be ignored or disabled by software. It is typically used to signal critical system errors that require immediate attention from the processor. NMIs have the highest priority among all interrupts in ARM systems.
Overview of Interrupts in ARM
Interrupts allow external events to interrupt normal program execution in a processor like ARM. When an interrupt occurs, the processor halts execution of the current program, saves its state, and runs an interrupt handler routine. After the handler finishes, the processor restores the state and resumes the original program.
There are three main types of interrupts in ARM:
- IRQ – Normal interrupt request generated by peripherals/devices
- FIQ – Fast interrupt request for time critical events
- NMI – Non-maskable interrupt that cannot be ignored
Both IRQ and FIQ can be disabled/masked by setting bits in the CPSR (Current Program Status Register). But NMI is always enabled.
Key Characteristics of NMI
The key characteristics of NMI in ARM are:
- Cannot be ignored – NMIs cannot be disabled or masked by software. The NMI pin is typically connected to critical system circuits.
- Highest priority – NMI has higher priority than any other interrupt. NMIs preempt both IRQ and FIQ.
- Reserved vector – Each NMI has a reserved exception vector. This ensures quick processing without vector arbitration.
- Minimal context saving – Only minimal processor context is stored, allowing fastest possible handling.
- Precise exceptions – NMIs are precise, meaning the instruction causing the NMI is not allowed to complete.
Typical Uses of NMI
Here are some typical uses of NMI in ARM systems:
- Signaling system failures – NMI is used to signal catastrophic failures like memory errors, bus errors, or power failures.
- Debugging – Debuggers can leverage NMI to halt the system immediately.
- Profiling – Using the NMI for accurate profiling and instrumentation of the system.
- Critical interrupts – Hard real-time systems often use NMI for their most critical interrupt routines.
NMI Handling Process
When an NMI occurs in an ARM system, the following sequence of events happens:
- The NMI exception is recognized after completion of the current instruction.
- Processor state is saved to banked registers (R13, R14). Only minimal context is saved.
- The processor selects the NMI exception vector using the reserved NMI interrupt number.
- Execution begins at the NMI interrupt vector.
- The NMI handler runs to completion. It has unrestricted access to the system.
- The saved banked registers are restored once the handler finishes.
- Processor execution resumes from the point after NMI recognition.
NMI Handler Code
The NMI handler code resides at the NMI exception vector. It should have the following structure:
@ Function name for disassembly
NMI_Handler:
// Save remaining context if needed
// Process NMI source
// Clear source if needed
// Restore context if changed
// Return from exception
The key steps are:
- Save any additional context not already saved by hardware.
- Check source of NMI using system registers.
- Take appropriate action based on NMI source.
- Clear the source if needed, so NMI is not retriggered.
- Restore any context that was modified.
- Execute exception return instruction to resume execution.
Enabling NMI on ARM Cortex-M
On ARM Cortex-M processors, the NMI is enabled by setting the Non-Maskable Interrupt Enable bit in the Program Status Register (PRIMASK).
// Enable NMI
__disable_irq();
PRIMASK = 0;
__enable_irq();
By default, the PRIMASK bit is set to 1 on reset, so NMI is initially disabled. The NMI enable only lasts for the duration of critical code. PRIMASK should be re-enabled after to block NMIs again.
Responding to NMI on ARM Cortex-A
On ARM Cortex-A series application processors, the Generic Interrupt Controller (GIC) is used to handle interrupts.
To enable the NMI:
// Configure NMI as non-maskable
GIC_Write_ICENABLERn(0, 1 << NMI_interrupt);
// Set priority
GIC_Set_Priority(NMI_interrupt, 0x01);
The NMI handler can read the Interrupt Acknowledge register to determine the source:
NMI_Source = GIC_Read_Interrupt_Acknowledge();
// Take action based on NMI_Source
Summary
In summary, NMI is a critical, high priority interrupt in ARM systems that cannot be ignored or disabled by software. It is typically used to handle catastrophic events and system failures. NMI handlers follow a special low-latency process to respond within minimal cycles. Both Cortex-M and Cortex-A series processors provide mechanisms to leverage NMI for time-critical interrupts.