From 6b74e25455c36ee1ad1600a8e1584497b67744b7 Mon Sep 17 00:00:00 2001 From: Tej Sharma Date: Thu, 24 Jul 2025 19:13:37 +0530 Subject: [PATCH] fix: add watchdog support and MCU recovery logic for fault scenarios - Added watchdog initialization and periodic refresh in application code. - Implemented software reset trigger when code enters Default_Handler (catch-all for unhandled interrupts). - Improved FOTA robustness: added logic to restore code execution and CAN communication when the IOT module resets unexpectedly during firmware update. - Verified recovery flow and communication reinitialization after system reset scenarios. --- Core/Include/ivec_mcal_wdt.h | 12 ++++ Core/Source/ivec_mcal_wdt.c | 135 +++++++++++++++++++++++++++++++++++ ivec_RTE/src/ivec_rte.c | 12 +++- main.c | 2 + startup_mspm0g350x_gcc.c | 1 + utils/utils.c | 9 ++- utils/utils.h | 21 ++++++ 7 files changed, 188 insertions(+), 4 deletions(-) create mode 100644 Core/Include/ivec_mcal_wdt.h create mode 100644 Core/Source/ivec_mcal_wdt.c diff --git a/Core/Include/ivec_mcal_wdt.h b/Core/Include/ivec_mcal_wdt.h new file mode 100644 index 0000000..bca3676 --- /dev/null +++ b/Core/Include/ivec_mcal_wdt.h @@ -0,0 +1,12 @@ +#ifndef CORE_INCLUDE_IVEC_MCAL_WDT_H_ +#define CORE_INCLUDE_IVEC_MCAL_WDT_H_ + +#include "../utils/utils.h" + +IVEC_McalStatus_e xMCAL_WatchdogInit(MCAL_WWDT_TIMER timer); + +IVEC_McalStatus_e xMCAL_WatchdogDeInit(void); + +IVEC_McalStatus_e xMCAL_WatchdogReset(void); + +#endif /* CORE_INCLUDE_IVEC_MCAL_WDT_H_ */ diff --git a/Core/Source/ivec_mcal_wdt.c b/Core/Source/ivec_mcal_wdt.c new file mode 100644 index 0000000..047dfba --- /dev/null +++ b/Core/Source/ivec_mcal_wdt.c @@ -0,0 +1,135 @@ +#include "ivec_mcal_wdt.h" + +static volatile bool b_WDInitFlag; + + +IVEC_McalStatus_e xMCAL_WatchdogInit(MCAL_WWDT_TIMER timer) +{ + DL_WWDT_CLOCK_DIVIDE Clk_Div; + DL_WWDT_TIMER_PERIOD Tmr_Per; + + assert(WATCHDOG_TIMER != NULL); + + switch(timer) + { + case MCAL_WDT_1_SEC_TIMER: + Clk_Div = DL_WWDT_CLOCK_DIVIDE_1; + Tmr_Per = DL_WWDT_TIMER_PERIOD_15_BITS; + break; + case MCAL_WDT_2_SEC_TIMER: + Clk_Div = DL_WWDT_CLOCK_DIVIDE_2; + Tmr_Per = DL_WWDT_TIMER_PERIOD_15_BITS; + break; + case MCAL_WDT_3_SEC_TIMER: + Clk_Div = DL_WWDT_CLOCK_DIVIDE_3; + Tmr_Per = DL_WWDT_TIMER_PERIOD_15_BITS; + break; + case MCAL_WDT_4_SEC_TIMER: + Clk_Div = DL_WWDT_CLOCK_DIVIDE_4; + Tmr_Per = DL_WWDT_TIMER_PERIOD_15_BITS; + break; + case MCAL_WDT_5_SEC_TIMER: + Clk_Div = DL_WWDT_CLOCK_DIVIDE_5; + Tmr_Per = DL_WWDT_TIMER_PERIOD_15_BITS; + break; + case MCAL_WDT_6_SEC_TIMER: + Clk_Div = DL_WWDT_CLOCK_DIVIDE_6; + Tmr_Per = DL_WWDT_TIMER_PERIOD_15_BITS; + break; + case MCAL_WDT_7_SEC_TIMER: + Clk_Div = DL_WWDT_CLOCK_DIVIDE_7; + Tmr_Per = DL_WWDT_TIMER_PERIOD_15_BITS; + break; + case MCAL_WDT_8_SEC_TIMER: + Clk_Div = DL_WWDT_CLOCK_DIVIDE_8; + Tmr_Per = DL_WWDT_TIMER_PERIOD_15_BITS; + break; + case MCAL_WDT_16_SEC_TIMER: + Clk_Div = DL_WWDT_CLOCK_DIVIDE_2; + Tmr_Per = DL_WWDT_TIMER_PERIOD_18_BITS; + break; + case MCAL_WDT_24_SEC_TIMER: + Clk_Div = DL_WWDT_CLOCK_DIVIDE_3; + Tmr_Per = DL_WWDT_TIMER_PERIOD_18_BITS; + break; + case MCAL_WDT_32_SEC_TIMER: + Clk_Div = DL_WWDT_CLOCK_DIVIDE_4; + Tmr_Per = DL_WWDT_TIMER_PERIOD_18_BITS; + break; + case MCAL_WDT_40_SEC_TIMER: + Clk_Div = DL_WWDT_CLOCK_DIVIDE_5; + Tmr_Per = DL_WWDT_TIMER_PERIOD_18_BITS; + break; + case MCAL_WDT_48_SEC_TIMER: + Clk_Div = DL_WWDT_CLOCK_DIVIDE_6; + Tmr_Per = DL_WWDT_TIMER_PERIOD_18_BITS; + break; + case MCAL_WDT_56_SEC_TIMER: + Clk_Div = DL_WWDT_CLOCK_DIVIDE_7; + Tmr_Per = DL_WWDT_TIMER_PERIOD_18_BITS; + break; + case MCAL_WDT_64_SEC_TIMER: + Clk_Div = DL_WWDT_CLOCK_DIVIDE_8; + Tmr_Per = DL_WWDT_TIMER_PERIOD_18_BITS; + break; + default: return IVEC_MCAL_STATUS_INIT_FAIL; + } + DL_WWDT_disablePower(WATCHDOG_TIMER); + if(b_WDInitFlag == false) + { + /* Set Window0 as active window */ + DL_WWDT_setActiveWindow(WATCHDOG_TIMER, DL_WWDT_WINDOW0); + + DL_WWDT_initWatchdogMode(WATCHDOG_TIMER, Clk_Div,Tmr_Per, DL_WWDT_RUN_IN_SLEEP, DL_WWDT_WINDOW_PERIOD_0, DL_WWDT_WINDOW_PERIOD_0); // DL_WWDT_WINDOW_PERIOD_0 is for selecting the closed percentage of the watchdog + if(DL_WWDT_isPowerEnabled(WATCHDOG_TIMER)) + { + while ((DL_SYSCTL_getClockStatus() & (DL_SYSCTL_CLK_STATUS_LFOSC_GOOD))!= (DL_SYSCTL_CLK_STATUS_LFOSC_GOOD)); + } + else + { + + return IVEC_MCAL_STATUS_TIMEOUT; + } + b_WDInitFlag = true; + + return IVEC_MCAL_STATUS_SUCCESS; + } + else + {; + return IVEC_MCAL_STATUS_INIT_FAIL; + } + +} + +IVEC_McalStatus_e xMCAL_WatchdogDeInit(void) +{ + assert(WATCHDOG_TIMER != NULL); + + if(b_WDInitFlag == true) + { + DL_WWDT_disablePower(WATCHDOG_TIMER); + + b_WDInitFlag = false; + + return IVEC_MCAL_STATUS_SUCCESS; + } + else + { + return IVEC_MCAL_STATUS_INIT_FAIL; + } +} + + +IVEC_McalStatus_e xMCAL_WatchdogReset(void) +{ + if(DL_WWDT_isRunning(WATCHDOG_TIMER) == true) + { + DL_WWDT_restart(WATCHDOG_TIMER); + + return IVEC_MCAL_STATUS_SUCCESS; + } + else + { + return IVEC_MCAL_STATUS_ERROR; + } +} diff --git a/ivec_RTE/src/ivec_rte.c b/ivec_RTE/src/ivec_rte.c index 8019aaa..a35e04d 100644 --- a/ivec_RTE/src/ivec_rte.c +++ b/ivec_RTE/src/ivec_rte.c @@ -498,6 +498,8 @@ void vCcUartRxToCanTx(IVEC_EcuCommonCanFrame_s* pxCanMsg) int l_i32Status = -1; l_i32RetSize = u16CMPLX_vFrameEncode((uint32_t)l_u32Id, (uint8_t*)&pu8Data[1], u8Len, l_u8UartBuffer, 30); l_i32Status = IVEC_ECUUartWrite(&__gprv_UartCcHandle, l_u8UartBuffer, l_i32RetSize); + vMCAL_WDG_Refresh(); + DL_WWDT_disablePower(WATCHDOG_TIMER); vMCAL_softReset(); } @@ -767,7 +769,10 @@ void vRTE_ProcessUartData(void) uint8_t u8Len = sizeof(pu8Data); // Length of data array iECU_UartInitiateTransmit(&g_xUartHandle, u32Id, pu8Data, u8Len); iECU_UartInitiateTransmit(&g_xUartHandle, 0x8, NULL, 0); + vMCAL_WDG_Refresh(); + DL_WWDT_disablePower(WATCHDOG_TIMER); vMCAL_softReset(); + } if(l_eRetCode > 0 && l_u32Id == 0x00) @@ -840,9 +845,10 @@ void vRTE_ProcessUartData(void) l_i32Status = IVEC_ECUUartWrite(&__gprv_UartCcHandle, l_u8UartBuffer, l_i32RetSize); } xECU_WriteDataOverCAN(&g_xCanHandle, &g_pu8UartBuffer[ecuUART_PKT_HEADER_u8], l_u32Id, l_eRetCode, 0); - } } + vMCAL_WDG_Refresh(); + } /** * @brief Processes CAN data and handles CAN communication. @@ -868,6 +874,7 @@ void vRTE_ProcessCanData(void) (l_xCanBuff.u8Data[3] == 'I') && (l_xCanBuff.u8Data[4] == 'O') && \ (l_xCanBuff.u8Data[5] == 'T')) { + DL_WWDT_disablePower(WATCHDOG_TIMER); vMCAL_softReset(); } @@ -880,7 +887,6 @@ void vRTE_ProcessCanData(void) { l_i32RetSize = u16CMPLX_vFrameEncode((uint32_t)0xabcdef, (uint8_t*)&l_xCanBuff.u8Data[0], (int32_t)l_xCanBuff.u8Length, l_u8UartBuffer, 30); - } l_i32Status = IVEC_ECUUartWrite(&__gprv_UartCcHandle, l_u8UartBuffer, l_i32RetSize); @@ -898,5 +904,5 @@ void vRTE_ProcessCanData(void) break; } xECU_CANGetStatus(&g_xCanHandle); - + vMCAL_WDG_Refresh(); } diff --git a/main.c b/main.c index 9181c3f..d87f4b4 100644 --- a/main.c +++ b/main.c @@ -31,6 +31,7 @@ int main(void) { __enable_irq(); volatile DL_SYSCTL_RESET_CAUSE l_xResetCause = DL_SYSCTL_getResetCause(); + vMCAL_WDG_Refresh(); vMCAL_mcuInit(); xMCAL_sysctlInit(IVEC_HFXT,IVEC_STANDBY0); xMCAL_systickInit(IVEC_SYSTICK_PERIOD_1MS); @@ -43,6 +44,7 @@ int main(void) while(1) { vRTE_AppRun(); + vMCAL_WDG_Refresh(); } } diff --git a/startup_mspm0g350x_gcc.c b/startup_mspm0g350x_gcc.c index aecd694..23a709e 100644 --- a/startup_mspm0g350x_gcc.c +++ b/startup_mspm0g350x_gcc.c @@ -231,6 +231,7 @@ void Default_Handler(void) // // You can use this to trace the fault location in your code /* Enter an infinite loop. */ + DL_SYSCTL_resetDevice(DL_SYSCTL_RESET_CPU); while(1) { } diff --git a/utils/utils.c b/utils/utils.c index 2810fde..9767825 100644 --- a/utils/utils.c +++ b/utils/utils.c @@ -158,11 +158,13 @@ void vMCAL_delayTicks(int32_t i32DelayMs) * * Calls the necessary functions to initialize power and GPIO configurations for the MCU. */ - void vMCAL_mcuInit(void) { SYSCFG_DL_initPower(); + DL_WWDT_enablePower(WATCHDOG_TIMER); + xMCAL_WatchdogInit(MCAL_WDT_4_SEC_TIMER); // Timer Inputs can be : 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 16 , 24 , 32 , 40 , 48 , 56 , 64 in seconds SYSCFG_DL_GPIO_init(); + } /** * @brief Delays execution for a specified number of microseconds. @@ -211,3 +213,8 @@ void vMCAL_softReset(void) { DL_SYSCTL_resetDevice(DL_SYSCTL_RESET_CPU); } + +void vMCAL_WDG_Refresh(void) +{ + xMCAL_WatchdogReset(); +} diff --git a/utils/utils.h b/utils/utils.h index 1128195..cac76cd 100644 --- a/utils/utils.h +++ b/utils/utils.h @@ -12,6 +12,26 @@ #include #include "ti_msp_dl_config.h" +#define WATCHDOG_TIMER WWDT1 +typedef enum +{ + MCAL_WDT_1_SEC_TIMER = 1, + MCAL_WDT_2_SEC_TIMER, + MCAL_WDT_3_SEC_TIMER, + MCAL_WDT_4_SEC_TIMER, + MCAL_WDT_5_SEC_TIMER, + MCAL_WDT_6_SEC_TIMER, + MCAL_WDT_7_SEC_TIMER, + MCAL_WDT_8_SEC_TIMER, + MCAL_WDT_16_SEC_TIMER = 16, + MCAL_WDT_24_SEC_TIMER = 24, + MCAL_WDT_32_SEC_TIMER = 32, + MCAL_WDT_40_SEC_TIMER = 40, + MCAL_WDT_48_SEC_TIMER = 48, + MCAL_WDT_56_SEC_TIMER = 56, + MCAL_WDT_64_SEC_TIMER = 64 +}MCAL_WWDT_TIMER; + /* Generic Status Codes */ typedef enum { @@ -86,5 +106,6 @@ void vMCAL_delayTicks(int32_t i32DelayMs); void vMCAL_softReset(void); void vMCAL_delayUs(uint32_t u32Us); IVEC_McalStatus_e xMCAL_vrefInit(void); +void vMCAL_WDG_Refresh(void); #endif /* UTILS_IVEC_UTILS_H_ */