cancel
Showing results for 
Search instead for 
Did you mean: 

STM32U545 Low-Power Mode with FreeRTOS

JPortilha
Associate III

Hello, I am currently using the NUCLEO-U545RE-Q and trying to set low-power modes with FreeRTOS. I have already seen videos from official ST channel and read documentation but I cannot get to set this functioning when using FreeRTOS and RTC. My goal is to blink an LED every 5 seconds and in the reamaining time go to STOP mode for low power consumption. This are my functions:

void StartDefaultTask(void *argument)
{
  /* USER CODE BEGIN defaultTask */
  /* Infinite loop */
  while(1)
  {
	  osSemaphoreAcquire(BinarySemaphoreHandle, osWaitForever);
	  printf("Toggle Led\n");
	  BSP_LED_Toggle(LED_GREEN);
  }
  /* USER CODE END defaultTask */
}

/* Private application code --------------------------------------------------*/
/* USER CODE BEGIN Application */

void HAL_RTCEx_WakeUpTimerEventCallback(RTC_HandleTypeDef *hrtc)
{
	printf("RTC Callback\n");
	osSemaphoreRelease(BinarySemaphoreHandle);
}

void PreSleepProcessing(uint32_t ulExpectedIdleTime)
{
	HAL_SuspendTick();

	/* Start low power timer */
	if (HAL_RTCEx_SetWakeUpTimer_IT(&hrtc, 2000, RTC_WAKEUPCLOCK_RTCCLK_DIV16, 0) != HAL_OK)
	{
		Error_Handler();
	}

	/* Enter STOP2 */
	HAL_PWREx_EnterSTOP2Mode(PWR_STOPENTRY_WFI);
}

void PostSleepProcessing(uint32_t ulExpectedIdleTime)
{
	HAL_RTCEx_DeactivateWakeUpTimer(&hrtc);
	SystemClock_Config();
	/* Resume HAL timebase */
	HAL_ResumeTick();
}

When I add the code inside PreSleep and PostSleep the LED simply does not blink. From printing debug, the application is always going to PreSleep and PostSleep non-stop and the RTC callback does not get fired. Can someone help me with this?

Best regards.

4 REPLIES 4
Khaled_DHIF
ST Employee

Hello @JPortilha ,

I think the key issue is that PostSleepProcessing() can run after any wakeup, not only after the RTC wakeup you intended.

In the FreeRTOS tickless flow, the sequence is roughly:

  1. The system goes idle.
  2. PreSleepProcessing() runs and arms the wake source.
  3. The MCU enters STOP mode.
  4. Any enabled interrupt can wake the core.
  5. PostSleepProcessing() runs.

So, if there is another interrupt source waking the MCU before the RTC expires, PostSleepProcessing() will still run, and if you call HAL_RTCEx_DeactivateWakeUpTimer() there, you may be disabling the RTC wakeup before it ever gets a chance to fire and release the semaphore. That would match what you are seeing: the code keeps cycling through pre-sleep and post-sleep, but the RTC callback never executes.

I would suggest checking two things:

  • Make sure there is no other periodic wakeup source active.
  • Do not deactivate the RTC wakeup timer unconditionally in PostSleepProcessing().That function is too early to assume the RTC was the wake source. A safer pattern is to leave PostSleepProcessing() only for clock restoration and tick resume, and stop/deactivate the RTC wakeup timer only from the RTC wakeup path itself.

Please let me know how it works out for you, 

Kind regards,

DHIF Khaled 

Please mark my answer as best by clicking on the “Accept as solution" button if it fully answered your question. This will help other users find this solution faster.​

Hello, I have changed the code a little bit. I now have this:

/* USER CODE BEGIN PREPOSTSLEEP */
void PreSleepProcessing(uint32_t ulExpectedIdleTime)
{
/* place for user code */
	HAL_PWREx_EnableUltraLowPowerMode();
	HAL_SuspendTick();
/* Start RTC */
  if (HAL_RTCEx_SetWakeUpTimer_IT(&hrtc, 20000, RTC_WAKEUPCLOCK_RTCCLK_DIV16, 0) != HAL_OK)
  {
	  Error_Handler();
  }
  /* Enter Stop2 mode, wake up on interrupt */
   HAL_PWREx_EnterSTOP2Mode(PWR_STOPENTRY_WFI);
}

void PostSleepProcessing(uint32_t ulExpectedIdleTime)
{
/* place for user code */
	/* Restore Clock settings */
	SystemClock_Config();
	/* Resume HAL timebase */
	HAL_ResumeTick();
}

void StartDefaultTask(void *argument)
{
  /* USER CODE BEGIN defaultTask */
  /* Infinite loop */
	for(;;osSemaphoreAcquire(appBinarySemHandle, osWaitForever))
	//while(1)
	{
		HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5);
	}
  /* USER CODE END defaultTask */
}

/* Private application code --------------------------------------------------*/
/* USER CODE BEGIN Application */
void HAL_RTCEx_WakeUpTimerEventCallback(RTC_HandleTypeDef *hrtc)
{
	osSemaphoreRelease(appBinarySemHandle);
}

Seems to be working, but my current consumption is around 30uA, when the datasheet says it should be around 3 or 4uA. Do you know what can be causing such high consumption?

BR.

Khaled_DHIF
ST Employee

Hello @JPortilha , 

Glad to hear that the default task is now running correctly. Your RTC/semaphore flow looks much closer to working as expected. If the LED is toggling properly but the current consumption is still high, I would suspect one of two things:

  1. The device is not actually spending most of its time in STOP2, or
  2. The current measurement is including board-level consumption rather than only the MCU supply path.

A few points are worth checking:

  •  Look for any other interrupt source that may be waking the MCU periodically before the RTC wakeup expires.
    Even if the RTC path is correct, another timer, HAL timebase source, UART activity, EXTI interrupt, or debug-related wakeup can bring the core out of STOP2 often enough to keep the average current high.
  • Keeping PostSleepProcessing() minimal is still the right approach. Restoring the clocks and resuming the HAL tick there is fine. However, it is better NOT to stop or deactivate the RTC wakeup timer in PostSleepProcessing(), since that function runs after any wakeup source, not only the RTC wakeup.
  • The measurement setup matters on a NUCLEO board. In our low-power examples, we explicitly recommend measuring through the target current path and avoiding normal debug mode when performing low-power current measurements.

So, at this stage I would mainly check for a periodic wake source and confirm the current is being measured on the MCU supply path only, not the full NUCLEO board path.

Kind regards, 

DHIF Khaled 

 

Please mark my answer as best by clicking on the “Accept as solution" button if it fully answered your question. This will help other users find this solution faster.​
JPortilha
Associate III

Hello, I have analyzed the PCB layout (using the CAD documentation provided by the ST), and I am measuring the current using an external power supply with measuring capabilities (SMU). I have removed the JP5 and JP4 of NUCELO-U545RE-Q and I am supplying through JP5 pin 1. According to the layout on Altium, this pin will only supply the MCU, so I think that part should be ok. I have added prints for debugging and the system seems to only be entering and exiting the low power states every 10 seconds (driven by RTC). I have also added this line after peripheral init to disable the debugger

HAL_DBGMCU_DisableDBGStopMode();

I can leave a print of my current measurement, but according to datasheet STOP2 mode with RTC at 3.3V should be around 3.5uA.

image (9).png

BR