Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
afec3d6
init branch
khoulihan27 Mar 2, 2026
6af6596
correct ordering of debug message logging
SlowThomas Mar 3, 2026
72f980d
fixed discharge logic and CAN id
khoulihan27 Mar 3, 2026
69f028a
added comment
khoulihan27 Mar 3, 2026
bed7192
Automatic Clang-Format: Standardized formatting automatically
github-actions[bot] Mar 3, 2026
b39c345
reduce some bloat in StateData
SlowThomas Mar 6, 2026
ccdfc8b
Reduce all timing-related states in StateData
SlowThomas Mar 6, 2026
b850f64
reconcile state of charge with storage fmt
kzwicker Mar 6, 2026
48d5f12
reconcile state of charge with storage fmt
kzwicker Mar 6, 2026
e6af82b
Merge branch 'ECU-Shutdown/Error-Logic' of https://github.com/Gaucho-…
kzwicker Mar 6, 2026
25ab021
be so fr
kzwicker Mar 6, 2026
abbac89
Automatic Clang-Format: Standardized formatting automatically
github-actions[bot] Mar 6, 2026
f6f84f8
Fix failling fdcan include for FDCAN_EXTENDED_ID
SlowThomas Mar 6, 2026
5845e29
Automatic Clang-Format: Standardized formatting automatically
github-actions[bot] Mar 6, 2026
dd73c3b
Replace Comm Error checking with precharge timeout checking.
SlowThomas Mar 6, 2026
2175d8b
catch critical error in precharge engaged
kzwicker Mar 6, 2026
1269c50
Merge branch 'main' into ECU-Shutdown/Error-Logic
dchansen06 Mar 10, 2026
93f53ab
correct ts maximum permitted discharge time
SlowThomas Mar 10, 2026
2a3b814
Merge branch 'main' into ECU-Shutdown/Error-Logic
dchansen06 Mar 10, 2026
ab58bf9
Merge branch 'main' into ECU-Shutdown/Error-Logic
dchansen06 Mar 10, 2026
cd7a33f
fix timer variable name
SlowThomas Mar 10, 2026
d153332
Merge branch 'main' into ECU-Shutdown/Error-Logic
dchansen06 Mar 10, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 0 additions & 8 deletions ECU/Application/Inc/StateData.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,14 +51,6 @@ typedef volatile struct ECU_StateData {

// TODO: Remove unneeded states

uint32_t millisSinceBoot;
uint32_t can_msg_cooldown_tick;

int32_t dischargeStartMillis;
uint32_t lastECUStatusMsgMillis;
uint32_t lastTSSIFlash;
int32_t last_drive_active_control_ms;

float min_amk_heat_cap_throttle_percent;
float ts_voltage;
float max_cell_temp_c; /** Temperature of hottest cell, celsius */
Expand Down
6 changes: 5 additions & 1 deletion ECU/Application/Inc/StateUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,16 @@ uint32_t MillisecondsSinceBoot(void);
#define MAX_CURRENT_AMPS 42.0f // TODO: Change as appropriate
#define MAX_REVERSE_CURRENT_AMPS 20.0f // TODO: Change as appropriate

#define MAX_PRECHARGE_TIME 15000 // in ms

#define ECU_STATUS_MSG_PERIOD_MILLIS (1000)
#define TRACTIVE_SYSTEM_MAX_PERMITTED_DISCHARGE_TIME_MILLIS (5000)

// Checks stateData for critical errors
bool CriticalError(volatile const ECU_StateData *stateData);
bool bmsFailure(volatile const ECU_StateData *stateData);
bool imdFailure(volatile const ECU_StateData *stateData);
bool bspdFailure(volatile const ECU_StateData *stateData);
bool CommunicationError(volatile const ECU_StateData *stateData);
bool APPS_BSE_Violation(volatile const ECU_StateData *stateData);
bool PressingBrake(volatile const ECU_StateData *stateData);
float CalcBrakePercent(volatile const ECU_StateData *stateData);
Expand Down
4 changes: 2 additions & 2 deletions ECU/Application/Src/CANdler.c
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,8 @@ void ECU_CAN_MessageHandler(ECU_StateData *state_data, GR_OLD_BUS_ID bus_id, GR_
break;
}
GR_OLD_BCU_STATUS_1_MSG *bcu_status_1 = (GR_OLD_BCU_STATUS_1_MSG *)data;
state_data->tractivebattery_soc = bcu_status_1->tractivebattery_soc * 0.01;
state_data->glv_soc = bcu_status_1->glv_soc * 20 / 51;
state_data->tractivebattery_soc = bcu_status_1->tractivebattery_soc;
state_data->glv_soc = bcu_status_1->glv_soc;
state_data->ts_voltage = bcu_status_1->ts_voltage * 0.01;
break;

Expand Down
7 changes: 4 additions & 3 deletions ECU/Application/Src/CANutils.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include "StateUtils.h"
#include "can.h"
#include "main.h"
#include "stm32g4xx_hal_fdcan.h"
#include "string.h"

uint32_t lastTickECUStateDataSent = 0;
Expand All @@ -24,7 +25,7 @@ void ECU_CAN_Send(GR_OLD_BUS_ID bus, GR_OLD_NODE_ID destNode, GR_OLD_MSG_ID mess

FDCAN_TxHeaderTypeDef header = {
.Identifier = ID,
.IdType = FDCAN_STANDARD_ID,
.IdType = FDCAN_EXTENDED_ID,
.TxFrameType = FDCAN_DATA_FRAME,
.ErrorStateIndicator = FDCAN_ESI_ACTIVE,
.DataLength = size,
Expand Down Expand Up @@ -101,8 +102,8 @@ void SendECUStateDataOverCAN(ECU_StateData *stateData)
.StatusBits = {stateData->status_bits[0], stateData->status_bits[1], stateData->status_bits[2]},
.PowerLevelTorqueMap = stateData->powerlevel_torquemap,
.MaxCellTemp = (uint8_t)(stateData->max_cell_temp_c * 4),
.AccumulatorStateOfCharge = (uint8_t)(stateData->tractivebattery_soc * 51 / 20),
.GLVStateOfCharge = (uint8_t)(stateData->glv_soc * 51 / 20),
.AccumulatorStateOfCharge = (uint8_t)(stateData->tractivebattery_soc),
.GLVStateOfCharge = (uint8_t)(stateData->glv_soc),
.TractiveSystemVoltage = (uint16_t)(stateData->ts_voltage * 100),
.VehicleSpeed = (uint16_t)(stateData->vehicle_speed_mph * 100),
.FRWheelRPM = (uint16_t)(stateData->fr_wheel_rpm * 10 + 32768),
Expand Down
2 changes: 1 addition & 1 deletion ECU/Application/Src/Lights.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ void TSSILightControl(ECU_StateData *stateLump)
// Here we chose a period of 350ms
if (stateLump->tssi_fault) {
LL_GPIO_ResetOutputPin(TSSI_G_CONTROL_GPIO_Port, TSSI_G_CONTROL_Pin);
if (stateLump->millisSinceBoot % 350 < 175) {
if (MillisecondsSinceBoot() % 350 < 175) {
LL_GPIO_SetOutputPin(TSSI_R_CONTROL_GPIO_Port, TSSI_R_CONTROL_Pin);
} else {
LL_GPIO_ResetOutputPin(TSSI_R_CONTROL_GPIO_Port, TSSI_R_CONTROL_Pin);
Expand Down
63 changes: 37 additions & 26 deletions ECU/Application/Src/StateTicks.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,24 +25,21 @@
*
* @remark Intentionally not a globally accessible variable
*/

ECU_StateData stateLump = {.ecu_state = GR_GLV_ON, .bcu_software_latch = 1};
static uint32_t buzzer_start_millis;
static uint32_t last_can_inverter_request_millis;

CANHandle *primary_can;
CANHandle *data_can;

#define ECU_STATUS_MSG_PERIOD_MILLIS (1000)
// EV.5.6.3: The Discharge Circuit must be designed to handle the maximum Tractive System voltage for minimum 15 seconds
#define TRACTIVE_SYSTEM_MAX_PERMITTED_DISCHARGE_TIME_MILLIS (15000)

static uint32_t millis_since_boot;
void ECU_State_Tick(void)
{
stateLump.millisSinceBoot = MillisecondsSinceBoot();
millis_since_boot = MillisecondsSinceBoot();

if (stateLump.millisSinceBoot - stateLump.lastECUStatusMsgMillis >= ECU_STATUS_MSG_PERIOD_MILLIS) {
static uint32_t last_ECU_status_msg_millis;
if (millis_since_boot - last_ECU_status_msg_millis >= ECU_STATUS_MSG_PERIOD_MILLIS) {
LOGOMATIC("ECU Current State: %d\n", stateLump.ecu_state);
stateLump.lastECUStatusMsgMillis = stateLump.millisSinceBoot;
last_ECU_status_msg_millis = millis_since_boot;
}

if (bmsFailure(&stateLump) || imdFailure(&stateLump)) {
Expand Down Expand Up @@ -86,26 +83,29 @@ void ECU_GLV_Off(ECU_StateData *stateData)
void ECU_GLV_On(ECU_StateData *stateData)
{
if (stateData->ts_voltage >= SAFE_VOLTAGE_LIMIT) {
ECU_Transition_To_Tractive_System_Discharge(stateData);
LOGOMATIC("Error: TS Voltage >= %d!\n", SAFE_VOLTAGE_LIMIT);
ECU_Transition_To_Tractive_System_Discharge(stateData);
ECU_CAN_Send(GR_OLD_BUS_PRIMARY, GR_DEBUGGER, MSG_DEBUG_2_0, "TS-Runwy", 8);
return;
}

if (stateData->ts_active_button_active /* && stateData->ir_plus*/) { // TODO: Talk to Owen if this is correct for precharge start confirmation
ECU_Transition_To_Precharge_Engaged(stateData);
LOGOMATIC("GLV ON to PRECHARGE START!\n");
ECU_Transition_To_Precharge_Engaged(stateData);
return;
}
}

static uint32_t time_start_precharge; // for potential comms errors while precharging

void ECU_Transition_To_Precharge_Engaged(ECU_StateData *stateData)
{
/*send message to BCU to start precharging*/
GR_OLD_BCU_PRECHARGE_MSG message = {.precharge = 1}; // Go TS Active/Precharge
ECU_CAN_Send(GR_OLD_BUS_PRIMARY, GR_BCU, MSG_BCU_PRECHARGE, &message, sizeof(message));
stateData->ecu_state = GR_PRECHARGE_ENGAGED;
LOGOMATIC("PRECHARGE START to PRECHARGE ENGAGED!\n");
time_start_precharge = millis_since_boot;
return;
}

Expand All @@ -117,10 +117,10 @@ void ECU_Precharge_Engaged(ECU_StateData *stateData)
return;
}

if (!stateData->ts_active_button_active || CommunicationError(stateData)) {
ECU_Transition_To_Tractive_System_Discharge(stateData);
if (!stateData->ts_active_button_active || CriticalError(stateData) || (millis_since_boot - time_start_precharge) >= MAX_PRECHARGE_TIME) {
LOGOMATIC("ERROR or ts_active OFF! PRECHARGE ENGAGED to TS DISCHARGE START!\n");
ECU_CAN_Send(GR_OLD_BUS_PRIMARY, GR_DEBUGGER, MSG_DEBUG_2_0, "TS-P-ITR", 8);
ECU_Transition_To_Tractive_System_Discharge(stateData);
return;
}
}
Expand All @@ -129,13 +129,13 @@ void ECU_Precharge_Engaged(ECU_StateData *stateData)
void ECU_Precharge_Complete(ECU_StateData *stateData)
{
if (!stateData->ts_active_button_active) {
ECU_Transition_To_Tractive_System_Discharge(stateData);
LOGOMATIC("TS Active Toggled Off. Discharging Tractive System.\n");
ECU_Transition_To_Tractive_System_Discharge(stateData);
return;
}
if (CriticalError(stateData)) {
ECU_Transition_To_Tractive_System_Discharge(stateData);
LOGOMATIC("Error: Critical Error Occurred. Discharging Tractive System.\n");
ECU_Transition_To_Tractive_System_Discharge(stateData);
ECU_CAN_Send(GR_OLD_BUS_PRIMARY, GR_DEBUGGER, MSG_DEBUG_2_0, "HV-CritE", 8);
return;
}
Expand All @@ -149,23 +149,24 @@ void ECU_Precharge_Complete(ECU_StateData *stateData)
}
}

static uint32_t buzzer_start_millis;

void ECU_Transition_To_Drive_Active(ECU_StateData *stateData)
{
buzzer_start_millis = stateData->millisSinceBoot;
last_can_inverter_request_millis = stateData->millisSinceBoot;
buzzer_start_millis = millis_since_boot;
stateData->ecu_state = GR_DRIVE_ACTIVE;
}

void ECU_Drive_Active(ECU_StateData *stateData)
{
if (!stateData->ts_active_button_active || CriticalError(stateData)) {
ECU_Transition_To_Tractive_System_Discharge(stateData);
LOGOMATIC("Error: Critical Error Occured. Discharging Tractive System.\n");
ECU_Transition_To_Tractive_System_Discharge(stateData);
ECU_CAN_Send(GR_OLD_BUS_PRIMARY, GR_DEBUGGER, MSG_DEBUG_2_0, "DA-CritE", 8);
return;
}

if (stateData->millisSinceBoot - buzzer_start_millis > 2000) {
if (millis_since_boot - buzzer_start_millis > 2000) {
LL_GPIO_ResetOutputPin(RTD_CONTROL_GPIO_Port, RTD_CONTROL_Pin);
} else {
LL_GPIO_SetOutputPin(RTD_CONTROL_GPIO_Port, RTD_CONTROL_Pin);
Expand All @@ -192,28 +193,30 @@ void ECU_Drive_Active(ECU_StateData *stateData)

static uint32_t last_apps_plausible_frame_millis;
if (APPS_Plausible(stateData)) {
last_apps_plausible_frame_millis = stateData->millisSinceBoot;
last_apps_plausible_frame_millis = millis_since_boot;
}

// Stop throttle if implausible for > 100ms
if (stateData->apps_bse_violation || stateData->millisSinceBoot - last_apps_plausible_frame_millis > 100) {
if (stateData->apps_bse_violation || millis_since_boot - last_apps_plausible_frame_millis > 100) {
torque_request = 0;
}

if (stateData->millisSinceBoot - last_can_inverter_request_millis > 10) {
static uint32_t last_can_inverter_request_millis;
if (millis_since_boot - last_can_inverter_request_millis > 10) {
GR_OLD_INVERTER_COMMAND_MSG message = {.ac_current = torque_request * 100 + 32768, .dc_current = torque_request * 100 + 32768, .drive_enable = 1, .rpm_limit = 0};
ECU_CAN_Send(GR_OLD_BUS_PRIMARY, GR_GR_INVERTER_1, MSG_INVERTER_COMMAND, &message, sizeof(message));
last_can_inverter_request_millis = stateData->millisSinceBoot;
last_can_inverter_request_millis = millis_since_boot;
}
}

static uint32_t discharge_start_millis;
void ECU_Transition_To_Tractive_System_Discharge(ECU_StateData *stateData)
{
stateData->ecu_state = GR_TS_DISCHARGE;
LOGOMATIC("ECU: BCU discharge Tractive System\n");
GR_OLD_BCU_PRECHARGE_MSG message = {.precharge = 0};
ECU_CAN_Send(GR_OLD_BUS_PRIMARY, GR_BCU, MSG_BCU_PRECHARGE, &message, sizeof(message));
stateData->dischargeStartMillis = stateData->millisSinceBoot;
discharge_start_millis = millis_since_boot;
}

void ECU_Tractive_System_Discharge(ECU_StateData *stateData)
Expand All @@ -230,8 +233,16 @@ void ECU_Tractive_System_Discharge(ECU_StateData *stateData)
If TS fails to discharge over time then stay and emit a warning,
see #129
*/
if (stateData->millisSinceBoot - stateData->dischargeStartMillis > TRACTIVE_SYSTEM_MAX_PERMITTED_DISCHARGE_TIME_MILLIS) {
LOGOMATIC("Warning: Tractive System fails to discharge in time.\n");
if (millis_since_boot - discharge_start_millis > TRACTIVE_SYSTEM_MAX_PERMITTED_DISCHARGE_TIME_MILLIS) {
LOGOMATIC("Warning: Tractive System fails to discharge in %d seconds.\n", TRACTIVE_SYSTEM_MAX_PERMITTED_DISCHARGE_TIME_MILLIS);
ECU_CAN_Send(GR_OLD_BUS_PRIMARY, GR_DEBUGGER, MSG_DEBUG_2_0, "TS-D-TLE", 8);
}

// Discharge the car @ 100 Hz
static uint32_t last_discharge_request_millis;
if (millis_since_boot - last_discharge_request_millis > 10) {
GR_OLD_BCU_PRECHARGE_MSG message = {.precharge = 0};
ECU_CAN_Send(GR_OLD_BUS_PRIMARY, GR_BCU, MSG_BCU_PRECHARGE, &message, sizeof(message));
last_discharge_request_millis = millis_since_boot;
}
}
7 changes: 0 additions & 7 deletions ECU/Application/Src/StateUtils.c
Original file line number Diff line number Diff line change
Expand Up @@ -48,13 +48,6 @@ bool bspdFailure(volatile const ECU_StateData *stateData)
// TODO: shutdown switch stuff
}

bool CommunicationError(volatile const ECU_StateData *stateData)
{
UNUSED(stateData);
// TODO: Check for communication errors
return false;
}

bool APPS_BSE_Violation(volatile const ECU_StateData *stateData)
{
// Checks 2 * APPS_1 is within 10% of APPS_2 and break + throttle at the same time
Expand Down
4 changes: 3 additions & 1 deletion ECU/Core/Src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -436,9 +436,11 @@ int main(void)
if (MillisecondsSinceBoot() >= nextPing) {
pingAll();

// TODO: implement error handling
if (nextPing != 0) {
if (getRTT(GR_BCU) == PINGTIMEOUT_VALUE) {
LOGOMATIC("ERROR: BCU is not responding to pings!\n");
ECU_CAN_Send(GR_OLD_BUS_PRIMARY, GR_DEBUGGER, MSG_DEBUG_2_0, "ECU-P-ITR", 8);
}
if (getRTT(GR_DASH_PANEL) == PINGTIMEOUT_VALUE) {
LOGOMATIC("ERROR: Dash Panel is not responding to pings!\n");
Expand All @@ -459,7 +461,7 @@ int main(void)
write_adc_values_to_state_data();
ECU_State_Tick();
lightControl(&stateLump);
LOGOMATIC("Main Loop Tick Complete. I use Arch btw\n");
// LOGOMATIC("Main Loop Tick Complete. I use Arch btw\n");
}
/* USER CODE END 3 */
}
Expand Down
6 changes: 6 additions & 0 deletions ECU/Test/Inc/stm32g4xx_hal_fdcan.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#ifndef STM32G4xx_HAL_FDCAN_H
#define STM32G4xx_HAL_FDCAN_H

#define FDCAN_EXTENDED_ID ((uint32_t)0x40000000U) /*!< Extended ID element */

#endif
9 changes: 1 addition & 8 deletions ECU/Test/Src/StateTicksTest.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include "StateUtils.h"
#include "can.h"
#include "stm32g4xx_hal.h"
#include "stm32g4xx_hal_fdcan.h"

/*
- GLV ON
Expand All @@ -21,18 +22,10 @@
- TS DISCHARGE (ts voltage > 60), then less than 60 -> GLV ON
*/

#define ECU_STATUS_MSG_PERIOD_MILLIS (1000)
// EV.5.6.3: The Discharge Circuit must be designed to handle the maximum Tractive System voltage for minimum 15 seconds
#define TRACTIVE_SYSTEM_MAX_PERMITTED_DISCHARGE_TIME_MILLIS (15000)

// static void ECU_Pseudo_Time_Progress(uint32_t dt) { stateLumpTest.millisSinceBoot += dt; }

static void ECU_Pseudo_State_Tick(ECU_StateData *stateLumpTest)
{
if (stateLumpTest->millisSinceBoot - stateLumpTest->lastECUStatusMsgMillis >= ECU_STATUS_MSG_PERIOD_MILLIS) {
LOGOMATIC("ECU Current State: %d\n", stateLumpTest->ecu_state);
stateLumpTest->lastECUStatusMsgMillis = stateLumpTest->millisSinceBoot;
}

if (bmsFailure(stateLumpTest) || imdFailure(stateLumpTest)) {
stateLumpTest->tssi_fault = true;
Expand Down
Loading