ulTaskNotifyTake timeout accuracy

Here’s what seems to be happening. There is another edge case not handled properly in vPortSuppressTicksAndSleep(). If something other than systick wakes the CPU, and if the time remaining until the next tick is very small, then a very tiny value is loaded into the reload register here. Then the systick expires while vTaskStepTick() executes here, which pends the systick ISR and starts another very small systick period. While this second period is underway, we finally load the standard value into the reload register here. Then we unmask interrupts, at which point the pending systick ISR executes, and then very soon thereafter another systick interrupt occurs from the second very small systick period ending.

What’s interesting about this edge case is that there is a small window of reload values that can cause the error. Only values larger than e.g. 2 and smaller than e.g. 10 would ever cause the error. But in this case the ITM usage, or traceINCREASE_TICK_COUNT() usage, in vTaskStepTick() would expand the error window a bit because those things delay our loading the correct value into the reload register.

For a quick experiment and fix, can you swap the last two statements:

Current Code:

portNVIC_SYSTICK_CTRL_REG |= portNVIC_SYSTICK_ENABLE_BIT;
vTaskStepTick( ulCompleteTickPeriods );
portNVIC_SYSTICK_LOAD_REG = ulTimerCountsForOneTick - 1UL;

Proposed (testing only):

portNVIC_SYSTICK_CTRL_REG |= portNVIC_SYSTICK_ENABLE_BIT;
portNVIC_SYSTICK_LOAD_REG = ulTimerCountsForOneTick - 1UL;
vTaskStepTick( ulCompleteTickPeriods );