cancel
Showing results for 
Search instead for 
Did you mean: 

Clocks reset to HSI after exiting STOP mode STM32F091

MStam.1
Associate II

Hello,

I'm using the Zephyr RTOS on a STM32F091 and have recently started working on implementing some low-power states (sleep and STOP). The system is fed by the PLL (48MHz) which is in turn fed by a HSE (20MHz).

I'm using the RTC peripheral to manage wake-ups, I simply set ALARMA at ~500ms before going to sleep.

What I see after waking up from STOP mode, is a bunch of garbage characters on the UART output and the whole system seemed to have slowed down significantly. A blinking LED for example, is now blinking much slower.

This is the code I use to enter the STOP mode:

//Switch to HSI clock before entering stop mode, needed so we can turn HSE off before entering (page 87 of RM)
/* Enable HSI if not enabled */
if (LL_RCC_HSI_IsReady() != 1) {
	/* Enable HSI */
	LL_RCC_HSI_Enable();
	while (LL_RCC_HSI_IsReady() != 1) {
	/* Wait for HSI ready */
	}
}
 
/* Set HSI as SYSCLCK source */
LL_RCC_SetSysClkSource(LL_RCC_SYS_CLKSOURCE_HSI);
while (LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_HSI) {
}
//Disable the HSE now that the HSI is enabled
LL_RCC_HSE_Disable();
 
LL_RCC_PLL_Disable();
 
LL_PWR_SetPowerMode(LL_PWR_MODE_STOP_MAINREGU);
LL_LPM_EnableDeepSleep();
 
//Disable SysTick interrupts so we don't immediately wake up
LL_SYSTICK_DisableIT();
 
//This calls __WFI();
k_cpu_idle();

Then this is called whenever the STOP mode is exited:

LL_LPM_DisableSleepOnExit();
 
//Restore clock configuration
stm32_clock_control_init(NULL);
 
//Re-enable the systick interrupt
LL_SYSTICK_EnableIT();
 
irq_unlock(0);

The stm32_clock_control_init(NULL) does the following in sequence:

  • Configure some init struct for peripheral clock configuration
  • Enable default clocks (only SYSCFG peripheral clock in this case)
  • Clock is switched to HSI
  • PLL is disabled
  • Configure and switch to PLL with HSE as source clock
  • Disable HSI and MSI

I've verified that this does what it is supposed to do by checking the peripherals in a debug session, after this function, the RCC configuration is the same after exiting STOP as before entering STOP. Other users of Zephyr with the STM32 platform have used this function with success in the same use case as me.

Then however, a couple of instructions later, the RCC configuration is reset back to exit STOP conditions, i.e. HSI on, HSE and PLL off, HSI as system clock. This seems to happen asynchronously and I can't pinpoint why it happens.

This does not happen when I enter/exit sleep mode, only STOP.

I've verified that the Clock Security System is off. 

Any help with this would be greatly appreciated, as I am grasping at straws at this point.

Thank you.

1 ACCEPTED SOLUTION

Accepted Solutions

This issue has been solved by calling LL_LPM_EnableSleep() function in the STOP mode exit routine. This function clears the SLEEPDEEP bit in the SCB register.

I suppose what happened, is that the SLEEPDEEP bit was still set, and whenever the Idle thread triggered another __WFI() after having exited STOP mode, it would re-enter stopmode without being properly configured.

View solution in original post

11 REPLIES 11

> Then however, a couple of instructions later, the RCC configuration is reset back

And what are those instructions? By single-stepping and observing the RCC registers, can't you pinpoint where exactly does this happen?

JW

MStam.1
Associate II

I have tried doing this, however since the Power Management module of Zephyr calls the Low-Power routine from the idle thread, it is also returned to the idle thread after exiting STOP mode. Meaning if I single step afterwards, I just single step through the idle thread endlessly.

However I still see the RCC configuration resetting when just stepping through the idle thread. I've tried setting a watchpoint on the RCC register (tried watch, awatch and rwatch) and none of them trigger, even though the RCC configuration is reset.

Could this be indication that the RCC config is not reset by the application, but by the CPU itself in some way?

It could also mean, that what you see is not true (i.e. debugger shows you some cached values for the RCC registers).

Step through the function setting the RCC registers and observe - do they change in the expected way? Output HSE/sysclock to MCO pin and observe using oscilloscope/LA.

JW

PS. Do you use CSS?

MStam.1
Associate II

I've verified that the SYSCLK actually behaves as observed in the registers. I hooked up an oscilloscope to the MCO pin and routed the SYSCLK to it. I see 48MHz until the system goes into STOP, after which it turns to 8MHz. When I step through the functions setting the RCC registers, it does as expected. The SYSCLK is set back to 48MHz up until it "randomly" resets back to 8MHz.

I have also verified that no CSS is used (seems like this exact scenario could be because of CSS, but alas)

[desperate mode on]

What is the likelyhood you would miss a genuine reset? Try toggling a pin at reset and observe.

Post readouts of RCC (all of them) and PWR registers before and after the event, to have something to chew on.

JW

MStam.1
Associate II

I'm sorry but I'm not entirely sure what you mean. I can force a reset through the RESET line on the CPU and I could simply toggle some LED but I'm not entirely sure what I am looking for here or when to toggle what.

Well, you see RCC registers revert inexplicably to a state which may be also consequence of a reset, however unlikely it sounds. In other words, if setting "high" clocks results e.g. in momentary drop in power supply voltage, resulting in reset, how would you notice it?

When it comes to mysterious behaviour, I try to treat the debugger as untrustworthy. So, toggling a LED after reset should be a relatively definitive method to exclude the above assertion.

And showing the registers content has the benefit of fresh couple of eyes seeing them.

Btw., how do you manage FLASH latencies?

JW

MStam.1
Associate II

Thanks for the explanation, my workday is over for now so I will get back to you tomorrow with new information.

This issue has been solved by calling LL_LPM_EnableSleep() function in the STOP mode exit routine. This function clears the SLEEPDEEP bit in the SCB register.

I suppose what happened, is that the SLEEPDEEP bit was still set, and whenever the Idle thread triggered another __WFI() after having exited STOP mode, it would re-enter stopmode without being properly configured.