diff --git a/Core/Inc/status_led.h b/Core/Inc/status_led.h new file mode 100644 index 0000000..586c7af --- /dev/null +++ b/Core/Inc/status_led.h @@ -0,0 +1,10 @@ +#ifndef INC_STATUS_LED_H +#define INC_STATUS_LED_H + +#include "ts_state_machine.h" + +void status_led_init(); + +void status_led_state(TSState state, TSErrorKind error); + +#endif // INC_STATUS_LED_H \ No newline at end of file diff --git a/Core/Inc/ts_state_machine.h b/Core/Inc/ts_state_machine.h index 363edfc..223a198 100644 --- a/Core/Inc/ts_state_machine.h +++ b/Core/Inc/ts_state_machine.h @@ -4,6 +4,7 @@ #include "stm32f3xx_hal.h" #include +#include // Minimum vehicle side voltage to exit precharge #define MIN_VEHICLE_SIDE_VOLTAGE 150000 // mV @@ -37,13 +38,17 @@ typedef enum { TS_ERRORKIND_SHUNT_OVERCURRENT = 0x04, TS_ERRORKIND_SHUNT_OVERTEMP = 0x05 } TSErrorKind; -#define TS_ERROR_SOURCE_SHUNT (1 << 0) -#define TS_ERROR_SOURCE_SLAVES (1 << 1) + +typedef enum { + TS_ERROR_SOURCE_SHUNT = (1 << 0), + TS_ERROR_SOURCE_SLAVES = (1 << 1) +} TSErrorSource; typedef struct { TSState current_state; TSState target_state; - uint32_t error; + uint16_t error_source; // TSErrorSource (bitmask) + uint16_t error_type; // TSErrorKind } TSStateHandle; extern TSStateHandle ts_state; @@ -66,6 +71,6 @@ void ts_sm_check_close_wait(int *is_closed, int should_close); void ts_sm_handle_ams_in(const uint8_t *data); -void ts_sm_set_error_source(uint32_t flag, int state); +void ts_sm_set_error_source(TSErrorSource source, TSErrorKind error_type, bool is_errored); #endif // INC_TS_STATE_MACHINE_H diff --git a/Core/Src/main.c b/Core/Src/main.c index 8372409..cdc8b0d 100644 --- a/Core/Src/main.c +++ b/Core/Src/main.c @@ -27,6 +27,7 @@ #include "slave_monitoring.h" #include "soc_estimation.h" #include "ts_state_machine.h" +#include "status_led.h" #include "stm32f3xx_hal.h" #include "stm32f3xx_hal_gpio.h" @@ -487,6 +488,9 @@ static void MX_GPIO_Init(void) { GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; HAL_GPIO_Init(PRECHARGE_CTRL_GPIO_Port, &GPIO_InitStruct); + /*Configure GPIO pins for Status LEDs */ + status_led_init(); + /* USER CODE BEGIN MX_GPIO_Init_2 */ /* USER CODE END MX_GPIO_Init_2 */ } diff --git a/Core/Src/shunt_monitoring.c b/Core/Src/shunt_monitoring.c index 8fcd540..22a5265 100644 --- a/Core/Src/shunt_monitoring.c +++ b/Core/Src/shunt_monitoring.c @@ -25,17 +25,21 @@ void shunt_init() { void shunt_check() { int is_error = 0; + TSErrorKind error_type = TS_ERRORKIND_NONE; if (HAL_GetTick() - shunt_data.last_message > SHUNT_TIMEOUT) { is_error = 1; + error_type = TS_ERRORKIND_SHUNT_TIMEOUT; can_send_error(TS_ERRORKIND_SHUNT_TIMEOUT, 0); } else if (shunt_data.current >= SHUNT_THRESH_OVERCURRENT) { is_error = 1; - can_send_error(TS_ERRORKIND_SHUNT_OVERTEMP, 0); + error_type = TS_ERRORKIND_SHUNT_OVERCURRENT; + can_send_error(TS_ERRORKIND_SHUNT_OVERCURRENT, 0); } else if (shunt_data.busbartemp >= SHUNT_THRESH_OVERTEMP) { is_error = 1; + error_type = TS_ERRORKIND_SHUNT_OVERTEMP; can_send_error(TS_ERRORKIND_SHUNT_OVERTEMP, 0); } - ts_sm_set_error_source(TS_ERROR_SOURCE_SHUNT, is_error); + ts_sm_set_error_source(TS_ERROR_SOURCE_SHUNT, error_type, is_error); } void shunt_handle_can_msg(uint16_t id, const uint8_t *data) { diff --git a/Core/Src/slave_monitoring.c b/Core/Src/slave_monitoring.c index 1066215..e00f190 100644 --- a/Core/Src/slave_monitoring.c +++ b/Core/Src/slave_monitoring.c @@ -57,9 +57,12 @@ void slaves_init() { void slaves_check() { int any_slave_error = 0; + TSErrorKind slave_error = TS_ERRORKIND_NONE; + uint32_t now = HAL_GetTick(); uint16_t min_voltage_new = 0xFFFF; int16_t max_temp_new = 0xFFFF; + for (int i = 0; i < N_SLAVES; i++) { // Update timeout errors if (now - slaves[i].last_message >= SLAVE_TIMEOUT) { @@ -82,12 +85,13 @@ void slaves_check() { if (slaves[i].error.kind != SLAVE_ERR_NONE) { any_slave_error = 1; + slave_error = (slaves[i].error.kind == SLAVE_ERR_TIMEOUT) ? TS_ERRORKIND_SLAVE_TIMEOUT : TS_ERRORKIND_SLAVE_PANIC; } } min_voltage = min_voltage_new; max_temp = max_temp_new; - ts_sm_set_error_source(TS_ERROR_SOURCE_SLAVES, any_slave_error); + ts_sm_set_error_source(TS_ERROR_SOURCE_SLAVES, slave_error, any_slave_error); } void slaves_handle_panic(const uint8_t *data) { @@ -111,7 +115,7 @@ void slaves_handle_panic(const uint8_t *data) { } slaves[idx].error.data = ftcan_unmarshal_unsigned(&data, 4); slaves[idx].last_message = HAL_GetTick(); - ts_sm_set_error_source(TS_ERROR_SOURCE_SLAVES, 1); + ts_sm_set_error_source(TS_ERROR_SOURCE_SLAVES, TS_ERRORKIND_SLAVE_PANIC, 1); can_send_error(TS_ERRORKIND_SLAVE_PANIC, slave_id); } diff --git a/Core/Src/status_led.c b/Core/Src/status_led.c new file mode 100644 index 0000000..6df6be0 --- /dev/null +++ b/Core/Src/status_led.c @@ -0,0 +1,132 @@ +#include "status_led.h" +#include "stm32f3xx_hal_gpio.h" +#include "ts_state_machine.h" +#include + +#define STATUS_LED_GPIO_PORT GPIOA //TODO: change to correct values for the board + +#define STATUS_LED_1_RED_PIN GPIO_PIN_10 //TODO: change to correct values for the board +#define STATUS_LED_1_GREEN_PIN GPIO_PIN_11 +#define STATUS_LED_1_BLUE_PIN GPIO_PIN_12 + +#define STATUS_LED_2_RED_PIN GPIO_PIN_13 //TODO: change to correct values for the board +#define STATUS_LED_2_GREEN_PIN GPIO_PIN_14 +#define STATUS_LED_2_BLUE_PIN GPIO_PIN_15 + +#warning "GPIO pins for status LEDs are not set correctly" + +typedef struct { + uint8_t red : 1; + uint8_t green : 1; + uint8_t blue : 1; +} LedColor; + +typedef enum { + LED_1, + LED_2 +} LedId; + +void status_led_init() { + GPIO_InitTypeDef GPIO_InitStruct = {0}; + + GPIO_InitStruct.Pin = STATUS_LED_1_RED_PIN | STATUS_LED_1_GREEN_PIN | STATUS_LED_1_BLUE_PIN | STATUS_LED_2_RED_PIN | STATUS_LED_2_GREEN_PIN | STATUS_LED_2_BLUE_PIN; + GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; + + HAL_GPIO_Init(STATUS_LED_GPIO_PORT, &GPIO_InitStruct); +} + +static void set_led_color(LedId id, LedColor color) { + GPIO_PinState red = color.red ? GPIO_PIN_SET : GPIO_PIN_RESET; + GPIO_PinState green = color.green ? GPIO_PIN_SET : GPIO_PIN_RESET; + GPIO_PinState blue = color.blue ? GPIO_PIN_SET : GPIO_PIN_RESET; + + switch (id) { + case LED_1: + HAL_GPIO_WritePin(STATUS_LED_GPIO_PORT, STATUS_LED_1_RED_PIN, red); + HAL_GPIO_WritePin(STATUS_LED_GPIO_PORT, STATUS_LED_1_GREEN_PIN, green); + HAL_GPIO_WritePin(STATUS_LED_GPIO_PORT, STATUS_LED_1_BLUE_PIN, blue); + break; + case LED_2: + HAL_GPIO_WritePin(STATUS_LED_GPIO_PORT, STATUS_LED_2_RED_PIN, red); + HAL_GPIO_WritePin(STATUS_LED_GPIO_PORT, STATUS_LED_2_GREEN_PIN, green); + HAL_GPIO_WritePin(STATUS_LED_GPIO_PORT, STATUS_LED_2_BLUE_PIN, blue); + break; + } +} + +/** + * @brief Sets the status LEDs to the given state + * + * @param state The state to set the LEDs to + * + * State -> Color mapping: + * TS_INACTIVE -> LED_1: off, LED_2: off + * TS_ACTIVE -> LED_1: blue, LED_2: off + * TS_PRECHARGE -> LED_1: blue, LED_2: cyan + * TS_DISCHARGE -> LED_1: blue, LED_2: magenta + * TS_ERROR -> LED_1: red, LED_2: + * TS_CHARGING_CHECK -> LED_1: green, LED_2: cyan + * TS_CHARGING -> LED_1: green, LED_2: off + * + * Error -> LED_2 mapping: + * TS_ERRORKIND_NONE -> off + * TS_ERRORKIND_SLAVE_TIMEOUT -> blue + * TS_ERRORKIND_SLAVE_PANIC -> magenta + * TS_ERRORKIND_SHUNT_TIMEOUT -> green + * TS_ERRORKIND_SHUNT_OVERCURRENT -> yellow + * TS_ERRORKIND_SHUNT_OVERTEMP -> red + */ + +void status_led_state(TSState state, TSErrorKind error) { + switch (state) { + case TS_INACTIVE: + set_led_color(LED_1, (LedColor) {.red = 0, .green = 0, .blue = 0}); + set_led_color(LED_2, (LedColor) {.red = 0, .green = 0, .blue = 0}); + break; + case TS_ACTIVE: + set_led_color(LED_1, (LedColor) {.red = 0, .green = 0, .blue = 1}); + set_led_color(LED_2, (LedColor) {.red = 0, .green = 0, .blue = 0}); + break; + case TS_PRECHARGE: + set_led_color(LED_1, (LedColor) {.red = 0, .green = 0, .blue = 1}); + set_led_color(LED_2, (LedColor) {.red = 0, .green = 1, .blue = 1}); + break; + case TS_DISCHARGE: + set_led_color(LED_1, (LedColor) {.red = 0, .green = 0, .blue = 1}); + set_led_color(LED_2, (LedColor) {.red = 1, .green = 0, .blue = 1}); + break; + case TS_ERROR: + set_led_color(LED_1, (LedColor) {.red = 1, .green = 0, .blue = 0}); + switch (error) { + case TS_ERRORKIND_NONE: + set_led_color(LED_2, (LedColor) {.red = 0, .green = 0, .blue = 0}); + break; + case TS_ERRORKIND_SLAVE_TIMEOUT: + set_led_color(LED_2, (LedColor) {.red = 0, .green = 0, .blue = 1}); + break; + case TS_ERRORKIND_SLAVE_PANIC: + set_led_color(LED_2, (LedColor) {.red = 1, .green = 0, .blue = 1}); + break; + case TS_ERRORKIND_SHUNT_TIMEOUT: + set_led_color(LED_2, (LedColor) {.red = 0, .green = 1, .blue = 0}); + break; + case TS_ERRORKIND_SHUNT_OVERCURRENT: + set_led_color(LED_2, (LedColor) {.red = 1, .green = 1, .blue = 0}); + break; + case TS_ERRORKIND_SHUNT_OVERTEMP: + set_led_color(LED_2, (LedColor) {.red = 1, .green = 0, .blue = 0}); + break; + } + break; + case TS_CHARGING_CHECK: + set_led_color(LED_1, (LedColor) {.red = 0, .green = 1, .blue = 0}); + set_led_color(LED_2, (LedColor) {.red = 0, .green = 1, .blue = 1}); + break; + case TS_CHARGING: + set_led_color(LED_1, (LedColor) {.red = 0, .green = 1, .blue = 0}); + set_led_color(LED_2, (LedColor) {.red = 0, .green = 0, .blue = 0}); + break; + } +} \ No newline at end of file diff --git a/Core/Src/ts_state_machine.c b/Core/Src/ts_state_machine.c index 834ec58..920c55e 100644 --- a/Core/Src/ts_state_machine.c +++ b/Core/Src/ts_state_machine.c @@ -4,6 +4,7 @@ #include "shunt_monitoring.h" #include "stm32f3xx_hal.h" #include "stm32f3xx_hal_gpio.h" +#include "status_led.h" #include TSStateHandle ts_state; @@ -15,11 +16,11 @@ static uint32_t discharge_begin_timestamp = 0; void ts_sm_init() { ts_state.current_state = TS_INACTIVE; ts_state.target_state = TS_INACTIVE; - ts_state.error = 0; + ts_state.error_source = 0; } void ts_sm_update() { - if (ts_state.error) { + if (ts_state.error_source) { ts_state.current_state = TS_ERROR; } @@ -48,6 +49,7 @@ void ts_sm_update() { } ts_sm_set_relay_positions(ts_state.current_state); + status_led_state(ts_state.current_state, (TSErrorKind) ts_state.error_type); } TSState ts_sm_update_inactive() { @@ -89,7 +91,7 @@ TSState ts_sm_update_precharge() { uint32_t now = HAL_GetTick(); if (precharge_95_reached_timestamp == 0) { precharge_95_reached_timestamp = now; - } else if (now - precharge_95_reached_timestamp >= PRECHARGE_95_DURATION) { + } else if ((now - precharge_95_reached_timestamp) >= PRECHARGE_95_DURATION) { precharge_95_reached_timestamp = 0; return TS_ACTIVE; } @@ -108,7 +110,7 @@ TSState ts_sm_update_discharge() { TSState ts_sm_update_error() { static uint32_t no_error_since = 0; - if (ts_state.error == 0) { + if (ts_state.error_source == 0) { uint32_t now = HAL_GetTick(); if (no_error_since == 0) { no_error_since = now; @@ -220,10 +222,12 @@ void ts_sm_handle_ams_in(const uint8_t *data) { } } -void ts_sm_set_error_source(uint32_t flag, int state) { - if (state) { - ts_state.error |= flag; +void ts_sm_set_error_source(TSErrorSource source, TSErrorKind error_type, bool is_errored) { + if (is_errored) { + ts_state.error_source |= source; + ts_state.error_type = error_type; } else { - ts_state.error &= ~flag; + ts_state.error_source &= ~source; + ts_state.error_type = ~error_type; } }