2025-09-09 12:43 AM - last edited on 2025-09-09 2:36 AM by mƎALLEm
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?
2025-09-09 12:54 AM
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.
2025-09-09 1:01 AM
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.
2025-09-09 1:20 AM
@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.
2025-09-09 2:24 AM
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);
}
2025-09-09 11:11 AM
Then you'll need to figure out where the program spins. Disable the watchdog, connect debugger in hot-plug mode.