Hi,
Why there is an ASSERT in vTaskStepTick function ,
*configASSERT( ( xTickCount + xTicksToJump ) <= xNextTaskUnblockTime );
*
In my application, sometimes I have to wake up before the expected Idle Time, so in that cases when Im trying to correct the ticks with a lower TickstoJump ASSERT is hitting.
What is the size of xTickCount? This assert seems to be checking to see if there’s a rollover (overflow) condition. I guess I should pull up the source code and look, but a wrap-around should be handled gracefully rather than causing a panic.
You can think of an assert statement as if it uses the word “verify” in place of assert. The meaning is the same. The statement won’t do anything if the asserted/verified condition is true. The statement will take an action (stop execution for example) if the condition is false.
Typical causes of assertion failure on this particular line are:
Custom tickless implementation has bugs
You implemented pre/post sleep processing to induce a special sleep mode
xTicksToJump, xUpdatedTickCount, xTickCount, and xNextTaskUnblockTime are all type TickType_t, which is defined based on the definition of the configuration macro configTICK_TYPE_WIDTH_IN_BITS.
The procedure vTaskStepTick() is used to advance the scheduler’s idea of what the current tick count is by the number of ticks elapsed between the last update (when the processor entered sleep mode) and “now” and xTicksToJump is that number of ticks.
The configASSERT() therefore is checking to see if the adjusted tick count is at or before the next known task wakeup event (timeout, taskDelay(), etc.). If the assertion fails, it means that the tick has gone beyond that time, so the scheduler has missed the wakeup event.
I can see this happening if the thing calling vTaskStepTick() is calculating xTicksToJump incorrectly such as simply passing in the current free-running tick counter value rather than calculating the ticks elapsed while tick interrupts were suppressed or using a counter that has a higher granularity than the FreeRTOS tick rate.
((x) == 0) is true only if (x) is false. xTicksToJump is the number of ticks to bump xTickCount by. configASSERT(x) will only go into the “panic” loop if the expression represented by x is false.
The possible problem I see is that there is nothing I see in the code to account for xTickCount + xExpectedIdleTime (as the argument to portSUPPRESS_TICKS_AND_SLEEP()) can be less than xTickCount due to counter roll-over in some cases. FreeRTOS supports defining TickType_t as a 16, 32 or 64-bit unsigned integer. If you’re using a 100Hz tick, a 16-bit xTickCount rolls over every 655.35 seconds. This is not the problem I suspect you’re encountering, though it could be.
My experience with tickless idle in FreeRTOS is minimal, and I was using a 64-bit TickType_t with a 1000Hz tick rate on an ARM Cortex M4 core with an external (to the CPU complex) 1MHz free-running counter which had a 32 bit register and generated an external interrupt on roll-over or when the counter matched the alarm register (this was in a SmartFusion FPGA SoC). Because none of my application tasks used vTaskDelay(), external interrupts were used to wake up the CPU, and the expected delay was always the time between the current and alarm times divided by 1000 (to account for the tick time of 1 millisecond vs. the timer rate of 1 microsecond). The alarm time was set to when the next SW timer expired. This was done with a custom HW timer driver that accounted for rollover.
[Correction: I checked the source code for the project where I used tickless idle, and I misremembered a few details: the rate of the counter in the FPGA logic was 100MHz, the FPGA logic had a sample register, the counter, alarm and sample registers were 64-bits, and a number of other details I’d forgotten.]
Not read the whole thread so might have the gist wrong - but the counters are unsigned so overflows handle themselves.
[Edit] The above is true for normal tick handling. In the case of tickless idle guarding against counter overflow is actually done before the clock is stopped. The wake time is set to either the time the next task has to wake up, or when the counter overflows, whichever is soonest. [/Edit]