Skip to main content
Associate II
January 30, 2026
Solved

STM32U5G9: wfi() instruction does not execute, no shutdown or standby

  • January 30, 2026
  • 2 replies
  • 312 views

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 

Best answer by robintechnology4u

I solved the issue, it was quite a search.
To get it to sleep, you need to:

  1. de-init all peripherals which use interrupts or DMA.
  2. Clear and disable all pending interrupts and events. 
  3. Suspend SysTick

Monitor NVIC->ISER and NVIC->ISPR. If one of them is not 0, shutdown / standby will not happen. 

 

2 replies

Technical Moderator
January 30, 2026
"To give better visibility on the answered topics, please click on ""Accept as Solution"" on the reply which solved your issue or answered your question.Saket_Om"
Associate II
January 30, 2026

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? 

Technical Moderator
January 30, 2026

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);
}
"To give better visibility on the answered topics, please click on ""Accept as Solution"" on the reply which solved your issue or answered your question.Saket_Om"
Associate II
February 2, 2026

@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: 

 

WhatsApp Image 2026-02-02 at 09.41.37.jpeg

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