Prevent from going to sleep after using osDelay

Hello everyone,

I’m using a STM32H7 for a device that basically do some stuff and then goes to sleep indefinitely with configUSE_TICKLESS_IDLE configured, until some external interruption wakes him up. For going to sleep, stop mode of the uC is entered inside PreSleepProcessing().

Everything is working fine, except that when using osDelay() (based on vTaskDelay()) sometimes the uC goes to sleep and never wakes up (due to being tickless, basically it goes to sleep indefined until an external interruption happens).

I was expecting eTaskConfirmSleepModeStatus to prevent the OS from going to sleep whenever there is some task that is delayed due to having used the osDelay(). However, this is not happening, it just returns eSleepModeStatus eReturn = eStandardSleep and therefore the task that is currently blocked and waiting for a timeout, just that blocked “forever”. Therefore, I understand that eTaskConfirmSleepModeStatus is just used to cover the case of a task going from suspended to ready during the going to sleep procedure, right?

If so, my next question is, how should I solve this problem in order to assure that the osDelay is respected and that the task where it was called is executed on time?

I can think of a couple of solutions, such as for example creating some condition (to allow sleeping) managed by us and that can be checked by configPRE_SUPPRESS_TICKS_AND_SLEEP_PROCESSING(). But I’m not sure about it, as I feel that freeRTOS might already have some mechanism for these cases. Is that so? am I missing some configuration maybe? or is this a case that is supposed to be covered with custom application code?

If more details are needed in order to evaluate this, please let me know so I can provide them.

Thank you!

By design, tickless idle goes to sleep whether there are tasks in osDelay() or not. If some tasks are in osDelay(), the tickless implementation configures the timer for the task scheduled to finish its delay first.

In your case, eTaskConfirmSleepModeStatus() can tell you when all tasks are in a “wait-forever” state. It will return eNoTasksWaitingTimeout.

Then your PreSleepProcessing function can call eTaskConfirmSleepModeStatus() to distinguish between eNoTasksWaitingTimeout and eStandardSleep. If no tasks are waiting for a timeout, then you could use stop mode. But for eStandardSleep, you would not use stop mode.

1 Like

Hi Jeff, thanks for your answer.

Indeed one of the ideas that I had was to change this line inside vPortSuppressTicksAndSleep:
if( eTaskConfirmSleepModeStatus() == eAbortSleep )
for something like:
if( eTaskConfirmSleepModeStatus() != eNoTasksWaitingTimeout )

This way, I make sure that I’ll only go to sleep whenever I’m in eNoTasksWaitingTimeout status.

I did have to make another change for this: in eTaskConfirmSleepModeStatus I had to increase const UBaseType_t uxNonApplicationTasks = 1; to 2. This is because I have not only the idle task active all the time, but also the one timer_TCB due to configSUPPORT_STATIC_ALLOCATION. If not doing this change, I was never entering the corresponding if to get eReturn = eNoTasksWaitingTimeout.

Please let me know if you know of a cleaner way of doing this. If not, I think overall this will do the job.

Thanks!

You shouldn’t need to change uxNonApplicationTasks from 1 to 2. If the timer task is not on the suspended tasks list, then there must be at least one active timer it plans to wake up for. If you stop all timers, then the timer task will join the suspended task list. Do you have active timers when you hope to use stop mode?

Remember there are two levels of sleep here. Sleep and Stop. For eStandardSleep, you could let tickless sleep proceed in that case – just not using stop mode.
vPortSuppressTicksAndSleep() gives you that functionality already.

For eNoTasksWaitingTimeout, you could use Stop mode.

All of this assumes you plan to call eTaskConfirmSleepModeStatus() from within your PreSleepProcessing function.

I don’t see any active timer, at least not the ones that I’m controlling in my application: I made sure of that by calling osTimerStop on all of them before doing the osDelay that I mentioned. The only one that I see that is on xDelayedTaskList1 and not in xSuspendedTaskList is the one linked to vApplicationGetTimerTaskMemory. It’s the xTimerTaskTCB shown in the implementation example at https://www.freertos.org/a00110.html.

I think at the moment I’m not understanding 100% why that task is “delayed” and it seems to be the one causing that I can never obtain the state eNoTasksWaitingTimeout. Any ideas on this?

Regarding the sleep levels, yes, actually we want to eventually reach the standby mode provided by the uC. The idea is to do all necessary configurations (deinits, inits, etc.) and add some additional logic in PreSleepProcessing . But first I want to make sure I understand how all this other stuff works, have it robustly working on Stop mode, and then continue further.

If your debugger is FreeRTOS aware, it can show you a list of timers and their states. As you know, when you create a timer you also supply a name which can be helpful in identifying the timer. The debugger’s FreeRTOS plug-in can show you the names.

Ok so now I checked with more detail, and I identified which timer was still active. It’s the one we use for the watchdog. We use a software timer to refresh it, and we configure the IWDG to stop counting when entering in low power mode.

Therefore I can think of 2 solutions right now:
1- Stopping the watchdog software timer when we go to sleep, and activate it again when waking up. This is just to have all tasks suspended (and be able to use eTaskConfirmSleepModeStatus() as you said), beacuse in fact we are already ignoring the watchdog when going to sleep anyways.
2- Change our way of refreshing the watchdog. Maybe do it with a LPTIM interrupt and not with a software timer?

I’d go with (1), at least for now. Maybe in the future I’m interesting in waking up with internal timers to “do stuff” but at the moment I’m ok with sleeping for hours and just waking up with my external peripherals interruptions.

But of course let me know if I’m missing something or if there is some other good practices for these cases.

Thanks!

Yes solution 1 seems best.

When you get to that point, the RTC is best for automatically waking the system from the “off” modes like standby and shutdown.

1 Like