diff --git a/AMS_Master_Code/Core/Inc/battery.h b/AMS_Master_Code/Core/Inc/battery.h index 7d43ea3..aaecfcc 100644 --- a/AMS_Master_Code/Core/Inc/battery.h +++ b/AMS_Master_Code/Core/Inc/battery.h @@ -6,15 +6,36 @@ #include #include -extern uint16_t min_voltage; -extern uint16_t max_voltage; -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]; +#define ADBMS_NO_LOGGING_DEFS +#include "ADBMS_Driver.h" -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_update(); diff --git a/AMS_Master_Code/Core/Inc/soc_estimation.h b/AMS_Master_Code/Core/Inc/soc_estimation.h index 057c27d..707f94d 100644 --- a/AMS_Master_Code/Core/Inc/soc_estimation.h +++ b/AMS_Master_Code/Core/Inc/soc_estimation.h @@ -3,8 +3,6 @@ #include -extern float current_soc; - void soc_init(); void soc_update(); diff --git a/AMS_Master_Code/Core/Src/battery.c b/AMS_Master_Code/Core/Src/battery.c index 018ec34..6585bf0 100644 --- a/AMS_Master_Code/Core/Src/battery.c +++ b/AMS_Master_Code/Core/Src/battery.c @@ -16,16 +16,8 @@ #define MAX_ERRORS_WINDOW_SIZE 16 // size of the error window for error detection #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 size_t error_window_index = 0; @@ -59,6 +51,20 @@ HAL_StatusTypeDef battery_init(SPI_HandleTypeDef *hspi) { } 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"); return HAL_OK; } @@ -100,70 +106,61 @@ HAL_StatusTypeDef battery_update() { } update_error_window(false, ret.bms_id); - - min_voltage = 0xFFFF; - max_voltage = 0; - min_temp = INT16_MAX; - max_temp = INT16_MIN; + + battery.pack.min_voltage = 0xFFFF; + battery.pack.max_voltage = 0; + battery.pack.min_temp = INT16_MAX; + battery.pack.max_temp = INT16_MIN; for (size_t i = 0; i < N_BMS; i++) { - // Calculate standard deviation for each module - if (DEBUG_CHANNEL_ENABLED(DEBUG_CHANNEL)) { - float sum = 0; - float mean = 0; - float variance = 0; - - // First pass: calculate mean - 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); - } - + // Initialize min/max indices for this module + battery.module[i].min_v_idx = 0; + battery.module[i].max_v_idx = 0; + battery.module[i].min_t_idx = 0; + battery.module[i].max_t_idx = 0; + + // Track min/max voltages for (size_t j = 0; j < N_CELLS; j++) { - if (bms_data[i].cellVoltages[j] > min_voltage) { - min_voltage = bms_data[i].cellVoltages[j]; + if (bms_data[i].cellVoltages[j] < battery.pack.min_voltage) { + battery.pack.min_voltage = bms_data[i].cellVoltages[j]; } - if (bms_data[i].cellVoltages[j] < max_voltage) { - max_voltage = bms_data[i].cellVoltages[j]; + if (bms_data[i].cellVoltages[j] > battery.pack.max_voltage) { + 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) { - module_voltages[i].min = bms_data[i].cellVoltages[j]; + if (bms_data[i].cellVoltages[j] > bms_data[i].cellVoltages[battery.module[i].max_v_idx]) { + battery.module[i].max_v_idx = j; } } + // Process temperature values 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) { - min_temp = cellTemps[i][j]; + if (battery.module[i].cellTemps[j] < battery.pack.min_temp) { + 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) { - module_temps[i].max = cellTemps[i][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]); + // Check for overtemperature condition + 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]); can_send_error(TS_ERRORKIND_CELL_OVERTEMP, i); ts_sm_set_error_source(TS_ERROR_SOURCE_SLAVES, TS_ERRORKIND_CELL_OVERTEMP, true); } else { diff --git a/AMS_Master_Code/Core/Src/can.c b/AMS_Master_Code/Core/Src/can.c index 0850ff0..3e3b6d9 100644 --- a/AMS_Master_Code/Core/Src/can.c +++ b/AMS_Master_Code/Core/Src/can.c @@ -49,9 +49,9 @@ void can_init(FDCAN_HandleTypeDef *handle) { HAL_StatusTypeDef can_send_status() { uint8_t data[8]; data[0] = ts_state.current_state | (sdc_closed << 7); - data[1] = roundf(current_soc); - ftcan_marshal_unsigned(&data[2], min_voltage, 2); - ftcan_marshal_signed(&data[4], max_temp, 2); + data[1] = roundf(battery.pack.soc); // Use the battery struct now + ftcan_marshal_unsigned(&data[2], battery.pack.min_voltage, 2); // Use the battery struct now + ftcan_marshal_signed(&data[4], battery.pack.max_temp, 2); // Use the battery struct now data[6] = imd_data.state | (imd_data.ok << 7); if (imd_data.r_iso < 0xFFF) { data[7] = imd_data.r_iso >> 4; @@ -136,7 +136,7 @@ HAL_StatusTypeDef can_send_details() { // Marshal temperature data 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) { diff --git a/AMS_Master_Code/Core/Src/print_master_status.c b/AMS_Master_Code/Core/Src/print_master_status.c index 53da49b..b5a658c 100644 --- a/AMS_Master_Code/Core/Src/print_master_status.c +++ b/AMS_Master_Code/Core/Src/print_master_status.c @@ -61,32 +61,25 @@ void print_master_status() { swo_write(" Time delta: %lu ms", HAL_GetTick() - shunt_data.last_message); swo_write("\nBattery data:"); - swo_write(" Min/Max voltage: %d mV / %d mV", min_voltage, max_voltage); - swo_write(" Min/Max temp: %d °C / %d °C", min_temp, max_temp); - swo_write(" SoC: %.2f %%", current_soc); - swo_write(" Module data: Min V | Max V | Std Dev | 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]; - } - } + 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", battery.pack.min_temp, battery.pack.max_temp); + swo_write(" SoC: %.2f %%", battery.pack.soc); + swo_write(" Module data: Min V | Max V | Min T | Max T"); for (size_t i = 0; i < N_BMS; i++) { + auto module_data = getModuleMinMax(i); #if USE_ANSI_ESCAPE_CODES #define COLOR_MIN "\033[38;5;75m" //blue for min #define COLOR_MAX "\033[38;5;203m" //red for max #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, - (module_voltages[i].min == min_voltage) ? COLOR_MIN : "", (module_voltages[i].min), COLOR_RESET, - (module_voltages[i].max == max_voltage) ? COLOR_MAX : "", (module_voltages[i].max), COLOR_RESET, - (module_std_deviation[i] > max_std_dev) ? COLOR_MAX : "", module_std_deviation[i], COLOR_RESET, - (module_temps[i].min == min_temp) ? COLOR_MIN : "", (module_temps[i].min), COLOR_RESET, - (module_temps[i].max == max_temp) ? COLOR_MAX : "", (module_temps[i].max), COLOR_RESET); + swo_write(" %2zu: %s%5d mV%s | %s%5d mV%s | %s%3d °C%s | %s%3d °C%s", i, + (module_data.min_v == battery.pack.min_voltage) ? COLOR_MIN : "", (module_data.min_v), COLOR_RESET, + (module_data.max_v == battery.pack.max_voltage) ? COLOR_MAX : "", (module_data.max_v), COLOR_RESET, + (module_data.min_t == battery.pack.min_temp) ? COLOR_MIN : "", (module_data.min_t), COLOR_RESET, + (module_data.max_t == battery.pack.max_temp) ? COLOR_MAX : "", (module_data.max_t), COLOR_RESET); #else - swo_write(" %2zu: %5d mV | %5d mV | %.2f mV | %3d °C | %3d °C", i, - module_voltages[i].min, module_voltages[i].max, - module_std_deviation[i], - module_temps[i].min, module_temps[i].max); + swo_write(" %2zu: %5d mV | %5d mV | %3d °C | %3d °C", i, + module_data.min_v, module_data.max_v, + module_data.min_t, module_data.max_t); #endif } diff --git a/AMS_Master_Code/Core/Src/print_module_status.c b/AMS_Master_Code/Core/Src/print_module_status.c index c1627aa..092b634 100644 --- a/AMS_Master_Code/Core/Src/print_module_status.c +++ b/AMS_Master_Code/Core/Src/print_module_status.c @@ -62,12 +62,12 @@ void print_battery_info() { swo_write(" GPIO as temperatures (°C):"); swo_write( " G0: %4d G1: %4d G2: %4d G3: %4d G4: %4d", - cellTemps[i][0], cellTemps[i][1], cellTemps[i][2], - cellTemps[i][3], cellTemps[i][4]); + battery.module[i].cellTemps[0], battery.module[i].cellTemps[1], battery.module[i].cellTemps[2], + battery.module[i].cellTemps[3], battery.module[i].cellTemps[4]); swo_write( " G5: %4d G6: %4d G7: %4d G8: %4d G9: %4d", - cellTemps[i][5], cellTemps[i][6], cellTemps[i][7], - cellTemps[i][8], cellTemps[i][9]); + battery.module[i].cellTemps[5], battery.module[i].cellTemps[6], battery.module[i].cellTemps[7], + battery.module[i].cellTemps[8], battery.module[i].cellTemps[9]); swo_write( " Internal temp: %d, VAnalog: %d, VDigital: %d, VRef: %d", diff --git a/AMS_Master_Code/Core/Src/soc_estimation.c b/AMS_Master_Code/Core/Src/soc_estimation.c index 5854b0e..4059d66 100644 --- a/AMS_Master_Code/Core/Src/soc_estimation.c +++ b/AMS_Master_Code/Core/Src/soc_estimation.c @@ -24,15 +24,12 @@ ocv_soc_pair_t OCV_SOC_PAIRS[] = { {4010, 83.79f}, {4020, 90.26f}, {4040, 94.58f}, {4100, 98.89f}, {4200, 100.00f}}; -float current_soc; - int current_was_flowing; uint32_t last_current_time; float soc_before_current; float mAs_before_current; void soc_init() { - current_soc = 0; last_current_time = 0; current_was_flowing = 1; } @@ -74,7 +71,7 @@ void soc_update() { if (abs(shunt_data.current) >= SOC_ESTIMATION_NO_CURRENT_THRESH) { last_current_time = now; if (!current_was_flowing) { - soc_before_current = current_soc; + soc_before_current = battery.pack.soc; mAs_before_current = shunt_data.current_counter; } current_was_flowing = 1; @@ -86,11 +83,11 @@ void soc_update() { last_current_time == 0) { // Assume we're measuring OCV if there's been no current for a while (or // 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 { // Otherwise, use the current counter to update SoC const float as_delta = shunt_data.current_counter - mAs_before_current; 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; } }