The basepri register is one of the system control registers in ARM Cortex-M processors. It allows setting the base priority mask level that determines the lowest priority of exceptions allowed to interrupt the execution of code running in Thread mode. The basepri register plays a key role in the ARM Cortex-M nested vectored interrupt controller (NVIC) for managing interrupt priorities and preemption.
Overview of basepri
The basepri register is an 8-bit read/write register that contains the value of the base priority mask. This mask value determines the lowest priority level of exception that is allowed to interrupt the execution of threads in Thread mode. The lower 5 bits of the basepri are used to hold the mask value. The upper 3 bits are reserved and must be kept as 0.
The priority levels in Cortex-M NVIC range from 0 to 255, with 0 being the highest priority and 255 the lowest. When basepri is set to a non-zero value N, it masks all interrupt priority levels lower than N from interrupting thread execution. Priority levels higher than N can still cause exceptions and preempt thread execution.
For example, setting basepri to 16 prevents all priority levels 16 and below from generating exceptions when threads are running. But higher priority interrupts like levels 15, 14, etc can still preempt thread execution. basepri does not affect exceptions running in Handler mode.
Effects of basepri
The key effects of the basepri register are:
- It sets a priority mask level N below which no exceptions are generated when threads are executing in Thread mode.
- Exceptions with priorities higher than N can still preempt running threads.
- basepri does not affect exceptions happening in Handler mode.
- Setting basepri to 0 disables its masking effect and allows all exception priority levels.
- basepri directly controls the priority masking without interacting with PRIMASK or FAULTMASK.
- basepri allows threads to avoid lower priority interrupts without having to alter actual interrupt priorities.
By controlling the base priority mask level dynamically via basepri, threads can temporarily block lower priority exceptions without modifying the core NVIC priorities. This provides flexible run-time management of preemption in Cortex-M devices.
Controlling preemption with basepri
The basepri register is commonly used by threads to manage preemption during critical sections of code. A thread can raise its base priority mask level to prevent lower priority interrupts from occurring during sensitive processing. This avoids the need to change the actual NVIC priorities globally.
A typical usage pattern is: /* Read current basepri value */ uint32_t tmp = basepri_read(); /* Set basepri to new level to block interrupts */ basepri_set(NEW_LEVEL); /* Critical section */ /* Restore basepri to original level */ basepri_set(tmp);
This allows the thread to execute critical code without interference from most lower priority exceptions. The original basepri value is restored after, so normal preemption resumes afterwards.
Startup basepri state
At system reset, the basepri register resets to 0. This allows exceptions of all priority levels to be generated. Software needs to explicitly program basepri to utilize its priority masking capabilities.
Accessing basepri
There are a few ways to access and modify the basepri register in Cortex-M devices:
- Direct read/write using the MRS and MSR instructions.
- Using the CMSIS intrinsics basepri_read() and basepri_set().
- Using CMSIS-Core functions like __get_BASEPRI() and __set_BASEPRI().
- Setting basepri in exception handler code on exception entry/exit.
It is common to use the CMSIS intrinsics to get and set basepri during thread execution. The CMSIS functions can be used in exception handlers. Direct MRS/MSR access is useful for bare metal programming without an RTOS.
basepri vs PRIMASK vs FAULTMASK
The basepri register operates independently of the PRIMASK and FAULTMASK registers which also control exception masking in Cortex-M. The differences are:
- basepri sets a priority threshold, lower priority exceptions are masked.
- PRIMASK globally disables all exceptions when set to 1.
- FAULTMASK masks all exceptions during a fault sequence.
basepri allows finer grained control during normal operation. PRIMASK can fully mask exceptions without having to set basepri to the max value of 255. FAULTMASK is hardware controlled during fault handling.
basepri takes priority over PRIMASK and FAULTMASK – setting basepri prevents exceptions below its mask level regardless of the PRIMASK/FAULTMASK state.
Uses of basepri
The main uses of the basepri register are:
- Blocking interrupts during critical sections without modifying global priorities.
- Priority ceiling emulation for mutexes or resource locking.
- Ensuring minimum interrupt latency for time critical interrupts.
- Preventing priority inversion for real-time applications.
- Improving determinism and robustness of interrupt handling.
With careful programming of basepri, interrupt response and latency can be optimized. basepri gives developers and RTOSes more control over managing preemption in Cortex-M implementations.
Conclusion
The basepri register is an important mechanism for controlling interrupt preemption in ARM Cortex-M processors. It allows setting a priority mask threshold below which exceptions will not interrupt thread execution, while still allowing higher priority exceptions. This enables critical code sections to run without lower priority interference. basepri gives developers more flexibility in managing preemption and interrupt latencies without having to alter global NVIC priorities.