cleanup part 4

This commit is contained in:
Kilian Bracher 2025-05-09 14:49:16 +02:00
parent d4dc7e4533
commit 1edc8d3e1c
Signed by: k.bracher
SSH Key Fingerprint: SHA256:mXpyZkK7RDiJ7qeHCKJX108woM0cl5TrCvNBJASu6lM
12 changed files with 113 additions and 110 deletions

View File

@ -0,0 +1,2 @@
IndentWidth: 4
ColumnLimit: 120

View File

@ -8,11 +8,4 @@ extern float current_soc;
void soc_init(); void soc_init();
void soc_update(); void soc_update();
typedef struct {
uint16_t ocv;
float soc;
} ocv_soc_pair_t;
extern ocv_soc_pair_t OCV_SOC_PAIRS[];
float soc_for_ocv(uint16_t ocv);
#endif // INC_SOC_ESTIMATION_H #endif // INC_SOC_ESTIMATION_H

View File

@ -17,9 +17,9 @@ ADBMS_Internal_Status amsReset();
ADBMS_Internal_Status initAMS(USER_PTR_TYPE ptr); ADBMS_Internal_Status initAMS(USER_PTR_TYPE ptr);
ADBMS_Internal_Status amsWakeUp(); ADBMS_Internal_Status amsWakeUp();
ADBMS_Internal_Status amsCellMeasurement(Cell_Module (*module)[N_BMS]); ADBMS_Internal_Status amsCellMeasurement(BMS_Chip (*module)[N_BMS]);
ADBMS_Internal_Status amsAuxAndStatusMeasurement(Cell_Module (*module)[N_BMS]); ADBMS_Internal_Status amsAuxAndStatusMeasurement(BMS_Chip (*module)[N_BMS]);
ADBMS_Internal_Status amsConfigBalancing(const uint32_t channels[static N_BMS], uint8_t dutyCycle); ADBMS_Internal_Status amsConfigBalancing(const uint32_t channels[static N_BMS], uint8_t dutyCycle);
ADBMS_Internal_Status amsStartBalancing(); ADBMS_Internal_Status amsStartBalancing();
@ -29,12 +29,12 @@ ADBMS_Internal_Status amsSelfTest();
ADBMS_Internal_Status amsConfigOverUnderVoltage(uint16_t overVoltage, uint16_t underVoltage); //arguments in mV ADBMS_Internal_Status amsConfigOverUnderVoltage(uint16_t overVoltage, uint16_t underVoltage); //arguments in mV
ADBMS_Internal_Status amsCheckUnderOverVoltage(Cell_Module (*module)[N_BMS]); ADBMS_Internal_Status amsCheckUnderOverVoltage(BMS_Chip (*module)[N_BMS]);
ADBMS_Internal_Status amsClearFlag(); ADBMS_Internal_Status amsClearFlag();
ADBMS_Internal_Status amsClearAux(); ADBMS_Internal_Status amsClearAux();
ADBMS_Internal_Status amsClearOVUV(); ADBMS_Internal_Status amsClearOVUV();
ADBMS_Internal_Status amsReadCellVoltages(Cell_Module (*module)[N_BMS]); ADBMS_Internal_Status amsReadCellVoltages(BMS_Chip (*module)[N_BMS]);
#endif /* INC_ADBMS_ABSTRACTION_H_ */ #endif /* INC_ADBMS_ABSTRACTION_H_ */

View File

@ -86,9 +86,9 @@ typedef struct {
int16_t cellVoltages[MAXIMUM_CELL_VOLTAGES]; int16_t cellVoltages[MAXIMUM_CELL_VOLTAGES];
int16_t auxVoltages[MAXIMUM_AUX_VOLTAGES]; int16_t auxVoltages[MAXIMUM_AUX_VOLTAGES];
} Cell_Module; } BMS_Chip;
extern Cell_Module modules[N_BMS]; extern BMS_Chip bms_data[N_BMS];
[[gnu::nonnull]] ADBMS_DetailedStatus AMS_Init(USER_PTR_TYPE ptr); [[gnu::nonnull]] ADBMS_DetailedStatus AMS_Init(USER_PTR_TYPE ptr);

View File

@ -53,7 +53,7 @@ static inline void mcuDelay(uint32_t delay) {
// Optional logging, leave as is if not needed // Optional logging, leave as is if not needed
#if !ADBMS_NO_LOGGING_DEFS #ifndef ADBMS_NO_LOGGING_DEFS
#define LOG_PREFIX "[ADBMS] " #define LOG_PREFIX "[ADBMS] "
#include "log.h" #include "log.h"

View File

@ -53,7 +53,7 @@ ADBMS_Internal_Status amsReset() {
for (size_t j = 0; j < SID_GROUP_SIZE; j++) { for (size_t j = 0; j < SID_GROUP_SIZE; j++) {
id |= sidbuffer[BUFFER_BMS_OFFSET(i, SID_GROUP_SIZE) + j] << (j * 8); id |= sidbuffer[BUFFER_BMS_OFFSET(i, SID_GROUP_SIZE) + j] << (j * 8);
} }
modules[i].bmsID = id; bms_data[i].bmsID = id;
debug_log_cont(ADBMS_LOG_LEVEL_INFO, "0x%08lx%08lx ", (uint32_t)(id >> 32), (uint32_t)(id & 0xFFFFFFFF)); //newlib does not support %llu debug_log_cont(ADBMS_LOG_LEVEL_INFO, "0x%08lx%08lx ", (uint32_t)(id >> 32), (uint32_t)(id & 0xFFFFFFFF)); //newlib does not support %llu
} }
} }
@ -83,13 +83,13 @@ ADBMS_Internal_Status amsWakeUp() {
return __pollCMD(PLADC, 100); //wake up ADBMS6830, wait for T_wake = 200 us (100 cycles at 500 kHz) return __pollCMD(PLADC, 100); //wake up ADBMS6830, wait for T_wake = 200 us (100 cycles at 500 kHz)
} }
ADBMS_Internal_Status amsCellMeasurement(Cell_Module (*module)[N_BMS]) { ADBMS_Internal_Status amsCellMeasurement(BMS_Chip (*module)[N_BMS]) {
#warning check conversion counter to ensure that continuous conversion has not been stopped #warning check conversion counter to ensure that continuous conversion has not been stopped
#warning check for OW conditions: ADSV | ADSV_OW_0 / ADSV_OW_1 #warning check for OW conditions: ADSV | ADSV_OW_0 / ADSV_OW_1
return amsReadCellVoltages(module); return amsReadCellVoltages(module);
} }
ADBMS_Internal_Status amsAuxAndStatusMeasurement(Cell_Module (*module)[N_BMS]) { ADBMS_Internal_Status amsAuxAndStatusMeasurement(BMS_Chip (*module)[N_BMS]) {
uint8_t rxbuf[CMD_BUFFER_SIZE(STATUS_GROUP_C_SIZE)] = {}; uint8_t rxbuf[CMD_BUFFER_SIZE(STATUS_GROUP_C_SIZE)] = {};
CHECK_RETURN(readCMD(RDSTATC, rxbuf, STATUS_GROUP_C_SIZE)); CHECK_RETURN(readCMD(RDSTATC, rxbuf, STATUS_GROUP_C_SIZE));
for (size_t i = 0; i < N_BMS; i++) { for (size_t i = 0; i < N_BMS; i++) {
@ -237,7 +237,7 @@ ADBMS_Internal_Status amsConfigOverUnderVoltage(uint16_t overVoltage, uint16_t u
return writeCMD(WRCFGB, buffer, CFG_GROUP_B_SIZE); return writeCMD(WRCFGB, buffer, CFG_GROUP_B_SIZE);
} }
ADBMS_Internal_Status amsCheckUnderOverVoltage(Cell_Module (*module)[N_BMS]) { ADBMS_Internal_Status amsCheckUnderOverVoltage(BMS_Chip (*module)[N_BMS]) {
uint8_t regbuffer[CMD_BUFFER_SIZE(STATUS_GROUP_D_SIZE)] = {}; uint8_t regbuffer[CMD_BUFFER_SIZE(STATUS_GROUP_D_SIZE)] = {};
CHECK_RETURN(readCMD(RDSTATD, regbuffer, STATUS_GROUP_D_SIZE)); CHECK_RETURN(readCMD(RDSTATD, regbuffer, STATUS_GROUP_D_SIZE));
@ -274,7 +274,7 @@ ADBMS_Internal_Status amsClearOVUV() {
return writeCMD(CLOVUV, buffer, 6); return writeCMD(CLOVUV, buffer, 6);
} }
ADBMS_Internal_Status amsReadCellVoltages(Cell_Module (*module)[N_BMS]) { ADBMS_Internal_Status amsReadCellVoltages(BMS_Chip (*module)[N_BMS]) {
uint8_t rxbuffer[CMD_BUFFER_SIZE(CV_GROUP_A_SIZE)] = {}; uint8_t rxbuffer[CMD_BUFFER_SIZE(CV_GROUP_A_SIZE)] = {};
CHECK_RETURN(readCMD(RDCVA, rxbuffer, CV_GROUP_A_SIZE)); CHECK_RETURN(readCMD(RDCVA, rxbuffer, CV_GROUP_A_SIZE));

View File

@ -6,7 +6,7 @@
#include <string.h> #include <string.h>
Cell_Module modules[N_BMS] = {}; BMS_Chip bms_data[N_BMS] = {};
uint8_t packetChecksumFails = 0; uint8_t packetChecksumFails = 0;
#define MAX_PACKET_CHECKSUM_FAILS 5 #define MAX_PACKET_CHECKSUM_FAILS 5
@ -40,7 +40,7 @@ ADBMS_DetailedStatus AMS_Init(USER_PTR_TYPE ptr) {
({ \ ({ \
int first_match = -1; \ int first_match = -1; \
for (size_t __any_intern_i = 0; __any_intern_i < N_BMS; __any_intern_i++) { \ for (size_t __any_intern_i = 0; __any_intern_i < N_BMS; __any_intern_i++) { \
Cell_Module module = modules[__any_intern_i]; \ BMS_Chip module = bms_data[__any_intern_i]; \
if ((x)) { \ if ((x)) { \
first_match = __any_intern_i; \ first_match = __any_intern_i; \
break; \ break; \
@ -55,7 +55,7 @@ ADBMS_DetailedStatus AMS_Idle_Loop() {
// set_error_source(ERROR_SOURCE_INTERNAL); //so we can't tell if we timed out // set_error_source(ERROR_SOURCE_INTERNAL); //so we can't tell if we timed out
} }
packetChecksumFails += (amsAuxAndStatusMeasurement(&modules) == ADBMS_ERROR); packetChecksumFails += (amsAuxAndStatusMeasurement(&bms_data) == ADBMS_ERROR);
int match = 0; int match = 0;
if ((match = any(module.status.SLEEP))) { if ((match = any(module.status.SLEEP))) {
@ -75,7 +75,7 @@ ADBMS_DetailedStatus AMS_Idle_Loop() {
amsClearFlag(); amsClearFlag();
// Log specific BMS fault details // Log specific BMS fault details
debug_log(ADBMS_LOG_LEVEL_ERROR, "Fault on BMS %d: ", match - 1); debug_log(ADBMS_LOG_LEVEL_ERROR, "Fault on BMS %d: ", match - 1);
auto faultyModule = &modules[match - 1]; auto faultyModule = &bms_data[match - 1];
if (faultyModule->status.CS_FLT) debug_log_cont(ADBMS_LOG_LEVEL_ERROR, "CS_FLT "); if (faultyModule->status.CS_FLT) debug_log_cont(ADBMS_LOG_LEVEL_ERROR, "CS_FLT ");
if (faultyModule->status.SPIFLT) debug_log_cont(ADBMS_LOG_LEVEL_ERROR, "SPIFLT "); if (faultyModule->status.SPIFLT) debug_log_cont(ADBMS_LOG_LEVEL_ERROR, "SPIFLT ");
if (faultyModule->status.CMED) debug_log_cont(ADBMS_LOG_LEVEL_ERROR, "CMED "); if (faultyModule->status.CMED) debug_log_cont(ADBMS_LOG_LEVEL_ERROR, "CMED ");
@ -88,8 +88,8 @@ ADBMS_DetailedStatus AMS_Idle_Loop() {
return (ADBMS_DetailedStatus){ADBMS_INTERNAL_BMS_FAULT, match - 1}; return (ADBMS_DetailedStatus){ADBMS_INTERNAL_BMS_FAULT, match - 1};
} }
packetChecksumFails += (amsCellMeasurement(&modules) == ADBMS_ERROR); packetChecksumFails += (amsCellMeasurement(&bms_data) == ADBMS_ERROR);
packetChecksumFails += (amsCheckUnderOverVoltage(&modules) == ADBMS_ERROR); packetChecksumFails += (amsCheckUnderOverVoltage(&bms_data) == ADBMS_ERROR);
if (packetChecksumFails > MAX_PACKET_CHECKSUM_FAILS) { if (packetChecksumFails > MAX_PACKET_CHECKSUM_FAILS) {
return (ADBMS_DetailedStatus){ADBMS_INTERNAL_BMS_CHECKSUM_FAIL, -1}; return (ADBMS_DetailedStatus){ADBMS_INTERNAL_BMS_CHECKSUM_FAIL, -1};

View File

@ -72,6 +72,8 @@ void log_message(log_level_t level, const char *msg, ...);
#ifdef LOG_PREFIX #ifdef LOG_PREFIX
#define log_message(level, fmt, ...) \ #define log_message(level, fmt, ...) \
static_assert(__builtin_constant_p(fmt), "Format string must be a compile-time constant if using LOG_PREFIX"); \
static_assert(__builtin_constant_p(LOG_PREFIX), "LOG_PREFIX must be a compile-time constant"); \
log_message(level, LOG_PREFIX fmt, ##__VA_ARGS__) log_message(level, LOG_PREFIX fmt, ##__VA_ARGS__)
#endif #endif

View File

@ -1,5 +1,5 @@
#include "battery.h" #include "battery.h"
#define ADBMS_NO_LOGGING_DEFS true // fix conficting defines #define ADBMS_NO_LOGGING_DEFS // fix conflicting defines
#include "ADBMS_Driver.h" #include "ADBMS_Driver.h"
#include "NTC.h" #include "NTC.h"
#include "can.h" #include "can.h"
@ -77,15 +77,15 @@ HAL_StatusTypeDef battery_update() {
if (ret.bms_id != -1 && ret.bms_id < N_BMS) { if (ret.bms_id != -1 && ret.bms_id < N_BMS) {
const char* error_type = (ret.status == ADBMS_OVERVOLT) ? "overvoltage" : "undervoltage"; const char* error_type = (ret.status == ADBMS_OVERVOLT) ? "overvoltage" : "undervoltage";
const uint32_t voltage_flags = (ret.status == ADBMS_OVERVOLT) ? const uint32_t voltage_flags = (ret.status == ADBMS_OVERVOLT) ?
modules[ret.bms_id].overVoltage : bms_data[ret.bms_id].overVoltage :
modules[ret.bms_id].underVoltage; bms_data[ret.bms_id].underVoltage;
debug_log(LOG_LEVEL_ERROR, "Cell %s detected on module %d, affected cells: ", debug_log(LOG_LEVEL_ERROR, "Cell %s detected on module %d, affected cells: ",
error_type, ret.bms_id); error_type, ret.bms_id);
for (size_t cell = 0; cell < N_CELLS; cell++) { for (size_t cell = 0; cell < N_CELLS; cell++) {
if (voltage_flags & (1UL << cell)) { if (voltage_flags & (1UL << cell)) {
debug_log_cont(LOG_LEVEL_ERROR, "%u (%d mV) ", cell, modules[ret.bms_id].cellVoltages[cell]); debug_log_cont(LOG_LEVEL_ERROR, "%u (%d mV) ", cell, bms_data[ret.bms_id].cellVoltages[cell]);
} }
} }
@ -115,13 +115,13 @@ HAL_StatusTypeDef battery_update() {
// First pass: calculate mean // First pass: calculate mean
for (size_t j = 0; j < N_CELLS; j++) { for (size_t j = 0; j < N_CELLS; j++) {
sum += modules[i].cellVoltages[j]; sum += bms_data[i].cellVoltages[j];
} }
mean = sum / N_CELLS; mean = sum / N_CELLS;
// Second pass: calculate variance // Second pass: calculate variance
for (size_t j = 0; j < N_CELLS; j++) { for (size_t j = 0; j < N_CELLS; j++) {
const float diff = modules[i].cellVoltages[j] - mean; const float diff = bms_data[i].cellVoltages[j] - mean;
variance += diff * diff; variance += diff * diff;
} }
variance /= N_CELLS; variance /= N_CELLS;
@ -131,22 +131,22 @@ HAL_StatusTypeDef battery_update() {
} }
for (size_t j = 0; j < N_CELLS; j++) { for (size_t j = 0; j < N_CELLS; j++) {
if (modules[i].cellVoltages[j] > min_voltage) { if (bms_data[i].cellVoltages[j] > min_voltage) {
min_voltage = modules[i].cellVoltages[j]; min_voltage = bms_data[i].cellVoltages[j];
} }
if (modules[i].cellVoltages[j] < max_voltage) { if (bms_data[i].cellVoltages[j] < max_voltage) {
max_voltage = modules[i].cellVoltages[j]; max_voltage = bms_data[i].cellVoltages[j];
} }
if (modules[i].cellVoltages[j] > module_voltages[i].max) { if (bms_data[i].cellVoltages[j] > module_voltages[i].max) {
module_voltages[i].max = modules[i].cellVoltages[j]; module_voltages[i].max = bms_data[i].cellVoltages[j];
} }
if (modules[i].cellVoltages[j] < module_voltages[i].min) { if (bms_data[i].cellVoltages[j] < module_voltages[i].min) {
module_voltages[i].min = modules[i].cellVoltages[j]; module_voltages[i].min = bms_data[i].cellVoltages[j];
} }
} }
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(modules[i].auxVoltages[j]); cellTemps[i][j] = ntc_mv_to_celsius(bms_data[i].auxVoltages[j]);
if (cellTemps[i][j] > max_temp) { if (cellTemps[i][j] > max_temp) {
max_temp = cellTemps[i][j]; max_temp = cellTemps[i][j];

View File

@ -70,8 +70,8 @@ HAL_StatusTypeDef can_send_status() {
HAL_StatusTypeDef can_send_details() { HAL_StatusTypeDef can_send_details() {
static uint8_t module_index = 0; static uint8_t module_index = 0;
static uint8_t data[103] = {}; //sizeof(Cell_Module) + 10 + 1 static uint8_t data[103] = {}; //sizeof(BMS_Chip) + 10 + 1
auto const module = &modules[module_index]; auto const module = &bms_data[module_index];
auto data_ptr = &data[1]; auto data_ptr = &data[1];
isotp_status_t status = isotp_try_add_message(isotp_connection_id, data, sizeof(data)); isotp_status_t status = isotp_try_add_message(isotp_connection_id, data, sizeof(data));

View File

@ -28,36 +28,36 @@ void print_battery_info() {
for (size_t i = 0; i < N_BMS; i++) { for (size_t i = 0; i < N_BMS; i++) {
swo_write("Module %d status:", i); swo_write("Module %d status:", i);
swo_write(" BMS ID: 0x%08lx%08lx", (uint32_t)(modules[i].bmsID >> 32), (uint32_t)(modules[i].bmsID & 0xFFFFFFFF)); swo_write(" BMS ID: 0x%08lx%08lx", (uint32_t)(bms_data[i].bmsID >> 32), (uint32_t)(bms_data[i].bmsID & 0xFFFFFFFF));
// Print cell voltages in 4x4 format // Print cell voltages in 4x4 format
swo_write(" Cell voltages (mV):"); swo_write(" Cell voltages (mV):");
swo_write(" C0: %4d C1: %4d C2: %4d C3: %4d", swo_write(" C0: %4d C1: %4d C2: %4d C3: %4d",
modules[i].cellVoltages[0], modules[i].cellVoltages[1], bms_data[i].cellVoltages[0], bms_data[i].cellVoltages[1],
modules[i].cellVoltages[2], modules[i].cellVoltages[3]); bms_data[i].cellVoltages[2], bms_data[i].cellVoltages[3]);
swo_write(" C4: %4d C5: %4d C6: %4d C7: %4d", swo_write(" C4: %4d C5: %4d C6: %4d C7: %4d",
modules[i].cellVoltages[4], modules[i].cellVoltages[5], bms_data[i].cellVoltages[4], bms_data[i].cellVoltages[5],
modules[i].cellVoltages[6], modules[i].cellVoltages[7]); bms_data[i].cellVoltages[6], bms_data[i].cellVoltages[7]);
swo_write(" C8: %4d C9: %4d C10: %4d C11: %4d", swo_write(" C8: %4d C9: %4d C10: %4d C11: %4d",
modules[i].cellVoltages[8], modules[i].cellVoltages[9], bms_data[i].cellVoltages[8], bms_data[i].cellVoltages[9],
modules[i].cellVoltages[10], modules[i].cellVoltages[11]); bms_data[i].cellVoltages[10], bms_data[i].cellVoltages[11]);
swo_write(" C12: %4d C13: %4d C14: %4d C15: %4d", swo_write(" C12: %4d C13: %4d C14: %4d C15: %4d",
modules[i].cellVoltages[12], modules[i].cellVoltages[13], bms_data[i].cellVoltages[12], bms_data[i].cellVoltages[13],
modules[i].cellVoltages[14], modules[i].cellVoltages[15]); bms_data[i].cellVoltages[14], bms_data[i].cellVoltages[15]);
// Print GPIO values // Print GPIO values
swo_write(" GPIO voltages (mV):"); swo_write(" GPIO voltages (mV):");
swo_write( swo_write(
" G0: %4d G1: %4d G2: %4d G3: %4d G4: %4d", " G0: %4d G1: %4d G2: %4d G3: %4d G4: %4d",
modules[i].auxVoltages[0], modules[i].auxVoltages[1], bms_data[i].auxVoltages[0], bms_data[i].auxVoltages[1],
modules[i].auxVoltages[2], modules[i].auxVoltages[3], bms_data[i].auxVoltages[2], bms_data[i].auxVoltages[3],
modules[i].auxVoltages[4]); bms_data[i].auxVoltages[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",
modules[i].auxVoltages[5], modules[i].auxVoltages[6], bms_data[i].auxVoltages[5], bms_data[i].auxVoltages[6],
modules[i].auxVoltages[7], modules[i].auxVoltages[8], bms_data[i].auxVoltages[7], bms_data[i].auxVoltages[8],
modules[i].auxVoltages[9]); bms_data[i].auxVoltages[9]);
// Print temperatures // Print temperatures
swo_write(" GPIO as temperatures (°C):"); swo_write(" GPIO as temperatures (°C):");
swo_write( swo_write(
@ -68,91 +68,91 @@ void print_battery_info() {
" 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], cellTemps[i][5], cellTemps[i][6], cellTemps[i][7],
cellTemps[i][8], cellTemps[i][9]); cellTemps[i][8], cellTemps[i][9]);
swo_write( swo_write(
" Internal temp: %d, VAnalog: %d, VDigital: %d, VRef: %d", " Internal temp: %d, VAnalog: %d, VDigital: %d, VRef: %d",
modules[i].internalDieTemp, modules[i].analogSupplyVoltage, bms_data[i].internalDieTemp, bms_data[i].analogSupplyVoltage,
modules[i].digitalSupplyVoltage, modules[i].refVoltage); bms_data[i].digitalSupplyVoltage, bms_data[i].refVoltage);
// Print error flags if any are set // Print error flags if any are set
bool hasFlags = false; bool hasFlags = false;
char flagBuffer[128] = ""; char flagBuffer[128] = "";
char *bufPos = flagBuffer; char *bufPos = flagBuffer;
if (modules[i].status.CS_FLT) { if (bms_data[i].status.CS_FLT) {
bufPos = stpcpy(bufPos, "CS_FLT "); bufPos = stpcpy(bufPos, "CS_FLT ");
hasFlags = true; hasFlags = true;
} }
if (modules[i].status.SMED) { if (bms_data[i].status.SMED) {
bufPos = stpcpy(bufPos, "SMED "); bufPos = stpcpy(bufPos, "SMED ");
hasFlags = true; hasFlags = true;
} }
if (modules[i].status.SED) { if (bms_data[i].status.SED) {
bufPos = stpcpy(bufPos, "SED "); bufPos = stpcpy(bufPos, "SED ");
hasFlags = true; hasFlags = true;
} }
if (modules[i].status.CMED) { if (bms_data[i].status.CMED) {
bufPos = stpcpy(bufPos, "CMED "); bufPos = stpcpy(bufPos, "CMED ");
hasFlags = true; hasFlags = true;
} }
if (modules[i].status.CED) { if (bms_data[i].status.CED) {
bufPos = stpcpy(bufPos, "CED "); bufPos = stpcpy(bufPos, "CED ");
hasFlags = true; hasFlags = true;
} }
if (modules[i].status.VD_UV) { if (bms_data[i].status.VD_UV) {
bufPos = stpcpy(bufPos, "VD_UV "); bufPos = stpcpy(bufPos, "VD_UV ");
hasFlags = true; hasFlags = true;
} }
if (modules[i].status.VD_OV) { if (bms_data[i].status.VD_OV) {
bufPos = stpcpy(bufPos, "VD_OV "); bufPos = stpcpy(bufPos, "VD_OV ");
hasFlags = true; hasFlags = true;
} }
if (modules[i].status.VA_UV) { if (bms_data[i].status.VA_UV) {
bufPos = stpcpy(bufPos, "VA_UV "); bufPos = stpcpy(bufPos, "VA_UV ");
hasFlags = true; hasFlags = true;
} }
if (modules[i].status.VA_OV) { if (bms_data[i].status.VA_OV) {
bufPos = stpcpy(bufPos, "VA_OV "); bufPos = stpcpy(bufPos, "VA_OV ");
hasFlags = true; hasFlags = true;
} }
if (modules[i].status.THSD) { if (bms_data[i].status.THSD) {
bufPos = stpcpy(bufPos, "THSD "); bufPos = stpcpy(bufPos, "THSD ");
hasFlags = true; hasFlags = true;
} }
if (modules[i].status.SLEEP) { if (bms_data[i].status.SLEEP) {
bufPos = stpcpy(bufPos, "SLEEP "); bufPos = stpcpy(bufPos, "SLEEP ");
hasFlags = true; hasFlags = true;
} }
if (modules[i].status.SPIFLT) { if (bms_data[i].status.SPIFLT) {
bufPos = stpcpy(bufPos, "SPIFLT "); bufPos = stpcpy(bufPos, "SPIFLT ");
hasFlags = true; hasFlags = true;
} }
if (modules[i].status.COMPARE) { if (bms_data[i].status.COMPARE) {
bufPos = stpcpy(bufPos, "COMPARE "); bufPos = stpcpy(bufPos, "COMPARE ");
hasFlags = true; hasFlags = true;
} }
if (modules[i].status.VDE) { if (bms_data[i].status.VDE) {
bufPos = stpcpy(bufPos, "VDE "); bufPos = stpcpy(bufPos, "VDE ");
hasFlags = true; hasFlags = true;
} }
if (modules[i].status.VDEL) { if (bms_data[i].status.VDEL) {
bufPos = stpcpy(bufPos, "VDEL "); bufPos = stpcpy(bufPos, "VDEL ");
hasFlags = true; hasFlags = true;
} }
swo_write(" Status flags: %s", hasFlags ? flagBuffer : "[none]"); swo_write(" Status flags: %s", hasFlags ? flagBuffer : "[none]");
if (modules[i].status.CS_FLT) { // Print out which ADCs are faulting if (bms_data[i].status.CS_FLT) { // Print out which ADCs are faulting
swo_write("Comparison fault on ADC/Cell(s): "); swo_write("Comparison fault on ADC/Cell(s): ");
for (ssize_t j = 0; j < 16; j++) { for (ssize_t j = 0; j < 16; j++) {
if (modules[i].status.CS_FLT & (1u << j)) { if (bms_data[i].status.CS_FLT & (1u << j)) {
swo_write("%d ", j); swo_write("%d ", j);
} }
} }
} }
swo_write(" Conversion counter: %d", swo_write(" Conversion counter: %d",
modules[i].status.CCTS); bms_data[i].status.CCTS);
} }
swo_write("\n------ Updated at %lu ------", HAL_GetTick()); swo_write("\n------ Updated at %lu ------", HAL_GetTick());
} }

View File

@ -12,6 +12,12 @@
#define SOC_ESTIMATION_NO_CURRENT_THRESH 200 // mA #define SOC_ESTIMATION_NO_CURRENT_THRESH 200 // mA
#define SOC_ESTIMATION_NO_CURRENT_TIME 100000 // ms #define SOC_ESTIMATION_NO_CURRENT_TIME 100000 // ms
#define SOC_ESTIMATION_BATTERY_CAPACITY 64800000 // mAs #define SOC_ESTIMATION_BATTERY_CAPACITY 64800000 // mAs
typedef struct {
uint16_t ocv;
float soc;
} ocv_soc_pair_t;
ocv_soc_pair_t OCV_SOC_PAIRS[] = { ocv_soc_pair_t OCV_SOC_PAIRS[] = {
{2500, 0.00f}, {2990, 3.97f}, {3230, 9.36f}, {3320, 12.60f}, {2500, 0.00f}, {2990, 3.97f}, {3230, 9.36f}, {3320, 12.60f},
{3350, 13.68f}, {3410, 20.15f}, {3530, 32.01f}, {3840, 66.53f}, {3350, 13.68f}, {3410, 20.15f}, {3530, 32.01f}, {3840, 66.53f},
@ -31,33 +37,7 @@ void soc_init() {
current_was_flowing = 1; current_was_flowing = 1;
} }
void soc_update() { static float soc_for_ocv(uint16_t ocv) {
const uint32_t now = HAL_GetTick();
if (abs(shunt_data.current) >= SOC_ESTIMATION_NO_CURRENT_THRESH) {
last_current_time = now;
if (!current_was_flowing) {
soc_before_current = current_soc;
mAs_before_current = shunt_data.current_counter;
}
current_was_flowing = 1;
} else {
current_was_flowing = 0;
}
if (now - last_current_time >= SOC_ESTIMATION_NO_CURRENT_TIME ||
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);
} 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;
}
}
float soc_for_ocv(uint16_t ocv) {
size_t i = 0; size_t i = 0;
const size_t array_length = sizeof(OCV_SOC_PAIRS) / sizeof(*OCV_SOC_PAIRS); const size_t array_length = sizeof(OCV_SOC_PAIRS) / sizeof(*OCV_SOC_PAIRS);
// Find the index of the first element with OCV greater than the target OCV // Find the index of the first element with OCV greater than the target OCV
@ -88,3 +68,29 @@ float soc_for_ocv(uint16_t ocv) {
return interpolated_soc; return interpolated_soc;
} }
void soc_update() {
const uint32_t now = HAL_GetTick();
if (abs(shunt_data.current) >= SOC_ESTIMATION_NO_CURRENT_THRESH) {
last_current_time = now;
if (!current_was_flowing) {
soc_before_current = current_soc;
mAs_before_current = shunt_data.current_counter;
}
current_was_flowing = 1;
} else {
current_was_flowing = 0;
}
if (now - last_current_time >= SOC_ESTIMATION_NO_CURRENT_TIME ||
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);
} 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;
}
}