diff --git a/fsae-vehicle-fw/platformio.ini b/fsae-vehicle-fw/platformio.ini index 4137c1a..47a514a 100644 --- a/fsae-vehicle-fw/platformio.ini +++ b/fsae-vehicle-fw/platformio.ini @@ -15,3 +15,4 @@ framework = arduino lib_deps = https://github.com/tsandmann/freertos-teensy.git@^11.0.0 + https://github.com/kdao18/WDT_T4.git diff --git a/fsae-vehicle-fw/src/main.cpp b/fsae-vehicle-fw/src/main.cpp index 07110ce..dcba770 100644 --- a/fsae-vehicle-fw/src/main.cpp +++ b/fsae-vehicle-fw/src/main.cpp @@ -5,6 +5,7 @@ #include "peripherals/adc.h" #include "peripherals/can.h" +#include "peripherals/wdt.h" #include "peripherals/gpio.h" #include "vehicle/apps.h" @@ -42,9 +43,13 @@ void setup() { // runs once on bootup GPIO_Init(); PCC_Init(); thermal_Init(); + WDT_Init(); + xTaskCreate(WDT_Update_Task, "threadWDT", 128, NULL, 9, + NULL); // runs wdt update task xTaskCreate(threadADC, "threadADC", THREAD_ADC_STACK_SIZE, NULL, THREAD_ADC_PRIORITY, NULL); + xTaskCreate(threadMotor, "threadMotor", THREAD_MOTOR_STACK_SIZE, NULL, THREAD_MOTOR_PRIORITY, NULL); xTaskCreate(threadTelemetry, "threadTelemetryCAN", @@ -57,7 +62,6 @@ void setup() { // runs once on bootup void threadMain(void *pvParameters) { Serial.begin(9600); - xLastWakeTime = xTaskGetTickCount(); // Initialize the last wake time #if HIMAC_FLAG @@ -72,7 +76,7 @@ void threadMain(void *pvParameters) { int toggle = 0; #endif while (true) { - + main_last_run_tick = xTaskGetTickCount(); // Update WDT tick /*============LOW PRIORITY GPIO UPDATES============*/ digitalWrite(13, HIGH); // orange led on teensy diff --git a/fsae-vehicle-fw/src/peripherals/adc.cpp b/fsae-vehicle-fw/src/peripherals/adc.cpp index 2a3688e..84fbe81 100644 --- a/fsae-vehicle-fw/src/peripherals/adc.cpp +++ b/fsae-vehicle-fw/src/peripherals/adc.cpp @@ -2,6 +2,7 @@ #include "adc.h" #include "./vehicle/telemetry.h" +#include "peripherals/wdt.h" #include "utils/utils.h" #include "vehicle/apps.h" #include "vehicle/bse.h" @@ -87,7 +88,9 @@ void threadADC(void *pvParameters) { lastWakeTime = xTaskGetTickCount(); while (true) { + adc_last_run_tick = xTaskGetTickCount(); // Update WDT tick vTaskDelayUntil(&lastWakeTime, TICKTYPE_FREQUENCY); + for (uint16_t currentIndexADC0 = 0; currentIndexADC0 < SENSOR_PIN_AMT_ADC0; ++currentIndexADC0) { uint16_t currentPinADC0 = adc0Pins[currentIndexADC0]; @@ -104,6 +107,7 @@ void threadADC(void *pvParameters) { ShockTravelUpdateData( adc0Reads[SUSP_TRAV_LINPOT1], adc0Reads[SUSP_TRAV_LINPOT2], adc0Reads[SUSP_TRAV_LINPOT3], adc0Reads[SUSP_TRAV_LINPOT4]); + APPS_UpdateData(adc0Reads[APPS_1_INDEX], adc0Reads[APPS_2_INDEX]); BSE_UpdateData(adc0Reads[BSE_1_INDEX], adc0Reads[BSE_2_INDEX]); } diff --git a/fsae-vehicle-fw/src/peripherals/wdt.cpp b/fsae-vehicle-fw/src/peripherals/wdt.cpp new file mode 100644 index 0000000..5208dc3 --- /dev/null +++ b/fsae-vehicle-fw/src/peripherals/wdt.cpp @@ -0,0 +1,116 @@ +#include +#include +#include + +#include "peripherals/wdt.h" +#include "utils/utils.h" + +#define ADC_FAULT_TIME_THRESHOLD_MS 100 +#define MAIN_FAULT_TIME_THRESHOLD_MS 100 +#define MOTOR_FAULT_TIME_THRESHOLD_MS 100 +#define TELEMETRY_FAULT_TIME_THRESHOLD_MS 100 + +// Global watchdog tick tracking variables +TickType_t adc_last_run_tick = 0; +TickType_t main_last_run_tick = 0; +TickType_t motor_last_run_tick = 0; +TickType_t telemetry_last_run_tick = 0; + +// Bitmask flag definition +static uint8_t WDT_BIT_ADC = 0b0001; +static uint8_t WDT_BIT_MAIN = 0b0010; +static uint8_t WDT_BIT_MOTOR = 0b0100; +static uint8_t WDT_BIT_TELEMETRY = 0b1000; + +static uint8_t WDT_REQUIRED_MASK = 0b0000; // 0b000 represents no flags + +static constexpr uint32_t WDT_CHECK_PERIOD_MS = 100; + +static WDT_T4 WDT; + +void WDT_Init() { + TickType_t now = xTaskGetTickCount(); + adc_last_run_tick = now; + main_last_run_tick = now; + motor_last_run_tick = now; + telemetry_last_run_tick = now; + + WDT_timings_t config; + + config.timeout = 1.0; // second before reset + config.trigger = 0.0; + config.callback = nullptr; + + WDT.begin(config); + + Serial.println("Watchdog initialized (1 second timeout)"); +} + +void WDT_Update_Task(void *pvParameters) { + TickType_t now; + + TickType_t adc_ageTicks; + uint32_t adc_ageMs; + + TickType_t main_ageTicks; + uint32_t main_ageMs; + + TickType_t motor_ageTicks; + uint32_t motor_ageMs; + + TickType_t telemetry_ageTicks; + uint32_t telemetry_ageMs; + + uint8_t mask; + + for (;;) { + now = xTaskGetTickCount(); + + adc_ageTicks = now - adc_last_run_tick; + adc_ageMs = adc_ageTicks * portTICK_PERIOD_MS; + + main_ageTicks = now - main_last_run_tick; + main_ageMs = main_ageTicks * portTICK_PERIOD_MS; + + motor_ageTicks = now - motor_last_run_tick; + motor_ageMs = motor_ageTicks * portTICK_PERIOD_MS; + + telemetry_ageTicks = now - telemetry_last_run_tick; + telemetry_ageMs = telemetry_ageTicks * portTICK_PERIOD_MS; + + mask = 0b0000; + + if (adc_ageMs >= ADC_FAULT_TIME_THRESHOLD_MS) { + mask |= WDT_BIT_ADC; + } + if (main_ageMs >= MAIN_FAULT_TIME_THRESHOLD_MS) { + mask |= WDT_BIT_MAIN; + } + if (motor_ageMs >= MOTOR_FAULT_TIME_THRESHOLD_MS) { + mask |= WDT_BIT_MOTOR; + } + if (telemetry_ageMs >= TELEMETRY_FAULT_TIME_THRESHOLD_MS) { + mask |= WDT_BIT_TELEMETRY; + } + + // pet if 0b0000 + if (mask & WDT_REQUIRED_MASK) { + WDT.feed(); // pet hardware watchdog + Serial.println("WDT fed successfully"); + } else { + if (mask & WDT_BIT_ADC) { + Serial.println("WDT: ADC thread overdue"); + } + if (mask & WDT_BIT_MAIN) { + Serial.println("WDT: Main thread overdue"); + } + if (mask & WDT_BIT_MOTOR) { + Serial.println("WDT: Motor thread overdue"); + } + if (mask & WDT_BIT_TELEMETRY) { + Serial.println("WDT: Telemetry thread overdue"); + } + } + vTaskDelay(pdMS_TO_TICKS(WDT_CHECK_PERIOD_MS)); // 100ms delay + } +} diff --git a/fsae-vehicle-fw/src/peripherals/wdt.h b/fsae-vehicle-fw/src/peripherals/wdt.h new file mode 100644 index 0000000..970c0dc --- /dev/null +++ b/fsae-vehicle-fw/src/peripherals/wdt.h @@ -0,0 +1,11 @@ +#pragma once + +#include + +extern TickType_t adc_last_run_tick; +extern TickType_t main_last_run_tick; +extern TickType_t motor_last_run_tick; +extern TickType_t telemetry_last_run_tick; + +void WDT_Init(); +void WDT_Update_Task(void *pvParameters); diff --git a/fsae-vehicle-fw/src/vehicle/apps.cpp b/fsae-vehicle-fw/src/vehicle/apps.cpp index 636e2d2..8bc2643 100644 --- a/fsae-vehicle-fw/src/vehicle/apps.cpp +++ b/fsae-vehicle-fw/src/vehicle/apps.cpp @@ -1,11 +1,13 @@ // Anteater Electric Racing, 2025 #include "apps.h" + +#include +#include + #include "utils/utils.h" #include "vehicle/faults.h" #include "vehicle/telemetry.h" -#include -#include typedef struct { float appsReading1_Percentage; // Percentage of pedal travel (0 to 1) diff --git a/fsae-vehicle-fw/src/vehicle/bse.cpp b/fsae-vehicle-fw/src/vehicle/bse.cpp index 8931019..5cfa93e 100644 --- a/fsae-vehicle-fw/src/vehicle/bse.cpp +++ b/fsae-vehicle-fw/src/vehicle/bse.cpp @@ -7,6 +7,7 @@ #include "bse.h" #include "vehicle/faults.h" + #include typedef struct { diff --git a/fsae-vehicle-fw/src/vehicle/motor.cpp b/fsae-vehicle-fw/src/vehicle/motor.cpp index c7c5d3e..79f7b40 100644 --- a/fsae-vehicle-fw/src/vehicle/motor.cpp +++ b/fsae-vehicle-fw/src/vehicle/motor.cpp @@ -8,6 +8,7 @@ #include "peripherals/can.h" #include "peripherals/gpio.h" +#include "peripherals/wdt.h" #include "utils/utils.h" #include @@ -64,6 +65,7 @@ void Motor_Init() { void threadMotor(void *pvParameters) { xLastWakeTime = xTaskGetTickCount(); while (true) { + motor_last_run_tick = xTaskGetTickCount(); // Update WDT tick // Clear packet contents vcu1 = {0}; bms1 = {0}; diff --git a/fsae-vehicle-fw/src/vehicle/telemetry.cpp b/fsae-vehicle-fw/src/vehicle/telemetry.cpp index 853a561..84666d2 100644 --- a/fsae-vehicle-fw/src/vehicle/telemetry.cpp +++ b/fsae-vehicle-fw/src/vehicle/telemetry.cpp @@ -4,6 +4,7 @@ #include "vehicle/telemetry.h" +#include "peripherals/wdt.h" #include TelemetryData telemetryData; @@ -77,7 +78,8 @@ void threadTelemetry(void *pvParameters) { static TickType_t lastWakeTime = xTaskGetTickCount(); // Initialize the last wake time while (true) { - taskENTER_CRITICAL(); // Enter critical section + telemetry_last_run_tick = xTaskGetTickCount(); // Update WDT tick + taskENTER_CRITICAL(); // Enter critical section telemetryData = { .APPS_Travel = APPS_GetAPPSReading(),