STM32 deepsleep modes (STOP, STOP2, STANDBY) with FreeRTOS
19 Mar 2021
STOP2 and STANDBY modes are great way to achieve uA and sub-uA consumption. When using an RTOS, the tasks must synchronize when to go to deepsleep, especially to STANDBY mode, which requires most hardware modules to be re-initialized.
You must either create complex synchronization between tasks, and possibly create a “managing” task that puts the system into deepsleep,
or you can use FreeRTOS hooks to achieve the same, but in a somewhat cleaner way.
I’ll show here the latter one.
The concept
FreeRTOS provides hooks, that are called both before and after sleep. The following snippet is from port.c’s vPortSuppressTicksAndSleep function:
I’d like an API, which allows individual tasks marking themselves as “ready to deepsleep”, and when all critical task set this flag, FreeRTOS should put the system into deepsleep. Something like this:
Implementation
Both RTOS hooks (configPRE_SLEEP_PROCESSING and configPOST_SLEEP_PROCESSING) are definable in FreeRTOSConfig.h:
Here are the implementation, note how I disable the SYSTICK timer, so I can control the wakeup sources.
Regarding the allow/prevent functions, I implemented a simple counting mechanism. For re-entrant semaphores or even more automated solutions, browse the FreeRTOS API. I shot here for the easiest & fastest solution. I fancy however a mechanism that iterate over each task, and checks their state - for example on threadlocal storage - and does this very same thing, but automagically without POWER_REQUIRED_TASK_COUNT_TO_STOP.
Usage
For somewhat more complex example, this is how I LoRaWAN with LMIC library. Whenever I want to send something, I call vTaskResume (which can be called for non-suspened tasks as well). Stopping the task at this critical moment ensures the LoRa transceiver remains in SLEEP mode.