STM32H725 IWDG fails to initialize
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2025-04-07 6:37 AM
Hi everyone,
I'm developing a bare-metal application with an STM32H725RG MCU using STM32CubeIDE (including HAL and code generation).
I want to use the IWDG1 for reliability purposes, but for some reason, it seems to not work for me at all - upon startup, the MCU enters the Error_Handler loop, due to the HAL_IWDG_Init call returning HAL_TIMEOUT.
In particular, I enabled the IWDG1 in the .ioc file editor, so it gets initialized and enabled by the generated HAL code. This enables the LSI as expected (RCC_CSR = 0x3), and I can confirm that the LSI itself works by outputting it to the RCC_MCO_2 pin.
However, the initialization of the IWDG doesn't seem to complete. As far as I can tell from debugging, all the initial writes to IWDG_KR work as expected, and IWDG_PR and IWDG_RLR receive their correct values. This results in IWDG_SR = 0x3 as expected, which should go back to 0x0 within a few LSI cycles as the changes are applied - but this never happens. Instead, IWDG_SR remains at 0x3 permanently, causing the initialization to time out and the MCU to get stuck.
There doesn't seem to be any mention of such behaviour in the datasheet, RM, or device errata - does anyone have any ideas about what could be going on?
Thanks,
Alex K
- Labels:
-
IWDG-WWDG
-
STM32H7 Series
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2025-04-08 2:04 AM
Hello @blockworker,
SR=0x03 meaning the watchdog reload and prescaler value are still updating, have you taken into consideration that this update can take up to 5 RC 40Hz cycles causing the timeout!
Rechecking with you the IWDG initialization, can you confirm you're following this sequence:
- Enable the IWDG by writing 0x0000 CCCC in IWDG_KR
- Enable register access by writing 0x0000 5555 in IWDG_KR.
- Write the prescaler by programming the IWDG_PR from 0 to 7.
- Write the IWDG reload register (IWDG_RLR).
- Wait for the registers to be updated: IWDG_SR = 0x0000 0000
- Refresh the counter value with IWDG_RLR (IWDG_KR = 0x0000 AAAA)
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.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2025-04-08 2:09 AM - edited ‎2025-04-08 2:10 AM
Hi @Sarra.S,
Thanks, yeah I understand that much. The HAL code I'm using (generated by STM32CubeIDE) follows the above procedure and takes this expected time (5 cycles) into account.
The problem is that in my case, IWDG_SR = 0x0 never happens, as far as I can observe - no matter how long I wait, even if I wait several seconds. It constantly stays at 0x3. So of course this init procedure will time out or get stuck.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2025-04-08 2:40 AM
Ok, that's quite odd, can you share your code so i can try and reproduce the behavior on my end?
Meanwhile, for the sake of checking every possible root cause with you, if there is an issue with the VDD voltage domain, the update operations might not complete!
Another thing is, if a write operation to the IWDG register is ongoing , maybe the value read is not up to date!
Could you check these two hypotheses?
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.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2025-04-08 2:52 AM
Sure, here is the IWDG initialization code, as generated by the IDE:
/**
* @brief Initialize the IWDG according to the specified parameters in the
* IWDG_InitTypeDef and start watchdog. Before exiting function,
* watchdog is refreshed in order to have correct time base.
* @PAram hiwdg pointer to a IWDG_HandleTypeDef structure that contains
* the configuration information for the specified IWDG module.
* @retval HAL status
*/
HAL_StatusTypeDef HAL_IWDG_Init(IWDG_HandleTypeDef *hiwdg)
{
uint32_t tickstart;
/* Check the IWDG handle allocation */
if (hiwdg == NULL)
{
return HAL_ERROR;
}
/* Check the parameters */
assert_param(IS_IWDG_ALL_INSTANCE(hiwdg->Instance));
assert_param(IS_IWDG_PRESCALER(hiwdg->Init.Prescaler));
assert_param(IS_IWDG_RELOAD(hiwdg->Init.Reload));
assert_param(IS_IWDG_WINDOW(hiwdg->Init.Window));
/* Enable IWDG. LSI is turned on automatically */
__HAL_IWDG_START(hiwdg);
/* Enable write access to IWDG_PR, IWDG_RLR and IWDG_WINR registers by writing
0x5555 in KR */
IWDG_ENABLE_WRITE_ACCESS(hiwdg);
/* Write to IWDG registers the Prescaler & Reload values to work with */
hiwdg->Instance->PR = hiwdg->Init.Prescaler;
hiwdg->Instance->RLR = hiwdg->Init.Reload;
/* Check pending flag, if previous update not done, return timeout */
tickstart = HAL_GetTick();
/* Wait for register to be updated */
while ((hiwdg->Instance->SR & IWDG_KERNEL_UPDATE_FLAGS) != 0x00u)
{
if ((HAL_GetTick() - tickstart) > HAL_IWDG_DEFAULT_TIMEOUT)
{
if ((hiwdg->Instance->SR & IWDG_KERNEL_UPDATE_FLAGS) != 0x00u)
{
return HAL_TIMEOUT;
}
}
}
/* If window parameter is different than current value, modify window
register */
if (hiwdg->Instance->WINR != hiwdg->Init.Window)
{
/* Write to IWDG WINR the IWDG_Window value to compare with. In any case,
even if window feature is disabled, Watchdog will be reloaded by writing
windows register */
hiwdg->Instance->WINR = hiwdg->Init.Window;
}
else
{
/* Reload IWDG counter with value defined in the reload register */
__HAL_IWDG_RELOAD_COUNTER(hiwdg);
}
/* Return function status */
return HAL_OK;
}
The timeout happens in the loop in lines 40-49. The HAL_IWDG_DEFAULT_TIMEOUT constant defaults to the maximum LSI startup time plus 6 cycles:
#define HAL_IWDG_DEFAULT_TIMEOUT (((6UL * 256UL * 1000UL) / LSI_VALUE) + ((LSI_STARTUP_TIME / 1000UL) + 1UL))
However, even if I increase the timeout to a large value (multiple thousand ticks, at 1 kHz tick rate), the behaviour stays the same - it still times out.
There shouldn't be any problems with the VDD voltage, as the MCU runs completely stable otherwise, at 520 MHz core frequency in VOS0.
At the point where the timeout happens, and after the timeout (in the error handler), there shouldn't be any more ongoing writes into IWDG registers - yet the debugger (expression watch) still reports IWDG_SR = 0x3 constantly, which is consistent with the fact that it times out.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2025-04-08 3:23 AM
Hi @Sarra.S,
An update - in trying to reproduce the error, I have fully restarted my development workstation and the IDE and rebuilt the code again. Now the IWDG initialization seems to work fine (where before, it was failing consistently).
Maybe my build system was stuck in some kind of invalid state before the restart, producing a bad binary? Either that, or the error is intermittent in some other way.
Thanks for your help either way.
