Why is vTaskStepTick available only for tickless idle mode?

There could be many systems and use cases where the tick interrupt can be masked for more than one tick. For example when using NordicSemi bluetooth stack, the stack can mask the RTC(tick) interrupt as much as 100 ms because BLE stack works on hightest priority and this priority is not available to others. For able to recover from this the only correction method that is possible to the RTOS tick is as below
if(diff > 1)
{
    /* This could happen if this interupt was masked for more than one RTOS tick period */
    vTaskStepTick(diff - 1);
}

/* Increment the RTOS tick as usual which checks if there is a need for rescheduling */
if ( xTaskIncrementTick() != pdFALSE )
{
    /* A context switch is required.  Context switching is performed in
    the PendSV interrupt.  Pend the PendSV interrupt. */
    SCB->ICSR = SCB_ICSR_PENDSVSET_Msk;
    __SEV();
}
But this is not possible if vTaskStepTick is only available for tickless idle. If not this system will be unusable with timers/queues working inacurately. Decreasing the tick precision to 100ms per tick is not at all attractive and unacceptable for many use cases. I know that the source code is available and we are free to modify it for our own use, but I came here to get an explanation from the experts to understand if I missed anything. /Aryan from devzone

Why is vTaskStepTick available only for tickless idle mode?

My first thought is that any piece of software that can block the system, including the tick interrupt, for 100ms is NOT compatible with most definitions of ‘Real Time’.

Why is vTaskStepTick available only for tickless idle mode?

I agree with you Richard about our FreeRTOS port not being real time when it is combined with BLE stack. Only our BLE stack can be real time in our system. There is no other workaround for it. Lots of applications that needs to be written on top of this stack prefer to use FreeRTOS instead of being standalone because they get nice features like timers, queues and other OS features. So you think that rationale behind having the restriction for vTaskStepTick not to be used in non tickless mode is that FreeRTOS is not designed/suitable for systems that can mask tick interrupt for more than one tick? Sorry for multiple edits, there is no option to calmly edit without notifications.

Why is vTaskStepTick available only for tickless idle mode?

This is an interesting conversation…you have a genuine requirement to adjust the clock, but the current implementation of vTaskStepTick() would not be safe to use for this purpose because it assumes the step in time will not jump over the time at which a task will unblock. If you tried to do that then you would hit an assert(). The implementation assumes the conditions for entering tickless mode have been met, and that the system will exit tickless mode before or at the time it is known that a task needs to leave the blocked state. Neither of these assumptions will hold true in your BLE case. For example, tickless mode will only be entered if the Idle task is the only task that is not Blocked, but presumably the BLE task will run at any time, and most of the time it runs there will be other tasks that are not Blocked. Second because it is assumed that the tick will only be stopped up to the time a task needs to leave the Blocked state the tick is really stepped, not ‘unwound’, so in your BLE case you may step over a time that a task was meant to leave the Blocked state. ….so vTaskStepTick() cannot be used, but we can add something in that can be used. So in your case, if you know how many ticks should have occurred while your BLE task was executing, we can add in a function that unblocks any tasks that would otherwise have been unblocked in that time, and THEN step the tick forwards. As Richard D points out, that would of course break any ‘real time’ or ‘determinism’ aspects of the application.

Why is vTaskStepTick available only for tickless idle mode?

Thanks for the reply. It is little more complicated with the BLE stack. I should have explained it before. Now I see what confuses you both. The BLE stack is a completely different binary running first at system start up. At system start up it is IDLE and it gives CPU to the RTOS application which is another binary running on top of BLE. We have interrupt forwarding mechanism for the interrupts that BLE stack does not consume which are forwarded to the application vector table. The communication between the RTOS and the BLE happens using SVC and when RTOS starts one of RTOS threads initializes the BLE stack (and this stack which runs out of the scope of the RTOS as this is a seperate binary listening and consuming a range of SVC numbers). So when i said that the BLE activity can mask interrupts for a long time, it means that this will happen completely outside RTOS scope. For example, one thread in RTOS triggers a SVC call that immediately transfers control to the BLE stack (not RTOS thread) and that sometimes could takes many milliseconds before it gives control back to the RTOS thread. The RTOS tick counter, RTC , is always ticking no matter what is running. So now even though the hardware tick is ticking, RTOS did not get CPU at all for doing its tick housekeeping, I understand that any RTOS does not like CPU being hijacked and in this scenario BLE stack is stealing the CPU time from it abruptly, which is OK and it is working fine because all the hardware timers are still ticking for the RTOS and* I just needed a way to tell the RTOS that you were not allowed your housekeeping for a while and here is the diff in the ticks and go do your housekeeping.* Now, back to your explanation. but presumably the BLE task will run at any time, and most of the time it runs there will be other tasks that are not Blocked The BLE activity that steals CPU from the RTOS is not an RTOS task, so when Tickless IDLE is triggered, then all other tasks apart from IDLE are blocked. This condition is still met on our port. ***and that the system will exit tickless mode before or at the time it is known that a task needs to leave the blocked state. *** When the system sleeps using tickless idle, it will never exceed the time to wakeup than what the RTOS has expected, because we configure a wakeup interrupt with that expected time. In many cases it wakes even earlier, because if we are triggering ticksleep sleep, that means that all the threads in the RTOS (apart from IDLETask) are in blocked state and the BLE stack is in IDLE state.So this condition is also met. I have experimented removing the compile flag fencing the implementation of xTaskIncrementTick() and used it in the system as mentioned in the question to see if i trigger any assert. All the systems have been up and running for more than 12 hours without any assert. And the timers have improved efficiency when i use vTaskStepTick to compensate the lost ticks.

Why is vTaskStepTick available only for tickless idle mode?

I would like to add one more thing. The tickless IDLE sleep and wakeup works perfectly without any problems because we are allowed to use vTaskStepTick() here. The problem is ONLY when the system is not sleeping and there is BLE stack activity + atleast one non IDLETASK RTOS thread running. This is the time I need to correct the RTOS tick when i see the diff in ticks is more than 1

Why is vTaskStepTick available only for tickless idle mode?

You can call xTaskIncrementTick() manually too – but it needs to be done from a critical section. If it returns non 0 then you should perform a context switch.

Why is vTaskStepTick available only for tickless idle mode?

If it returns non 0 then you should perform a context switch. I agree about this being in critical section. The most of tick interrupt handling is in critical section. But performing context switch, is it still needed even though the next call xTaskIncrementTick() will also result in context switch? Like the code shown ~~~ if(diff > 1) { /* This could happen if this interupt was masked for more than one RTOS tick period */ vTaskStepTick(diff – 1); } /* Increment the RTOS tick as usual which checks if there is a need for rescheduling / if ( xTaskIncrementTick() != pdFALSE ) { / A context switch is required. Context switching is performed in the PendSV interrupt. Pend the PendSV interrupt. */ SCB->ICSR = SCB_ICSR_PENDSVSET_Msk; __SEV(); } ~~~

Why is vTaskStepTick available only for tickless idle mode?

If that is the code that calls xTaskIncrementTick() then it is requesting a context switch for a non-zero value, so looks correctly. Where do you put this code? You should call xTaskIncrementTick() for each ‘missed’ tick interrupt, which I guess going to be handled by the if( diff > 1 ) line, but only if the code is executed regularly (like from the idle task).

Why is vTaskStepTick available only for tickless idle mode?

Yes, this code is inside xPortSysTickHandler, so it runs regularly. So can we agree that removing the restrictions on vTaskStepTick in my case is safe? Because xPortSysTickHandler runs even in non tickless idle modes and there is still a need for correction in this modes.

Why is vTaskStepTick available only for tickless idle mode?

I would agree that “from your description it sounds like” removing the restriction is safe – but would not like to say anything absolute without implementing and testing myself.

Why is vTaskStepTick available only for tickless idle mode?

Thank you for your initial thoughts. I would then remove the restriction from my port and hope that you get some time to test this.