cancel
Showing results for 
Search instead for 
Did you mean: 

Infinite loop at startup when optimization enabled.

KamilWierzbicki
Associate

Our STM32H745XIH microcontroller enters an infinite loop after updating the software with “Release” compilation flags (optimization enabled). This only happens with a specific build, and changing a single piece of code that is definitely not related to any hardware component can solve the problem (e.g., adding a single line such as int a = 45;). We believe the problem may be related to the watchdog reset, because when connected to the microcontroller via a debugger, it resets and starts working normally without any problems, the logic of our application works, and the device is fully functional. We thought the problem might be caused by the clock initializing too quickly, so we added a startup delay using:

static void __attribute__ ((optimize("-O0"))) StartupDelay(void)
{
	for(uint32_t i = 0x27614U; i > 0U; i--);
}

This seemed to solve the problem. However, after changing another part of the code, the problem started to reappear.
RCC_RSR value: 4FE0000

No hardfault is observed before the reset. Application runs, LED are set as expected for ~0.8 s and then reset comes.

The watchdog is properly refreshed every 50 ms with one of Freertos tasks. We confirmed it by setting the breakpoint. 

Watchdog config:

	// watchdog is clocked via internal LSI - 32kHz
	// we want a watchdog window of 1s

	// IWDG clk = 1 / (32000 / 8) = 1/4000 = 0.00025s
	// reload =  1 / 0.00025 = 4000

	hiwdg1.Init.Prescaler = IWDG_PRESCALER_8;
	hiwdg1.Instance		  = IWDG1;
	hiwdg1.Init.Window	  = IWDG_WINDOW_DISABLE;
	hiwdg1.Init.Reload	  = 4000U;

	// debugging halts the IWDG
	__HAL_DBGMCU_FREEZE_IWDG1();

	if (HAL_IWDG_Init(&hiwdg1) != HAL_OK)
	{
		HAL_NVIC_SystemReset();
	}

	// HAL doesn't disable write access, do it manually
	IWDG_DISABLE_WRITE_ACCESS(&hiwdg1);

 Watchdog is configured at the begining of main function and then startup delay comes (much less than 1s required for WDG reset) and then hal and clocks are initialized. 

int main(void)
{
	// NOTE: do not call any FreeRTOS API in the main, do it in the system_main instead
	// If a FreeRTOS API function is called before the scheduler has been started then most FreeRTOS ports will
	// deliberately disable interrupts, and not re-enable them until the first task starts to execute

	LibWdg_Init();

	StartupDelay(); // Add startup delay to stabilize external clock source

	MPU_Config();

	SCB_EnableICache();
	SCB_EnableDCache();

	HAL_Init();

	SystemClock_Config();

 Is there anything that we can check to find the reason? 

5 REPLIES 5
Pavel A.
Super User

Do you set up MPU on the CM7 to prevent the "speculative execution" issue? This issue can cause a "hang" of the core for a long time.

 

	MPU_Region_InitTypeDef MPU_InitStruct = { 0 };

	HAL_MPU_Disable();

	MPU_InitStruct.Enable			= MPU_REGION_ENABLE;
	MPU_InitStruct.Number			= MPU_REGION_NUMBER0;
	MPU_InitStruct.BaseAddress		= 0x24000000;
	MPU_InitStruct.Size				= MPU_REGION_SIZE_256KB;
	MPU_InitStruct.SubRegionDisable = 0x0;
	MPU_InitStruct.TypeExtField		= MPU_TEX_LEVEL0;
	MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
	MPU_InitStruct.DisableExec		= MPU_INSTRUCTION_ACCESS_ENABLE;
	MPU_InitStruct.IsShareable		= MPU_ACCESS_NOT_SHAREABLE;
	MPU_InitStruct.IsCacheable		= MPU_ACCESS_CACHEABLE;
	MPU_InitStruct.IsBufferable		= MPU_ACCESS_NOT_BUFFERABLE;

	HAL_MPU_ConfigRegion(&MPU_InitStruct);

	MPU_InitStruct.Number		= MPU_REGION_NUMBER1;
	MPU_InitStruct.BaseAddress	= 0x24040000;
	MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL1;
	MPU_InitStruct.IsShareable	= MPU_ACCESS_SHAREABLE;
	MPU_InitStruct.IsCacheable	= MPU_ACCESS_NOT_CACHEABLE;
	MPU_InitStruct.IsBufferable = MPU_ACCESS_NOT_BUFFERABLE;

	HAL_MPU_ConfigRegion(&MPU_InitStruct);

	MPU_InitStruct.Number		= MPU_REGION_NUMBER2;
	MPU_InitStruct.BaseAddress	= 0x08000000;
	MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0;
	MPU_InitStruct.Size			= MPU_REGION_SIZE_1MB;
	MPU_InitStruct.IsShareable	= MPU_ACCESS_NOT_SHAREABLE;
	MPU_InitStruct.IsCacheable	= MPU_ACCESS_CACHEABLE;

	HAL_MPU_ConfigRegion(&MPU_InitStruct);

	// strongly-ordered peripheral memory
	MPU_InitStruct.Number		= MPU_REGION_NUMBER3;
	MPU_InitStruct.BaseAddress	= 0x40000000U;
	MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0;
	MPU_InitStruct.Size			= MPU_REGION_SIZE_512MB;
	MPU_InitStruct.IsShareable	= MPU_ACCESS_NOT_SHAREABLE;
	MPU_InitStruct.IsCacheable	= MPU_ACCESS_NOT_CACHEABLE;
	MPU_InitStruct.IsBufferable = MPU_ACCESS_NOT_BUFFERABLE;

	HAL_MPU_ConfigRegion(&MPU_InitStruct);

	HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT);

This is our MPU configuration. 
But it seems like the program does not stop in any of the initialization functions, just runs normally for less than a second until the reset comes.

@KamilWierzbicki this MPU configuration does not contain the thing needed for the "speculative execution bug" prevention. 

 For example see this, function  MPU_Config() , region MPU_REGION_NUMBER0.

Sorry I can't recall the AN document.

Added speculative execution prevention section in MPU configuration, but it did not solve the problem.

void MPU_Config(void)
{
	MPU_Region_InitTypeDef MPU_InitStruct = { 0 };

	HAL_MPU_Disable();

	MPU_InitStruct.Enable			= MPU_REGION_ENABLE;
	MPU_InitStruct.Number			= MPU_REGION_NUMBER0;
	MPU_InitStruct.BaseAddress		= 0x0;
	MPU_InitStruct.Size				= MPU_REGION_SIZE_4GB;
	MPU_InitStruct.SubRegionDisable = 0x87;
	MPU_InitStruct.TypeExtField		= MPU_TEX_LEVEL0;
	MPU_InitStruct.AccessPermission = MPU_REGION_NO_ACCESS;
	MPU_InitStruct.DisableExec		= MPU_INSTRUCTION_ACCESS_DISABLE;
	MPU_InitStruct.IsShareable		= MPU_ACCESS_SHAREABLE;
	MPU_InitStruct.IsCacheable		= MPU_ACCESS_NOT_CACHEABLE;
	MPU_InitStruct.IsBufferable		= MPU_ACCESS_NOT_BUFFERABLE;

	HAL_MPU_ConfigRegion(&MPU_InitStruct);

	MPU_InitStruct.Enable			= MPU_REGION_ENABLE;
	MPU_InitStruct.Number			= MPU_REGION_NUMBER1;
	MPU_InitStruct.BaseAddress		= 0x24000000;
	MPU_InitStruct.Size				= MPU_REGION_SIZE_256KB;
	MPU_InitStruct.SubRegionDisable = 0x0;
	MPU_InitStruct.TypeExtField		= MPU_TEX_LEVEL0;
	MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
	MPU_InitStruct.DisableExec		= MPU_INSTRUCTION_ACCESS_ENABLE;
	MPU_InitStruct.IsShareable		= MPU_ACCESS_NOT_SHAREABLE;
	MPU_InitStruct.IsCacheable		= MPU_ACCESS_CACHEABLE;
	MPU_InitStruct.IsBufferable		= MPU_ACCESS_NOT_BUFFERABLE;

	HAL_MPU_ConfigRegion(&MPU_InitStruct);

	MPU_InitStruct.Number		= MPU_REGION_NUMBER2;
	MPU_InitStruct.BaseAddress	= 0x24040000;
	MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL1;
	MPU_InitStruct.IsShareable	= MPU_ACCESS_SHAREABLE;
	MPU_InitStruct.IsCacheable	= MPU_ACCESS_NOT_CACHEABLE;
	MPU_InitStruct.IsBufferable = MPU_ACCESS_NOT_BUFFERABLE;

	HAL_MPU_ConfigRegion(&MPU_InitStruct);

	MPU_InitStruct.Number		= MPU_REGION_NUMBER3;
	MPU_InitStruct.BaseAddress	= 0x08000000;
	MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0;
	MPU_InitStruct.Size			= MPU_REGION_SIZE_1MB;
	MPU_InitStruct.IsShareable	= MPU_ACCESS_NOT_SHAREABLE;
	MPU_InitStruct.IsCacheable	= MPU_ACCESS_CACHEABLE;

	HAL_MPU_ConfigRegion(&MPU_InitStruct);

	// strongly-ordered peripheral memory
	MPU_InitStruct.Number		= MPU_REGION_NUMBER4;
	MPU_InitStruct.BaseAddress	= 0x40000000U;
	MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0;
	MPU_InitStruct.Size			= MPU_REGION_SIZE_512MB;
	MPU_InitStruct.IsShareable	= MPU_ACCESS_NOT_SHAREABLE;
	MPU_InitStruct.IsCacheable	= MPU_ACCESS_NOT_CACHEABLE;
	MPU_InitStruct.IsBufferable = MPU_ACCESS_NOT_BUFFERABLE;

	HAL_MPU_ConfigRegion(&MPU_InitStruct);

	HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT);
}
Pavel A.
Super User

Then you'll need to figure out where the program spins. Disable the watchdog, connect debugger in hot-plug mode.