preliminary support for the two RGB status leds

Note: pin assignments not final
This commit is contained in:
Kilian Bracher 2023-12-04 18:45:29 +01:00
parent cef05f52bc
commit b24fc66caf
Signed by: k.bracher
SSH Key Fingerprint: SHA256:mXpyZkK7RDiJ7qeHCKJX108woM0cl5TrCvNBJASu6lM
7 changed files with 179 additions and 16 deletions

10
Core/Inc/status_led.h Normal file
View File

@ -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

View File

@ -4,6 +4,7 @@
#include "stm32f3xx_hal.h" #include "stm32f3xx_hal.h"
#include <stdint.h> #include <stdint.h>
#include <stdbool.h>
// Minimum vehicle side voltage to exit precharge // Minimum vehicle side voltage to exit precharge
#define MIN_VEHICLE_SIDE_VOLTAGE 150000 // mV #define MIN_VEHICLE_SIDE_VOLTAGE 150000 // mV
@ -37,13 +38,17 @@ typedef enum {
TS_ERRORKIND_SHUNT_OVERCURRENT = 0x04, TS_ERRORKIND_SHUNT_OVERCURRENT = 0x04,
TS_ERRORKIND_SHUNT_OVERTEMP = 0x05 TS_ERRORKIND_SHUNT_OVERTEMP = 0x05
} TSErrorKind; } 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 { typedef struct {
TSState current_state; TSState current_state;
TSState target_state; TSState target_state;
uint32_t error; uint16_t error_source; // TSErrorSource (bitmask)
uint16_t error_type; // TSErrorKind
} TSStateHandle; } TSStateHandle;
extern TSStateHandle ts_state; 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_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 #endif // INC_TS_STATE_MACHINE_H

View File

@ -27,6 +27,7 @@
#include "slave_monitoring.h" #include "slave_monitoring.h"
#include "soc_estimation.h" #include "soc_estimation.h"
#include "ts_state_machine.h" #include "ts_state_machine.h"
#include "status_led.h"
#include "stm32f3xx_hal.h" #include "stm32f3xx_hal.h"
#include "stm32f3xx_hal_gpio.h" #include "stm32f3xx_hal_gpio.h"
@ -487,6 +488,9 @@ static void MX_GPIO_Init(void) {
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(PRECHARGE_CTRL_GPIO_Port, &GPIO_InitStruct); 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 BEGIN MX_GPIO_Init_2 */
/* USER CODE END MX_GPIO_Init_2 */ /* USER CODE END MX_GPIO_Init_2 */
} }

View File

@ -25,17 +25,21 @@ void shunt_init() {
void shunt_check() { void shunt_check() {
int is_error = 0; int is_error = 0;
TSErrorKind error_type = TS_ERRORKIND_NONE;
if (HAL_GetTick() - shunt_data.last_message > SHUNT_TIMEOUT) { if (HAL_GetTick() - shunt_data.last_message > SHUNT_TIMEOUT) {
is_error = 1; is_error = 1;
error_type = TS_ERRORKIND_SHUNT_TIMEOUT;
can_send_error(TS_ERRORKIND_SHUNT_TIMEOUT, 0); can_send_error(TS_ERRORKIND_SHUNT_TIMEOUT, 0);
} else if (shunt_data.current >= SHUNT_THRESH_OVERCURRENT) { } else if (shunt_data.current >= SHUNT_THRESH_OVERCURRENT) {
is_error = 1; 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) { } else if (shunt_data.busbartemp >= SHUNT_THRESH_OVERTEMP) {
is_error = 1; is_error = 1;
error_type = TS_ERRORKIND_SHUNT_OVERTEMP;
can_send_error(TS_ERRORKIND_SHUNT_OVERTEMP, 0); 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) { void shunt_handle_can_msg(uint16_t id, const uint8_t *data) {

View File

@ -57,9 +57,12 @@ void slaves_init() {
void slaves_check() { void slaves_check() {
int any_slave_error = 0; int any_slave_error = 0;
TSErrorKind slave_error = TS_ERRORKIND_NONE;
uint32_t now = HAL_GetTick(); uint32_t now = HAL_GetTick();
uint16_t min_voltage_new = 0xFFFF; uint16_t min_voltage_new = 0xFFFF;
int16_t max_temp_new = 0xFFFF; int16_t max_temp_new = 0xFFFF;
for (int i = 0; i < N_SLAVES; i++) { for (int i = 0; i < N_SLAVES; i++) {
// Update timeout errors // Update timeout errors
if (now - slaves[i].last_message >= SLAVE_TIMEOUT) { if (now - slaves[i].last_message >= SLAVE_TIMEOUT) {
@ -82,12 +85,13 @@ void slaves_check() {
if (slaves[i].error.kind != SLAVE_ERR_NONE) { if (slaves[i].error.kind != SLAVE_ERR_NONE) {
any_slave_error = 1; 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; min_voltage = min_voltage_new;
max_temp = max_temp_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) { 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].error.data = ftcan_unmarshal_unsigned(&data, 4);
slaves[idx].last_message = HAL_GetTick(); 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); can_send_error(TS_ERRORKIND_SLAVE_PANIC, slave_id);
} }

132
Core/Src/status_led.c Normal file
View File

@ -0,0 +1,132 @@
#include "status_led.h"
#include "stm32f3xx_hal_gpio.h"
#include "ts_state_machine.h"
#include <stdint.h>
#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: <see below>
* 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;
}
}

View File

@ -4,6 +4,7 @@
#include "shunt_monitoring.h" #include "shunt_monitoring.h"
#include "stm32f3xx_hal.h" #include "stm32f3xx_hal.h"
#include "stm32f3xx_hal_gpio.h" #include "stm32f3xx_hal_gpio.h"
#include "status_led.h"
#include <stdint.h> #include <stdint.h>
TSStateHandle ts_state; TSStateHandle ts_state;
@ -15,11 +16,11 @@ static uint32_t discharge_begin_timestamp = 0;
void ts_sm_init() { void ts_sm_init() {
ts_state.current_state = TS_INACTIVE; ts_state.current_state = TS_INACTIVE;
ts_state.target_state = TS_INACTIVE; ts_state.target_state = TS_INACTIVE;
ts_state.error = 0; ts_state.error_source = 0;
} }
void ts_sm_update() { void ts_sm_update() {
if (ts_state.error) { if (ts_state.error_source) {
ts_state.current_state = TS_ERROR; ts_state.current_state = TS_ERROR;
} }
@ -48,6 +49,7 @@ void ts_sm_update() {
} }
ts_sm_set_relay_positions(ts_state.current_state); 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() { TSState ts_sm_update_inactive() {
@ -89,7 +91,7 @@ TSState ts_sm_update_precharge() {
uint32_t now = HAL_GetTick(); uint32_t now = HAL_GetTick();
if (precharge_95_reached_timestamp == 0) { if (precharge_95_reached_timestamp == 0) {
precharge_95_reached_timestamp = now; 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; precharge_95_reached_timestamp = 0;
return TS_ACTIVE; return TS_ACTIVE;
} }
@ -108,7 +110,7 @@ TSState ts_sm_update_discharge() {
TSState ts_sm_update_error() { TSState ts_sm_update_error() {
static uint32_t no_error_since = 0; static uint32_t no_error_since = 0;
if (ts_state.error == 0) { if (ts_state.error_source == 0) {
uint32_t now = HAL_GetTick(); uint32_t now = HAL_GetTick();
if (no_error_since == 0) { if (no_error_since == 0) {
no_error_since = now; 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) { void ts_sm_set_error_source(TSErrorSource source, TSErrorKind error_type, bool is_errored) {
if (state) { if (is_errored) {
ts_state.error |= flag; ts_state.error_source |= source;
ts_state.error_type = error_type;
} else { } else {
ts_state.error &= ~flag; ts_state.error_source &= ~source;
ts_state.error_type = ~error_type;
} }
} }