Skip to main content
JGUIT.1
Associate II
July 2, 2020
Question

How to enter SLEEP/STOP mode on STM32WB device ?

  • July 2, 2020
  • 12 replies
  • 12560 views

Hello,

I wonder how the STM32WB device should be entered in SLEEP or STOP mode. Any specific actions to reduce the total consumption to the minimum, particularly thinking to the radio? When is it good to enter SLEEP or STOP mode ?

If anyone can point a working example, it will be great :)

Context : I have Thread (and in near future BLE+Thread) running on my device. I would like to put the total consumption to the minimum because the board is supplied with a small battery. Then periodically the device is wake-up, processing, sending data to the Thread network and finally goes to STOP mode again.

Thanks,

Joel

This topic has been closed for replies.

12 replies

Piranha
Principal III
July 4, 2020

SLEEP is used while everything is working, but the CPU has nothing to do for some time. STOP is used when you turn off at least some part of the hardware.

JGUIT.1
JGUIT.1Author
Associate II
July 5, 2020

Hello @Piranha​ 

I'm aware of that, I just want to know how I can do it with the STM32WB :) I want to sleep properly the radio core too. Then when the MCU wakes up, turn on the radio again and connect to my thread network to send data.

I have tried some playing with "HAL_PWR_EnterSLEEPMode" function but with no success, even the main core does not enter sleep mode. I suppose I have to turn off the radio and then use "HAL_PWR_EnterSLEEPMode" but I have not found any example...

Thanks,

Joel

JGUIT.1
JGUIT.1Author
Associate II
July 6, 2020

Updates : I have used the example "Thread_Udp" in which the function "UTIL_SEQ_Idle" has the following content:

void UTIL_SEQ_Idle( void )
{
#if ( CFG_LPM_SUPPORTED == 1)
 UTIL_LPM_EnterLowPower( );
#endif
 return;
}

So I have defined CFM_LPM_SUPPORTED to enter low power mode. Seems the program enters this function but the best I have reach is 14mA on my P-NUCLEO-WB55 (open JP2 to measure CPU consumption).

This is not really the expected result. This document https://www.stmicroelectronics.com.cn/content/ccc/resource/training/technical/product_training/group0/38/e8/fa/59/e8/38/46/63/STM32WB-System-Power-control-PWR/files/STM32WB-System-Power-control-PWR.pdf/_jcr_content/translations/en.STM32WB-System-Power-control-PWR.pdf indicates 2µA in STOP2 mode.

Piranha
Principal III
July 6, 2020
JGUIT.1
JGUIT.1Author
Associate II
July 6, 2020

Thanks this suggestion is great and make some progress!

I have written the following in a blank project :

DBGMCU->CR = 0;
HAL_SuspendTick();
LL_PWR_SetPowerMode(LL_PWR_MODE_STOP2);
LL_C2_PWR_SetPowerMode(LL_PWR_MODE_STOP2);
LL_LPM_EnableDeepSleep();
__WFI();
SystemClock_Config();
HAL_ResumeTick();

The MCU goes in STOP2 and the power consumption is about 2µA which is conformed with the specification.

Now trying to add this in a Thread application. Still using "Thread_Udp" as a basis to make some testing.

ST Employee
July 30, 2020

Hello,

Generally speaking, the CPU1 shall never write CPU2 registers with LL_C2_***().

This can be done only in specific corner case under specific conditions.

The workaround described that recommends to use LL_C2_PWR_SetPowerMode(LL_PWR_MODE_STOP2); is required only in case CPU2 is not started.

In that case when CPU2 is not started ( which is not the case in all ST BLE examples), and only CPU1 is running , the reset value of the low power mode of CPU2 is set to Stop Mode 0. This will limit the full device to Stop Mode 0 at best.

So, the workaround is to use LL_C2_PWR_SetPowerMode(LL_PWR_MODE_STOP2) before CPU2 is started with C2BOOT. As soon as CPU2 has been started, LL_C2_PWR_SetPowerMode(LL_PWR_MODE_STOP2); shall not be used anymore as this will break the power management implemented on CPU2.

Each CPU subsystem on STM32WB has its own low power management and each CPU subsystem shall take care only of its own low power mode.

As soon as CPU2 is started, CPU1 has nothing to do to control low power mode on CPU2.

Basically, CPU1 shall handle sleep/stop low power mode has this will be done on any STM32 single core product with no worry of CPU2.

The only difference is that you should use the implementation of stm32_lpm_if.c as there are some RCC registers that may be accessed by both Cores when entering low power mode at the same time  so it is required to use some semaphore.

stm32_lpm_if.c implements the algorithm to use.

Regarding Thread project, you should start from a Thread_SED_*** application that implements the low power mode.

Regards.

Scott Löhr
Senior III
August 1, 2020

@Christophe Arnal​ , thank you for taking the time to make this valuable addition to understanding of the power modes between CPU1 and CPU2!

Now I fully appreciate the order of steps in the sample apps, and now fully understand the importance of once, before running CPU2 interface intialization, configuring the LL_C2_PWR_SetPowerMode().

But wrt the algorithm to use in stm32_lpm_if.c, it looks suspicious to me, referencing v1,8.0 code, PWR_EnterStopMode() function will attempt to enter STOP2 even if it fails to get the semaphore, CFG_HW_ENTRY_STOP_MODE_SEMID, and even if the CPU2 says it is busy by LL_PWR_IsActiveFlag_C2DS(). No matter what, the code flows down to invoke LL_PWR_SetPowerMode( LL_PWR_MODE_STOP2 );

It looks like a bug, because if it is always ok to just enter STOP2 on the CPU1, then why keep all of that code pretending to check if it is ok?

ST Employee
August 13, 2020

​Hello Scott,

 I understand you are referring to that code before entering Stop Mode 2

while( LL_HSEM_1StepLock( HSEM, CFG_HW_RCC_SEMID ) );
 
 if ( ! LL_HSEM_1StepLock( HSEM, CFG_HW_ENTRY_STOP_MODE_SEMID ) )
 {
 if( LL_PWR_IsActiveFlag_C2DS( ) )
 {
 /* Release ENTRY_STOP_MODE semaphore */
 LL_HSEM_ReleaseLock( HSEM, CFG_HW_ENTRY_STOP_MODE_SEMID, 0 );
 
 /**
 * The switch on HSI before entering Stop Mode is required 
 */
 Switch_On_HSI( );
 }
 }
 else
 {
 /**
 * The switch on HSI before entering Stop Mode is required 
 */
 Switch_On_HSI( );
 }

The purpose of this code is not to decide if we are allowed to enter Stop Mode or not. Whatever we are doing there, the decision has already been taken to enter Stop Mode.

The purpose of this code is to understand if we can switch on HSI or not before entering Stop Mode.

There are two points to check :

1/ We are checking C2DS because we dont want to switch on HSI if CPU2 is running as it requires a 32Mhz Clock.

2/ As both CPU are almost running the same algorithm, if each of them checks at the same time the CxDS bit, none of them will switch on HSI whereas they are both on the way to enter Stop Mode. The "Strange" use of CFG_HW_ENTRY_STOP_MODE_SEMID semaphore is there to handle this corner cases.

Now the only point is the reason why to switch on HSI before entering Stop Mode 2. This was mandatory on Cut2.0 and the bug is fixed on Cut2.1. Unless you get some board at mass market launch during some workshop, you should have a Cut2.1 board.

The workaround has been kept for Cut2.1 because it does not hurt and all our validation have been executed with the workaround. Therefor, it is recommended to keep it for safety.

Regards.

Scott Löhr
Senior III
August 1, 2020

Man-o-man, I am sorry to throw a monkey wrench into this discussion, but running with v1.8.0, it is more simple than you can imagine to get this beast into and out of STOP2. I am running from the HSE xtal, configuring the system clock to use the PLL, and before entering STOP2, I do not manually re-configure the clock for HSI (i.e. calling Switch_On_HSI() is unnecessary) and I do not try to get any of the semaphores shown in the stm32_lpm_if.c code. As I pointed out in a response above, that code looks suspect because regardless of the outcome of checks if STOP2 is ok with CPU2, it enters/attempts STOP2 anyway (and that is what inspired me to just go for it, without all of that rigamarow). Now that being said, it is obvious that this beast puts itself into HSI mode after wake from STOP2, so you do have to reconfig for the clock source and setup that you want for running full speed after STOP2. So its literally 4 lines to get in and out of STOP2:

   LL_PWR_SetPowerMode(LL_PWR_MODE_STOP2);

   LL_LPM_EnableDeepSleep();

   __WFI();

   sysClkCfg();

With the function sysClkCfg() implementing whatever clock configuration that you are running with, a subset of the clock initialization stuff that you do at powerup.

Also, of course, as Christophe Arnal (how to mention a community member "in-line" like right here? @Christophe is not doing anything for me using the Microsoft Edge browser) points out above, once at powerup, before starting the CPU2, you need to call LL_C2_PWR_SetPowerMode(LL_PWR_MODE_SHUTDOWN);

Can anyone confirm my observation of STOP2 simplicity running on the STM32WB Nucleo board and v1.8.0 stm32wb5x_BLE_Stack_full_fw.bin?

ST Employee
August 13, 2020

​Hello Scott,

If you decide to not switch on HSI before entering Stop Mode, then it is fine to skip all the code I have listed above.

Just take care that the code is running in critical section and I am affraid  sysClkCfg() is quite long.

Most of the time, there is just a couple of things to do to recover the clock so I would not go with the generic API to speed up the code in critical section but just use the required LL.

Regards.

Scott Löhr
Senior III
August 7, 2020

Ok, so just to keep this little conversation with myself going, I'll share a little gotcha with you wrt STOP2 and the IWDG (maybe it didn't/wouldn't get you, but it got me):

Although I configured the IWDG to freeze in STOP by clearing the IWDG_STOP bit in the FLASH_OPTR (a non-trivial effort), I discovered that even as CPU1 is in STOP2 with no reason to wakeup, if the BLE is connected, then apparently by the activity on CPU2, the IWDG continues to run and will reset the board if CPU1 doesn't pet it. I know, I know, it begs the question for you: why does CPU1 not just terminate the BLE connection if there is nothing to do but save battery in STOP2 ... it's a bit of an albatross of a scenario in our system that I would like to not to have to support, but I do.

ST Employee
August 13, 2020

​Hello Scott,

Here is the way it works :

As described in chapter 6.4 Low-power modes of the reference manual (Fig12), there is the concept of CSTOP and STOP.

The concept of CSTOP is basically the Stop Mode of one CPU subsystem when the DEEEPSLEEP bit of this CPU has been set and the CPU is in WFI ( in cour case). In that case, for the CPU in CSTOP, the CPU is not running and its clock tree is gated.

The concept of STOP applies to the whole system. When both CPUs are in CSTOP ( and there is no RF activity). In that case, both CPU are not running, both clock tree are gated and in addition, the system clock is switched OFF - this is basically the Stop Mode well known on any STM32 device.

According to the reference manual, the  IWDG  depends on the STOP Mode so in between BLE connection interval, the IWDG is not clocked because the full device is in Stop Mode but during Radio Activity, IWDG will receive a clock during the radio event because the system is not is STOP mode.

In order to check this, the timeout should depend on the BLE interval. You may try with a very short BLE interval versus a very long interval and you should see a significant change in the Timeout.

Regards.

ST Employee
August 14, 2020

​Hello @Scott L�hr​ ,

I have just been told that the WWDG should behave as you expect. It is only linked to CPU1 activity

Regards.

Scott Löhr
Senior III
August 13, 2020

@Christophe Arnal​ thank you for the valuable details which enable a great understanding of this system - a virtual white paper is being written among the posts in this group thanks to expert input from folks like you!