I’m using STM32L4S5 MCU and freeRTOS with two tasks and binary semaphore. I’m trying to integrate stop mode and somehow managed to make it work. Sort of. But when I include condition in gpio interrupt to check whether we’re in low power mode or not it will not work properly. It’s like the system clock slows down considerably. So If I comment out this condition: “if ( PWR->SR2 & 0x200 )” it will work properly.
Or is this even allowed way of using stop mode when RTOS is in use?
void Go2Sleep()
{
HAL_SuspendTick();
HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFI);
}
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
// If button is pressed. Either wake up and set button press flag or just flag
if ( GPIO_Pin == NAPPI_Pin)
{
FlagForButtonPress = true;
// Resume only if low power mode is active. (bit 9 Low-power regulator flag)
if ( PWR->SR2 & 0x200 )
{
SystemClock_Config ();
HAL_ResumeTick();
}
}
}
// Task 1
void Start_Task_Display_Up(void *argument)
{
for(;;)
{
if (xSemaphoreTake(DisplayUpdate_sem, portMAX_DELAY))
{
// do stuff
..
// in some condition go to sleep
Go2Sleep();
}
}
}
// Task 2
void Start_Task_Read_ADC(void *argument)
{
for(;;)
{
if (xSemaphoreTake(ADCRead_sem, portMAX_DELAY))
{
// Do stuff
}
}
}
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
/* USER CODE BEGIN Callback 0 */
long task_woken = 0;
/* USER CODE END Callback 0 */
if (htim->Instance == TIM6) {
HAL_IncTick();
}
/* USER CODE BEGIN Callback 1 */
if (htim->Instance == TIM16) {
// 0,25 second timer
xSemaphoreGiveFromISR(DisplayUpdate_sem, &task_woken);
}
if (htim->Instance == TIM17) {
// 0,004 second timer
xSemaphoreGiveFromISR(ADCRead_sem, &task_woken);
}
portYIELD_FROM_ISR(task_woken);
}
What does stop mode do? For example, does it shut down the core clocks but keep the RAM powered?
I think the code you show will result in time slippage. For example, if a task blocks for 1000ms, 500ms into the block period you enter sleep mode, 500ms later you exit, then the task should unblock – but the task will not have seen the time change between the system going to sleep and the system coming out of sleep.
Is there a reason you don’t use the built in tickles idle mode to go to sleep? You can use the pre and post sleep processing macros to do anything chip specific.
All clocks in Vcore domain are stopped. RAM and register contents are preserved.
This time slippage sounds exactly what is happening as I see after it is woken up it seems to go 6x slower. Eg. tested 10 seconds to sleep became 60 seconds. So all timers got six times slower.
The tickless idle mode will manage correcting the time as seen by the tasks and by default enter a light sleep mode. If you want to do more than the light sleep and enter stop mode then you need to do everything necessary to enter stop mode in the pre-sleep hook and everything necessary to exit stop mode in the post sleep hook.
There is an extra wrinkle to consider here. The built-in tickless mode depends on the systick timer to keep time. However, the systick timer stops in stop mode.
Using stop mode and keeping kernel time is like having your cake and eating it too. The FreeRTOS distribution has a couple of demos with custom tickless implementations to allow this very thing. The lptimTick.c gist goes one step further by moving the tick entirely off the systick, using the LPTIM timer instead. That way there’s no slippage in kernel time.
You’ll still need to implement the pre- and post-sleep hooks to induce and recover from stop mode when conditions permit, just like the built-in tickless mode. But kernel time will remain accurate.
One alternative is to not use the core timer for the FreeRTOS Tick interrupt but one of the Low Power Timers that can continue to run in some of the Stop modes.
Thank you everyone. I’ll have a look at those suggestions.
Just wondering as I also tried to suspend the tasks before going to sleep and then resume them on wake up but that didn’t work either. Like, in my case I don’t need to preserve anything during the time of stop mode. It would be ok to start the tasks completely fresh every time the device wake up. Would that be possible and would that get rid of the time slippage? Just trying to find some shortcuts if any…
The question is why do you think you need to suspend the tasks? Normally the pre-requirement for going into a low power mode like this is that every task (except the idle task) needs to be blocked on something and not expected to be woken in the near future.