The quick answer is that you can disable interrupt nesting in ARM Cortex M0+ by setting the PRIGROUP field in the Application Interrupt and Reset Control Register (AIRCR) to 111b. This will make all interrupts have the same priority level, preventing any nested interrupts.
Introduction to Interrupt Nesting
Interrupt nesting refers to the ability of an interrupt service routine (ISR) to be interrupted by a higher priority interrupt while it is still executing. This results in one ISR being nested within another. Nested interrupts allow for more responsive real-time processing, but can also introduce complexity in managing interrupt priorities and shared resources.
By default, interrupt nesting is enabled in Cortex M0+ processors. The processor supports up to 32 unique interrupt priority levels. Higher priority interrupts can preempt lower priority ones. This means a lower priority ISR can be interrupted and nested by a higher priority one.
Why Disable Nesting?
There are some cases where nested interrupts are undesirable in an application. Reasons you may want to disable nesting include:
- The application has interrupts that access shared hardware resources. Nested access could cause race conditions.
- Interrupt latency needs to be bounded and predictable.
- The application has “critical sections” that cannot be interrupted.
- Interrupt management becomes too complex when allowing nesting.
By disabling nesting, you simplify interrupt handling but lose some real-time responsiveness in exchange.
How Interrupt Priority Works in Cortex M0+
The Cortex M0+ NVIC (Nested Vectored Interrupt Controller) manages interrupt handling. It uses a prioritized scheme, with 0 being highest priority and >0 being lower. Some key points:
- The NVIC has 32 interrupt priority levels (0-31).
- Lower priority numbers equal higher interrupt priority.
- All interrupts start at priority 0 by default.
- Interrupt priority can be changed dynamically in software.
- Higher priority interrupts can preempt lower priority ones.
Thus, the priority scheme enables nesting. A lower priority routine can be interrupted by a higher priority one. Managing the priority levels appropriately is key to constructing well-behaved interrupt handling.
Using PRIGROUP to Disable Nesting
The simplest way to disable interrupt nesting in Cortex M0+ is by using the PRIGROUP field in the AIRCR register. This field configures how the NVIC priority bits are split into preemption priority and subpriority bits.
By setting PRIGROUP to 111b, all interrupt priorities will be forced to the same preemption level. This prevents any interrupts from preempting another, since they all have equal priority standing.
To set PRIGROUP to disable nesting: // Set PRIGROUP field in AIRCR to 111b AIRCR |= (7 << 8);
Now all interrupts will be non-nested regardless of their priority level field configurations. Any pending higher priority interrupts must wait for the currently executing routine to finish.
Preserving Unique Priority Levels
A downside to using PRIGROUP as above is that it forces all interrupts to the same priority level. You lose the ability to have interrupts with unique priority standings.
An alternative method is to group interrupts into priority levels yourself in software. For example, assign non-nested critical interrupts to priority 0. Assign groups of nested interrupts to priority levels 1, 2, 3, and so on. Then manage the grouping in code when setting interrupt priorities.
This preserves unique priority levels for interrupts, while still disabling nesting by careful management of the priority assignments.
Using BASEPRI Register
Another method to disable nesting is via the BASEPRI register. This register defines an active priority threshold – no interrupts with a priority less than BASEPRI will be processed.
By setting BASEPRI to 1 or higher, you prevent any interrupts with default priority 0 from triggering. This effectively disables nesting without altering the default priority levels. // Set BASEPRI to 1 to disable priority 0 interrupts BASEPRI = 1;
The downside is that BASEPRI is a global setting, so you lose fine grain control over specific interrupt priority masking. It’s a blunt instrument compared to carefully managing priority levels in code.
Using PRIMASK Register
Finally, the simplest method is to outright disable all interrupts by setting PRIMASK. This prevents any exceptions from triggering an interrupt. // Disable all interrupts by setting PRIMASK PRIMASK = 1;
This gives you complete control over enabling interrupts in code where needed. But it disables all nesting and real-time responsiveness. Use PRIMASK carefully only in critical sections that truly require it.
Nested interrupts provide powerful flexibility to Cortex M0+ applications. But they also introduce complexity. Several techniques exist to disable nesting:
- Set PRIGROUP to 111b to force same priority level
- Manage priority groups in software
- Use BASEPRI to mask priority 0 interrupts
- Use PRIMASK to disable all interrupts
Choose the right method based on your performance needs and how much interrupt flexibility your application requires. Judicious use of nesting vs non-nesting approaches gives great control over real-time behavior in Cortex M0+ designs.