Understanding Critical Sections in FreeRTOS

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.

  1. 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.

  • Protection of Critical SectionsTask Critical Section Protection
    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.

  • Function Implementation
    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)
        );}
  • Protection of Interrupt Critical Sections involves disabling interrupts while preserving and restoring the current interrupt priority
    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
    }
  • From the code implementation, after interrupt masking, timer interrupts are not disabled, only interrupt responses are disabled. The system’s timer interrupts will be delayed in processing. However, if the critical section processing time is too long, I understand that the system’s timing will indeed have issues (this is more likely to occur if the system’s tick is relatively small).
  • My understanding ends here, feel free to message me if you have any questions!!

    Leave a Comment