Compare commits

...

6 Commits

Author SHA1 Message Date
009a4d1cf5
refactor: crc calculation
this one's a copilot special, but looks good to me
2025-01-31 18:41:56 +01:00
7fbd335017
refactor: cell voltages, main loop 2025-01-31 18:27:37 +01:00
5d2b8fd09b
refactor: check data PEC again 2025-01-31 17:26:43 +01:00
13958bb7a5
refactor: config balancing 2025-01-31 16:49:06 +01:00
a1cc8bc9a2
refactor for multiple BMS:
reset, aux and status measurement
2025-01-31 01:03:36 +01:00
3ee15518d2
basic wire up of old slave code to master code 2025-01-31 00:59:13 +01:00
10 changed files with 356 additions and 408 deletions

View File

@ -2,6 +2,7 @@
#define INC_SLAVE_MONITORING_H
#include <stdint.h>
#include "stm32h7xx_hal.h"
#define N_SLAVES 7
#define N_CELLS_SERIES 15
@ -57,7 +58,7 @@ extern SlaveHandle slaves[N_SLAVES];
extern uint16_t min_voltage;
extern int16_t max_temp;
void slaves_init();
void slaves_init(SPI_HandleTypeDef *hspi);
void slaves_check();
void slaves_handle_panic(const uint8_t *data);

View File

@ -72,12 +72,12 @@ static inline void __swo_print(unsigned int channel, const char *str) {
if (DEBUG_CHANNEL_ENABLED(level)) { \
char buffer[MAX_MESSAGE_LENGTH]; \
size_t len = snprintf(buffer, sizeof(buffer), msg, ##__VA_ARGS__); \
__swo_putc('\n', level); \
__swo_print(level, log_level_names[level]); \
__swo_print(level, buffer); \
if (len >= sizeof(buffer)) { \
__swo_print(level, " [message length exceeded] "); \
} \
__swo_putc('\n', level); \
} \
} while (0)

View File

@ -63,44 +63,28 @@ 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)[N_BMS]);
uint8_t amsAuxAndStatusMeasurement(Cell_Module* module);
uint8_t amsConfigAuxMeasurement(uint16_t Channels);
HAL_StatusTypeDef amsAuxAndStatusMeasurement(Cell_Module (*module)[N_BMS]);
uint8_t amsConfigGPIO(uint16_t gpios);
uint8_t amsSetGPIO(uint16_t gpios);
uint8_t readGPIO(Cell_Module* module);
HAL_StatusTypeDef amsConfigBalancing(uint32_t channels[N_BMS], uint8_t dutyCycle);
HAL_StatusTypeDef amsStartBalancing(uint8_t dutyCycle);
HAL_StatusTypeDef amsStopBalancing();
uint8_t amsConfigBalancing(uint32_t Channels, uint8_t dutyCycle);
uint8_t amsStartBalancing(uint8_t dutyCycle);
uint8_t amsStopBalancing();
HAL_StatusTypeDef amsSelfTest();
uint8_t amsSelfTest();
HAL_StatusTypeDef amsConfigOverUnderVoltage(uint16_t overVoltage, uint16_t underVoltage);
uint8_t amsConfigOverUnderVoltage(uint16_t overVoltage, uint16_t underVoltage);
HAL_StatusTypeDef amsCheckUnderOverVoltage(Cell_Module (*module)[N_BMS]);
uint8_t amsCheckUnderOverVoltage(Cell_Module* module);
uint8_t amsConfigOverVoltage(uint16_t overVoltage);
HAL_StatusTypeDef amsClearFlag();
HAL_StatusTypeDef amsClearAux();
uint8_t amscheckOpenCellWire(Cell_Module* module);
uint8_t amsClearFlag();
uint8_t amsClearAux();
uint8_t amsClearCells();
uint8_t amsSendWarning();
uint8_t amsSendError();
uint8_t amsClearWarning();
uint8_t amsClearError();
uint8_t amsReadCellVoltages(Cell_Module* module);
HAL_StatusTypeDef amsReadCellVoltages(Cell_Module (*module)[N_BMS]);
#endif /* INC_ADBMS_ABSTRACTION_H_ */

View File

@ -47,10 +47,17 @@ static inline HAL_StatusTypeDef __writeCMD(uint16_t command, uint8_t * args, siz
#define writeCMD(command, args, arglen) \
__writeCMD(command, args, arglen, CMD_BUFFER_SIZE(arglen))
[[gnu::access(read_write, 2, 3), gnu::nonnull(2)]]
HAL_StatusTypeDef readCMD(uint16_t command, uint8_t * buffer, size_t buflen);
HAL_StatusTypeDef ___readCMD(uint16_t command, uint8_t * buffer, size_t arglen);
uint8_t pollCMD(uint16_t command);
[[gnu::access(read_write, 2, 4), gnu::nonnull(2), gnu::always_inline]] //add dummy size variable for bounds checking, should be optimized out
static inline HAL_StatusTypeDef __readCMD(uint16_t command, uint8_t * buffer, size_t arglen, size_t _) {
return ___readCMD(command, buffer, arglen);
}
#define readCMD(command, buffer, buflen) \
__readCMD(command, buffer, buflen, CMD_BUFFER_SIZE(buflen))
HAL_StatusTypeDef pollCMD(uint16_t command);
void mcuAdbmsCSLow();

View File

@ -11,6 +11,7 @@
#include "ADBMS_Abstraction.h"
#include "ADBMS_CMD_MAKROS.h"
#include "ADBMS_LL_Driver.h"
#include "config_ADBMS6830.h"
#include <stdbool.h>
@ -25,7 +26,7 @@ typedef enum {
} amsState;
extern amsState currentAMSState;
extern Cell_Module module;
extern Cell_Module modules[N_BMS];
extern uint32_t balancedCells;
extern bool BalancingActive;

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,26 +16,26 @@ extern uint8_t numberofCells;
#define CHECK_RETURN(x) \
{ \
uint8_t status = x; \
HAL_StatusTypeDef status = x; \
if (status != 0) \
return status; \
}
uint8_t amsReset() {
HAL_StatusTypeDef amsReset() {
amsWakeUp();
readCMD(SRST, CMD_EMPTY_BUFFER, CMD_EMPTY_BUFFER_SIZE);
readCMD(SRST, CMD_EMPTY_BUFFER, 0);
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, SID_GROUP_SIZE));
debug_log(LOG_LEVEL_INFO, "BMS reset complete\n");
debug_log(LOG_LEVEL_INFO, "BMS reset complete");
if (DEBUG_CHANNEL_ENABLED(LOG_LEVEL_INFO)) {
debug_log(LOG_LEVEL_INFO, "Found IDs: ");
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,214 +47,272 @@ 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));
return readCMD(RDCFGA, buffer, CFG_GROUP_A_SIZE);
}
uint8_t amsCellMeasurement(Cell_Module* module) {
HAL_StatusTypeDef amsCellMeasurement(Cell_Module (*module)[N_BMS]) {
#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);
return HAL_ERROR; //amsReadCellVoltages(module);
}
uint8_t amsAuxAndStatusMeasurement(Cell_Module* module) {
uint8_t rxbuf[AUX_GROUP_A_SIZE] = {};
HAL_StatusTypeDef amsAuxAndStatusMeasurement(Cell_Module (*module)[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
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));
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(RDAUXB, rxbuf, AUX_GROUP_A_SIZE));
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, AUX_GROUP_A_SIZE));
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(RDAUXD, rxbuf, AUX_GROUP_A_SIZE));
module->auxVoltages[9] = mV_from_ADBMS6830(rxbuf[0] | (rxbuf[1] << 8));
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;
if (pollCMD(PLAUX) == HAL_BUSY) {
return HAL_BUSY;
}
uint8_t amsConfigBalancing(uint32_t channels, uint8_t dutyCycle) {
uint8_t buffer_a[PWM_GROUP_A_SIZE] = {};
uint8_t buffer_b[PWM_GROUP_B_SIZE] = {};
CHECK_RETURN(readCMD(RDPWMA, buffer_a, CFG_GROUP_A_SIZE));
CHECK_RETURN(readCMD(RDPWMB, buffer_b, CFG_GROUP_B_SIZE));
if (dutyCycle > 0x0F) { // there are only 4 bits for duty cycle
return 1;
CHECK_RETURN(readCMD(RDAUXA, rxbuf, 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));
}
#warning fixme
CHECK_RETURN(readCMD(RDAUXB, rxbuf, 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));
}
for (size_t i = 0; i < 16; i += 2) {
if (i < 12) { // cells 0, 1 are in regbuffer[0], cells 2, 3 in regbuffer[1], ...
buffer_a[i / 2] = ((channels & (1 << (i + 1))) ? (dutyCycle << 4) : 0) |
((channels & (1 << i)) ? dutyCycle : 0);
CHECK_RETURN(readCMD(RDAUXC, rxbuf, 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(RDAUXD, rxbuf, 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));
}
CHECK_RETURN(readCMD(RDSTATA, rxbuf, 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(RDSTATB, rxbuf, 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));
}
CHECK_RETURN(writeCMD(ADAX | ADAX_CONV_ALL, rxbuf, 0)); //start aux conversion for next iteration
return HAL_OK;
}
HAL_StatusTypeDef amsConfigBalancing(uint32_t channels[N_BMS], uint8_t dutyCycle) {
if (dutyCycle > 0x0F) {
return HAL_ERROR; // only 4 bits are allowed for dutyCycle
}
uint8_t rxbufA[CMD_BUFFER_SIZE(PWM_GROUP_A_SIZE)] = {};
uint8_t rxbufB[CMD_BUFFER_SIZE(PWM_GROUP_B_SIZE)] = {};
CHECK_RETURN(readCMD(RDPWMA, rxbufA, PWM_GROUP_A_SIZE));
CHECK_RETURN(readCMD(RDPWMB, rxbufB, PWM_GROUP_B_SIZE));
for (size_t i = 0; i < N_BMS; i++) {
size_t offsetA = BUFFER_BMS_OFFSET(i, PWM_GROUP_A_SIZE);
size_t offsetB = BUFFER_BMS_OFFSET(i, PWM_GROUP_B_SIZE);
for (size_t c = 0; c < 16; c += 2) {
uint8_t high = (channels[i] & (1 << (c + 1))) ? (dutyCycle << 4) : 0;
uint8_t low = (channels[i] & (1 << c)) ? dutyCycle : 0;
if (c < 12) {
rxbufA[offsetA + (c / 2)] = high | low;
} else {
buffer_b[(i - 12) / 2] = ((channels & (1 << (i + 1))) ? (dutyCycle << 4) : 0) |
((channels & (1 << i)) ? dutyCycle : 0);
rxbufB[offsetB + ((c - 12) / 2)] = high | low;
}
}
CHECK_RETURN(writeCMD(WRPWMA, buffer_a, CFG_GROUP_A_SIZE));
CHECK_RETURN(writeCMD(WRPWMB, buffer_b, CFG_GROUP_B_SIZE));
return 0;
//log the new PWM settings
//output is: PWM - [BMS_ID]: [PWM0] ... [PWM16]
if (DEBUG_CHANNEL_ENABLED(LOG_LEVEL_DEBUG)) {
debug_log(LOG_LEVEL_DEBUG, "PWM - %d: ", i);
for (size_t j = 0; j < 6; j++) {
debug_log_cont(LOG_LEVEL_DEBUG, "%x %x ", rxbufA[offsetA + j] & 0x0F, rxbufA[offsetA + j] >> 4);
}
for (size_t j = 0; j < 2; j++) {
debug_log_cont(LOG_LEVEL_DEBUG, "%x %x ", rxbufB[offsetB + j] & 0x0F, rxbufB[offsetB + j] >> 4);
}
debug_log_cont(LOG_LEVEL_DEBUG, "\n");
}
}
uint8_t amsStartBalancing(uint8_t dutyCycle) { return writeCMD(UNMUTE, NULL, 0); }
CHECK_RETURN(writeCMD(WRPWMA, rxbufA, PWM_GROUP_A_SIZE));
CHECK_RETURN(writeCMD(WRPWMB, rxbufB, PWM_GROUP_B_SIZE));
uint8_t amsStopBalancing() { return writeCMD(MUTE, NULL, 0); }
return HAL_OK;
}
uint8_t amsSelfTest() { return 0; }
HAL_StatusTypeDef amsStartBalancing(uint8_t dutyCycle) { return writeCMD(UNMUTE, CMD_EMPTY_BUFFER, 0); }
uint8_t amsConfigOverUnderVoltage(uint16_t overVoltage, uint16_t underVoltage) {
uint8_t buffer[CFG_GROUP_A_SIZE];
HAL_StatusTypeDef amsStopBalancing() { return writeCMD(MUTE, CMD_EMPTY_BUFFER, 0); }
HAL_StatusTypeDef amsSelfTest() { return 0; }
HAL_StatusTypeDef amsConfigOverUnderVoltage(uint16_t overVoltage, uint16_t underVoltage) {
uint8_t buffer[CMD_BUFFER_SIZE(CFG_GROUP_B_SIZE)] = {};
if (underVoltage & 0xF000 || overVoltage & 0xF000) { // only 12 bits allowed
return 1;
return HAL_ERROR;
}
CHECK_RETURN(readCMD(RDCFGB, buffer, CFG_GROUP_A_SIZE));
debug_log(LOG_LEVEL_INFO, "Configuring OV/UV thresholds to %f/%f", mV_from_ADBMS6830(overVoltage), mV_from_ADBMS6830(underVoltage));
CHECK_RETURN(readCMD(RDCFGB, buffer, CFG_GROUP_B_SIZE));
for (size_t i = 0; i < N_BMS; i++) {
size_t offset = BUFFER_BMS_OFFSET(i, CFG_GROUP_B_SIZE);
//UV
buffer[0] = (uint8_t) (underVoltage & 0xFF);
buffer[1] &= 0xF0;
buffer[1] |= (uint8_t) ((underVoltage >> 8) & 0x0F);
buffer[offset + 0] = (uint8_t)(underVoltage & 0xFF);
buffer[offset + 1] &= 0xF0;
buffer[offset + 1] |= (uint8_t)((underVoltage >> 8) & 0x0F);
//OV
buffer[1] &= 0x0F;
buffer[1] |= (uint8_t) (overVoltage << 4);
buffer[2] = (uint8_t) (overVoltage >> 4);
return writeCMD(WRCFGB, buffer, CFG_GROUP_A_SIZE);
buffer[offset + 1] &= 0x0F;
buffer[offset + 1] |= (uint8_t)(overVoltage << 4);
buffer[offset + 2] = (uint8_t)(overVoltage >> 4);
}
uint8_t amsCheckUnderOverVoltage(Cell_Module* module) {
uint8_t regbuffer[STATUS_GROUP_D_SIZE];
uint32_t ov_uv_data = 0;
return writeCMD(WRCFGB, buffer, CFG_GROUP_B_SIZE);
}
HAL_StatusTypeDef amsCheckUnderOverVoltage(Cell_Module (*module)[N_BMS]) {
uint8_t regbuffer[CMD_BUFFER_SIZE(STATUS_GROUP_D_SIZE)] = {};
CHECK_RETURN(readCMD(RDSTATD, regbuffer, STATUS_GROUP_D_SIZE));
ov_uv_data = (regbuffer[0] << 0) | (regbuffer[1] << 8) |
(regbuffer[2] << 16) | (regbuffer[3] << 24);
module->overVoltage = 0;
module->underVoltage = 0;
for (size_t i = 0; i < N_BMS; i++) {
size_t offset = BUFFER_BMS_OFFSET(i, STATUS_GROUP_D_SIZE);
uint32_t ov_uv_data = 0;
ov_uv_data = (regbuffer[offset + 0] << 0) | (regbuffer[offset + 1] << 8) |
(regbuffer[offset + 2] << 16) | (regbuffer[offset + 3] << 24);
for (size_t i = 0; i < numberofCells; i++) { // ov/uv flags are 1-bit flags for each cell C0UV, C0OV, C1UV, C1OV, ...
module->underVoltage |= (ov_uv_data >> (i * 2)) & 0x01;
module->overVoltage |= (ov_uv_data >> (i * 2 + 1)) & 0x01;
module[i]->overVoltage = 0;
module[i]->underVoltage = 0;
for (size_t j = 0; j < numberofCells; j++) { // ov/uv flags are 1-bit flags for each cell C0UV, C0OV, C1UV, C1OV, ...
module[i]->underVoltage |= (ov_uv_data >> (j * 2)) & 0x01;
module[i]->overVoltage |= (ov_uv_data >> (j * 2 + 1)) & 0x01;
}
}
return 0;
return HAL_OK;
}
uint8_t amsClearFlag() {
uint8_t buffer[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
HAL_StatusTypeDef amsClearFlag() {
uint8_t buffer[CMD_BUFFER_SIZE(6)] = {[0 ... CMD_BUFFER_SIZE(6) - 1] = 0xFF};
return writeCMD(CLRFLAG, buffer, 6);
}
uint8_t amsClearAux() {
uint8_t buffer[6];
return writeCMD(CLRAUX, buffer, 0);
HAL_StatusTypeDef amsClearAux() {
return writeCMD(CLRAUX, CMD_EMPTY_BUFFER, 0);
}
uint8_t amsClearCells() {
uint8_t buffer[6];
return writeCMD(CLRCELL, buffer, 0);
}
HAL_StatusTypeDef amsReadCellVoltages(Cell_Module (*module)[N_BMS]) {
uint8_t rxbuffer[CMD_BUFFER_SIZE(CV_GROUP_A_SIZE)] = {};
uint8_t amsReadCellVoltages(Cell_Module* module) {
uint8_t rxbuffer[CV_GROUP_A_SIZE];
CHECK_RETURN(readCMD(RDCVA, rxbuffer, CV_GROUP_A_SIZE));
module->cellVoltages[0] = mV_from_ADBMS6830(rxbuffer[0] | (rxbuffer[1] << 8));
module->cellVoltages[1] = mV_from_ADBMS6830(rxbuffer[2] | (rxbuffer[3] << 8));
module->cellVoltages[2] = mV_from_ADBMS6830(rxbuffer[4] | (rxbuffer[5] << 8));
for (size_t i = 0; i < N_BMS; i++) {
size_t offset = BUFFER_BMS_OFFSET(i, CV_GROUP_A_SIZE);
module[i]->cellVoltages[0] = mV_from_ADBMS6830(rxbuffer[offset + 0] | (rxbuffer[offset + 1] << 8));
module[i]->cellVoltages[1] = mV_from_ADBMS6830(rxbuffer[offset + 2] | (rxbuffer[offset + 3] << 8));
module[i]->cellVoltages[2] = mV_from_ADBMS6830(rxbuffer[offset + 4] | (rxbuffer[offset + 5] << 8));
}
CHECK_RETURN(readCMD(RDCVB, rxbuffer, CV_GROUP_A_SIZE));
module->cellVoltages[3] = mV_from_ADBMS6830(rxbuffer[0] | (rxbuffer[1] << 8));
module->cellVoltages[4] = mV_from_ADBMS6830(rxbuffer[2] | (rxbuffer[3] << 8));
module->cellVoltages[5] = mV_from_ADBMS6830(rxbuffer[4] | (rxbuffer[5] << 8));
for (size_t i = 0; i < N_BMS; i++) {
size_t offset = BUFFER_BMS_OFFSET(i, CV_GROUP_A_SIZE);
module[i]->cellVoltages[3] = mV_from_ADBMS6830(rxbuffer[offset + 0] | (rxbuffer[offset + 1] << 8));
module[i]->cellVoltages[4] = mV_from_ADBMS6830(rxbuffer[offset + 2] | (rxbuffer[offset + 3] << 8));
module[i]->cellVoltages[5] = mV_from_ADBMS6830(rxbuffer[offset + 4] | (rxbuffer[offset + 5] << 8));
}
CHECK_RETURN(readCMD(RDCVC, rxbuffer, CV_GROUP_A_SIZE));
module->cellVoltages[6] = mV_from_ADBMS6830(rxbuffer[0] | (rxbuffer[1] << 8));
module->cellVoltages[7] = mV_from_ADBMS6830(rxbuffer[2] | (rxbuffer[3] << 8));
module->cellVoltages[8] = mV_from_ADBMS6830(rxbuffer[4] | (rxbuffer[5] << 8));
for (size_t i = 0; i < N_BMS; i++) {
size_t offset = BUFFER_BMS_OFFSET(i, CV_GROUP_A_SIZE);
module[i]->cellVoltages[6] = mV_from_ADBMS6830(rxbuffer[offset + 0] | (rxbuffer[offset + 1] << 8));
module[i]->cellVoltages[7] = mV_from_ADBMS6830(rxbuffer[offset + 2] | (rxbuffer[offset + 3] << 8));
module[i]->cellVoltages[8] = mV_from_ADBMS6830(rxbuffer[offset + 4] | (rxbuffer[offset + 5] << 8));
}
CHECK_RETURN(readCMD(RDCVD, rxbuffer, CV_GROUP_A_SIZE));
module->cellVoltages[9] = mV_from_ADBMS6830(rxbuffer[0] | (rxbuffer[1] << 8));
module->cellVoltages[10] = mV_from_ADBMS6830(rxbuffer[2] | (rxbuffer[3] << 8));
module->cellVoltages[11] = mV_from_ADBMS6830(rxbuffer[4] | (rxbuffer[5] << 8));
for (size_t i = 0; i < N_BMS; i++) {
size_t offset = BUFFER_BMS_OFFSET(i, CV_GROUP_A_SIZE);
module[i]->cellVoltages[9] = mV_from_ADBMS6830(rxbuffer[offset + 0] | (rxbuffer[offset + 1] << 8));
module[i]->cellVoltages[10] = mV_from_ADBMS6830(rxbuffer[offset + 2] | (rxbuffer[offset + 3] << 8));
module[i]->cellVoltages[11] = mV_from_ADBMS6830(rxbuffer[offset + 4] | (rxbuffer[offset + 5] << 8));
}
CHECK_RETURN(readCMD(RDCVE, rxbuffer, CV_GROUP_A_SIZE));
module->cellVoltages[12] = mV_from_ADBMS6830(rxbuffer[0] | (rxbuffer[1] << 8));
module->cellVoltages[13] = mV_from_ADBMS6830(rxbuffer[2] | (rxbuffer[3] << 8));
module->cellVoltages[14] = mV_from_ADBMS6830(rxbuffer[4] | (rxbuffer[5] << 8));
for (size_t i = 0; i < N_BMS; i++) {
size_t offset = BUFFER_BMS_OFFSET(i, CV_GROUP_A_SIZE);
module[i]->cellVoltages[12] = mV_from_ADBMS6830(rxbuffer[offset + 0] | (rxbuffer[offset + 1] << 8));
module[i]->cellVoltages[13] = mV_from_ADBMS6830(rxbuffer[offset + 2] | (rxbuffer[offset + 3] << 8));
module[i]->cellVoltages[14] = mV_from_ADBMS6830(rxbuffer[offset + 4] | (rxbuffer[offset + 5] << 8));
}
CHECK_RETURN(readCMD(RDCVF, rxbuffer, CV_GROUP_A_SIZE));
module->cellVoltages[15] = mV_from_ADBMS6830(rxbuffer[0] | (rxbuffer[1] << 8));
return 0;
for (size_t i = 0; i < N_BMS; i++) {
size_t offset = BUFFER_BMS_OFFSET(i, CV_GROUP_A_SIZE);
module[i]->cellVoltages[15] = mV_from_ADBMS6830(rxbuffer[offset + 0] | (rxbuffer[offset + 1] << 8));
}
return HAL_OK;
}

View File

@ -20,7 +20,6 @@
#warning ask about the timeout value
SPI_HandleTypeDef* adbmsspi;
uint8_t command_queue[N_BMS][12] = {0};
uint8_t adbmsDriverInit(SPI_HandleTypeDef* hspi) {
mcuAdbmsCSLow();
@ -49,210 +48,87 @@ static HAL_StatusTypeDef mcuSPITransmitReceive(uint8_t* rxbuffer, uint8_t* txbuf
//CRC-15
//x^15 + x^14 + x^10 + x^8 + x^7 + x^4 + x^3 + 1
static uint16_t updateCommandPEC(uint16_t currentPEC, uint8_t din) {
din = (din >> 7) & 0x01;
uint8_t in0 = din ^ ((currentPEC >> 14) & 0x01);
uint8_t in3 = in0 ^ ((currentPEC >> 2) & 0x01);
uint8_t in4 = in0 ^ ((currentPEC >> 3) & 0x01);
uint8_t in7 = in0 ^ ((currentPEC >> 6) & 0x01);
uint8_t in8 = in0 ^ ((currentPEC >> 7) & 0x01);
uint8_t in10 = in0 ^ ((currentPEC >> 9) & 0x01);
uint8_t in14 = in0 ^ ((currentPEC >> 13) & 0x01);
uint16_t newPEC = 0;
newPEC |= in14 << 14;
newPEC |= (currentPEC & (0x01 << 12)) << 1;
newPEC |= (currentPEC & (0x01 << 11)) << 1;
newPEC |= (currentPEC & (0x01 << 10)) << 1;
newPEC |= in10 << 10;
newPEC |= (currentPEC & (0x01 << 8)) << 1;
newPEC |= in8 << 8;
newPEC |= in7 << 7;
newPEC |= (currentPEC & (0x01 << 5)) << 1;
newPEC |= (currentPEC & (0x01 << 4)) << 1;
newPEC |= in4 << 4;
newPEC |= in3 << 3;
newPEC |= (currentPEC & (0x01 << 1)) << 1;
newPEC |= (currentPEC & (0x01)) << 1;
newPEC |= in0;
return newPEC;
static uint16_t computeCRC15(const uint8_t* data, size_t length) {
uint16_t remainder = INITIAL_COMMAND_PEC;
for (size_t i = 0; i < length; i++) {
remainder ^= (data[i] << 7);
for (int b = 0; b < 8; b++) {
if (remainder & 0x4000) {
remainder = (uint16_t)((remainder << 1) ^ 0xC599);
} else {
remainder <<= 1;
}
}
}
return remainder;
}
static uint8_t calculateCommandPEC(uint8_t* data, uint8_t datalen) {
uint16_t currentpec = INITIAL_COMMAND_PEC;
if (datalen >= 3) {
for (int i = 0; i < (datalen - 2); i++) {
for (int n = 0; n < 8; n++) {
uint8_t din = data[i] << (n);
currentpec = updateCommandPEC(currentpec, din);
}
}
data[datalen - 2] = (currentpec >> 7) & 0xFF;
data[datalen - 1] = (currentpec << 1) & 0xFF;
if (datalen < 3) { return 1; }
uint16_t pec = computeCRC15(data, datalen - 2);
data[datalen - 2] = (uint8_t)((pec >> 7) & 0xFF);
data[datalen - 1] = (uint8_t)((pec << 1) & 0xFF);
return 0;
} else {
return 1;
}
}
static uint8_t checkCommandPEC(uint8_t* data, uint8_t datalen) {
if (datalen <= 3) {
return 255;
}
uint16_t currentpec = INITIAL_COMMAND_PEC;
for (int i = 0; i < (datalen - 2); i++) {
for (int n = 0; n < 8; n++) {
uint8_t din = data[i] << (n);
currentpec = updateCommandPEC(currentpec, din);
}
}
uint8_t pechigh = (currentpec >> 7) & 0xFF;
uint8_t peclow = (currentpec << 1) & 0xFF;
if ((pechigh == data[datalen - 2]) && (peclow == data[datalen - 1])) {
return 0;
}
return 1;
if (datalen <= 3) { return 255; }
uint16_t pec = computeCRC15(data, datalen - 2);
uint8_t pech = (uint8_t)((pec >> 7) & 0xFF);
uint8_t pecl = (uint8_t)((pec << 1) & 0xFF);
return ((pech == data[datalen - 2]) && (pecl == data[datalen - 1])) ? 0 : 1;
}
//data PEC calculation
//CRC-10
//x^10 + x^7 + x^3 + x^2 + x + 1
static uint16_t pec10_calc(bool rx_cmd, int len, uint8_t* data) {
uint16_t remainder = 16; /* PEC_SEED; 0000010000 */
uint16_t polynom = 0x8F; /* x10 + x7 + x3 + x2 + x + 1 <- the CRC15 polynomial
100 1000 1111 48F */
static uint16_t computeCRC10(const uint8_t* data, size_t length, bool rx_cmd) {
uint16_t remainder = INITIAL_DATA_PEC;
const uint16_t poly = 0x8F;
size_t limit = length;
/* Perform modulo-2 division, a byte at a time. */
for (uint8_t pbyte = 0; pbyte < len; ++pbyte) {
/* Bring the next byte into the remainder. */
remainder ^= (uint16_t)(data[pbyte] << 2);
/* Perform modulo-2 division, a bit at a time.*/
for (uint8_t bit_ = 8; bit_ > 0; --bit_) {
/* Try to divide the current data bit. */
if ((remainder & 0x200) >
0) // equivalent to remainder & 2^14 simply check for MSB
{
remainder = (uint16_t)((remainder << 1));
remainder = (uint16_t)(remainder ^ polynom);
} else {
remainder = (uint16_t)(remainder << 1);
}
}
}
if (rx_cmd == true) {
remainder ^= (uint16_t)((data[len] & 0xFC) << 2);
/* Perform modulo-2 division, a bit at a time */
for (uint8_t bit_ = 6; bit_ > 0; --bit_) {
/* Try to divide the current data bit */
if ((remainder & 0x200) >
0) // equivalent to remainder & 2^14 simply check for MSB
{
remainder = (uint16_t)((remainder << 1));
remainder = (uint16_t)(remainder ^ polynom);
} else {
remainder = (uint16_t)((remainder << 1));
}
}
}
return ((uint16_t)(remainder & 0x3FF));
if (rx_cmd && (length > 0)) {
limit = length - 1;
}
typedef uint16_t crc;
static crc F_CRC_CalculaCheckSum(uint8_t const AF_Datos[], uint16_t VF_nBytes);
for (size_t i = 0; i < limit; i++) {
remainder ^= (uint16_t)(data[i] << 2);
for (int b = 0; b < 8; b++) {
if (remainder & 0x200) {
remainder = (uint16_t)((remainder << 1) ^ poly);
} else {
remainder <<= 1;
}
}
}
// If receiving a command, handle leftover bits
if (rx_cmd && (length > 0)) {
remainder ^= (uint16_t)((data[length - 1] & 0xFC) << 2);
for (int b = 0; b < 6; b++) {
if (remainder & 0x200) {
remainder = (uint16_t)((remainder << 1) ^ poly);
} else {
remainder <<= 1;
}
}
}
return (uint16_t)(remainder & 0x3FF);
}
static uint8_t calculateDataPEC(uint8_t* data, uint8_t datalen) {
if (datalen >= 3) {
crc currentpec = pec10_calc(true, datalen - 2, data) & 0x3FF; // mask to 10 bits
// memory layout is [[zeroes], PEC[9:8]], [PEC[7:0]]
data[datalen - 2] = (currentpec >> 8) & 0xFF;
data[datalen - 1] = currentpec & 0xFF;
volatile uint8_t result = pec10_calc(true, datalen, data);
if (datalen < 3) { return 1; }
uint16_t crcVal = computeCRC10(data, datalen - 2, true);
data[datalen - 2] = (uint8_t)((crcVal >> 8) & 0xFF);
data[datalen - 1] = (uint8_t)(crcVal & 0xFF);
return 0;
} else {
return 1;
}
}
static uint8_t checkDataPEC(uint8_t* data, uint8_t len) {
if (len <= 2) {
return 255;
}
crc currentpec = F_CRC_CalculaCheckSum(data, len);
return (currentpec == 0) ? 0 : 1;
}
static crc F_CRC_ObtenValorDeTabla(uint8_t VP_Pos_Tabla) {
crc VP_CRCTableValue = 0;
uint8_t VP_Pos_bit = 0;
VP_CRCTableValue = ((crc)(VP_Pos_Tabla)) << (10 - 8);
for (VP_Pos_bit = 0; VP_Pos_bit < 8; VP_Pos_bit++) {
if (VP_CRCTableValue & (((crc)1) << (10 - 1))) {
VP_CRCTableValue = (VP_CRCTableValue << 1) ^ 0x8F;
} else {
VP_CRCTableValue = (VP_CRCTableValue << 1);
}
}
return ((VP_CRCTableValue));
}
static crc F_CRC_CalculaCheckSum(uint8_t const AF_Datos[], uint16_t VF_nBytes) {
crc VP_CRCTableValue = 16;
int16_t VP_bytes = 0;
for (VP_bytes = 0; VP_bytes < VF_nBytes; VP_bytes++) {
VP_CRCTableValue = (VP_CRCTableValue << 8) ^
F_CRC_ObtenValorDeTabla(
((uint8_t)((VP_CRCTableValue >> (10 - 8)) & 0xFF)) ^
AF_Datos[VP_bytes]);
}
if ((8 * sizeof(crc)) > 10) {
VP_CRCTableValue = VP_CRCTableValue & ((((crc)(1)) << 10) - 1);
}
return (VP_CRCTableValue ^ 0x0000);
}
static uint16_t updateDataPEC(uint16_t currentPEC, uint8_t din) {
din = (din >> 7) & 0x01;
uint8_t in0 = din ^ ((currentPEC >> 9) & 0x01);
uint8_t in2 = in0 ^ ((currentPEC >> 1) & 0x01);
uint8_t in3 = in0 ^ ((currentPEC >> 2) & 0x01);
uint8_t in7 = in0 ^ ((currentPEC >> 6) & 0x01);
uint16_t newPEC = 0;
newPEC |= (currentPEC & (0x01 << 8)) << 1;
newPEC |= (currentPEC & (0x01 << 7)) << 1;
newPEC |= in7 << 7;
newPEC |= (currentPEC & (0x01 << 5)) << 1;
newPEC |= (currentPEC & (0x01 << 4)) << 1;
newPEC |= in3 << 3;
newPEC |= in2 << 2;
newPEC |= (currentPEC & (0x01)) << 1;
newPEC |= in0;
return newPEC;
if (len <= 2) { return 255; }
// Zero remainder means a valid CRC.
return (computeCRC10(data, len, false) == 0) ? 0 : 1;
}
HAL_StatusTypeDef ___writeCMD(uint16_t command, uint8_t * args, size_t arglen) {
@ -297,15 +173,13 @@ HAL_StatusTypeDef ___writeCMD(uint16_t command, uint8_t * args, size_t arglen) {
return ret;
}
HAL_StatusTypeDef readCMD(uint16_t command, uint8_t * buffer, size_t buflen) {
HAL_StatusTypeDef ___readCMD(uint16_t command, uint8_t * buffer, size_t arglen) {
buffer[0] = (command >> 8) & 0xFF;
buffer[1] = (command)&0xFF;
calculateCommandPEC(buffer, 4);
mcuAdbmsCSLow();
HAL_StatusTypeDef status = mcuSPITransmitReceive(buffer, buffer, buflen);
HAL_StatusTypeDef status = mcuSPITransmitReceive(buffer, buffer, CMD_BUFFER_SIZE(arglen));
mcuAdbmsCSHigh();
if (status != HAL_OK) return status;
@ -319,35 +193,41 @@ HAL_StatusTypeDef readCMD(uint16_t command, uint8_t * buffer, size_t buflen) {
//print out data bytes
for (size_t i = 0; i < N_BMS; i++) {
debug_log_cont(LOG_LEVEL_NOISY, "%d: ", i);
for (size_t j = 0; j < buflen; j++) {
debug_log_cont(LOG_LEVEL_NOISY, "%x ", buffer[4 + (i * (buflen + 2)) + j]);
for (size_t j = 0; j < arglen; j++) {
debug_log_cont(LOG_LEVEL_NOISY, "%x ", buffer[4 + (i * (arglen + 2)) + j]);
}
}
debug_log_cont(LOG_LEVEL_NOISY, "\n");
}
return checkDataPEC(&buffer[4], buflen + 2);
//check data PEC
for (size_t i = 0; i < N_BMS; i++) {
size_t offset = BUFFER_BMS_OFFSET(i, arglen);
if (checkDataPEC(&buffer[offset], arglen + 2) != 0) {
return HAL_ERROR;
}
}
return HAL_OK;
}
//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() {

View File

@ -15,7 +15,7 @@
#include <stdint.h>
#include <string.h>
Cell_Module module = {};
Cell_Module modules[N_BMS] = {};
uint32_t balancedCells = 0;
bool balancingActive = false;
@ -41,15 +41,25 @@ void AMS_Init(SPI_HandleTypeDef* hspi) {
pollingTimes = (struct pollingTimes) {HAL_GetTick(), HAL_GetTick()};
}
#define any(x) ({ \
bool any = false; \
for (size_t i = 0; i < N_BMS; i++) { \
Cell_Module module = modules[i]; \
any |= (x); \
} \
any; \
})
uint8_t AMS_Idle_Loop() {
if (!amsWakeUp()) {
//error_data.data_kind = SEK_INTERNAL_BMS_TIMEOUT; //we don't receive data for the wakeup command
//set_error_source(ERROR_SOURCE_INTERNAL); //so we can't tell if we timed out
}
packetChecksumFails += amsAuxAndStatusMeasurement(&module);
packetChecksumFails += amsAuxAndStatusMeasurement(&modules);
if (module.status.SLEEP) {
if (any(module.status.SLEEP)) {
deviceSleeps++;
if (deviceSleeps > MAX_DEVICE_SLEEP) {
set_error_source(SEK_INTERNAL_BMS_TIMEOUT);
@ -58,14 +68,17 @@ uint8_t AMS_Idle_Loop() {
}
}
if (module.status.CS_FLT || module.status.SPIFLT || module.status.CMED ||
module.status.SMED || module.status.VDE || module.status.VDEL ||
module.status.OSCCHK || module.status.TMODCHK) {
if (any(module.status.CS_FLT || module.status.SPIFLT || module.status.CMED || module.status.SMED ||
module.status.VDE || module.status.VDEL || module.status.OSCCHK || module.status.TMODCHK)) {
// TODO: handle errors
// ftcan_marshal_unsigned(&error_data[SEK_INTERNAL_BMS_FAULT].data[0], module.status.CS_FLT, 2);
const uint8_t* ptr = ((uint8_t*)&module.status) + 4; //skip conversion counter
/* const uint8_t* ptr = ((uint8_t*)&modules.status) + 4; //skip conversion counter
error_data[SEK_INTERNAL_BMS_FAULT].data[2] = ptr[1];
error_data[SEK_INTERNAL_BMS_FAULT].data[3] = ptr[0];
set_error_source(SEK_INTERNAL_BMS_FAULT);
set_error_source(SEK_INTERNAL_BMS_FAULT); */
// Fault bits are latched -- clear them so we can check again next
// iteration.
amsClearFlag();
@ -73,8 +86,8 @@ uint8_t AMS_Idle_Loop() {
clear_error_source(SEK_INTERNAL_BMS_FAULT);
}
packetChecksumFails += amsCellMeasurement(&module);
packetChecksumFails += amsCheckUnderOverVoltage(&module);
packetChecksumFails += amsCellMeasurement(&modules);
packetChecksumFails += amsCheckUnderOverVoltage(&modules);
if (packetChecksumFails > MAX_PACKET_CHECKSUM_FAILS) {
set_error_source(SEK_INTERNAL_BMS_CHECKSUM_FAIL);
@ -85,12 +98,12 @@ uint8_t AMS_Idle_Loop() {
bool overvolt = false;
bool undervolt = false;
for (size_t i = 0; i < numberofCells; i++) {
if (module.cellVoltages[i] < 2500) {
if (any(module.cellVoltages[i] < 2500)) {
undervolt = true;
error_data[SEK_UNDERVOLT].data[0] = i;
uint8_t* ptr = &error_data[SEK_UNDERVOLT].data[1];
//ftcan_marshal_unsigned(ptr, module.cellVoltages[i], 2);
} else if (module.cellVoltages[i] > 4200) {
} else if (any(module.cellVoltages[i] > 4200)) {
overvolt = true;
error_data[SEK_OVERVOLT].data[0] = i;
uint8_t* ptr = &error_data[SEK_OVERVOLT].data[1];
@ -98,7 +111,7 @@ uint8_t AMS_Idle_Loop() {
}
}
if (module.internalDieTemp > 28000 || module.status.THSD) { //TODO: change to correct value
if (any(module.internalDieTemp > 28000 || module.status.THSD)) { //TODO: change to correct value
//ftcan_marshal_unsigned(&error_data[SEK_INTERNAL_BMS_OVERTEMP].data[0], module.internalDieTemp, 2);
set_error_source(SEK_INTERNAL_BMS_OVERTEMP);
@ -120,9 +133,5 @@ uint8_t AMS_Idle_Loop() {
mcuDelay(10);
if ((module.overVoltage | module.underVoltage)) {
}
return 0;
}

View File

@ -163,7 +163,7 @@ int main(void)
MX_ADC2_Init();
/* USER CODE BEGIN 2 */
can_init(&hfdcan1);
slaves_init();
slaves_init(&hspi1);
shunt_init();
ts_sm_init();
soc_init();

View File

@ -1,5 +1,6 @@
#include "slave_monitoring.h"
#include "AMS_HighLevel.h"
#include "can.h"
#include "main.h"
#include "ts_state_machine.h"
@ -34,7 +35,7 @@ static size_t get_slave_index(uint8_t slave_id) {
return slave_id_to_index[slave_id];
}
void slaves_init() {
void slaves_init(SPI_HandleTypeDef *hspi) {
memset(slave_id_to_index, 0xFF, sizeof(slave_id_to_index));
for (int i = 0; i < N_SLAVES; i++) {
slaves[i].id = 0xFF;
@ -45,6 +46,8 @@ void slaves_init() {
slaves[i].max_temp = 0;
}
AMS_Init(hspi);
//HAL_GPIO_WritePin(SLAVE_POWER_0_GPIO_Port, SLAVE_POWER_0_Pin, GPIO_PIN_SET);
//HAL_GPIO_WritePin(SLAVE_POWER_1_GPIO_Port, SLAVE_POWER_1_Pin, GPIO_PIN_SET);
//HAL_GPIO_WritePin(SLAVE_POWER_DSEL_GPIO_Port, SLAVE_POWER_DSEL_Pin,
@ -58,6 +61,10 @@ void slaves_check() {
int any_slave_error = 0;
TSErrorKind slave_error = TS_ERRORKIND_NONE;
AMS_Idle_Loop();
//TODO: rewrite to use data from BMS driver
uint32_t now = HAL_GetTick();
uint16_t min_voltage_new = 0xFFFF;
int16_t max_temp_new = 0xFFFF;