cleanup part 5

This commit is contained in:
Kilian Bracher 2025-05-09 19:09:41 +02:00
parent 1edc8d3e1c
commit aa85867083
Signed by: k.bracher
SSH Key Fingerprint: SHA256:mXpyZkK7RDiJ7qeHCKJX108woM0cl5TrCvNBJASu6lM
7 changed files with 109 additions and 103 deletions

View File

@ -6,15 +6,36 @@
#include <stdint.h> #include <stdint.h>
#include <stddef.h> #include <stddef.h>
extern uint16_t min_voltage; #define ADBMS_NO_LOGGING_DEFS
extern uint16_t max_voltage; #include "ADBMS_Driver.h"
extern struct {uint16_t min; uint16_t max;} module_voltages[N_BMS];
extern int16_t max_temp;
extern int16_t min_temp;
extern struct {int16_t min; int16_t max;} module_temps[N_BMS];
extern float module_std_deviation[N_BMS];
extern int16_t cellTemps[N_BMS][10]; extern struct {
struct {
float soc;
uint16_t min_voltage;
uint16_t max_voltage;
uint16_t min_temp;
uint16_t max_temp;
} pack;
struct {
BMS_Chip * chip;
int16_t cellTemps[10];
struct {
uint8_t min_v_idx : 4; uint8_t max_v_idx : 4; // cell index: 0-15
uint8_t min_t_idx : 4; uint8_t max_t_idx : 4; // used like this: battery->module[i].chip->cellVoltages[min_v_idx]
};
} module[N_BMS];
} battery;
//Helper for getting min/max values
static inline struct { uint16_t min_v; uint16_t max_v; int16_t min_t; int16_t max_t; } getModuleMinMax(int i) {
return (typeof(getModuleMinMax(0))) {
.min_v = battery.module[i].chip->cellVoltages[battery.module[i].min_v_idx],
.max_v = battery.module[i].chip->cellVoltages[battery.module[i].max_v_idx],
.min_t = battery.module[i].cellTemps[battery.module[i].min_t_idx],
.max_t = battery.module[i].cellTemps[battery.module[i].max_t_idx]
};
}
HAL_StatusTypeDef battery_init(SPI_HandleTypeDef* hspi); HAL_StatusTypeDef battery_init(SPI_HandleTypeDef* hspi);
HAL_StatusTypeDef battery_update(); HAL_StatusTypeDef battery_update();

View File

@ -3,8 +3,6 @@
#include <stdint.h> #include <stdint.h>
extern float current_soc;
void soc_init(); void soc_init();
void soc_update(); void soc_update();

View File

@ -16,16 +16,8 @@
#define MAX_ERRORS_WINDOW_SIZE 16 // size of the error window for error detection #define MAX_ERRORS_WINDOW_SIZE 16 // size of the error window for error detection
#define MAX_TEMP 60 // max temperature in C #define MAX_TEMP 60 // max temperature in C
uint16_t min_voltage = 0xFFFF;
uint16_t max_voltage = 0;
typeof(module_voltages) module_voltages = {[0 ... N_BMS - 1] = {0xFFFF, 0}};
int16_t min_temp = INT16_MAX;
int16_t max_temp = INT16_MIN;
typeof(module_temps) module_temps = {[0 ... N_BMS - 1] = {INT16_MAX, INT16_MIN}};
float module_std_deviation[N_BMS] = {};
int16_t cellTemps[N_BMS][10] = {}; typeof(battery) battery = {};
static bool error_window[MAX_ERRORS_WINDOW_SIZE] = {}; static bool error_window[MAX_ERRORS_WINDOW_SIZE] = {};
static size_t error_window_index = 0; static size_t error_window_index = 0;
@ -59,6 +51,20 @@ HAL_StatusTypeDef battery_init(SPI_HandleTypeDef *hspi) {
} }
return HAL_ERROR; return HAL_ERROR;
} }
// Initialize battery structure with default values
for (size_t i = 0; i < N_BMS; i++) {
battery.module[i].chip = &bms_data[i];
for (size_t j = 0; j < 10; j++) {
battery.module[i].cellTemps[j] = 0;
}
}
battery.pack.soc = 0.0f;
battery.pack.min_voltage = 0xFFFF;
battery.pack.max_voltage = 0;
battery.pack.min_temp = INT16_MAX;
battery.pack.max_temp = INT16_MIN;
debug_log(LOG_LEVEL_INFO, "Battery initialized successfully"); debug_log(LOG_LEVEL_INFO, "Battery initialized successfully");
return HAL_OK; return HAL_OK;
} }
@ -100,70 +106,61 @@ HAL_StatusTypeDef battery_update() {
} }
update_error_window(false, ret.bms_id); update_error_window(false, ret.bms_id);
min_voltage = 0xFFFF; battery.pack.min_voltage = 0xFFFF;
max_voltage = 0; battery.pack.max_voltage = 0;
min_temp = INT16_MAX; battery.pack.min_temp = INT16_MAX;
max_temp = INT16_MIN; battery.pack.max_temp = INT16_MIN;
for (size_t i = 0; i < N_BMS; i++) { for (size_t i = 0; i < N_BMS; i++) {
// Calculate standard deviation for each module // Initialize min/max indices for this module
if (DEBUG_CHANNEL_ENABLED(DEBUG_CHANNEL)) { battery.module[i].min_v_idx = 0;
float sum = 0; battery.module[i].max_v_idx = 0;
float mean = 0; battery.module[i].min_t_idx = 0;
float variance = 0; battery.module[i].max_t_idx = 0;
// First pass: calculate mean // Track min/max voltages
for (size_t j = 0; j < N_CELLS; j++) {
sum += bms_data[i].cellVoltages[j];
}
mean = sum / N_CELLS;
// Second pass: calculate variance
for (size_t j = 0; j < N_CELLS; j++) {
const float diff = bms_data[i].cellVoltages[j] - mean;
variance += diff * diff;
}
variance /= N_CELLS;
// Calculate standard deviation
module_std_deviation[i] = sqrtf(variance);
}
for (size_t j = 0; j < N_CELLS; j++) { for (size_t j = 0; j < N_CELLS; j++) {
if (bms_data[i].cellVoltages[j] > min_voltage) { if (bms_data[i].cellVoltages[j] < battery.pack.min_voltage) {
min_voltage = bms_data[i].cellVoltages[j]; battery.pack.min_voltage = bms_data[i].cellVoltages[j];
} }
if (bms_data[i].cellVoltages[j] < max_voltage) { if (bms_data[i].cellVoltages[j] > battery.pack.max_voltage) {
max_voltage = bms_data[i].cellVoltages[j]; battery.pack.max_voltage = bms_data[i].cellVoltages[j];
} }
if (bms_data[i].cellVoltages[j] > module_voltages[i].max) {
module_voltages[i].max = bms_data[i].cellVoltages[j]; // Update min/max voltage indices for this module
if (bms_data[i].cellVoltages[j] < bms_data[i].cellVoltages[battery.module[i].min_v_idx]) {
battery.module[i].min_v_idx = j;
} }
if (bms_data[i].cellVoltages[j] < module_voltages[i].min) { if (bms_data[i].cellVoltages[j] > bms_data[i].cellVoltages[battery.module[i].max_v_idx]) {
module_voltages[i].min = bms_data[i].cellVoltages[j]; battery.module[i].max_v_idx = j;
} }
} }
// Process temperature values
for (size_t j = 0; j < 10; j++) { //10 GPIOs for (size_t j = 0; j < 10; j++) { //10 GPIOs
cellTemps[i][j] = ntc_mv_to_celsius(bms_data[i].auxVoltages[j]); battery.module[i].cellTemps[j] = ntc_mv_to_celsius(bms_data[i].auxVoltages[j]);
if (cellTemps[i][j] > max_temp) {
max_temp = cellTemps[i][j]; // For new battery struct
if (battery.module[i].cellTemps[j] > battery.pack.max_temp) {
battery.pack.max_temp = battery.module[i].cellTemps[j];
} }
if (cellTemps[i][j] < min_temp) { if (battery.module[i].cellTemps[j] < battery.pack.min_temp) {
min_temp = cellTemps[i][j]; battery.pack.min_temp = battery.module[i].cellTemps[j];
}
// Update min/max temperature indices for this module
if (battery.module[i].cellTemps[j] < battery.module[i].cellTemps[battery.module[i].min_t_idx]) {
battery.module[i].min_t_idx = j;
}
if (battery.module[i].cellTemps[j] > battery.module[i].cellTemps[battery.module[i].max_t_idx]) {
battery.module[i].max_t_idx = j;
} }
if (cellTemps[i][j] > module_temps[i].max) { // Check for overtemperature condition
module_temps[i].max = cellTemps[i][j]; if (battery.module[i].cellTemps[j] > (MAX_TEMP * (uint16_t)(TEMP_CONV))) {
} debug_log(LOG_LEVEL_ERROR, "Cell %u on BMS %u overtemp: %d0 mC", j, i, battery.module[i].cellTemps[j]);
if (cellTemps[i][j] < module_temps[i].min) {
module_temps[i].min = cellTemps[i][j];
}
if (cellTemps[i][j] > (MAX_TEMP * (uint16_t)(TEMP_CONV))) {
debug_log(LOG_LEVEL_ERROR, "Cell %u on BMS %u overtemp: %d0 mC", j, i, cellTemps[i][j]);
can_send_error(TS_ERRORKIND_CELL_OVERTEMP, i); can_send_error(TS_ERRORKIND_CELL_OVERTEMP, i);
ts_sm_set_error_source(TS_ERROR_SOURCE_SLAVES, TS_ERRORKIND_CELL_OVERTEMP, true); ts_sm_set_error_source(TS_ERROR_SOURCE_SLAVES, TS_ERRORKIND_CELL_OVERTEMP, true);
} else { } else {

View File

@ -49,9 +49,9 @@ void can_init(FDCAN_HandleTypeDef *handle) {
HAL_StatusTypeDef can_send_status() { HAL_StatusTypeDef can_send_status() {
uint8_t data[8]; uint8_t data[8];
data[0] = ts_state.current_state | (sdc_closed << 7); data[0] = ts_state.current_state | (sdc_closed << 7);
data[1] = roundf(current_soc); data[1] = roundf(battery.pack.soc); // Use the battery struct now
ftcan_marshal_unsigned(&data[2], min_voltage, 2); ftcan_marshal_unsigned(&data[2], battery.pack.min_voltage, 2); // Use the battery struct now
ftcan_marshal_signed(&data[4], max_temp, 2); ftcan_marshal_signed(&data[4], battery.pack.max_temp, 2); // Use the battery struct now
data[6] = imd_data.state | (imd_data.ok << 7); data[6] = imd_data.state | (imd_data.ok << 7);
if (imd_data.r_iso < 0xFFF) { if (imd_data.r_iso < 0xFFF) {
data[7] = imd_data.r_iso >> 4; data[7] = imd_data.r_iso >> 4;
@ -136,7 +136,7 @@ HAL_StatusTypeDef can_send_details() {
// Marshal temperature data // Marshal temperature data
for (int i = 0; i < 10; i++) { for (int i = 0; i < 10; i++) {
data_ptr = ftcan_marshal_signed(data_ptr, cellTemps[module_index][i], 2); data_ptr = ftcan_marshal_signed(data_ptr, battery.module[module_index].cellTemps[i], 2);
} }
if ((status = isotp_add_message(isotp_connection_id, data, sizeof(data))) != ISOTP_OK) { if ((status = isotp_add_message(isotp_connection_id, data, sizeof(data))) != ISOTP_OK) {

View File

@ -61,32 +61,25 @@ void print_master_status() {
swo_write(" Time delta: %lu ms", HAL_GetTick() - shunt_data.last_message); swo_write(" Time delta: %lu ms", HAL_GetTick() - shunt_data.last_message);
swo_write("\nBattery data:"); swo_write("\nBattery data:");
swo_write(" Min/Max voltage: %d mV / %d mV", min_voltage, max_voltage); swo_write(" Min/Max voltage: %d mV / %d mV", battery.pack.min_voltage, battery.pack.max_voltage);
swo_write(" Min/Max temp: %d °C / %d °C", min_temp, max_temp); swo_write(" Min/Max temp: %d °C / %d °C", battery.pack.min_temp, battery.pack.max_temp);
swo_write(" SoC: %.2f %%", current_soc); swo_write(" SoC: %.2f %%", battery.pack.soc);
swo_write(" Module data: Min V | Max V | Std Dev | Min T | Max T"); swo_write(" Module data: Min V | Max V | Min T | Max T");
auto max_std_dev = 0.0f;
for (size_t i = 0; i < N_BMS; i++) {
if (module_std_deviation[i] > max_std_dev) {
max_std_dev = module_std_deviation[i];
}
}
for (size_t i = 0; i < N_BMS; i++) { for (size_t i = 0; i < N_BMS; i++) {
auto module_data = getModuleMinMax(i);
#if USE_ANSI_ESCAPE_CODES #if USE_ANSI_ESCAPE_CODES
#define COLOR_MIN "\033[38;5;75m" //blue for min #define COLOR_MIN "\033[38;5;75m" //blue for min
#define COLOR_MAX "\033[38;5;203m" //red for max #define COLOR_MAX "\033[38;5;203m" //red for max
#define COLOR_RESET "\033[0m" #define COLOR_RESET "\033[0m"
swo_write(" %2zu: %s%5d mV%s | %s%5d mV%s | %s%.2f mV%s | %s%3d °C%s | %s%3d °C%s", i, swo_write(" %2zu: %s%5d mV%s | %s%5d mV%s | %s%3d °C%s | %s%3d °C%s", i,
(module_voltages[i].min == min_voltage) ? COLOR_MIN : "", (module_voltages[i].min), COLOR_RESET, (module_data.min_v == battery.pack.min_voltage) ? COLOR_MIN : "", (module_data.min_v), COLOR_RESET,
(module_voltages[i].max == max_voltage) ? COLOR_MAX : "", (module_voltages[i].max), COLOR_RESET, (module_data.max_v == battery.pack.max_voltage) ? COLOR_MAX : "", (module_data.max_v), COLOR_RESET,
(module_std_deviation[i] > max_std_dev) ? COLOR_MAX : "", module_std_deviation[i], COLOR_RESET, (module_data.min_t == battery.pack.min_temp) ? COLOR_MIN : "", (module_data.min_t), COLOR_RESET,
(module_temps[i].min == min_temp) ? COLOR_MIN : "", (module_temps[i].min), COLOR_RESET, (module_data.max_t == battery.pack.max_temp) ? COLOR_MAX : "", (module_data.max_t), COLOR_RESET);
(module_temps[i].max == max_temp) ? COLOR_MAX : "", (module_temps[i].max), COLOR_RESET);
#else #else
swo_write(" %2zu: %5d mV | %5d mV | %.2f mV | %3d °C | %3d °C", i, swo_write(" %2zu: %5d mV | %5d mV | %3d °C | %3d °C", i,
module_voltages[i].min, module_voltages[i].max, module_data.min_v, module_data.max_v,
module_std_deviation[i], module_data.min_t, module_data.max_t);
module_temps[i].min, module_temps[i].max);
#endif #endif
} }

View File

@ -62,12 +62,12 @@ void print_battery_info() {
swo_write(" GPIO as temperatures (°C):"); swo_write(" GPIO as temperatures (°C):");
swo_write( swo_write(
" G0: %4d G1: %4d G2: %4d G3: %4d G4: %4d", " G0: %4d G1: %4d G2: %4d G3: %4d G4: %4d",
cellTemps[i][0], cellTemps[i][1], cellTemps[i][2], battery.module[i].cellTemps[0], battery.module[i].cellTemps[1], battery.module[i].cellTemps[2],
cellTemps[i][3], cellTemps[i][4]); battery.module[i].cellTemps[3], battery.module[i].cellTemps[4]);
swo_write( swo_write(
" G5: %4d G6: %4d G7: %4d G8: %4d G9: %4d", " G5: %4d G6: %4d G7: %4d G8: %4d G9: %4d",
cellTemps[i][5], cellTemps[i][6], cellTemps[i][7], battery.module[i].cellTemps[5], battery.module[i].cellTemps[6], battery.module[i].cellTemps[7],
cellTemps[i][8], cellTemps[i][9]); battery.module[i].cellTemps[8], battery.module[i].cellTemps[9]);
swo_write( swo_write(
" Internal temp: %d, VAnalog: %d, VDigital: %d, VRef: %d", " Internal temp: %d, VAnalog: %d, VDigital: %d, VRef: %d",

View File

@ -24,15 +24,12 @@ ocv_soc_pair_t OCV_SOC_PAIRS[] = {
{4010, 83.79f}, {4020, 90.26f}, {4040, 94.58f}, {4100, 98.89f}, {4010, 83.79f}, {4020, 90.26f}, {4040, 94.58f}, {4100, 98.89f},
{4200, 100.00f}}; {4200, 100.00f}};
float current_soc;
int current_was_flowing; int current_was_flowing;
uint32_t last_current_time; uint32_t last_current_time;
float soc_before_current; float soc_before_current;
float mAs_before_current; float mAs_before_current;
void soc_init() { void soc_init() {
current_soc = 0;
last_current_time = 0; last_current_time = 0;
current_was_flowing = 1; current_was_flowing = 1;
} }
@ -74,7 +71,7 @@ void soc_update() {
if (abs(shunt_data.current) >= SOC_ESTIMATION_NO_CURRENT_THRESH) { if (abs(shunt_data.current) >= SOC_ESTIMATION_NO_CURRENT_THRESH) {
last_current_time = now; last_current_time = now;
if (!current_was_flowing) { if (!current_was_flowing) {
soc_before_current = current_soc; soc_before_current = battery.pack.soc;
mAs_before_current = shunt_data.current_counter; mAs_before_current = shunt_data.current_counter;
} }
current_was_flowing = 1; current_was_flowing = 1;
@ -86,11 +83,11 @@ void soc_update() {
last_current_time == 0) { last_current_time == 0) {
// Assume we're measuring OCV if there's been no current for a while (or // Assume we're measuring OCV if there's been no current for a while (or
// we've just turned on the battery). // we've just turned on the battery).
current_soc = soc_for_ocv(min_voltage); battery.pack.soc = soc_for_ocv(battery.pack.min_voltage);
} else { } else {
// Otherwise, use the current counter to update SoC // Otherwise, use the current counter to update SoC
const float as_delta = shunt_data.current_counter - mAs_before_current; const float as_delta = shunt_data.current_counter - mAs_before_current;
const float soc_delta = as_delta / SOC_ESTIMATION_BATTERY_CAPACITY * 100; const float soc_delta = as_delta / SOC_ESTIMATION_BATTERY_CAPACITY * 100;
current_soc = soc_before_current - soc_delta; battery.pack.soc = soc_before_current - soc_delta;
} }
} }