Extend watchdog coverage with IWDG, a watchdog running from an independent LF oscillator. If any of the threads being monitored does not report for more than 12ms, a reset will be asserted. When a WDG reset happens, the user can see it in the fault logs from vesc tool

Signed-off-by: Marcos Chaparro <mchaparro@paltatech.com>
This commit is contained in:
Marcos Chaparro 2019-01-24 12:19:44 -03:00
parent f1978ac5b4
commit 17f97763c0
14 changed files with 582 additions and 5 deletions

View File

@ -0,0 +1,131 @@
/**
******************************************************************************
* @file stm32f4xx_iwdg.h
* @author MCD Application Team
* @version V1.6.0
* @date 10-July-2015
* @brief This file contains all the functions prototypes for the IWDG
* firmware library.
******************************************************************************
* @attention
*
* <h2><center>&copy; COPYRIGHT 2015 STMicroelectronics</center></h2>
*
* Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.st.com/software_license_agreement_liberty_v2
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __STM32F4xx_IWDG_H
#define __STM32F4xx_IWDG_H
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ------------------------------------------------------------------*/
#include "stm32f4xx.h"
/** @addtogroup STM32F4xx_StdPeriph_Driver
* @{
*/
/** @addtogroup IWDG
* @{
*/
/* Exported types ------------------------------------------------------------*/
/* Exported constants --------------------------------------------------------*/
/** @defgroup IWDG_Exported_Constants
* @{
*/
/** @defgroup IWDG_WriteAccess
* @{
*/
#define IWDG_WriteAccess_Enable ((uint16_t)0x5555)
#define IWDG_WriteAccess_Disable ((uint16_t)0x0000)
#define IS_IWDG_WRITE_ACCESS(ACCESS) (((ACCESS) == IWDG_WriteAccess_Enable) || \
((ACCESS) == IWDG_WriteAccess_Disable))
/**
* @}
*/
/** @defgroup IWDG_prescaler
* @{
*/
#define IWDG_Prescaler_4 ((uint8_t)0x00)
#define IWDG_Prescaler_8 ((uint8_t)0x01)
#define IWDG_Prescaler_16 ((uint8_t)0x02)
#define IWDG_Prescaler_32 ((uint8_t)0x03)
#define IWDG_Prescaler_64 ((uint8_t)0x04)
#define IWDG_Prescaler_128 ((uint8_t)0x05)
#define IWDG_Prescaler_256 ((uint8_t)0x06)
#define IS_IWDG_PRESCALER(PRESCALER) (((PRESCALER) == IWDG_Prescaler_4) || \
((PRESCALER) == IWDG_Prescaler_8) || \
((PRESCALER) == IWDG_Prescaler_16) || \
((PRESCALER) == IWDG_Prescaler_32) || \
((PRESCALER) == IWDG_Prescaler_64) || \
((PRESCALER) == IWDG_Prescaler_128)|| \
((PRESCALER) == IWDG_Prescaler_256))
/**
* @}
*/
/** @defgroup IWDG_Flag
* @{
*/
#define IWDG_FLAG_PVU ((uint16_t)0x0001)
#define IWDG_FLAG_RVU ((uint16_t)0x0002)
#define IS_IWDG_FLAG(FLAG) (((FLAG) == IWDG_FLAG_PVU) || ((FLAG) == IWDG_FLAG_RVU))
#define IS_IWDG_RELOAD(RELOAD) ((RELOAD) <= 0xFFF)
/**
* @}
*/
/**
* @}
*/
/* Exported macro ------------------------------------------------------------*/
/* Exported functions --------------------------------------------------------*/
/* Prescaler and Counter configuration functions ******************************/
void IWDG_WriteAccessCmd(uint16_t IWDG_WriteAccess);
void IWDG_SetPrescaler(uint8_t IWDG_Prescaler);
void IWDG_SetReload(uint16_t Reload);
void IWDG_ReloadCounter(void);
/* IWDG activation function ***************************************************/
void IWDG_Enable(void);
/* Flag management function ***************************************************/
FlagStatus IWDG_GetFlagStatus(uint16_t IWDG_FLAG);
#ifdef __cplusplus
}
#endif
#endif /* __STM32F4xx_IWDG_H */
/**
* @}
*/
/**
* @}
*/
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

View File

@ -0,0 +1,270 @@
/**
******************************************************************************
* @file stm32f4xx_iwdg.c
* @author MCD Application Team
* @version V1.6.0
* @date 10-July-2015
* @brief This file provides firmware functions to manage the following
* functionalities of the Independent watchdog (IWDG) peripheral:
* + Prescaler and Counter configuration
* + IWDG activation
* + Flag management
*
@verbatim
===============================================================================
##### IWDG features #####
===============================================================================
[..]
The IWDG can be started by either software or hardware (configurable
through option byte).
The IWDG is clocked by its own dedicated low-speed clock (LSI) and
thus stays active even if the main clock fails.
Once the IWDG is started, the LSI is forced ON and cannot be disabled
(LSI cannot be disabled too), and the counter starts counting down from
the reset value of 0xFFF. When it reaches the end of count value (0x000)
a system reset is generated.
The IWDG counter should be reloaded at regular intervals to prevent
an MCU reset.
The IWDG is implemented in the VDD voltage domain that is still functional
in STOP and STANDBY mode (IWDG reset can wake-up from STANDBY).
IWDGRST flag in RCC_CSR register can be used to inform when a IWDG
reset occurs.
Min-max timeout value @32KHz (LSI): ~125us / ~32.7s
The IWDG timeout may vary due to LSI frequency dispersion. STM32F4xx
devices provide the capability to measure the LSI frequency (LSI clock
connected internally to TIM5 CH4 input capture). The measured value
can be used to have an IWDG timeout with an acceptable accuracy.
For more information, please refer to the STM32F4xx Reference manual
##### How to use this driver #####
===============================================================================
[..]
(#) Enable write access to IWDG_PR and IWDG_RLR registers using
IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable) function
(#) Configure the IWDG prescaler using IWDG_SetPrescaler() function
(#) Configure the IWDG counter value using IWDG_SetReload() function.
This value will be loaded in the IWDG counter each time the counter
is reloaded, then the IWDG will start counting down from this value.
(#) Start the IWDG using IWDG_Enable() function, when the IWDG is used
in software mode (no need to enable the LSI, it will be enabled
by hardware)
(#) Then the application program must reload the IWDG counter at regular
intervals during normal operation to prevent an MCU reset, using
IWDG_ReloadCounter() function.
@endverbatim
******************************************************************************
* @attention
*
* <h2><center>&copy; COPYRIGHT 2015 STMicroelectronics</center></h2>
*
* Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.st.com/software_license_agreement_liberty_v2
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "stm32f4xx_iwdg.h"
#ifndef assert_param
#define assert_param(expr) ((void)0)
#endif
/** @addtogroup STM32F4xx_StdPeriph_Driver
* @{
*/
/** @defgroup IWDG
* @brief IWDG driver modules
* @{
*/
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* KR register bit mask */
#define KR_KEY_RELOAD ((uint16_t)0xAAAA)
#define KR_KEY_ENABLE ((uint16_t)0xCCCC)
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/* Private functions ---------------------------------------------------------*/
/** @defgroup IWDG_Private_Functions
* @{
*/
/** @defgroup IWDG_Group1 Prescaler and Counter configuration functions
* @brief Prescaler and Counter configuration functions
*
@verbatim
===============================================================================
##### Prescaler and Counter configuration functions #####
===============================================================================
@endverbatim
* @{
*/
/**
* @brief Enables or disables write access to IWDG_PR and IWDG_RLR registers.
* @param IWDG_WriteAccess: new state of write access to IWDG_PR and IWDG_RLR registers.
* This parameter can be one of the following values:
* @arg IWDG_WriteAccess_Enable: Enable write access to IWDG_PR and IWDG_RLR registers
* @arg IWDG_WriteAccess_Disable: Disable write access to IWDG_PR and IWDG_RLR registers
* @retval None
*/
void IWDG_WriteAccessCmd(uint16_t IWDG_WriteAccess)
{
/* Check the parameters */
assert_param(IS_IWDG_WRITE_ACCESS(IWDG_WriteAccess));
IWDG->KR = IWDG_WriteAccess;
}
/**
* @brief Sets IWDG Prescaler value.
* @param IWDG_Prescaler: specifies the IWDG Prescaler value.
* This parameter can be one of the following values:
* @arg IWDG_Prescaler_4: IWDG prescaler set to 4
* @arg IWDG_Prescaler_8: IWDG prescaler set to 8
* @arg IWDG_Prescaler_16: IWDG prescaler set to 16
* @arg IWDG_Prescaler_32: IWDG prescaler set to 32
* @arg IWDG_Prescaler_64: IWDG prescaler set to 64
* @arg IWDG_Prescaler_128: IWDG prescaler set to 128
* @arg IWDG_Prescaler_256: IWDG prescaler set to 256
* @retval None
*/
void IWDG_SetPrescaler(uint8_t IWDG_Prescaler)
{
/* Check the parameters */
assert_param(IS_IWDG_PRESCALER(IWDG_Prescaler));
IWDG->PR = IWDG_Prescaler;
}
/**
* @brief Sets IWDG Reload value.
* @param Reload: specifies the IWDG Reload value.
* This parameter must be a number between 0 and 0x0FFF.
* @retval None
*/
void IWDG_SetReload(uint16_t Reload)
{
/* Check the parameters */
assert_param(IS_IWDG_RELOAD(Reload));
IWDG->RLR = Reload;
}
/**
* @brief Reloads IWDG counter with value defined in the reload register
* (write access to IWDG_PR and IWDG_RLR registers disabled).
* @param None
* @retval None
*/
void IWDG_ReloadCounter(void)
{
IWDG->KR = KR_KEY_RELOAD;
}
/**
* @}
*/
/** @defgroup IWDG_Group2 IWDG activation function
* @brief IWDG activation function
*
@verbatim
===============================================================================
##### IWDG activation function #####
===============================================================================
@endverbatim
* @{
*/
/**
* @brief Enables IWDG (write access to IWDG_PR and IWDG_RLR registers disabled).
* @param None
* @retval None
*/
void IWDG_Enable(void)
{
IWDG->KR = KR_KEY_ENABLE;
}
/**
* @}
*/
/** @defgroup IWDG_Group3 Flag management function
* @brief Flag management function
*
@verbatim
===============================================================================
##### Flag management function #####
===============================================================================
@endverbatim
* @{
*/
/**
* @brief Checks whether the specified IWDG flag is set or not.
* @param IWDG_FLAG: specifies the flag to check.
* This parameter can be one of the following values:
* @arg IWDG_FLAG_PVU: Prescaler Value Update on going
* @arg IWDG_FLAG_RVU: Reload Value Update on going
* @retval The new state of IWDG_FLAG (SET or RESET).
*/
FlagStatus IWDG_GetFlagStatus(uint16_t IWDG_FLAG)
{
FlagStatus bitstatus = RESET;
/* Check the parameters */
assert_param(IS_IWDG_FLAG(IWDG_FLAG));
if ((IWDG->SR & IWDG_FLAG) != (uint32_t)RESET)
{
bitstatus = SET;
}
else
{
bitstatus = RESET;
}
/* Return the flag status */
return bitstatus;
}
/**
* @}
*/
/**
* @}
*/
/**
* @}
*/
/**
* @}
*/
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

View File

@ -8,6 +8,7 @@ STM32SRC = ${CHIBIOS}/ext/stdperiph_stm32f4/src/misc.c \
${CHIBIOS}/ext/stdperiph_stm32f4/src/stm32f4xx_rcc.c \
${CHIBIOS}/ext/stdperiph_stm32f4/src/stm32f4xx_syscfg.c \
${CHIBIOS}/ext/stdperiph_stm32f4/src/stm32f4xx_tim.c \
${CHIBIOS}/ext/stdperiph_stm32f4/src/stm32f4xx_iwdg.c \
${CHIBIOS}/ext/stdperiph_stm32f4/src/stm32f4xx_wwdg.c
STM32INC = ${CHIBIOS}/ext/stdperiph_stm32f4/inc

View File

@ -122,6 +122,9 @@ static THD_FUNCTION(cancom_read_thread, arg) {
chEvtRegister(&CANDx.rxfull_event, &el, 0);
while(!chThdShouldTerminateX()) {
// Feed watchdog
timeout_feed_WDT(THREAD_CANBUS);
if (chEvtWaitAnyTimeout(ALL_EVENTS, MS2ST(10)) == 0) {
continue;
}

View File

@ -333,6 +333,7 @@ bool conf_general_store_app_configuration(app_configuration *conf) {
mc_interface_lock();
RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG, DISABLE);
timeout_configure_IWDT_slowest();
bool is_ok = true;
uint8_t *conf_addr = (uint8_t*)conf;
@ -352,6 +353,7 @@ bool conf_general_store_app_configuration(app_configuration *conf) {
}
RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG, ENABLE);
timeout_configure_IWDT();
chThdSleepMilliseconds(100);
mc_interface_unlock();
@ -400,6 +402,7 @@ bool conf_general_store_mc_configuration(mc_configuration *conf) {
mc_interface_lock();
RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG, DISABLE);
timeout_configure_IWDT_slowest();
bool is_ok = true;
uint8_t *conf_addr = (uint8_t*)conf;
@ -419,6 +422,7 @@ bool conf_general_store_mc_configuration(mc_configuration *conf) {
}
RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG, ENABLE);
timeout_configure_IWDT();
chThdSleepMilliseconds(100);
mc_interface_unlock();

View File

@ -79,7 +79,8 @@ typedef enum {
FAULT_CODE_OVER_TEMP_MOTOR,
FAULT_CODE_GATE_DRIVER_OVER_VOLTAGE,
FAULT_CODE_GATE_DRIVER_UNDER_VOLTAGE,
FAULT_CODE_MCU_UNDER_VOLTAGE
FAULT_CODE_MCU_UNDER_VOLTAGE,
FAULT_CODE_BOOTING_FROM_WATCHDOG_RESET
} mc_fault_code;
typedef enum {

View File

@ -23,6 +23,7 @@
#include "stm32f4xx_conf.h"
#include "utils.h"
#include "mc_interface.h"
#include "timeout.h"
#include "hw.h"
#include <string.h>
@ -90,6 +91,7 @@ uint16_t flash_helper_erase_new_app(uint32_t new_app_size) {
mc_interface_release_motor();
utils_sys_lock_cnt();
RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG, DISABLE);
timeout_configure_IWDT_slowest();
for (int i = 0;i < NEW_APP_SECTORS;i++) {
if (new_app_size > flash_addr[NEW_APP_BASE + i]) {
@ -103,6 +105,7 @@ uint16_t flash_helper_erase_new_app(uint32_t new_app_size) {
}
RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG, ENABLE);
timeout_configure_IWDT();
utils_sys_unlock_cnt();
return FLASH_COMPLETE;
@ -116,6 +119,7 @@ uint16_t flash_helper_write_new_app_data(uint32_t offset, uint8_t *data, uint32_
mc_interface_release_motor();
utils_sys_lock_cnt();
RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG, DISABLE);
timeout_configure_IWDT_slowest();
for (uint32_t i = 0;i < len;i++) {
uint16_t res = FLASH_ProgramByte(flash_addr[NEW_APP_BASE] + offset + i, data[i]);
@ -125,6 +129,8 @@ uint16_t flash_helper_write_new_app_data(uint32_t offset, uint8_t *data, uint32_
}
RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG, ENABLE);
timeout_configure_IWDT();
utils_sys_unlock_cnt();
return FLASH_COMPLETE;
@ -147,6 +153,7 @@ void flash_helper_jump_to_bootloader(void) {
// Disable watchdog
RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG, DISABLE);
timeout_configure_IWDT_slowest();
chSysDisable();

8
main.c
View File

@ -171,6 +171,7 @@ static THD_FUNCTION(timer_thread, arg) {
for(;;) {
packet_timerfunc();
timeout_feed_WDT(THREAD_TIMER);
chThdSleepMilliseconds(1);
}
}
@ -197,6 +198,7 @@ int main(void) {
mc_configuration mcconf;
conf_general_read_mc_configuration(&mcconf);
mc_interface_init(&mcconf);
commands_init();
@ -226,9 +228,6 @@ int main(void) {
}
#endif
timeout_init();
timeout_configure(appconf.timeout_msec, appconf.timeout_brake_current);
#if WS2811_ENABLE
ws2811_init();
#if !WS2811_TEST
@ -304,6 +303,9 @@ int main(void) {
}
#endif
timeout_init();
timeout_configure(appconf.timeout_msec, appconf.timeout_brake_current);
for(;;) {
chThdSleepMilliseconds(10);

View File

@ -307,6 +307,7 @@ const char* mc_interface_fault_to_string(mc_fault_code fault) {
case FAULT_CODE_GATE_DRIVER_OVER_VOLTAGE: return "FAULT_CODE_GATE_DRIVER_OVER_VOLTAGE"; break;
case FAULT_CODE_GATE_DRIVER_UNDER_VOLTAGE: return "FAULT_CODE_GATE_DRIVER_UNDER_VOLTAGE"; break;
case FAULT_CODE_MCU_UNDER_VOLTAGE: return "FAULT_CODE_MCU_UNDER_VOLTAGE"; break;
case FAULT_CODE_BOOTING_FROM_WATCHDOG_RESET: return "FAULT_CODE_BOOTING_FROM_WATCHDOG_RESET"; break;
default: return "FAULT_UNKNOWN"; break;
}
}

View File

@ -30,6 +30,7 @@
#include "utils.h"
#include "ledpwm.h"
#include "terminal.h"
#include "timeout.h"
#include "encoder.h"
// Structs
@ -460,6 +461,10 @@ void mcpwm_init(volatile mc_configuration *configuration) {
chThdCreateStatic(timer_thread_wa, sizeof(timer_thread_wa), NORMALPRIO, timer_thread, NULL);
chThdCreateStatic(rpm_thread_wa, sizeof(rpm_thread_wa), NORMALPRIO, rpm_thread, NULL);
// Check if the system has resumed from IWDG reset
if (timeout_had_IWDG_reset())
mc_interface_fault_stop(FAULT_CODE_BOOTING_FROM_WATCHDOG_RESET);
// WWDG configuration
RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG, ENABLE);
WWDG_SetPrescaler(WWDG_Prescaler_1);
@ -1721,6 +1726,7 @@ void mcpwm_adc_int_handler(void *p, uint32_t flags) {
// Reset the watchdog
WWDG_SetCounter(100);
timeout_feed_WDT(THREAD_MCPWM);
const float input_voltage = GET_INPUT_VOLTAGE();
int ph1, ph2, ph3;

View File

@ -445,6 +445,10 @@ void mcpwm_foc_init(volatile mc_configuration *configuration) {
timer_thd_stop = false;
chThdCreateStatic(timer_thread_wa, sizeof(timer_thread_wa), NORMALPRIO, timer_thread, NULL);
// Check if the system has resumed from IWDG reset
if (timeout_had_IWDG_reset())
mc_interface_fault_stop(FAULT_CODE_BOOTING_FROM_WATCHDOG_RESET);
// WWDG configuration
RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG, ENABLE);
WWDG_SetPrescaler(WWDG_Prescaler_1);
@ -1487,6 +1491,7 @@ void mcpwm_foc_adc_int_handler(void *p, uint32_t flags) {
// Reset the watchdog
WWDG_SetCounter(100);
timeout_feed_WDT(THREAD_MCPWM);
int curr0 = ADC_Value[ADC_IND_CURR1];
int curr1 = ADC_Value[ADC_IND_CURR2];

View File

@ -13,6 +13,7 @@
#include "stm32f4xx_syscfg.h"
#include "stm32f4xx_tim.h"
#include "stm32f4xx_wwdg.h"
#include "stm32f4xx_iwdg.h"
#ifdef USE_FULL_ASSERT
#define assert_param(expr) ((expr) ? (void)0 : assert_failed((uint8_t *)__FILE__, __LINE__))

130
timeout.c
View File

@ -19,23 +19,31 @@
#include "timeout.h"
#include "mc_interface.h"
#include "stm32f4xx_conf.h"
// Private variables
static volatile systime_t timeout_msec;
static volatile systime_t last_update_time;
static volatile float timeout_brake_current;
static volatile bool has_timeout;
static volatile uint32_t feed_counter[MAX_THREADS_MONITOR];
// Threads
static THD_WORKING_AREA(timeout_thread_wa, 512);
static THD_FUNCTION(timeout_thread, arg);
void timeout_init_IWDT(void);
void timeout_init(void) {
timeout_msec = 1000;
last_update_time = 0;
timeout_brake_current = 0.0;
has_timeout = false;
timeout_init_IWDT();
chThdSleepMilliseconds(10);
chThdCreateStatic(timeout_thread_wa, sizeof(timeout_thread_wa), NORMALPRIO, timeout_thread, NULL);
}
@ -60,6 +68,102 @@ float timeout_get_brake_current(void) {
return timeout_brake_current;
}
void timeout_feed_WDT(uint8_t index) {
++feed_counter[index];
}
void timeout_init_IWDT(void) {
/* Enable write access to IWDG_PR and IWDG_RLR registers */
IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable);
/* IWDG counter clock: LSI/4 */
IWDG_SetPrescaler(IWDG_Prescaler_4);
/* Set counter reload value to obtain 12ms IWDG TimeOut.
*
* LSI timer per datasheet is 32KHz typical, but 17KHz min
* and 47KHz max over the complete range of operating conditions,
* so reload time must ensure watchdog will work correctly under
* all conditions.
*
* Timeout threads runs every 10ms. Take 20% margin so wdt should
* be fed every 12ms. The worst condition occurs when the wdt clock
* runs at the max freq (47KHz) due to oscillator tolerances.
*
* t_IWDG(ms) = t_LSI(ms) * 4 * 2^(IWDG_PR[2:0]) * (IWDG_RLR[11:0] + 1)
* t_LSI(ms) [MAX] = 0.021276ms
* 12ms = 0.0212765 * 4 * 1 * (140 + 1)
Counter Reload Value = 140
When LSI clock runs the slowest, the IWDG will expire every 33.17ms
*/
IWDG_SetReload(140);
IWDG_ReloadCounter();
/* Enable IWDG (the LSI oscillator will be enabled by hardware) */
IWDG_Enable();
}
void timeout_configure_IWDT_slowest(void) {
while(((IWDG->SR & IWDG_SR_RVU) != 0) || ((IWDG->SR & IWDG_SR_PVU) != 0))
{
// Continue to kick the dog
IWDG_ReloadCounter();
}
// Unlock register
IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable);
// Update configuration
IWDG_SetReload(1400);
IWDG_SetPrescaler(IWDG_Prescaler_256);
// Wait for the new configuration to be taken into account
while(((IWDG->SR & IWDG_SR_RVU) != 0) || ((IWDG->SR & IWDG_SR_PVU) != 0))
{
// Continue to kick the dog
IWDG_ReloadCounter();
}
}
void timeout_configure_IWDT(void) {
while(((IWDG->SR & IWDG_SR_RVU) != 0) || ((IWDG->SR & IWDG_SR_PVU) != 0))
{
// Continue to kick the dog
IWDG_ReloadCounter();
}
// Unlock register
IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable);
// Update configuration
IWDG_SetReload(140);
IWDG_SetPrescaler(IWDG_Prescaler_4);
// Wait for the new configuration to be taken into account
while(((IWDG->SR & IWDG_SR_RVU) != 0) || ((IWDG->SR & IWDG_SR_PVU) != 0))
{
// Continue to kick the dog
IWDG_ReloadCounter();
}
}
bool timeout_had_IWDG_reset(void) {
// Check if the system has resumed from IWDG reset
if (RCC_GetFlagStatus(RCC_FLAG_IWDGRST) != RESET) {
/* IWDGRST flag set */
/* Clear reset flags */
RCC_ClearFlag();
return true;
}
// Check if the system has resumed from WWDG reset
if (RCC_GetFlagStatus(RCC_FLAG_WWDGRST) != RESET) {
/* IWDGRST flag set */
/* Clear reset flags */
RCC_ClearFlag();
return true;
}
return false;
}
static THD_FUNCTION(timeout_thread, arg) {
(void)arg;
@ -74,6 +178,32 @@ static THD_FUNCTION(timeout_thread, arg) {
has_timeout = false;
}
bool threads_ok = true;
// Monitored threads (foc, can, timer) must report at least one iteration,
// otherwise the watchdog won't be feed and MCU will reset. All threads should
// be monitored
if(feed_counter[THREAD_MCPWM] < MIN_THREAD_ITERATIONS)
threads_ok = false;
if(feed_counter[THREAD_CANBUS] < MIN_THREAD_ITERATIONS)
threads_ok = false;
if(feed_counter[THREAD_TIMER] < MIN_THREAD_ITERATIONS)
threads_ok = false;
for( int i = 0; i < MAX_THREADS_MONITOR; i++)
feed_counter[i] = 0;
if (threads_ok == true) {
// Feed WDT
IWDG_ReloadCounter();
}
else
{
// not reloading the watchdog will produce a reset.
// This can be checked from the GUI logs as
// "FAULT_CODE_BOOTING_FROM_WATCHDOG_RESET"
}
chThdSleepMilliseconds(10);
}
}

View File

@ -24,12 +24,27 @@
#include "chtypes.h"
#include "chsystypes.h"
#define MAX_THREADS_MONITOR 10
#define MIN_THREAD_ITERATIONS 1
typedef enum {
THREAD_MCPWM = 0,
THREAD_CANBUS,
THREAD_TIMER,
THREAD_USB,
THREAD_APP
} WWDT_THREAD_TYPES;
// Functions
void timeout_init(void);
void timeout_configure(systime_t timeout, float brake_current);
void timeout_reset(void);
bool timeout_has_timeout(void);
systime_t timeout_get_timeout_msec(void);
void timeout_configure_IWDT(void);
void timeout_configure_IWDT_slowest(void);
bool timeout_had_IWDG_reset(void);
void timeout_feed_WDT(uint8_t index);
float timeout_get_brake_current(void);
#endif /* TIMEOUT_H_ */