Question
Window Watchdog (WWDG) Early Wakeup Interrupt (EWI) configuration bugs in firmware library
Posted on November 06, 2015 at 16:44
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.40Board: STM32746G-Discovery (STM32F746NG embedded)Firmware version: V1.2.0HAL_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 callbackvoid 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 EWIYou can add a long delay in the user button interrupt handler, which will block the normal refresh of the WWDG. #window-watchdog