[EFM32HG][FreeRTOS] vTaskDelay hangs after switching from EM2 to EM0

I am using the official FreeRTOS-Kernel build on a EFM32HG MCU with the tickless idle mode being activated.

In order to achieve more energy saving I am using the energy management unit to enter EM2 mode in the inactive time.
For this purpose, I have configured to RTC to generate an interrupt when the standby time is spent in EM2.
The RTC forces a switch to EM0 then and the real time tasks are active again.
The issue I am facing is that one of the tasks hangs on vTaskDelay indefinitely. And when keep the RTC running on the active time, vTaskDelay is unblocked when the RTC ticks again.

The FreeRTOS kernel is driven by the system clock and the RTC interrupt priority is lower than the SysTick.

Also, this behavior is not seen when the debugger is connected to the board (debug session with no breakpoints).

Did someone of you guys faces such an issue before? any explanations?

Thanks

Hi @Boussetta , Thanks for your post. I’ve couple of questions,

How are you calculating the inactive/standby time?

Since you are handling entering and exiting EM2, have you made sure that xModifiableIdleTime (https://github.com/FreeRTOS/FreeRTOS-Kernel/blob/main/portable/GCC/ARM_CM0/port.c#L497) is 0 so that wfi is not executed?

A debug event wakes up the processor from sleep. I guess the behaviour is similar for EM2, hence behaviour is not seen when the debugger is connected.

Thanks

Hi @urutva, thank you for the response.

How are you calculating the inactive/standby time?
I have a duty cycle written to the flash memory user data page.

The standby time is the calculated by subtracting the active time from the duty cycle. That will be spent in EM2.

have you made sure that xModifiableIdleTime is 0 so that wfi is not executed?

I didn’t modify the vPortSuppressTicksAndSleep function to let the scheduler decide about the tickless idle mode for short energy saving periods during EM0 time / active.

the task hangs after a call to vTaskDelay(pdMS_TO_TICKS(sensor_conversion_time));
sensor_conversion_time = 30ms
#define configTICK_RATE_HZ 200 /* 5ms time slices. */
therefore:
xModifiableIdleTime = 6

In this case I want the tickless idle mode to operate nominally. We will have a call to __asm volatile ( "wfi" );

After finising all the processing I am calling Enter_EM2 from outside vPortSuppressTicksAndSleep (which is limited to xMaximumPossibleSuppressedTicks) to spend the inactive time in pure EM2 and only keep the RTC, which will be driven by a low frequency oscillator LFXO, up to the wakeup time.

@Boussetta Thanks for the explanation.

It seems like after switching from EM2 to EM0, SysTick is not firing. I’m not sure which library are you using for EM, but looking at the comments in https://github.com/FreeRTOS/FreeRTOS/blob/main/FreeRTOS/Demo/CORTEX_EFM32_Giant_Gecko_Simplicity_Studio/SiLabs_Source/emlib/em_emu.c#L372, (When entering EM2, the high frequency clocks are disabled, ie HFXO, HFRCO and AUXHFRCO (for AUXHFRCO, see exception note below). When re-entering EM0, HFRCO is re-enabled and the core will be clocked by the configured HFRCO band. This ensures a quick wakeup from EM2..
However, prior to entering EM2, the core may have been using another oscillator than HFRCO. The @p restore parameter gives the user the option to restore all HF oscillators according to state prior to entering EM2, as well as the clock used to clock the core.), have you tried to set the restore parameter true and check if the SysTick is fired.

From the datasheet https://www.silabs.com/documents/public/data-sheets/efm32hg-datasheet.pdf, I couldn’t identify which clock is used for clocking the SysTick. Can you please check this?

It seems like after switching from EM2 to EM0, SysTick is not firing

Actually the scheduler is back to work, and I can check the tasks execution. It’s hanging only when calling to vTaskDelay.

I’m not sure which library are you using for EM

I am using the Gecko SDK EMU

I couldn’t identify which clock is used for clocking the SysTick

I am using EFM32HG350F64 MCU:
The core clock HFCORECLK is driven by the high-frequency oscillator (HFRCO) at 14MHz,

have you tried to set the restore parameter true and check if the SysTick is fired.

Of course, When entering the EM2 I set the restore value to true so that when getting back to EM0 the High frequency clocks are restored.

Actually, I set an ugly work around this issue, the code looks like this:
rtc_enable(); rtc_compare_register_set(sensor_conversion_time); vTaskDelay(pdMS_TO_TICKS(sensor_conversion_time)); rtc_disable();
But I have to find the real solution so that vTaskDelay(pdMS_TO_TICKS(sensor_conversion_time));doesn’t hang.
:laughing:

I’m not familiar with the port side of things but vTaskDelay() has this behavior where

  1. assuming you have INCLUDE_vTaskSuspend set to 1 in your FreeRTOSConfig.h
  2. vTaskDelay(pdMS_TO_TICKS(sensor_conversion_time)) is called when the value of pdMS_TO_TICKS(sensor_conversion_time) is greater than whatever you set as portMAX_DELAY in your FreeRTOSConfig.h

vTaskDelay will put your task into the suspended list. Could you check your FreeRTOS config settings to see if this scenario can happen?

Can you whether this task is still on the delay list?

I still believe that the issue is related to the transition back from EM2 to EM0.

Before entering EM2 for the first time, when the task waits for the conversion time (I don’t have a feedback pin to trigger a GPIO interrupt) vTaskDelay doesn’t hang and the FreeRTOS-Kernel decides to enter a tickless periode that covers the conversion time (for this specific case 6 Ticks / 30millis) and therefore we have a call to __asm volatile ( "wfi" ); inside the vPortSuppressTicksAndSleep function.

After the EM2 period and when performing the same process again vTaskDelay hangs if I don’t make the RTC fire a tick to make the Kernel exit the tickless period.

I am not sure which clock was used before entering the EM2. I disable the RTC in active time, I enable it only when we enter the EM2 mode to wake up the MCU for the next duty cycle.

For the official FreeRTOS-Kernel build, which clock is used to track time in tickless periods?

If I figure out this I can later check if this clock is being disabled when entering the EM2 but not restored when back to EM0.

The EFM32HG Reference Manual, section 10.3.2 Entering a Low Energy Mode indicates that issuing wfi causes entering low energy mode EM1 (the reset value of EM4CTRL and SLEEPDEEP are 0). I believe this is is what is happening when __asm volatile ( "wfi" ); inside the vPortSuppressTicksAndSleep. Section 10.3.3 Leaving a Low Energy Mode shows EMU wakeup triggers and SysTick isn’t listed there.

Just to make sure, can you try disabling entering EM2 and see if SysTick triggers EM1 to EM0 transition?

In my project FreeRTOS configuration:

  • SYSTICK_CLOCK_HZ = 14000000UL
  • TICK_RATE_HZ = 200

Therefore:

MaximumPossibleTicks = 239 or 1195ms

If I write the instruction vTaskDelay(1000); (RTC being disabled at this stage) the FreeRTOS-Kernel will loop on vPortSuppressTicksAndSleep until achieving the desired delay. And only then returns from vTaskDelay(1000); and goes to the next instruction.

The issue is seen after the coming back from EM2 and any value passed to vTaskDelay(); function will drive the kernel to an indefinite hang caused by the wait for interrupt instruction.

The issue is not seen when spending Standby time in EM1 instead of EM2.

I believe this makes sense since entring EM1 will keep the High frequency peripheral clock trees and the High frequency oscillator On.

Actually, I can’t tell if it’s a bug in Gecko SDK or not. But when exiting from EM2 the SLEEPDEEP bit is not cleared from the System Control Register.

Keeping the SLEEPDEEP bit enabled will force a transition to EM2 instead of EM1 during tickless periods which are not required for very short periods of time.

When the EM2 time is elapsed, I clear the SLEEPDEEP bit:
SCB->SCR &= ~SCB_SCR_SLEEPDEEP_Msk;
and that way vTaskDelaywill not be hanging just like before entering EM2.

Therefore, there is no longer need for the RTC to watch the vTaskDelay function, and it could just be disabled during active time / EM0.

1 Like

Good work figuring it out. The Gecko SDK probably should not leave SLEEPDEEP set after their WFI instruction.

1 Like

@Boussetta Thanks for reporting back! Good work identifying the issue.

1 Like

@urutva Thank you for assisting me all the way to the explanation and solution.

1 Like