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

View File

@ -17,9 +17,9 @@ ADBMS_Internal_Status amsReset();
ADBMS_Internal_Status initAMS(USER_PTR_TYPE ptr);
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 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 amsCheckUnderOverVoltage(Cell_Module (*module)[N_BMS]);
ADBMS_Internal_Status amsCheckUnderOverVoltage(BMS_Chip (*module)[N_BMS]);
ADBMS_Internal_Status amsClearFlag();
ADBMS_Internal_Status amsClearAux();
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_ */

View File

@ -86,9 +86,9 @@ typedef struct {
int16_t cellVoltages[MAXIMUM_CELL_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);

View File

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

View File

@ -53,7 +53,7 @@ ADBMS_Internal_Status amsReset() {
for (size_t j = 0; j < SID_GROUP_SIZE; j++) {
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
}
}
@ -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)
}
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 for OW conditions: ADSV | ADSV_OW_0 / ADSV_OW_1
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)] = {};
CHECK_RETURN(readCMD(RDSTATC, rxbuf, STATUS_GROUP_C_SIZE));
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);
}
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)] = {};
CHECK_RETURN(readCMD(RDSTATD, regbuffer, STATUS_GROUP_D_SIZE));
@ -274,7 +274,7 @@ ADBMS_Internal_Status amsClearOVUV() {
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)] = {};
CHECK_RETURN(readCMD(RDCVA, rxbuffer, CV_GROUP_A_SIZE));

View File

@ -6,7 +6,7 @@
#include <string.h>
Cell_Module modules[N_BMS] = {};
BMS_Chip bms_data[N_BMS] = {};
uint8_t packetChecksumFails = 0;
#define MAX_PACKET_CHECKSUM_FAILS 5
@ -40,7 +40,7 @@ ADBMS_DetailedStatus AMS_Init(USER_PTR_TYPE ptr) {
({ \
int first_match = -1; \
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)) { \
first_match = __any_intern_i; \
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
}
packetChecksumFails += (amsAuxAndStatusMeasurement(&modules) == ADBMS_ERROR);
packetChecksumFails += (amsAuxAndStatusMeasurement(&bms_data) == ADBMS_ERROR);
int match = 0;
if ((match = any(module.status.SLEEP))) {
@ -75,7 +75,7 @@ ADBMS_DetailedStatus AMS_Idle_Loop() {
amsClearFlag();
// Log specific BMS fault details
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.SPIFLT) debug_log_cont(ADBMS_LOG_LEVEL_ERROR, "SPIFLT ");
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};
}
packetChecksumFails += (amsCellMeasurement(&modules) == ADBMS_ERROR);
packetChecksumFails += (amsCheckUnderOverVoltage(&modules) == ADBMS_ERROR);
packetChecksumFails += (amsCellMeasurement(&bms_data) == ADBMS_ERROR);
packetChecksumFails += (amsCheckUnderOverVoltage(&bms_data) == ADBMS_ERROR);
if (packetChecksumFails > MAX_PACKET_CHECKSUM_FAILS) {
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
#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__)
#endif

View File

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

View File

@ -70,8 +70,8 @@ HAL_StatusTypeDef can_send_status() {
HAL_StatusTypeDef can_send_details() {
static uint8_t module_index = 0;
static uint8_t data[103] = {}; //sizeof(Cell_Module) + 10 + 1
auto const module = &modules[module_index];
static uint8_t data[103] = {}; //sizeof(BMS_Chip) + 10 + 1
auto const module = &bms_data[module_index];
auto data_ptr = &data[1];
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++) {
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
swo_write(" Cell voltages (mV):");
swo_write(" C0: %4d C1: %4d C2: %4d C3: %4d",
modules[i].cellVoltages[0], modules[i].cellVoltages[1],
modules[i].cellVoltages[2], modules[i].cellVoltages[3]);
bms_data[i].cellVoltages[0], bms_data[i].cellVoltages[1],
bms_data[i].cellVoltages[2], bms_data[i].cellVoltages[3]);
swo_write(" C4: %4d C5: %4d C6: %4d C7: %4d",
modules[i].cellVoltages[4], modules[i].cellVoltages[5],
modules[i].cellVoltages[6], modules[i].cellVoltages[7]);
bms_data[i].cellVoltages[4], bms_data[i].cellVoltages[5],
bms_data[i].cellVoltages[6], bms_data[i].cellVoltages[7]);
swo_write(" C8: %4d C9: %4d C10: %4d C11: %4d",
modules[i].cellVoltages[8], modules[i].cellVoltages[9],
modules[i].cellVoltages[10], modules[i].cellVoltages[11]);
bms_data[i].cellVoltages[8], bms_data[i].cellVoltages[9],
bms_data[i].cellVoltages[10], bms_data[i].cellVoltages[11]);
swo_write(" C12: %4d C13: %4d C14: %4d C15: %4d",
modules[i].cellVoltages[12], modules[i].cellVoltages[13],
modules[i].cellVoltages[14], modules[i].cellVoltages[15]);
bms_data[i].cellVoltages[12], bms_data[i].cellVoltages[13],
bms_data[i].cellVoltages[14], bms_data[i].cellVoltages[15]);
// Print GPIO values
swo_write(" GPIO voltages (mV):");
swo_write(
" G0: %4d G1: %4d G2: %4d G3: %4d G4: %4d",
modules[i].auxVoltages[0], modules[i].auxVoltages[1],
modules[i].auxVoltages[2], modules[i].auxVoltages[3],
modules[i].auxVoltages[4]);
bms_data[i].auxVoltages[0], bms_data[i].auxVoltages[1],
bms_data[i].auxVoltages[2], bms_data[i].auxVoltages[3],
bms_data[i].auxVoltages[4]);
swo_write(
" G5: %4d G6: %4d G7: %4d G8: %4d G9: %4d",
modules[i].auxVoltages[5], modules[i].auxVoltages[6],
modules[i].auxVoltages[7], modules[i].auxVoltages[8],
modules[i].auxVoltages[9]);
bms_data[i].auxVoltages[5], bms_data[i].auxVoltages[6],
bms_data[i].auxVoltages[7], bms_data[i].auxVoltages[8],
bms_data[i].auxVoltages[9]);
// Print temperatures
swo_write(" GPIO as temperatures (°C):");
swo_write(
@ -68,91 +68,91 @@ void print_battery_info() {
" 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]);
swo_write(
" Internal temp: %d, VAnalog: %d, VDigital: %d, VRef: %d",
modules[i].internalDieTemp, modules[i].analogSupplyVoltage,
modules[i].digitalSupplyVoltage, modules[i].refVoltage);
bms_data[i].internalDieTemp, bms_data[i].analogSupplyVoltage,
bms_data[i].digitalSupplyVoltage, bms_data[i].refVoltage);
// Print error flags if any are set
bool hasFlags = false;
char flagBuffer[128] = "";
char *bufPos = flagBuffer;
if (modules[i].status.CS_FLT) {
if (bms_data[i].status.CS_FLT) {
bufPos = stpcpy(bufPos, "CS_FLT ");
hasFlags = true;
}
if (modules[i].status.SMED) {
if (bms_data[i].status.SMED) {
bufPos = stpcpy(bufPos, "SMED ");
hasFlags = true;
}
if (modules[i].status.SED) {
if (bms_data[i].status.SED) {
bufPos = stpcpy(bufPos, "SED ");
hasFlags = true;
}
if (modules[i].status.CMED) {
if (bms_data[i].status.CMED) {
bufPos = stpcpy(bufPos, "CMED ");
hasFlags = true;
}
if (modules[i].status.CED) {
if (bms_data[i].status.CED) {
bufPos = stpcpy(bufPos, "CED ");
hasFlags = true;
}
if (modules[i].status.VD_UV) {
if (bms_data[i].status.VD_UV) {
bufPos = stpcpy(bufPos, "VD_UV ");
hasFlags = true;
}
if (modules[i].status.VD_OV) {
if (bms_data[i].status.VD_OV) {
bufPos = stpcpy(bufPos, "VD_OV ");
hasFlags = true;
}
if (modules[i].status.VA_UV) {
if (bms_data[i].status.VA_UV) {
bufPos = stpcpy(bufPos, "VA_UV ");
hasFlags = true;
}
if (modules[i].status.VA_OV) {
if (bms_data[i].status.VA_OV) {
bufPos = stpcpy(bufPos, "VA_OV ");
hasFlags = true;
}
if (modules[i].status.THSD) {
if (bms_data[i].status.THSD) {
bufPos = stpcpy(bufPos, "THSD ");
hasFlags = true;
}
if (modules[i].status.SLEEP) {
if (bms_data[i].status.SLEEP) {
bufPos = stpcpy(bufPos, "SLEEP ");
hasFlags = true;
}
if (modules[i].status.SPIFLT) {
if (bms_data[i].status.SPIFLT) {
bufPos = stpcpy(bufPos, "SPIFLT ");
hasFlags = true;
}
if (modules[i].status.COMPARE) {
if (bms_data[i].status.COMPARE) {
bufPos = stpcpy(bufPos, "COMPARE ");
hasFlags = true;
}
if (modules[i].status.VDE) {
if (bms_data[i].status.VDE) {
bufPos = stpcpy(bufPos, "VDE ");
hasFlags = true;
}
if (modules[i].status.VDEL) {
if (bms_data[i].status.VDEL) {
bufPos = stpcpy(bufPos, "VDEL ");
hasFlags = true;
}
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): ");
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(" Conversion counter: %d",
modules[i].status.CCTS);
bms_data[i].status.CCTS);
}
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_TIME 100000 // ms
#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[] = {
{2500, 0.00f}, {2990, 3.97f}, {3230, 9.36f}, {3320, 12.60f},
{3350, 13.68f}, {3410, 20.15f}, {3530, 32.01f}, {3840, 66.53f},
@ -31,33 +37,7 @@ void soc_init() {
current_was_flowing = 1;
}
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;
}
}
float soc_for_ocv(uint16_t ocv) {
static float soc_for_ocv(uint16_t ocv) {
size_t i = 0;
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
@ -88,3 +68,29 @@ float soc_for_ocv(uint16_t ocv) {
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;
}
}