You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Fix tickless idle when stopping systick on zero...
...and don't stop SysTick at all in the eAbortSleep case.
Prior to this commit, if vPortSuppressTicksAndSleep() happens to stop
the SysTick on zero, then after tickless idle ends, xTickCount advances
one full tick more than the time that actually elapsed as measured by
the SysTick. See "bug 1" in this forum post:
https://forums.freertos.org/t/ultasknotifytake-timeout-accuracy/9629/40
SysTick
-------
The SysTick is the hardware timer that provides the OS tick interrupt
in the official ports for Cortex M. SysTick starts counting down from
the value stored in its reload register. When SysTick reaches zero, it
requests an interrupt. On the next SysTick clock cycle, it loads the
counter again from the reload register. To get periodic interrupts
every N SysTick clock cycles, the reload register must be N - 1.
Bug Example
-----------
- Idle task calls vPortSuppressTicksAndSleep(xExpectedIdleTime = 2).
[Doesn't have to be "2" -- could be any number.]
- vPortSuppressTicksAndSleep() stops SysTick, and the current-count
register happens to stop on zero.
- SysTick ISR executes, setting xPendedTicks = 1
- vPortSuppressTicksAndSleep() masks interrupts and calls
eTaskConfirmSleepModeStatus() which confirms the sleep operation. ***
- vPortSuppressTicksAndSleep() configures SysTick for 1 full tick
(xExpectedIdleTime - 1) plus the current-count register (which is 0)
- One tick period elapses in sleep.
- SysTick wakes CPU, ISR executes and increments xPendedTicks to 2.
- vPortSuppressTicksAndSleep() calls vTaskStepTick(1), then returns.
- Idle task resumes scheduler, which increments xTickCount twice (for
xPendedTicks = 2)
In the end, two ticks elapsed as measured by SysTick, but the code
increments xTickCount three times. The root cause is that the code
assumes the SysTick current-count register always contains the number of
SysTick counts remaining in the current tick period. However, when the
current-count register is zero, there are ulTimerCountsForOneTick
counts remaining, not zero. This error is not the kind of time slippage
normally associated with tickless idle.
*** Note that a recent commit e1b98f0
results in eAbortSleep in this case, due to xPendedTicks != 0. That
commit does mostly resolve this bug without specifically mentioning
it, and without this commit. But that resolution allows the code in
port.c not to directly address the special case of stopping SysTick on
zero in any code or comments. That commit also generates additional
instances of eAbortSleep, and a second purpose of this commit is to
optimize how vPortSuppressTicksAndSleep() behaves for eAbortSleep, as
noted below.
This commit also includes an optimization to avoid stopping the SysTick
when eTaskConfirmSleepModeStatus() returns eAbortSleep. This
optimization belongs with this fix because the method of handling the
SysTick being stopped on zero changes with this optimization.
0 commit comments