When it comes to critical sections in FreeRTOS, there are several questions that need to be addressed:1. How is the protection of critical sections implemented?2. What is the relationship with interrupt priority?3. Will masking interrupts affect the operating system’s tick timing and cause a temporary loss of the system clock?With these questions in mind, let’s take a look at the specific implementation of critical sections in FreeRTOS.
- Interrupt Priority
-
FreeRTOS uses configMAX_SYSCALL_INTERRUPT_PRIORITY (or configMAX_API_CALL_INTERRUPT_PRIORITY) to define the highest interrupt priority that can call FreeRTOS APIs.
-
Interrupts above this priority will not be delayed by FreeRTOS and cannot call FreeRTOS APIs.
-
Interrupts below this priority can be delayed by FreeRTOS and can safely call most FreeRTOS APIs.
taskENTER_CRITICAL();// Critical section code
taskEXIT_CRITICAL();
Interrupt Critical Section Protection
taskENTER_CRITICAL_FROM_ISR();// Critical section code
taskEXIT_CRITICAL_FROM_ISR(xHigherPriorityTaskWoken);
<span>Implementation of the function <span>taskENTER_CRITICAL</span>()</span>Taking PPC as an example:
static portFORCE_INLINE void vPortMaskInterrupts( void ){
BaseType_t msr;
uint32_t core_ID;
portGetSPR(core_ID,286); // Get the value of the status register
__asm__ volatile
(
"mfmsr %0 \n\t" // Save the value of MSR to variable msr
/* disable interrupts */
"wrteei 0 \n\t" // Disable interrupts
: "=r" (msr)
);
/* Set current interrupt priority to max API priority */
portINTC_CPR(core_ID) = configMAX_API_CALL_INTERRUPT_PRIORITY; // Set the current core's priority to the highest priority
__asm__ volatile
(
/* ensure INTC_CPR write completes before re-enabling interrupts */
"mbar \n\t" // Memory barrier, ensure register is fully written
/* re-enable interrupts if they were previously enabled */
"wrtee %0 \n\t" // Restore previously saved msr
/* re-fetch Processor pipeline */
"se_isync \n\t" // Synchronize instruction pipeline
: : "r" (msr)
);
}
By disabling interrupts + memory barrier + pipeline synchronization, it ensures that modifications to interrupt priority are atomic.Only interrupts above configMAX_API_CALL_INTERRUPT_PRIORITY will be responded to.
static portFORCE_INLINE void vPortUnmaskInterrupts( UBaseType_t priority ){
BaseType_t msr;
uint32_t core_ID;
portGetSPR(core_ID,286);
__asm__ volatile
(
/* flush out writes from store buffer */
"mbar \n\t" // Memory barrier, ensure storage consistency
"mfmsr %0 \n\t" // Save current MSR register to msr
/* disable interrupts */
"wrteei 0 \n\t" // Disable interrupts
: "=r" (msr)
);
/* Restore current interrupt priority */
portINTC_CPR(core_ID) = priority;
__asm__ volatile
(
/* re-enable interrupts if they were previously enabled. no mbar needed: OK if INTC_CPR write takes a few cycles to show up. */
"wrtee %0 \n\t" // Restore previous msr to MSR register
: : "r" (msr)
);}
static portFORCE_INLINE UBaseType_t ulPortMaskInterruptsFromISR( void ){
uint32_t core_ID;
portGetSPR(core_ID,286);
UBaseType_t originalPriority = portINTC_CPR(core_ID); // Original interrupt priority
vPortMaskInterrupts();
return originalPriority; // Record original priority
}
My understanding ends here, feel free to message me if you have any questions!!