2025-08-11 2:58 PM
Howdy;
I have a li'l stm32u031, with a pushbutton attached to PA0. This MCU is clocked with no external oscillators.
I've configured the button/pin to work with Timer2/Channel1 in Input Capture mode when the MCU is in run mode, to detect and measure button presses. This works swell.
I'd like to be able to put this device into STOP2 mode, and be able to re-awaken it with the button. My understanding is that I'd do this by de-initing it as an alt function pin, and re-initing it for EXTI.
At the moment, I'm doing this:
// Stop all timer channels
HAL_TIM_IC_Stop_IT(&htim2, TIM_CHANNEL_1);
HAL_TIM_OC_Stop_IT(&htim2, TIM_CHANNEL_2);
HAL_TIM_OC_Stop_IT(&htim2, TIM_CHANNEL_3);
// Stop the timer itself
HAL_TIM_Base_Stop(&htim2);
// Mask any stray interrupts and clear latched flags
__HAL_TIM_DISABLE_IT(&htim2, TIM_IT_UPDATE | TIM_IT_CC1 | TIM_IT_CC2 | TIM_IT_CC3 | TIM_IT_CC4);
__HAL_TIM_CLEAR_FLAG(&htim2, TIM_FLAG_UPDATE | TIM_FLAG_CC1 | TIM_FLAG_CC2 | TIM_FLAG_CC3 | TIM_FLAG_CC4 |
TIM_FLAG_CC1OF | TIM_FLAG_CC2OF | TIM_FLAG_CC3OF | TIM_FLAG_CC4OF);
// Switch NVIC off + clear any pending interrupts
// to avoid surprise ISR on resume
NVIC_DisableIRQ(TIM2_IRQn);
NVIC_ClearPendingIRQ(TIM2_IRQn);
// Disconnect the peripheral clock for a few extra µA
__HAL_RCC_TIM2_CLK_DISABLE();
// Now we are going to configure our
// button to create an interrupt when pressed
// using EXTI instead of our timer.
// We are going to de-init our pin
// which disconnect it from Timer2.
HAL_GPIO_DeInit(MAIN_BUTTON_GPIO_Port, MAIN_BUTTON_Pin);
// Then re-configure it thusly:
GPIO_InitTypeDef gpio_config = {0};
gpio_config.Pin = MAIN_BUTTON_Pin;
gpio_config.Mode = GPIO_MODE_IT_RISING;
gpio_config.Pull = GPIO_NOPULL;
HAL_GPIO_Init(MAIN_BUTTON_GPIO_Port, &gpio_config);
// Clear any stale pending before sleeping
__HAL_GPIO_EXTI_CLEAR_IT(MAIN_BUTTON_Pin);
NVIC_ClearPendingIRQ(EXTI0_1_IRQn);
HAL_NVIC_SetPriority(EXTI0_1_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(EXTI0_1_IRQn);
// now, sleepytime:
__HAL_PWR_CLEAR_FLAG(PWR_FLAG_WU);
RCC->CFGR |= RCC_CFGR_STOPWUCK;
HAL_SuspendTick();
HAL_PWREx_EnterSTOP2Mode(PWR_STOPENTRY_WFI);
This only partially works - I can put it to sleep, then wake it up a time or two using this button. But eventually it seems to get 'stuck' in STOP2, and the button presses no longer work. This behavior is repeatable, but the 'number of wakeups" I seem to be able to perform changes each time I restart the device - sometimes it won't wake up at all, sometimes I get 2-3 wakeups before it stops working.
I've tried all manner of mucking around using the higher-level HAL stuff, as well as individual LL syntax, but I can't quite seem to fix this problem, nor do I understand why it's happening. This line:
RCC->CFGR |= RCC_CFGR_STOPWUCK;
I found in this thread, where someone else seemed to be having a similar problem (maybe), but it doesn't seem to affect the experience I'm having.
I'm curious if anyone might have some advice.
thanks!
2025-08-12 6:59 AM
Hello @sb_st
Please refer to the example below:
2025-08-12 11:00 AM - edited 2025-08-12 11:02 AM
Thanks @Saket_Om!
It seems that what's causing me trouble is trying to rebuild the system clock after coming out of Stop2.
Initially, I was doing this:
SystemClock_Config();
immediately after coming out of stop2. Your example shows something slightly different, which I've modified to fit my own clock panel settings:
static void resume_clocks() {
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
uint32_t pFLatency = 0;
/* Enable Power Control clock */
__HAL_RCC_PWR_CLK_ENABLE();
/* Get the Oscillators configuration according to the internal RCC registers */
HAL_RCC_GetOscConfig(&RCC_OscInitStruct);
/* After wake-up from STOP reconfigure the system clock: Enable HSI.
Note in my setup, I do not use PLL */
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI|RCC_OSCILLATORTYPE_MSI;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
RCC_OscInitStruct.MSIState = RCC_MSI_ON;
RCC_OscInitStruct.MSICalibrationValue = RCC_MSICALIBRATION_DEFAULT;
RCC_OscInitStruct.MSIClockRange = RCC_MSIRANGE_11;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
/* Get the Clocks configuration according to the internal RCC registers */
HAL_RCC_GetClockConfig(&RCC_ClkInitStruct, &pFLatency);
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV16;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK)
{
Error_Handler();
}
HAL_InitTick(TICK_INT_PRIORITY);
HAL_ResumeTick();
}
In either case, I experience this "works a few times, then stops working" behavior, where I can successfully put the device into stop2, but can no longer awaken it.
However, I notice that if I completely skip this clock configuration step, and just simply go straight to:
HAL_InitTick(TICK_INT_PRIORITY);
HAL_ResumeTick();
this "sometimes it works, sometimes it doesn't" behavior goes away completely...the device can be put to sleep and successfully awakened repeatedly with no issues.
This seems quite strange to me - most resources I can find say that it's absolutely mandatory to do this clock-rebuilding step, and I can't quite understand why skipping it completely seems to make my system stable.
FWIW, the way I am testing this is by simply turning on an LED after coming out of sleep immediately after the above.
2025-08-13 3:00 AM
Hello @sb_st
To assist you more efficiently, could you please share your project with us?
2025-08-13 5:04 AM - edited 2025-08-13 5:09 AM
Happily! Attached below is a self-contained, trimmed down project that exemplifies the problem I'm experiencing. With apologies for a bit more complexity than I'd otherwise like to foist on you, this shows how I'm shifting the functionality of my main button (which I don't think is actually causing the issue here, but I could be wrong).
I feel like the most interesting part is resume_clocks(), which contains the code used to reconfigure the clocks after coming out of stop2. When I comment out these lines (skipping this reconfigure), my device works as I expect. But running these lines causes it to (sometimes - not always; I can't figure out why this seems inconsistent) hang when coming out of stop2.
// First steps to bootstrapping our system
// from stop2 is restoring our clocks properly.
static void resume_clocks() {
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
uint32_t pFLatency = 0;
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
//
// HERE BE DRAGONS
//
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
//
// I observe that when I run the below lines
// wherein the clock tree gets 'rebuilt' - as I see
// recommended in numerous online references - that
// my device often seems to "hang", not making it
// to the point of being able to turn the LED
// back on just below these lines.
//
// Commenting out these lines seems to allow the
// device to come out of stop2 repeatably, and I can
// observe no odd or broken behavior. Perplexing.
/* Enable Power Control clock */
__HAL_RCC_PWR_CLK_ENABLE();
/* Get the Oscillators configuration according to the internal RCC registers */
HAL_RCC_GetOscConfig(&RCC_OscInitStruct);
/* After wake-up from STOP reconfigure the system clock: Enable HSI and PLL */
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
/* Get the Clocks configuration according to the internal RCC registers */
HAL_RCC_GetClockConfig(&RCC_ClkInitStruct, &pFLatency);
/* Select HSI as system clock source */
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_SYSCLK;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, pFLatency) != HAL_OK)
{
Error_Handler();
}
//
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
HAL_InitTick(TICK_INT_PRIORITY);
HAL_ResumeTick();
// We turn our onboard LED back on,
// to signal we've successfully made it
// back to the real world.
HAL_GPIO_WritePin(BOOST_EN_GPIO_Port,
BOOST_EN_Pin,
GPIO_PIN_SET);
}
2025-08-13 5:51 AM
Hello @sb_st
It is better to start with a simple use case by putting the MCU in STOP2 mode and then wakeup with EXTI interrupt.
2025-08-13 1:56 PM
Hello @Saket_Om;
I can get your previously-mentioned EXTI example ported onto my board and it runs fine, if that's what you're asking. And I can get other examples working fine as well. However, these do not fully represent my use case. I would like to user a timer in Input Capture mode with my button when in run mode, but need to reconfigure it to EXTI before putting it into STOP2 so that I can bring it back out again. I am having trouble getting that to work consistently, which is why I'm asking for help.
I've tried simplifying my example project further, and am attaching it here. It is still exhibiting the behavior I'm asking about.
2025-08-14 11:44 AM - edited 2025-08-14 1:42 PM
To try to add info after further testing:
I can enter SLEEP mode using my current logic, and come out of it fine.
HAL_PWR_EnterSLEEPMode(PWR_LOWPOWERREGULATOR_ON, PWR_SLEEPENTRY_WFI);
but entering any of Stop0, Stop1 or Stop2 modes seems to 'trap' the device, and I'm unable to consistently wake it:
HAL_PWR_EnterSTOPMode(PWR_MAINREGULATOR_ON, PWR_SLEEPENTRY_WFI);
HAL_PWREx_EnterSTOP1Mode(PWR_STOPENTRY_WFI);
HAL_PWREx_EnterSTOP2Mode(PWR_STOPENTRY_WFI);
2025-08-15 1:56 AM
Hello @sb_st
I tried to implement your scenario based on the example STM32CubeU0/Projects/NUCLEO-U083RC/Examples/PWR/PWR_STOP2 at main · STMicroelectronics/STM32CubeU0 · GitHub
It works fine on my end. Please find the main file attached.
I used the same system clock config as in the example and I set the GPIO pull configuration to gpio_config.Pull = GPIO_PULLUP for GPIO EXTI in main_button_standby().
2025-08-15 4:29 AM
I found what seems like a smoking gun.
My system uses RNG, which - by default - is clocked by MSI. I notice that when I disable RNG, this odd behavior goes away completely. When I configure the RNG to be clocked by PLLQ instead of MSI, this also seems to get rid of the problematic behavior.
I'm attaching files exemplifying these three scenarios here.
I am still trying to understand what I might be missing in the MSI case that causes this sporadic hanging, and whether there's a way to solve this (mostly because I am interested in learning - it makes me feel a little itchy to just switch to PLLQ without clearly understanding why that works and the MSI case does not).