refactor for multiple BMS:

reset, aux and status measurement
This commit is contained in:
Kilian Bracher 2025-01-31 01:03:36 +01:00
parent 3ee15518d2
commit a1cc8bc9a2
Signed by: k.bracher
SSH Key Fingerprint: SHA256:mXpyZkK7RDiJ7qeHCKJX108woM0cl5TrCvNBJASu6lM
4 changed files with 97 additions and 83 deletions

View File

@ -63,15 +63,14 @@ typedef struct {
} Cell_Module;
uint8_t amsReset();
HAL_StatusTypeDef amsReset();
uint8_t initAMS(SPI_HandleTypeDef* hspi);
uint8_t amsWakeUp();
HAL_StatusTypeDef initAMS(SPI_HandleTypeDef* hspi);
HAL_StatusTypeDef amsWakeUp();
uint8_t amsCellMeasurement(Cell_Module* module);
uint8_t amsConfigCellMeasurement(uint8_t numberofChannels);
HAL_StatusTypeDef amsCellMeasurement(Cell_Module* module);
uint8_t amsAuxAndStatusMeasurement(Cell_Module* module);
HAL_StatusTypeDef amsAuxAndStatusMeasurement(Cell_Module * module[static N_BMS]);
uint8_t amsConfigAuxMeasurement(uint16_t Channels);
uint8_t amsConfigGPIO(uint16_t gpios);

View File

@ -50,7 +50,7 @@ static inline HAL_StatusTypeDef __writeCMD(uint16_t command, uint8_t * args, siz
[[gnu::access(read_write, 2, 3), gnu::nonnull(2)]]
HAL_StatusTypeDef readCMD(uint16_t command, uint8_t * buffer, size_t buflen);
uint8_t pollCMD(uint16_t command);
HAL_StatusTypeDef pollCMD(uint16_t command);
void mcuAdbmsCSLow();

View File

@ -8,6 +8,7 @@
#include "ADBMS_Abstraction.h"
#include "ADBMS_CMD_MAKROS.h"
#include "ADBMS_LL_Driver.h"
#include "config_ADBMS6830.h"
#include "swo_log.h"
#include <stddef.h>
@ -15,17 +16,17 @@ extern uint8_t numberofCells;
#define CHECK_RETURN(x) \
{ \
uint8_t status = x; \
uint8_t status = x; \
if (status != 0) \
return status; \
}
uint8_t amsReset() {
HAL_StatusTypeDef amsReset() {
amsWakeUp();
readCMD(SRST, CMD_EMPTY_BUFFER, CMD_EMPTY_BUFFER_SIZE);
uint8_t buffer[CMD_BUFFER_SIZE(SID_GROUP_SIZE)] = {0};
CHECK_RETURN(readCMD(RDSID, buffer, CMD_BUFFER_SIZE(SID_GROUP_SIZE)));
uint8_t sidbuffer[CMD_BUFFER_SIZE(SID_GROUP_SIZE)] = {};
CHECK_RETURN(readCMD(RDSID, sidbuffer, CMD_BUFFER_SIZE(SID_GROUP_SIZE)));
debug_log(LOG_LEVEL_INFO, "BMS reset complete\n");
@ -34,7 +35,7 @@ uint8_t amsReset() {
for (size_t i = 0; i < N_BMS; i++) {
uint64_t id = 0;
for (size_t j = 0; j < SID_GROUP_SIZE; j++) {
id |= buffer[BUFFER_BMS_OFFSET(i, SID_GROUP_SIZE) + j] << (j * 8);
id |= sidbuffer[BUFFER_BMS_OFFSET(i, SID_GROUP_SIZE) + j] << (j * 8);
}
debug_log_cont(LOG_LEVEL_INFO, "0x%llx ", id);
}
@ -46,94 +47,110 @@ uint8_t amsReset() {
amsStopBalancing();
amsConfigOverUnderVoltage(DEFAULT_OV, DEFAULT_UV);
CHECK_RETURN(writeCMD(CLRFLAG, buffer, 6)); //clear flags,
CHECK_RETURN(writeCMD(CLOVUV, buffer, 6)); //OVUV flags
CHECK_RETURN(writeCMD(ADCV | ADCV_CONT | ADCV_RD, NULL, 0)); //start continuous cell voltage measurement with redundancy
CHECK_RETURN(writeCMD(ADAX | ADAX_CONV_ALL, NULL, 0)); //start aux measurement
uint8_t flagsbuffer[CMD_BUFFER_SIZE(6)] = {[0 ... CMD_BUFFER_SIZE(6) - 1] = 0xFF}; //technically not all 6 bytes are used, but it's easier to just set all to 0xFF
//see page 27 of the datasheet for the memory map
CHECK_RETURN(writeCMD(CLRFLAG, flagsbuffer, 6)); //clear flags,
CHECK_RETURN(writeCMD(CLOVUV, flagsbuffer, 6)); //OVUV flags
CHECK_RETURN(writeCMD(ADCV | ADCV_CONT | ADCV_RD, flagsbuffer, 0)); //start continuous cell voltage measurement with redundancy
CHECK_RETURN(writeCMD(ADAX | ADAX_CONV_ALL, flagsbuffer, 0)); //start aux measurement
return 0;
}
uint8_t initAMS(SPI_HandleTypeDef* hspi) {
HAL_StatusTypeDef initAMS(SPI_HandleTypeDef* hspi) {
adbmsDriverInit(hspi);
return amsReset();
}
uint8_t amsWakeUp() {
HAL_StatusTypeDef amsWakeUp() {
uint8_t buffer[CMD_BUFFER_SIZE(CFG_GROUP_A_SIZE)] = {0};
return readCMD(RDCFGA, buffer, CMD_BUFFER_SIZE(CFG_GROUP_A_SIZE));
}
uint8_t amsCellMeasurement(Cell_Module* module) {
HAL_StatusTypeDef amsCellMeasurement(Cell_Module* module) {
#warning check conversion counter to ensure that continous conversion has not been stopped
#warning check for OW conditions: ADSV | ADSV_OW_0 / ADSV_OW_1
return amsReadCellVoltages(module);
}
uint8_t amsAuxAndStatusMeasurement(Cell_Module* module) {
uint8_t rxbuf[AUX_GROUP_A_SIZE] = {};
HAL_StatusTypeDef amsAuxAndStatusMeasurement(Cell_Module * module[static N_BMS]) {
uint8_t rxbuf[CMD_BUFFER_SIZE(STATUS_GROUP_C_SIZE)] = {};
CHECK_RETURN(readCMD(RDSTATC, rxbuf, STATUS_GROUP_C_SIZE));
module->status.CS_FLT = rxbuf[0] | (rxbuf[1] << 8);
module->status.CCTS = rxbuf[2] | (rxbuf[3] << 8);
module->status.VA_OV = (rxbuf[4] >> 7) & 0x01;
module->status.VA_UV = (rxbuf[4] >> 6) & 0x01;
module->status.VD_OV = (rxbuf[4] >> 5) & 0x01;
module->status.VD_UV = (rxbuf[4] >> 4) & 0x01;
module->status.CED = (rxbuf[4] >> 3) & 0x01;
module->status.CMED = (rxbuf[4] >> 2) & 0x01;
module->status.SED = (rxbuf[4] >> 1) & 0x01;
module->status.SMED = (rxbuf[4] >> 0) & 0x01;
module->status.VDEL = (rxbuf[5] >> 7) & 0x01;
module->status.VDE = (rxbuf[5] >> 6) & 0x01;
module->status.COMPARE= (rxbuf[5] >> 5) & 0x01;
module->status.SPIFLT = (rxbuf[5] >> 4) & 0x01;
module->status.SLEEP = (rxbuf[5] >> 3) & 0x01;
module->status.THSD = (rxbuf[5] >> 2) & 0x01;
module->status.TMODCHK= (rxbuf[5] >> 1) & 0x01;
module->status.OSCCHK = (rxbuf[5] >> 0) & 0x01;
if (pollCMD(PLAUX) == 0x0) { //TODO: check for SPI fault
return 0; // aux ADC data not ready
CHECK_RETURN(readCMD(RDSTATC, rxbuf, sizeof rxbuf));
for (size_t i = 0; i < N_BMS; i++) {
size_t offset = BUFFER_BMS_OFFSET(i, STATUS_GROUP_C_SIZE);
module[i]->status.CS_FLT = rxbuf[offset + 0] | (rxbuf[offset + 1] << 8);
module[i]->status.CCTS = rxbuf[offset + 2] | (rxbuf[offset + 3] << 8);
module[i]->status.VA_OV = (rxbuf[offset + 4] >> 7) & 0x01;
module[i]->status.VA_UV = (rxbuf[offset + 4] >> 6) & 0x01;
module[i]->status.VD_OV = (rxbuf[offset + 4] >> 5) & 0x01;
module[i]->status.VD_UV = (rxbuf[offset + 4] >> 4) & 0x01;
module[i]->status.CED = (rxbuf[offset + 4] >> 3) & 0x01;
module[i]->status.CMED = (rxbuf[offset + 4] >> 2) & 0x01;
module[i]->status.SED = (rxbuf[offset + 4] >> 1) & 0x01;
module[i]->status.SMED = (rxbuf[offset + 4] >> 0) & 0x01;
module[i]->status.VDEL = (rxbuf[offset + 5] >> 7) & 0x01;
module[i]->status.VDE = (rxbuf[offset + 5] >> 6) & 0x01;
module[i]->status.COMPARE= (rxbuf[offset + 5] >> 5) & 0x01;
module[i]->status.SPIFLT = (rxbuf[offset + 5] >> 4) & 0x01;
module[i]->status.SLEEP = (rxbuf[offset + 5] >> 3) & 0x01;
module[i]->status.THSD = (rxbuf[offset + 5] >> 2) & 0x01;
module[i]->status.TMODCHK= (rxbuf[offset + 5] >> 1) & 0x01;
module[i]->status.OSCCHK = (rxbuf[offset + 5] >> 0) & 0x01;
}
CHECK_RETURN(readCMD(RDAUXA, rxbuf, AUX_GROUP_A_SIZE));
if (pollCMD(PLAUX) == HAL_BUSY) {
return HAL_BUSY;
}
module->auxVoltages[0] = mV_from_ADBMS6830(rxbuf[0] | (rxbuf[1] << 8));
module->auxVoltages[1] = mV_from_ADBMS6830(rxbuf[2] | (rxbuf[3] << 8));
module->auxVoltages[2] = mV_from_ADBMS6830(rxbuf[4] | (rxbuf[5] << 8));
CHECK_RETURN(readCMD(RDAUXA, rxbuf, CMD_BUFFER_SIZE(AUX_GROUP_A_SIZE))); //STATUS_GROUP_C_SIZE is the same as AUX_GROUP_A_SIZE, so we can reuse the buffer
for (size_t i = 0; i < N_BMS; i++) {
size_t offset = BUFFER_BMS_OFFSET(i, AUX_GROUP_A_SIZE);
module[i]->auxVoltages[0] = mV_from_ADBMS6830(rxbuf[offset + 0] | (rxbuf[offset + 1] << 8));
module[i]->auxVoltages[1] = mV_from_ADBMS6830(rxbuf[offset + 2] | (rxbuf[offset + 3] << 8));
module[i]->auxVoltages[2] = mV_from_ADBMS6830(rxbuf[offset + 4] | (rxbuf[offset + 5] << 8));
}
CHECK_RETURN(readCMD(RDAUXB, rxbuf, AUX_GROUP_A_SIZE));
CHECK_RETURN(readCMD(RDAUXB, rxbuf, CMD_BUFFER_SIZE(AUX_GROUP_B_SIZE)));
for (size_t i = 0; i < N_BMS; i++) {
size_t offset = BUFFER_BMS_OFFSET(i, AUX_GROUP_B_SIZE);
module[i]->auxVoltages[3] = mV_from_ADBMS6830(rxbuf[offset + 0] | (rxbuf[offset + 1] << 8));
module[i]->auxVoltages[4] = mV_from_ADBMS6830(rxbuf[offset + 2] | (rxbuf[offset + 3] << 8));
module[i]->auxVoltages[5] = mV_from_ADBMS6830(rxbuf[offset + 4] | (rxbuf[offset + 5] << 8));
}
module->auxVoltages[3] = mV_from_ADBMS6830(rxbuf[0] | (rxbuf[1] << 8));
module->auxVoltages[4] = mV_from_ADBMS6830(rxbuf[2] | (rxbuf[3] << 8));
module->auxVoltages[5] = mV_from_ADBMS6830(rxbuf[4] | (rxbuf[5] << 8));
CHECK_RETURN(readCMD(RDAUXC, rxbuf, CMD_BUFFER_SIZE(AUX_GROUP_C_SIZE)));
for (size_t i = 0; i < N_BMS; i++) {
size_t offset = BUFFER_BMS_OFFSET(i, AUX_GROUP_C_SIZE);
module[i]->auxVoltages[6] = mV_from_ADBMS6830(rxbuf[offset + 0] | (rxbuf[offset + 1] << 8));
module[i]->auxVoltages[7] = mV_from_ADBMS6830(rxbuf[offset + 2] | (rxbuf[offset + 3] << 8));
module[i]->auxVoltages[8] = mV_from_ADBMS6830(rxbuf[offset + 4] | (rxbuf[offset + 5] << 8));
}
CHECK_RETURN(readCMD(RDAUXC, rxbuf, AUX_GROUP_A_SIZE));
CHECK_RETURN(readCMD(RDAUXD, rxbuf, CMD_BUFFER_SIZE(AUX_GROUP_D_SIZE)));
for (size_t i = 0; i < N_BMS; i++) {
size_t offset = BUFFER_BMS_OFFSET(i, AUX_GROUP_D_SIZE);
module[i]->auxVoltages[9] = mV_from_ADBMS6830(rxbuf[offset + 0] | (rxbuf[offset + 1] << 8));
}
module->auxVoltages[6] = mV_from_ADBMS6830(rxbuf[0] | (rxbuf[1] << 8));
module->auxVoltages[7] = mV_from_ADBMS6830(rxbuf[2] | (rxbuf[3] << 8));
module->auxVoltages[8] = mV_from_ADBMS6830(rxbuf[4] | (rxbuf[5] << 8));
CHECK_RETURN(readCMD(RDSTATA, rxbuf, CMD_BUFFER_SIZE(STATUS_GROUP_A_SIZE)));
for (size_t i = 0; i < N_BMS; i++) {
size_t offset = BUFFER_BMS_OFFSET(i, STATUS_GROUP_A_SIZE);
module[i]->internalDieTemp = rxbuf[offset + 2] | (rxbuf[offset + 3] << 8);
}
CHECK_RETURN(readCMD(RDAUXD, rxbuf, AUX_GROUP_A_SIZE));
CHECK_RETURN(readCMD(RDSTATB, rxbuf, CMD_BUFFER_SIZE(STATUS_GROUP_B_SIZE)));
for (size_t i = 0; i < N_BMS; i++) {
size_t offset = BUFFER_BMS_OFFSET(i, STATUS_GROUP_B_SIZE);
module[i]->digitalSupplyVoltage = mV_from_ADBMS6830(rxbuf[offset + 0] | (rxbuf[offset + 1] << 8));
module[i]->analogSupplyVoltage = mV_from_ADBMS6830(rxbuf[offset + 2] | (rxbuf[offset + 3] << 8));
module[i]->refVoltage = mV_from_ADBMS6830(rxbuf[offset + 4] | (rxbuf[offset + 5] << 8));
}
module->auxVoltages[9] = mV_from_ADBMS6830(rxbuf[0] | (rxbuf[1] << 8));
CHECK_RETURN(writeCMD(ADAX | ADAX_CONV_ALL, rxbuf, 0)); //start aux conversion for next iteration
uint8_t rxbuffer[STATUS_GROUP_A_SIZE];
CHECK_RETURN(readCMD(RDSTATA, rxbuffer, STATUS_GROUP_A_SIZE));
module->internalDieTemp = rxbuffer[2] | (rxbuffer[3] << 8);
CHECK_RETURN(readCMD(RDSTATB, rxbuffer, STATUS_GROUP_B_SIZE));
module->digitalSupplyVoltage = mV_from_ADBMS6830(rxbuffer[0] | (rxbuffer[1] << 8));
module->analogSupplyVoltage = mV_from_ADBMS6830(rxbuffer[2] | (rxbuffer[3] << 8));
module->refVoltage = mV_from_ADBMS6830(rxbuffer[4] | (rxbuffer[5] << 8));
CHECK_RETURN(writeCMD(ADAX | ADAX_CONV_ALL, NULL, 0)); //start aux measurement for next cycle
return 0;
return HAL_OK;
}
uint8_t amsConfigBalancing(uint32_t channels, uint8_t dutyCycle) {

View File

@ -331,23 +331,21 @@ HAL_StatusTypeDef readCMD(uint16_t command, uint8_t * buffer, size_t buflen) {
}
//check poll command - no data PEC sent back
uint8_t pollCMD(uint16_t command) {
uint8_t txbuffer[5] = {};
uint8_t rxbuffer[5] = {};
HAL_StatusTypeDef pollCMD(uint16_t command) {
uint8_t buffer[4 + (N_BMS * 2) + 1] = {}; //poll is only valid after 2 * N_BMS clock cycles (datasheet page 55)
//being conservative and adding 1 byte for the poll response
txbuffer[0] = (command >> 8) & 0xFF;
txbuffer[1] = (command)&0xFF;
calculateCommandPEC(txbuffer, 4);
buffer[0] = (command >> 8) & 0xFF;
buffer[1] = (command) & 0xFF;
calculateCommandPEC(buffer, 4);
mcuAdbmsCSLow();
uint8_t status = mcuSPITransmitReceive(rxbuffer, txbuffer, 5);
HAL_StatusTypeDef status = mcuSPITransmitReceive(buffer, buffer, 4 + (N_BMS * 2) + 1);
mcuAdbmsCSHigh();
if (status != 0) {
return status;
}
if (status != HAL_OK) return status;
return rxbuffer[4]; //last byte will be poll response
return ((buffer[4 + (N_BMS * 2)] & 0x0F) == 0x0) ? HAL_BUSY : HAL_OK; //SDO goes high when data is ready
}
void mcuAdbmsCSLow() {