cleanup part 4
This commit is contained in:
parent
d4dc7e4533
commit
1edc8d3e1c
2
AMS_Master_Code/.clang-format
Normal file
2
AMS_Master_Code/.clang-format
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
IndentWidth: 4
|
||||||
|
ColumnLimit: 120
|
@ -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
|
||||||
|
@ -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_ */
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
@ -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"
|
||||||
|
@ -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));
|
||||||
|
@ -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};
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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];
|
||||||
|
@ -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));
|
||||||
|
@ -28,35 +28,35 @@ 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):");
|
||||||
@ -71,88 +71,88 @@ void print_battery_info() {
|
|||||||
|
|
||||||
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());
|
||||||
}
|
}
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user