The basepri register is a key component of the interrupt handling system in Cortex-M4 processors. It allows priority filtering of interrupts and provides more control over interrupt preemption. The basepri register works together with the primask register to allow flexible interrupt prioritization and masking in Cortex-M4 cores.
What is the Basepri Register?
The basepri register is an 8-bit read/write register present in NVIC (Nested Vectored Interrupt Controller) of Cortex-M4 processors. It holds a priority value that is used for priority filtering of interrupts. The basepri value acts as a “priority floor” – only interrupts with a priority higher than the basepri value can interrupt the current execution. Interrupts with priority equal to or lower than basepri remain pending but are ignored for preemption purposes.
This allows selective enabling/disabling of preemption based on interrupt priority. Setting basepri to 0 allows preemption from all interrupts as normal. Setting it to higher priority values prevents lower priority interrupts from preempting current execution. This provides finer control over interrupt preemption compared to simply enabling/disabling all interrupts using primask.
How Basepri Works
The Cortex-M4 interrupt handling scheme assigns a priority from 0 (highest) to 255 (lowest) to each interrupt. At any time, the “threshold” for preemption is determined by the MAX(basepri, Current running priority).
When an interrupt occurs:
- If its priority is higher than the threshold, it will preempt current execution.
- If its priority is equal or lower than the threshold, it will be held pending and ignored for preemption purposes.
Therefore, by adjusting basepri, the threshold can be moved up and down to selectively allow or prevent preemption from certain priority levels. Setting basepri = 0 means the threshold is the current running priority. Setting it higher raises the threshold to prevent lower priority interrupts.
Typical Uses of Basepri
Critical Sections
A common use of basepri is to protect critical sections of code from preemption. This is done by:
- Saving current basepri value to a temporary variable on function entry.
- Setting basepri to the highest priority in critical section to lock out all interrupts.
- Restoring original basepri value on exit.
This prevents any lower priority interrupts from interrupting the critical section. basepri manipulations are typically faster than disalbing/enabling interrupts using primask.
Interrupt Priority Management
basepri allows selective filtering out of lower priority interrupts without having to individually disable each one. For example, a periodic motor control ISR may need to run without interruption from lower priority interrupts like ADC sampling. This can be ensured by setting basepri to the motor control priority.
Interrupt Nesting Control
Setting basepri can also manage interrupt nesting behaviors. An interrupt service routine (ISR) executing with basepri > 0 will prevent nesting of equal or lower priority interrupts. This saves on stack usage in nested interrupts.
Interaction Between Basepri and Primask
basepri and primask registers can be used together to flexibly control interrupt blocking. The priority threshold for preemption is: Threshold = MAX(basepri, Current running priority) if primask = 0 = 255 if primask = 1
Therefore:
- primask globally enables/disables all interrupts
- basepri selectivity filters interrupts for preemption
Typical use is to disable all interrupts using primask in the most critical sections, and use basepri for less critical ones. primask disables and saves more context than basepri.
Defining Interrupt Priority Levels
Proper priority assignment to interrupts is important for basepri to work effectively. Higher priority values need to be assigned to more critical interrupts. Some guidelines include:
- The SysTick timer must have the highest priority to ensure correct RTOS timing.
- Time critical interrupts like motor control PWM should have priorities just lower than SysTick.
- High frequency interrupts like ADC sampling can have moderate priorities.
- Low priority for simple communications and user interface tasks.
Higher priority interrupts should have lower ISR execution times. The priorities can be adjusted during development for optimal real-time performance.
Configuring Basepri
The basepri register is memory mapped into the System Control Block(SCB) in the Cortex-M4 core. It can be set directly by writing to the register address. For example: #define SCB_BASE 0xE000ED00 #define SCB_BASEPRI (SCB_BASE + 0x5C) void SetBasepri(uint32_t basePri) { *(volatile uint32_t *)SCB_BASEPRI = basePri; }
This writes the basePri value directly into the basepri register address. The CMSIS core headers define the BASEPRI register as: #define SCB_BASEPRI_R (*((volatile uint32_t *)0xE000ED1C))
So it can also be accessed using: SCB_BASEPRI_R = basePri;
The basepri value written must be between 0 and 255, corresponding to the priority levels. Reads of basepri return the current value.
Saving and Restoring Basepri
When using basepri to protect critical sections, the original value needs to be saved and restored: // Save current basepri uint32_t priMask = __get_BASEPRI(); // Set basepri to new level __set_BASEPRI(newLevel); // Critical section… // Restore original basepri __set_BASEPRI(priMask);
This prevents any change to basepri from affecting other parts of the program. The CMSIS intrinsic functions are used here for convenience.
Conclusion
The basepri register gives finer control over interrupt preemption in Cortex-M4 processors. It allows selective priority filtering of interrupts for preemption purposes. Together with optimal priority assignment, basepri usage can improve real-time performance and deterministic behaviors in Cortex-M4 applications.