cancel
Showing results for 
Search instead for 
Did you mean: 

How to enter Standby or Shutdown mode on STM32

Piranha
Chief II

Entering low-power modes, especially the Standby and Shutdown modes, is another mostly software related disaster from ST. Additionally there also seems to be one or two hardware bugs and/or undocumented conditions. This topic provides an example of how to do it correctly and reliably and an explanation of the issues present in the current ST provided code and documentation.

 

Correct example code based on L43x devices:

void Power_Off(void)
{
	// Configure wake-up features
	// WKUP1(PA0) - active high, WKUP4(PA2) - active low, pull-up
	PWR->PUCRA = PWR_PUCRA_PA2; // Set pull-ups for standby modes
	PWR->CR4 = PWR_CR4_WP4; // Set wakeup pins' polarity to low level
	PWR->CR3 = PWR_CR3_APC | PWR_CR3_EWUP4 | PWR_CR3_EWUP1; // Enable pin pull configurations and wakeup pins
	PWR->SCR = PWR_SCR_CWUF; // Clear wakeup flags
 
	// Configure MCU low-power mode for CPU deep sleep mode
	PWR->CR1 |= PWR_CR1_LPMS_STANDBY; // PWR_CR1_LPMS_SHUTDOWN
	(void)PWR->CR1; // Ensure that the previous PWR register operations have been completed
 
	// Configure CPU core
	SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk; // Enable CPU deep sleep mode
#ifdef NDEBUG
	DBGMCU->CR = 0; // Disable debug, trace and IWDG in low-power modes
#endif
 
	// Enter low-power mode
	for (;;) {
		__DSB();
		__WFI();
	}
}

 

Issues and solutions explained:

 

// Configure wake-up features
...
PWR->SCR = PWR_SCR_CWUF; // Clear wakeup flags

1. Clearing of the wakeup flags must be done as the last operation after configuring wakeup features. When clearing the flags is not the last operation, MCU wakes up immediately after entering the low-power mode. After that, if the firmware will enter the low-power mode again with the same wakeup configuration, then because of some internal hardware logic nuances the second time the MCU will stay in low-power mode and wait for an actual wakeup event.

 

(void)PWR->CR1; // Ensure that the previous PWR register operations have been completed

2. Because the PWR peripheral is located on APB bus, the values written to the PWR registers take some time (clock cycles) to reach the peripheral. To ensure that the last (and therefore all) of the previous store operations have been completed, a read operation of some PWR register is required. If this is not ensured, the CPU can enter low-power mode before the PWR peripheral is configured.

 

#ifdef NDEBUG
	DBGMCU->CR = 0; // Disable debug, trace and IWDG in low-power modes
#endif

3a. To reach the lowest power consumption, the debug interface must also be disabled. When enabled, it typically results in up to 5 mA of additional current consumption. At least in debug builds the firmware can set these bits to enable debugging with low-power modes or, for example, J-Link debuggers always set these bits after the connection. As these bits are not reset by a system reset and power-on reset can be problematic on some devices, including because of a capacitors of a few uF can retain the voltage for several minutes, it is recommended to always clear those bits manually at least in release builds.

3b. If debug interface is enabled, contrary to the reference manual, IWDG continues running in shutdown mode and resets (and therefore wakes up) the MCU after the configured time. Another way to disable the IWDG in shutdown (and standby) mode is clearing the IWDG_STDBY bit in option bytes.

 

for (;;) {
	__DSB();
	__WFI();
}

4. If a debug request or interrupt happens at the same time the WFI instruction is executed, the WFI instruction acts as a NOP instruction. That means the CPU doesn't enter a (deep) sleep mode but instead continues executing the code. If the code relies on the idea that the CPU will not execute the instructions beyond the WFI instruction, it's a bug and the consequences can be unpredictable. As the standby and shutdown modes are designed to stop the code execution after the WFI instruction anyway, the issue can be solved by just putting the WFI instruction in an endless loop. Also before the WFI instruction HAL code uses __force_stores() intrinsic only for ARM compiler, but the __DSB() macro is universal for all compilers and is required by ARM architecture.

 

I can confirm this behavior on L43x devices, but it seems that it is the same at least for many other parts also. For example, this topic confirms the same for a L0 series device.

 

Tasks for ST to fix:

  • 1, 3b - Potential hardware bugs and could be closely related. Must be checked/confirmed and, depending on that, should be documented in erratas and/or reference manuals.
  • 2, 3a, 4 - Should be documented (reminded) in reference manuals.
  • 2, 4 - HAL functions HAL_PWR_EnterSTANDBYMode() and HAL_PWREx_EnterSHUTDOWNMode() should be fixed.
  • 1, 3 - Code examples should be fixed.
17 REPLIES 17
Robmar
Senior III

These->>>> flags no longer exist in the H743 HAL:-

PWR->SCR = ->>>>PWR_SCR_CWUF; // Clear wakeup flags

 

// Configure MCU low-power mode for CPU deep sleep mode

PWR->CR1 |= ->>>>>PWR_CR1_LPMS_STANDBY; // PWR_CR1_LPMS_SHUTDOWN

 

I start to wonder if STM are going to stop making MCUs... hence near to zero support

ocean_rse
Associate II

Old thread, I know, but I wanted to add to this that I was able to patch up the behavior of Shutdown mode with the STM32U5A5 with this. I am inclined to believe it was adding the clearing of wakeup flags that did the trick, that and putting __WFI() with __DSB() in a loop. I did notice after doing this that, in debug mode, it would loop around multiple times.

I was having an issue where the device would go into Shutdown mode and wakeup via a wakeup pin, all perfectly, but only once. Every subsequent time, the device would go into reset immediately after entering Shutdown mode. Even though the power status (PWR->SR) register showed no flags, it would wake/ reset immediately, in and out of debug mode. I reread the reference manual a great many times and tries all kinds of writes and bit clearing in the PWR registers to no avail.

An interesting observation is that this behavior was not present until I added Stop2 mode calls when the RTOS is idle. Another reason that there must be some undocumented behavior or hardware bug, seeings that there is a STOPF flag also in PWR-SR register. Stranger still is that I would clear the STOPF flag (and by proxy, the SBF flag) in PWR->SR on wakeup from Stop2 mode, so it would enter into the shutdown function with no flags set.

If this can help anyone else, this is the code I have working on STM32U5A5 (Don't hate on the HAL call ... it works):

void enter_shutdown_mode ( void )
{
  // Make sure the RTC and LSE are enabled in Shutdown mode (optional)
  SET_BIT(RCC->BDCR, RCC_BDCR_LSEON);
  SET_BIT(RCC->BDCR, RCC_BDCR_RTCEN);

  // Clear the backup ram retention bit
  CLEAR_BIT(PWR->BDCR1, PWR_BDCR1_BREN);

  // PWR_WAKEUP_PIN2_HIGH_1 = PC13 -> Nucleo User Button (technically an Errata item...)
  HAL_PWR_EnableWakeUpPin (PWR_WAKEUP_PIN2_HIGH_1);

  // By the way, if you are working with the U5 series, READ THE ERRATA!
  // Seriously, can't tell you how many times I have butted heads against
  // hardware bugs in the U5 series. U575/585 are the worst for hardware bugs.

  // Clear the stop mode and standby mode flags
  SET_BIT(PWR->SR, PWR_SR_CSSF);

#ifndef DEBUG
  DBGMCU->CR = 0; // Disable debug, trace and IWDG in low-power modes
#endif

  /* Set Shutdown mode */
  MODIFY_REG(PWR->CR1, PWR_CR1_LPMS, (PWR_CR1_LPMS_1 | PWR_CR1_LPMS_2));

  /* Set SLEEPDEEP bit of Cortex System Control Register */
  SET_BIT(SCB->SCR, ((uint32_t)SCB_SCR_SLEEPDEEP_Msk));

  // Make sure register operations are complete
  (void) PWR->CR1;
  (void) SCB->SCR;

  // Enter low-power mode
  while ( 1 )
  {
    __DSB ();
    __WFI();
  }
}

 

Jorgie
Associate III

Is there a solution to this yet?

I'm having the same problem on the STM32U083 keeps resetting after entering SHUTDOWNMode.

 

Have you tried the code posted above? I have not worked with the U0 series yet, but I can confirm this works for the U5A5 and U575 series.

Hi 

I've tried the following code without success.

			  PWR->SCR = PWR_SCR_CWUF; // Clear wakeup flags
			  /* Set Shutdown mode */
			  MODIFY_REG(PWR->CR1, PWR_CR1_LPMS, PWR_CR1_LPMS_2);


			  /* Set SLEEPDEEP bit of Cortex System Control Register */
			  SET_BIT(SCB->SCR, ((uint32_t)SCB_SCR_SLEEPDEEP_Msk));

			  /* This option is used to ensure that store operations are completed */
			#if defined ( __CC_ARM)
			  __force_stores();
			#endif /* __CC_ARM */
			  /* Request Wait For Interrupt */
				for (;;) {
					__DSB();
					__WFI();
				}
Jorgie
Associate III

I have run the PWR_SHUTDOWN on 3 different Nucleo-STM32U083 boards. One works as expected the other two will do a reset and exit from shutdown.

So the code appears to be correct.

i wonder if there is an issue with a certain batch of the processor?

Robmar
Senior III

I also found the H743VIT6 did not handle power-down as expected, but STM have not responded.

Very poor support.

Are you waking the device by wakeup pin? If so, have you set the pull up/down resistors? In an early attempt I had set my system up for wakeup via pin but did not set a pull resistor and the behavior was, as you would expect, unpredictable.

Since you mentioned using a Nucleo board, keep in mind that PC13 is typically connected to the "User Button", which is commonly used as a wakeup source in examples. There is an errata item regarding using PC13 as it will disturb the LSE. For development with Nucleo boards, I have taken to switching the user button to the alternative configuration (PA0, in my case with the U5A5 Nucleo board) to alleviate this. If this applies to you, might be worth trying.