Assert ERR may occurs after vTaskStepTick() make tick compensation(wakeup from tickless)

Hi,
I use FreeRtos V9,ASSERT ERR may occurs after call vTaskStepTick().

[Background]:
I enabel the tickless sleep mode on my project. And use vTaskStepTick() API to make the systick counter compensation after the chip wakeup from ticklss mode.

Sometime the ASSERT ERR occurs by: xTaskIncrementTick → call taskSWITCH_DELAYED_LISTS → configASSERT( ( listLIST_IS_EMPTY( pxDelayedTaskList ) ) )

[Reproduce method]:
In case of the chip wakeup form tickless sleep mode ->then make systick counter compensation by vTaskStepTick(). If the sytick counter value becomes 0xFFFFFFFF(32bit counter), ASSERT ERR will occurs by next systick interrupt handle.

BaseType_t xTaskIncrementTick( void )
{

if( xConstTickCount == ( TickType_t ) 0U )
{
taskSWITCH_DELAYED_LISTS(); ← code stop here
}

[Question]:
Why vTaskStepTick() only increase the systick counter?
It does NOT call the tick hook function; The task scheuler will not make the task status checking and management.
It causes the task(the expected wakeup tick == 0xFFFFFFFF) in pxDelayedTaskList will NOT switch from block → Ready. And then 1ms(systick timer use 1ms interval) later the systick counter will overfolw(reset to 0), FreeRtos check the pxDelayedTaskList is not empty and ASSERT ERR occurs.

void vTaskStepTick( const TickType_t xTicksToJump )

{
    /* Correct the tick count value after a period during which the tick
    was suppressed.  Note this does *not* call the tick hook function for
    each stepped tick. */

    configASSERT( ( xTickCount + xTicksToJump ) <= xNextTaskUnblockTime );

    xTickCount += xTicksToJump;

    traceINCREASE_TICK_COUNT( xTicksToJump );

}

I suspect there is an issue in the tickless implementation you are using. It seems you are not using the official version from FreeRTOS. Can you share your version?

If the expected wakeup tick is 0xFFFFFFFF, then a tick interrupt should occur at that time to end the tickless period. The tick interrupt handler would “pend” the tick in xPendedTicks because the scheduler is disabled. Then vTaskStepTick() should advance the tick to 0xFFFFFFFE. Once the scheduler resumes, the pended tick is processed in xTaskIncrementTick() to reach 0xFFFFFFFF. In other words, that version of vTaskStepTick() assumes there is a tick pended in xPendedTicks if the expected idle time elapsed fully.

Thans for checking,
So,the key point might be the tick compensation result should never be 0xFFFFFFFF?
Is my understanding correct?

I did modify the function vPortSuppressTicksAndSleep to make the chip can sleep much longer, I will check the tick compensation value calculate method.

That’s correct if a task needs to wake up at 0xFFFFFFFF.

This is the key point here. When calculating the compensation value, don’t forget to account for the tick that got counted (or more accurately, the tick that got pended) in the tick ISR that ended the sleep. See the official freeRTOS version of vPortSuppressTicksAndSleep() for reference.

The official code seems keep the systick timer works during the sleep mode. And set the systick timer with the expected reload value calculate by:
ulReloadValue = portNVIC_SYSTICK_CURRENT_VALUE_REG + ( ulTimerCountsForOneTick * ( xExpectedIdleTime - 1UL ) ); )
Then the CPU may wakeup by the systick counter down to 0 or some other interrupts.

However on my project, the systick use the same clock source with CPU clock(48MHz). If I want to stop the CPU clock for power saving and the ststick timer also stop work.
That’s why I modify this function:
Stop systick timer when enter the sleep mode and set another timer(a hibernation timer with 32KHz CLK, it will not stop in sleep mode) with the counter value = ‘xExpectedIdleTime’ (without -1).
The systick compensation step depends on the hibernation timer counter when wakeup.
Maybe that’s why the compensation result can be 0xFFFFFFFF insead of 0xFFFFFE.

You are right.

The case you describe was recently considered as part of a small change to vTaskStepTick(). This change is expected to be included in the next release of FreeRTOS.

You could apply that change in your own copy of FreeRTOS.

Or, as an alternative, you could add a call to xTaskIncrementTick() to your hibernation timer’s ISR. Don’t forget to adjust the value passed to vTaskStepTick() to compensate for that tick.

1 Like

Hi Jeff,
Appreciate for your help!
Currently I just disable the sleep mode when the tick value close to the overfolw(> 0xFFFFF000). I will try the method to call xTaskIncrementTick() from hibernation timer interrupt.