Skip to main content
RWeil.2
Associate III
December 2, 2023
Question

BLE, sleep mode and HSE

  • December 2, 2023
  • 6 replies
  • 4317 views

Hi,

as I understand it:
I can activate the low power manager in CubeIDE. This will automatically add code, so each time the Sequencer has nothing to do, the system enters low power mode.

So far, this works. I can see it in the current consumption.

What I don´t understand: Is the HSE deactivated during sleep? I think it has to be, otherwise the current consumption should be much higher. But I cannot confirm it, when I use a scope and set test point in the code.

If I go to the file stm32_lpm_if.c and edit:

 

static void EnterLowPower(void)

{

/**

* This function is called from CRITICAL SECTION

*/

HAL_GPIO_WritePin(testpin_GPIO_Port, testpin_Pin, 0);

...

 

and

 

static void ExitLowPower(void)
{
HAL_GPIO_WritePin(testpin_GPIO_Port, testpin_Pin, 1);
/* Release ENTRY_STOP_MODE semaphore */
...

 

then I can see that each 100 ms (advertising interval), the microcontroller wakes up (current spike and test pin goes high)

and then goes back to sleep (test pin goes low).

testpin_powerMode.png

 
But if I remove the testpin write and add it here:

 

static void Switch_On_HSI(void)
{
HAL_GPIO_WritePin(testpin_GPIO_Port, testpin_Pin, 0);
...

 

and here

 

static void ExitLowPower(void)
{
/* Release ENTRY_STOP_MODE semaphore */
LL_HSEM_ReleaseLock(HSEM, CFG_HW_ENTRY_STOP_MODE_SEMID, 0);
while(LL_HSEM_1StepLock(HSEM, CFG_HW_RCC_SEMID));
if(LL_RCC_GetSysClkSource() == LL_RCC_SYS_CLKSOURCE_STATUS_HSI)
{
/* Restore the clock configuration of the application in this user section */
/* USER CODE BEGIN ExitLowPower_1 */
HAL_GPIO_WritePin(testpin_GPIO_Port, testpin_Pin, 1);
LL_RCC_HSE_Enable( );
__HAL_FLASH_SET_LATENCY(FLASH_LATENCY_1);
while(!LL_RCC_HSE_IsReady( ));
LL_RCC_SetSysClkSource(LL_RCC_SYS_CLKSOURCE_HSE);
while (LL_RCC_GetSysClkSource( ) != LL_RCC_SYS_CLKSOURCE_STATUS_HSE);
/* USER CODE END ExitLowPower_1 */
}
...

 

then I observe, that the HSE is only turned on each 2,4 seconds.

testpin_HSE.png

I thought the procedure is:

Switch to HSI, go to sleep,

wakeup, turn on HSE, wait till it is ready, send advertisement package

swtich to HSI, go to sleep and so on.

 

From the readings on the oscilloscope, I cannot confirm that the HSE is turned on each 100 ms, as I would suppose it would be.

Also, when I monitor the MCO output (I output the HSE to a pin), it shows the HSI clock during sleep, but during the advertising there seems to be no clock signal on MCO pin (with prescaler = 16).

mco.png

Btw. all these measurements are done during debugging.

Sorry for the bad quality of the oscilloscope, I am using relatively simple equipment and an improvised test setup.

Kind regards

René

 

6 replies

Piranha
Principal III
December 2, 2023

That low-power mode code is broken, because it doesn't disable interrupts on a CPU, when it goes into low-power mode. As a result after wake-up before the clock configuration is complete any interrupt can run it's service routine and do things that probably should not be done in that MCU state. A proper example is there:

https://community.st.com/t5/stm32-mcus-motor-control/mc-sdk-not-work-with-mcu-stop-mode/m-p/94522

https://community.st.com/t5/stm32-mcus-embedded-software/how-to-enter-standby-or-shutdown-mode-on-stm32/m-p/145849

RWeil.2
RWeil.2Author
Associate III
December 4, 2023

Most of the code is automatically generated by CubeIDE. So you are saying that ST is generating "broken" code as default in their development environment?

The device I´m measuring is working in the field for about a year now, with optimal current consumption (~3 uA in sleep, ~13 mA peak during advertising).

I am just wondering, why I cannot see the HSE signal on the MCO pin during debug. I am pretty sure the microcontroller switches correctly, as BLE functionality is working without problems.

Piranha
Principal III
December 6, 2023

Yes, all (HAL library, CubeMX generated and examples) of ST's low-power related (and most of other) code is broken. It is explained in the links I gave. Read those!

And you are talking about "sleep mode", but most likely are using a Stop mode. Anyway all of the modes, including what exactly they do, are explained in the reference manual.

Remy ISSALYS
Technical Moderator
December 7, 2023

Hello,

On STM32WB in BLE example, depending on low power mode used, HSE clock is disable or not. In sleep mode, HSE clock still enable and in stop mode and deeper mode, HSE clock is disable. 

During advertising, CPU1 has nothing to do, CPU1 is in CSTOP, only CPU2 wakes up to manage the advertising.

When debugger is enabled, DBG_SLEEP and DBG_STOP bits of DBGMCU_CR register are set. When DBG_STOP bit is set: "Automatic clock stop disabled. All active clocks and oscillators continue to run during STOP mode, allowing full CPU1 debug capability. On exit from STOP mode, the clock settings are set to the STOP mode exit state."

In your case, you can disable the debugger and output HSE clock on MCO to see the right behavior.

Best Regards

RWeil.2
RWeil.2Author
Associate III
December 10, 2023

@Remy ISSALYS wrote:

During advertising, CPU1 has nothing to do, CPU1 is in CSTOP, only CPU2 wakes up to manage the advertising.


What do you mean? From my understanding, CPU1 and CPU2 have to wake up during advertising? CPU1 has to turn on the accurate 32 MHz clock and CPU2 has to do the rf stuff. Is that not correct?

RWeil.2
RWeil.2Author
Associate III
December 11, 2023

Ok, I did some more testing.

I think I observed that the HSE is activated before CPU1 wakes up from sleep mode.

CPU1 does wake up from sleep mode after advertising.

I set a test pin (LED_FLASH) high and low directly after _WFI(), so I can see when the microcontroller wakes up.

void PWR_EnterStopMode(void)
{
/* USER CODE BEGIN PWR_EnterStopMode_1 */

/* USER CODE END PWR_EnterStopMode_1 */
 /**
 * When HAL_DBGMCU_EnableDBGStopMode() is called to keep the debugger active in Stop Mode,
 * the systick shall be disabled otherwise the cpu may crash when moving out from stop mode
 *
 * When in production, the HAL_DBGMCU_EnableDBGStopMode() is not called so that the device can reach best power consumption
 * However, the systick should be disabled anyway to avoid the case when it is about to expire at the same time the device enters
 * stop mode (this will abort the Stop Mode entry).
 */
 HAL_SuspendTick();

 /**
 * This function is called from CRITICAL SECTION
 */
 EnterLowPower();

 /************************************************************************************
 * ENTER STOP MODE
 ***********************************************************************************/
 LL_PWR_SetPowerMode(LL_PWR_MODE_STOP2);

 LL_LPM_EnableDeepSleep(); /**< Set SLEEPDEEP bit of Cortex System Control Register */

 /**
 * This option is used to ensure that store operations are completed
 */
#if defined (__CC_ARM)
 __force_stores();
#endif
// LED_FLASH_GPIO_Port->BRR = (uint32_t)LED_FLASH_Pin;
 __WFI();

/* USER CODE BEGIN PWR_EnterStopMode_2 */
 LED_FLASH_GPIO_Port->BSRR = (uint32_t)LED_FLASH_Pin;
 	 for(uint32_t i; i<32; i++)
 	 {
 		 __asm__("nop");
 	 }
 LED_FLASH_GPIO_Port->BRR = (uint32_t)LED_FLASH_Pin;
/* USER CODE END PWR_EnterStopMode_2 */
 return;
}

I also measured the current consumption, so I can see when the microcontroller is advertising.

RWeil2_0-1702296102578.png

Interesting to see is that the microcontroller seems to stars advertising before CPU1 wakes up.

I also connected CH1 to the MCO to observe the clock change:

RWeil2_1-1702296160172.png

How does it do that? I thought the HSE is "actuated" by the CPU1? Here we clearly see, that the HSE is running before CPU1 wakes up, which confirms my findings from previous posts.

If I wake up the microcontroller with a timer task, then it first wakes up and then starts the HSE:

RWeil2_2-1702296314253.png

 

 

 

RWeil.2
RWeil.2Author
Associate III
December 11, 2023

Would someone please confirm my findings?

Why is the wake up handler for CPU1 triggered after all, when CPU2 can do the advertising (and activation of HSE) by itself?

Does that mean that I cannot use an external clock (like the ECS-3225MV) if I want to turn it on and off during sleep? I thought about: When entering low power and switching to HSI, I turn off the external clock, go to sleep, when advertising is triggered, I activate the external clock again, wait till it is ready, then advertise.

With regard to my observation this does not seem to be possible. So is the Bypass function for OSC_IN just in case you want to connect an external clock and keep it turned on?

RWeil.2
RWeil.2Author
Associate III
January 24, 2024

In the datasheet of the STM32WBXX you find the different sleep modes and what peripherals are active during these sleep modes. Usually, if you are using the low power manager (from CubeIDE), the HSE is deactivated in STOP1 mode I think.
But how do you want to use UART during sleep? To send something, you would have to wake up, activate HSE, do your stuff like:

static void ExitLowPower(void)
{
 /* Release ENTRY_STOP_MODE semaphore */
 LL_HSEM_ReleaseLock(HSEM, CFG_HW_ENTRY_STOP_MODE_SEMID, 0);

 while(LL_HSEM_1StepLock(HSEM, CFG_HW_RCC_SEMID));

 if(LL_RCC_GetSysClkSource() == LL_RCC_SYS_CLKSOURCE_STATUS_HSI)
 {
/* Restore the clock configuration of the application in this user section */
/* USER CODE BEGIN ExitLowPower_1 */

	 LL_RCC_HSE_Enable( );
	 __HAL_FLASH_SET_LATENCY(FLASH_LATENCY_1);
	 while(!LL_RCC_HSE_IsReady( ));
	 LL_RCC_SetSysClkSource(LL_RCC_SYS_CLKSOURCE_HSE);
 //LL_RCC_SetSMPSClockSource(LL_RCC_SMPS_CLKSOURCE_HSE);
	 //LL_RCC_SetADCClockSource(LL_RCC_ADC_CLKSOURCE_SYSCLK);
	 while (LL_RCC_GetSysClkSource( ) != LL_RCC_SYS_CLKSOURCE_STATUS_HSE);

/* USER CODE END ExitLowPower_1 */
 }
 else
 {
/* If the application is not running on HSE restore the clock configuration in this user section */
/* USER CODE BEGIN ExitLowPower_2 */

/* USER CODE END ExitLowPower_2 */
 }

 /* Release RCC semaphore */
 LL_HSEM_ReleaseLock(HSEM, CFG_HW_RCC_SEMID, 0);

 return;
}