SoC
  • Home
  • Arm
  • Arm Cortex M0/M0+
  • Arm Cortex M4
  • Arm Cortex M3
  • Contact
Reading: Preventing Interrupt Nesting on Cortex-M using BASEPRI
SUBSCRIBE
SoCSoC
Font ResizerAa
  • Home
  • Arm
  • Arm Cortex M0/M0+
  • Arm Cortex M4
Search
  • Home
  • Arm
  • Arm Cortex M0/M0+
  • Arm Cortex M4
Have an existing account? Sign In
Follow US
  • Looking for Something?
  • Privacy Policy
  • About Us
  • Sitemap
  • Contact Us
© S-O-C.ORG, All Rights Reserved.
Arm

Preventing Interrupt Nesting on Cortex-M using BASEPRI

Elijah Erickson
Last updated: September 21, 2023 1:47 pm
Elijah Erickson 8 Min Read
Share
SHARE

The Cortex-M processor implements a scheme called “priority masking” to prevent lower priority interrupts from interrupting higher priority code sequences. This is achieved by setting the BASEPRI register to mask interrupts below a certain priority level. For example, setting BASEPRI to 16 prevents interrupts with priority lower than 16 from triggering. This allows critical sections of code to run atomically without being interrupted by lower priority interrupts.

Contents
1. Interrupt Priority in Cortex-M1.1 Default Priority Levels1.2 Changing Priority Levels2. Priority Masking and BASEPRI2.1 How BASEPRI Works2.2 Using BASEPRI for Critical Sections3. Preventing Interrupt Nesting3.1 Issues with Nested Interrupts3.2 Preventing Nesting with BASEPRI3.3 Configuring Max Nesting Level4. Use Cases for BASEPRI Register5. Choosing Priority Levels6. Limitations of BASEPRI7. Conclusion

1. Interrupt Priority in Cortex-M

In Cortex-M, interrupts are assigned a priority from 0 (highest) to 255 (lowest). The NVIC interrupt controller uses this priority to decide which interrupt to service first when multiple interrupts are pending at the same time. Higher priority interrupts always preempt lower priority ones.

By default, all interrupts have priority 0. This means they will all be treated equally by the processor. To prevent unwanted preemption, different priority levels should be assigned to different interrupts using the NVIC set priority register.

1.1 Default Priority Levels

On reset, the Cortex-M processor configures interrupt priority levels as follows:

  • All NVIC interrupts at priority 0
  • SysTick exception at priority 1
  • PendSV and DebugMonitor exceptions at priority -2
  • SVC exception at priority -1 (highest priority)

This ensures SVC interrupts are always serviced first, followed by PendSV, SysTick and finally external NVIC interrupts.

1.2 Changing Priority Levels

The application can change priority levels dynamically by programming the NVIC priority registers. For example: NVIC_SetPriority(EXTI0_IRQn, 5); //set EXTI0 priority to 5 NVIC_SetPriority(TIM2_IRQn, 3); //TIM2 priority to 3

This will make TIM2 interrupt preempt EXTI0 interrupt due to its higher priority level.

2. Priority Masking and BASEPRI

The Cortex-M processor implements priority masking to prevent interrupts below a certain level from triggering. This is accomplished using the BASEPRI register.

2.1 How BASEPRI Works

BASEPRI can be set to a value between 0 and 255. This masks interrupts with a priority lower than the value in BASEPRI. For example: BASEPRI = 16; //will mask interrupts with priority 16 and below

Setting BASEPRI does not prevent exceptions like SVCall or PendSV from triggering. It only masks external interrupts from the NVIC.

2.2 Using BASEPRI for Critical Sections

A common use case of BASEPRI is to protect critical sections of code from preemption by lower priority interrupts. For example: void critical_function() { //disable interrupts below priority 2 __disable_irq(); BASEPRI = 2 << (8 – __NVIC_PRIO_BITS); //critical section __enable_irq(); //restore BASEPRI BASEPRI = 0; }

This prevents any interrupt with priority lower than 2 from disrupting the critical section. Common critical sections include modifying multi-byte variables, accessing hardware registers, and updating non-atomic flags.

3. Preventing Interrupt Nesting

By default, Cortex-M allows interrupts to nest or preempt each other. For example, a higher priority interrupt can preempt a lower priority ISR that is already in progress. This nested execution can be prevented by masking lower priority interrupts.

3.1 Issues with Nested Interrupts

Allowing nested interrupts can lead to several issues, including:

  • Stack overflow if too many levels of nesting occur
  • Priority inversion when a high priority interrupt gets blocked by lower priority ISRs
  • Deadlock due to complex nested execution flows
  • Difficulty reasoning about concurrent flows in the application

For these reasons, deeply nested interrupts are often best avoided in embedded applications.

3.2 Preventing Nesting with BASEPRI

To prevent interrupt nesting, the BASEPRI register can be used on entry to ISR routines to mask lower priority interrupts. For example: void TIM2_IRQHandler() { //disable interrupts below priority 4 __disable_irq(); BASEPRI = 4 << (8 – __NVIC_PRIO_BITS); //ISR handling TIM2->SR = 0; //clear interrupt flags __enable_irq(); //restore BASEPRI BASEPRI = 0; }

This prevents any interrupt with priority lower than 4 from nesting into the TIM2_IRQHandler.

A similar scheme can be implemented in a HAL driver or middleware to prevent nesting globally across all external interrupt handlers.

3.3 Configuring Max Nesting Level

The NVIC provides configuration options to limit the nesting depth:

  • NVIC_SetPriorityGrouping() – Sets max preemption levels from 0 to 7
  • SCB_AIRCR.PRIGROUP – Sets priority grouping in exception handlers

This can help prevent stack overflows and reduce nested interrupt latency. But using BASEPRI masking gives the flexibility to allow selective nesting if needed.

4. Use Cases for BASEPRI Register

Some common use cases of BASEPRI priority masking include:

  • Implementing critical sections – Prevent disruption of critical code sequences
  • Data structure protection – Guard multi-byte variables or data structures
  • Accessing hardware – Prevent concurrent access to hardware registers
  • Entering low power modes – Mask interrupts temporarily to enter low power modes atomically

BASEPRI can also be used with OS kernels and RTOS to disable preemption of thread level code for short durations.

5. Choosing Priority Levels

Some tips for assigning priority levels in Cortex-M applications:

  • Higher priority for time critical interrupts like timer ticks
  • Higher priority for high frequency interrupts
  • Similar priorities for related peripherals (DMA channels, ADC sampling)
  • Lower priorities for infrequent interrupts like GPIO
  • Separate priorities for groups with different latency requirements

Higher priority interrupts should use lower BASEPRI levels for masking. This ensures lower priority ISRs are masked first.

Tuning the priorities and playing with BASEPRI levels can help achieve the right real-time response in complex applications.

6. Limitations of BASEPRI

While useful, BASEPRI masking has some limitations:

  • Only prevents NVIC interrupts, not internal exceptions
  • Only stops preemption, not concurrent execution of same priority interrupts
  • Requires manual programming before and after critical sections
  • Does not disable already pending higher priority interrupts
  • Can increase interrupt latencies by disabling preemption

Proper design is required to account for these limitations in the application’s use of BASEPRI.

7. Conclusion

The BASEPRI register provides an efficient mechanism for preventing interrupt nesting and lower priority preemption in Cortex-M applications. When used judiciously, it can help build robust real-time embedded software.

Priority levels, BASEPRI values and nesting behavior should be carefully tuned for the needs of the application. This will lead to responsive interrupt handling while also preventing unintended concurrency issues.

BASEPRI forms an important tool in the Cortex-M developer’s toolkit for managing interrupts and writing predictable software on ARM microcontrollers.

Newsletter Form (#3)

More ARM insights right in your inbox

 


Share This Article
Facebook Twitter Email Copy Link Print
Previous Article Changing Interrupt Priority on Cortex-M Microcontrollers
Next Article Dynamic Interrupt Priority Changes on Cortex-M3/M4
Leave a comment Leave a comment

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

2k Followers Like
3k Followers Follow
10.1k Followers Pin
- Sponsored-
Ad image

You Might Also Like

Arm Cortex M4 Errata

The Arm Cortex-M4 processor is a popular 32-bit microcontroller core…

6 Min Read

Configuring Memory and Caches for Arm Cortex-M1

The Arm Cortex-M1 processor is designed for low-power embedded applications.…

6 Min Read

What are Saturated Math Instructions in Arm Cortex-M Series?

Saturated math instructions in Arm Cortex-M series refer to arithmetic…

9 Min Read

What is the SVC instruction in the arm cortex?

The SVC (Supervisor Call) instruction in ARM Cortex processors is…

7 Min Read
SoCSoC
  • Looking for Something?
  • Privacy Policy
  • About Us
  • Sitemap
  • Contact Us
Welcome Back!

Sign in to your account