CM4:port.c->vPortSuppressTicksAndSleep()

The code and comments are as follows:
/* Enter a critical section but don’t use the taskENTER_CRITICAL()
* method as that will mask interrupts that should exit sleep mode. */
__disable_interrupt();

Question: taskENTER_CRITICAL() is use basepri to mask SYSCALL interrupt, and the __disable_interrupt() is use primask to disable all interrupt , why can’t use taskENTER_CRITICAL()?

During low-power sleep, the Cortex M will not wake up for interrupts that are masked by BASEPRI.

2 Likes

there is another question:
After waking up from the interrupt, there is the following code:

        /* Re-enable interrupts to allow the interrupt that brought the MCU
         * out of sleep mode to execute immediately.  See comments above
         * the __disable_interrupt() call above. */
        __enable_interrupt();
        __DSB();
        __ISB();

        /* Disable interrupts again because the clock is about to be stopped
         * and interrupts that execute while the clock is stopped will increase
         * any slippage between the time maintained by the RTOS and calendar
         * time. */
        __disable_interrupt();
        __DSB();
        __ISB();

question: when __enable_interrupt(), It is possible that a systick interrupt occurred, and the counter of systick will increase by 1. If there are other interrupt events happening, could it lead to task switching? If task switching occurs, the value of the systick counter is not the actual count. The last systick interrupt may contain multiple tick values, but the count only increases by 1.

Task switching is disabled for the entire duration of vPortSuppressTicksAndSleep(). So there will be no task code executing (besides the idle task) until the tick count is fully corrected for the time spent in tickless sleep.

Note that the FromISR() functions called by the ISR that wakes the system do see the uncorrected tick count.

there is another question:
After waking up from the interrupt,
there is the following code:

        portNVIC_SYSTICK_CTRL_REG = portNVIC_SYSTICK_CLK_BIT | 
        portNVIC_SYSTICK_INT_BIT | portNVIC_SYSTICK_ENABLE_BIT;
        #if ( portNVIC_SYSTICK_CLK_BIT_CONFIG == portNVIC_SYSTICK_CLK_BIT )
        {
            portNVIC_SYSTICK_LOAD_REG = ulTimerCountsForOneTick - 1UL;
        }
        #else
        {
            /* The temporary usage of the core clock has served its purpose,
            * as described above.  Resume usage of the other clock. */
           portNVIC_SYSTICK_CTRL_REG = portNVIC_SYSTICK_CLK_BIT | 
           portNVIC_SYSTICK_INT_BIT;

            if( ( portNVIC_SYSTICK_CTRL_REG & portNVIC_SYSTICK_COUNT_FLAG_BIT ) != 0 )
            {
                /* The partial tick period already ended.  Be sure the SysTick
                 * counts it only once. */
                portNVIC_SYSTICK_CURRENT_VALUE_REG = 0;
            }

question:
After waking up from the interrupt, first calculate the value of SysTick decrements remaining (in the case where it is not awakened by a SysTick interrupt), write it into the load register. If the clock source of SysTick is not core clk, then select core clk as the clock source first so that the current register can quickly load the value of decrements remaining. Then switch to the configured clock source for SysTick and set the load register to its normal value. There should be no other code between enabling and disabling SysTick, so a SysTick interrupt should not occur. What does the above code do?

That is true. The case you described is when the code must temporarily use the core clock. We want the time spent using the core clock to be a short as possible. Thus there is no code in between the enabling and disabling of SysTick. Removing all of the conditional compilation we are left with these two statements back to back:

portNVIC_SYSTICK_CTRL_REG = portNVIC_SYSTICK_CLK_BIT | portNVIC_SYSTICK_INT_BIT | portNVIC_SYSTICK_ENABLE_BIT;
portNVIC_SYSTICK_CTRL_REG = portNVIC_SYSTICK_CLK_BIT | portNVIC_SYSTICK_INT_BIT;

Preventing a SysTick interrupt here is neither the intent nor the outcome of having no other code between the enabling and disabling of SysTick. The code specifically allows SysTick to request an interrupt as needed based on the number of counts remaining. Shortly after the code you posted, the code reenables interrupts and allows the SysTick interrupt request (if any) to be handled.