mirror of https://github.com/rusefi/bldc.git
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:
parent
f1978ac5b4
commit
17f97763c0
|
@ -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>© 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****/
|
|
@ -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>© 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****/
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
8
main.c
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
6
mcpwm.c
6
mcpwm.c
|
@ -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;
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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
130
timeout.c
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
15
timeout.h
15
timeout.h
|
@ -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_ */
|
||||
|
|
Loading…
Reference in New Issue