2026-01-30 2:01 AM
Hello,
I have a issue with my STM32U5G9. It does not go into standby or shutdown mode. I want to achieve a wake-up by the power button of my device. The powerbutton is connected to PWR_WKUP6 (pin PB5). The button has a 100k pull-up. I verified the voltage levels with a scope (3.3V --> 0V).
I checked with the examples in the STM32CubeU5 Github repo. This my code:
void LowPower::EnterStandbyMode(void) {
PrepareForLowPower();
__disable_irq();
for(int i = WWDG_IRQn; i <= JPEG_IRQn; i++) {
NVIC_ClearPendingIRQ((IRQn_Type)i);
}
/* Enable WakeUp Pin PWR_WAKEUP_PIN6 connected to PB.5 */
HAL_PWR_EnableWakeUpPin(PWR_WAKEUP_PIN6_LOW_0);
/* Clear all related wakeup flags*/
__HAL_PWR_CLEAR_FLAG(PWR_WAKEUP_FLAG6);
HAL_DBGMCU_DisableDBGStandbyMode();
/* Enter the Standby mode */
HAL_PWR_EnterSTANDBYMode();
// If entry fails (e.g., if a debugger is attached), reset the system
NVIC_SystemReset();
}I have a similar function for shutdown mode. I tried to clear all interrupt flags to make sure the WFI() instruction executes. I have the following code in my main.c:
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the System Power */
SystemPower_Config();
/* Configure the system clock */
SystemClock_Config();
/* Configure the peripherals common clocks */
PeriphCommonClock_Config();
/* USER CODE BEGIN SysInit */
/* Uncomment to be able to debug after wake-up from Standby. Consuption will be increased */
HAL_DBGMCU_EnableDBGStandbyMode();
if (__HAL_PWR_GET_FLAG(PWR_FLAG_SBF) != RESET)
{
/* Clear Standby flag */
__HAL_PWR_CLEAR_FLAG(PWR_FLAG_SBF);
/* Check and Clear the Wakeup flag */
if (__HAL_PWR_GET_FLAG(PWR_WAKEUP_FLAG6) != RESET)
{
__HAL_PWR_CLEAR_FLAG(PWR_WAKEUP_FLAG6);
}
}
/* USER CODE END SysInit */I call the LowPower::EnterStandbyMode() after a long press of my power button, but it just runs into the NVIC_SystemReset(), with or without debugger connected. To test this I tried to put a while(1) loop in the main if the SBF flag is set, but it just starts normal operation.
Is there anything which can block the WFI() instruction? I use the following peripherals: LTDC, GPU2D, DMA2D, USB, I2C, SAI,TIMER, ICACHE, DCACHE, CRC, ADC, DMA, OCTOSPI, RNG. The code runs on ThreadX / TouchGFX. My assumption is standby and shutdown mode stop peripheral clocks and there is no need to disable. Is my assumption correct?
Or can ThreadX block the sleep / standby?
Thanks in advance.
Robin
Solved! Go to Solution.
2026-02-04 7:04 AM
I solved the issue, it was quite a search.
To get it to sleep, you need to:
Monitor NVIC->ISER and NVIC->ISPR. If one of them is not 0, shutdown / standby will not happen.
2026-01-30 5:38 AM
Hello @robintechnology4u
Please refer to the example below:
2026-01-30 5:50 AM
I got one step further.. just before I call HAL_PWR_EnterStandbyMode() I watched the contents of the NVIC peripheral in the debugger. The contents of the ISPR registers show that interrupt flag no. 135 doesnt clear (LTDC), so I guess I have my cause, now for the solution. How can I properly power down the LTDC?
2026-01-30 5:58 AM
Hello @robintechnology4u
Just before entering Standby/Shutdown, do something like:
void LTDC_StopAndDeinit(void)
{
/* 1. Disable LTDC interrupts at peripheral */
__HAL_LTDC_DISABLE_IT(&hltdc, LTDC_IT_LI | LTDC_IT_FU | LTDC_IT_TE | LTDC_IT_RR);
// adapt mask to what you actually use
/* 2. Clear all pending LTDC interrupt flags */
__HAL_LTDC_CLEAR_FLAG(&hltdc, LTDC_FLAG_LI | LTDC_FLAG_FU | LTDC_FLAG_TE | LTDC_FLAG_RR);
/* 3. Disable LTDC */
__HAL_LTDC_DISABLE(&hltdc); // or HAL_LTDC_DeInit(&hltdc);
/* 4. Disable NVIC interrupt */
HAL_NVIC_DisableIRQ(LTDC_IRQn);
/* 5. Clear any pending in NVIC (after source is disabled/reset) */
NVIC_ClearPendingIRQ(LTDC_IRQn);
}
2026-01-30 7:04 AM
// A. Stop the peripheral logic first
__HAL_LTDC_DISABLE(&hltdc);
// B. Silence the peripheral interrupts
LTDC->IER = 0; // Disable ALL LTDC interrupts
LTDC->ICR = 0x3F; // Clear ALL LTDC flags
(void)LTDC->ISR; // Force bus sync
__DSB();
// C. Now it is safe to kill the clock
__HAL_RCC_LTDC_CLK_DISABLE();
// D. Now the NVIC can be cleared without it "springing back"
NVIC_ClearPendingIRQ(LTDC_IRQn);
NVIC_ClearPendingIRQ(LTDC_ER_IRQn);The code above solved the persistent LTDC interrupt. Next problem is it doesnt wake up anymore from standby. The PWR_WKUP6 does not work. Any thoughts on that?
2026-02-02 7:57 AM
@Saket_Om Your latest post crossed mine. I implemented your solution but still no luck. I do have all the interrupt pending bits (NVIC->ISPR[0 - 15]) cleared now before calling standby, but it still resets. In the post before I thought it stayed in standby, but I was fooled by some test code in the main init code. I measured my current consumption by removing the ferrite on the MCU 3V3 supply line:
It looks like it enters standby shortly, but on the small dip the current is still 130 uA, so it is not fully in standby. I have the following code to stop all peripherals using GPDMA:
void PowerThread::PowerManagerCallback(PowerManager::EventType event) {
if(event == PowerManager::EventType::Event_Sleep) {
Scheduler::Stop();
__disable_irq();
_batteryCharger.EnterLowPowerMode();
//stop and disable all peripherals using DMA and possibly interfering with standby mode
GPU2D_StopAndDeinit();
DMA2D_StopAndDeinit();
JPEG_StopAndDeinit();
LTDC_StopAndDeinit();
USB_StopAndDeinit();
SPI2_StopAndDeinit();
_enable5V.SetLow();
_enable3V3.SetLow();
}
}
void PowerThread::LTDC_StopAndDeinit(void)
{
/* 1. Disable LTDC interrupts at peripheral */
__HAL_LTDC_DISABLE_IT(&hltdc, LTDC_IT_LI | LTDC_IT_FU | LTDC_IT_TE | LTDC_IT_RR);
// adapt mask to what you actually use
/* 2. Clear all pending LTDC interrupt flags */
__HAL_LTDC_CLEAR_FLAG(&hltdc, LTDC_FLAG_LI | LTDC_FLAG_FU | LTDC_FLAG_TE | LTDC_FLAG_RR);
/* 3. Disable LTDC */
__HAL_LTDC_DISABLE(&hltdc); // or HAL_LTDC_DeInit(&hltdc);
/* 4. Disable NVIC interrupt */
HAL_NVIC_DisableIRQ(LTDC_IRQn);
HAL_NVIC_DisableIRQ(LTDC_ER_IRQn);
/* 5. Clear any pending in NVIC (after source is disabled/reset) */
NVIC_ClearPendingIRQ(LTDC_IRQn);
NVIC_ClearPendingIRQ(LTDC_ER_IRQn);
}
void PowerThread::GPU2D_StopAndDeinit(void)
{
HAL_GPU2D_DeInit(&hgpu2d);
/* 4. Disable NVIC interrupt */
HAL_NVIC_DisableIRQ(GPU2D_IRQn);
HAL_NVIC_DisableIRQ(GPU2D_ER_IRQn);
/* 5. Clear any pending in NVIC (after source is disabled/reset) */
NVIC_ClearPendingIRQ(GPU2D_IRQn);
NVIC_ClearPendingIRQ(GPU2D_ER_IRQn);
}
void PowerThread::DMA2D_StopAndDeinit(void) {
HAL_DMA2D_Abort(&hdma2d);
__HAL_RCC_DMA2D_CLK_DISABLE();
HAL_DMA2D_DeInit(&hdma2d);
HAL_NVIC_DisableIRQ(DMA2D_IRQn);
NVIC_ClearPendingIRQ(DMA2D_IRQn);
__HAL_RCC_DMA2D_CLK_DISABLE();
}
void PowerThread::JPEG_StopAndDeinit(void) {
HAL_JPEG_DeInit(&hjpeg);
if (hjpeg.hdmain != NULL) {
HAL_DMA_Abort(hjpeg.hdmain);
}
if (hjpeg.hdmaout != NULL) {
HAL_DMA_Abort(hjpeg.hdmaout);
}
__HAL_RCC_JPEG_CLK_DISABLE();
HAL_NVIC_DisableIRQ(JPEG_IRQn);
NVIC_ClearPendingIRQ(JPEG_IRQn);
__HAL_RCC_DMA2D_CLK_DISABLE();
}
void PowerThread::USB_StopAndDeinit(void) {
HAL_PCD_Stop(&hpcd_USB_OTG_HS);
HAL_PCD_DeInit(&hpcd_USB_OTG_HS);
HAL_NVIC_DisableIRQ(OTG_HS_IRQn);
NVIC_ClearPendingIRQ(OTG_HS_IRQn);
__HAL_RCC_USB_OTG_HS_CLK_DISABLE();
__HAL_RCC_USBPHYC_CLK_DISABLE();
}
void PowerThread::SPI2_StopAndDeinit(void) {
// 1. Wait for SPI to finish the last byte
while (HAL_SPI_GetState(&hspi2) != HAL_SPI_STATE_READY);
// 2. Disable SPI
__HAL_SPI_DISABLE(&hspi2);
// 3. Stop the associated DMA Channel
// This is crucial: an enabled DMA channel blocks low-power entry
if (hspi2.hdmatx != NULL) {
HAL_DMA_Abort(hspi2.hdmatx);
}
// 4. Disable Peripheral Clocks
__HAL_RCC_SPI2_CLK_DISABLE();
}After PowerManagerCallback the following function is called:
void LowPower::EnterStandbyMode(void) {
PrepareForLowPower();
EXTI->RPR1 = 0xFFFFFFFF;
EXTI->FPR1 = 0xFFFFFFFF;
// 4. Clear the NVIC Pending bits
for (uint8_t i = 0; i < 8; i++) {
NVIC->ICPR[i] = 0xFFFFFFFF;
}
/* Enable WakeUp Pin PWR_WAKEUP_PIN2 connected to PC.13 */
HAL_PWR_EnableWakeUpPin(PWR_WAKEUP_PIN6_LOW_0);
/* Clear all related wakeup flags*/
__HAL_PWR_CLEAR_FLAG(PWR_WAKEUP_FLAG6);
HAL_PWREx_EnableUltraLowPowerMode();
/* Enter the Standby mode */
HAL_PWR_EnterSTANDBYMode();
// If entry fails (e.g., if a debugger is attached), reset the system
NVIC_SystemReset();
}
With or without debugger attached, it just resets, so the WFI() is aborted for some reason. Can you point me in the right direction?
Thanks,
Robin
2026-02-04 7:04 AM
I solved the issue, it was quite a search.
To get it to sleep, you need to:
Monitor NVIC->ISER and NVIC->ISPR. If one of them is not 0, shutdown / standby will not happen.