AnsweredAssumed Answered

Window Watchdog (WWDG) Early Wakeup Interrupt (EWI) configuration bugs in firmware library

Question asked by Zhong.Wenbin.001 on Nov 6, 2015
Latest reply on Jul 15, 2016 by FTITI.Walid
Hello, WWDG should be used in my application, some safety operations should be done in the EWI, I found some bugs in the firmware library, which will be discussed here to help other developers.


Experiment set-ups:
IDE: IAR 7.40
Board: STM32746G-Discovery (STM32F746NG embedded)
Firmware version: V1.2.0


HAL_WWDG_Start_IT function should be used to start WWDG and enable EWI. Below is the original implementation:
HAL_StatusTypeDef HAL_WWDG_Start_IT(WWDG_HandleTypeDef *hwwdg)
{
  /* Process Locked */
  __HAL_LOCK(hwwdg); 


  /* Change WWDG peripheral state */  
  hwwdg->State = HAL_WWDG_STATE_BUSY;


  /* Enable the Early Wakeup Interrupt */ 
  __HAL_WWDG_ENABLE_IT(hwwdg, WWDG_IT_EWI);


  /* Enable the peripheral */
  __HAL_WWDG_ENABLE(hwwdg);  


  /* Return function status */
  return HAL_OK;
}


Bug1:
WWDG isn't unlocked and isn't changed to READY state before leaving. The WWDG resets the system immediately when calling this function.


Bug2:
EWI should be enabled (Set EWI bit) after enabling WWDG (Set WDGA bit), or the WWDG resets the system immediately. I don't know why, can't find in the manual.


Bug3:
Early Wakeup flag (EWIF bit) should be cleared when enabling the EWI, because the EWIF won't be cleared by hardware reset. If the flag is set, WWDG will reset the system immediately.


So the correct implementation of the function is like this:
HAL_StatusTypeDef HAL_WWDG_Start_IT(WWDG_HandleTypeDef *hwwdg)
{
  /* Process Locked */
  __HAL_LOCK(hwwdg); 


  /* Change WWDG peripheral state */  
  hwwdg->State = HAL_WWDG_STATE_BUSY;
  
  /* Enable the peripheral */
  __HAL_WWDG_ENABLE(hwwdg);
  
  /* Clear the WWDG Early Wakeup flag */
  __HAL_WWDG_CLEAR_FLAG(hwwdg, WWDG_FLAG_EWIF);
      
  /* Enable the Early Wakeup Interrupt */ 
  __HAL_WWDG_ENABLE_IT(hwwdg, WWDG_IT_EWI);


  /* Change WWDG peripheral state */    
  hwwdg->State = HAL_WWDG_STATE_READY; 
  
  /* Process Unlocked */
  __HAL_UNLOCK(hwwdg);
  
  /* Return function status */
  return HAL_OK;
}


The key codes of testing WWDG are listed below:
Step 1: Configure the WWDG in the main function
  /*###-Step 1- Check if the system has resumed from WWDG reset ##############*/
  if (__HAL_RCC_GET_FLAG(RCC_FLAG_WWDGRST) != RESET)
  {
    /* WWDGRST flag set: send msg */
    printf("** The system has resumed from a WWDG reset ** \r\n");


    /* Clear reset flags */
    __HAL_RCC_CLEAR_RESET_FLAGS();
  }
  /*###-Step 2- Set the WWDG clock ###########################################*/
  /* WWDG clock counter = (PCLK1 (54MHz)/4096)/8) = 1648 Hz (~607 us) 
     WWDG Window value = 80 means that the WWDG counter should be refreshed only 
     when the counter is below 80 (and greater than 64) otherwise a reset will 
     be generated. 
     WWDG Counter value = 127, WWDG timeout = ~607 us * 64 = 25.5 ms */
  WwdgHandle.Instance = WWDG;
  WwdgHandle.Init.Prescaler = WWDG_PRESCALER_8;
  WwdgHandle.Init.Window    = 80;
  WwdgHandle.Init.Counter   = 127;
  if (HAL_WWDG_Init(&WwdgHandle) != HAL_OK)
  {
    /* Initialization Error */
    Error_Handler();
  }
  /*###-Step 3- Start the WWDG ###############################################*/
  /* Enable and set the WWDG Early Wakeup Interrupt to has higher priority than other used interrupts */
  HAL_NVIC_SetPriority(WWDG_IRQn, 0x0D, 0x00); // Priority Group 4
  HAL_NVIC_EnableIRQ(WWDG_IRQn);
  if (HAL_WWDG_Start_IT(&WwdgHandle) != HAL_OK)
  {
    Error_Handler();
  }
  
  /* Infinite loop */
  while (1)
  {
   /* Toggle LED1 */
    BSP_LED_Toggle(LED1);


    /* Insert 30 ms delay */
    HAL_Delay(30);


    /* Refresh WWDG: update counter value to 127, the refresh window is:
 between 28.5 ms (~607 * (127-80)) and 38.8 ms (~607 * (127-63)) */
    if (HAL_WWDG_Refresh(&WwdgHandle, 127) != HAL_OK)
    {
      Error_Handler();
    }
  }
  
Step 2: Add the interrupt handler and re-write the callback
void WWDG_IRQHandler(void)
{
  HAL_WWDG_IRQHandler(&WwdgHandle);
}
void HAL_WWDG_WakeupCallback(WWDG_HandleTypeDef* hwwdg)
{
  /* Reload the downcounter */
  if (HAL_WWDG_Refresh(&WwdgHandle, 127) != HAL_OK)
  {
    Error_Handler();
  }
  
  /* Do some safety operations, which should be within 38.8 ms in this case
 or the WWDG will reset the system again */
  printf("** The system will be reset by WWDG ** \r\n");
  
  /* I would rather let the WWDG reset the system gracefully,
 because the original dog feeding pace has interrupted, which should never happen.
 Or comment the infinite loop to let the code run back to normal */
  while(1)
  {
  }
}


Step 3: Simulate an software problem to trigger EWI
You can add a long delay in the user button interrupt handler, which will block the normal refresh of the WWDG.

Outcomes