Compare commits

...

5 Commits

Author SHA1 Message Date
f3cae7b757
use standard uintxx_t types 2025-01-22 18:50:20 +01:00
fb93bc5018
read out IDs as test for functionality 2025-01-22 18:35:23 +01:00
96b069a5a5
add daisy chain isospi 2025-01-22 18:03:29 +01:00
7f3eac554e
more cleanup 2025-01-20 19:53:17 +01:00
975bc6ad58
pretty up logging 2025-01-20 19:16:46 +01:00
8 changed files with 309 additions and 250 deletions

View File

@ -13,6 +13,8 @@
#include <stdarg.h>
#include <stdio.h>
#define MAX_MESSAGE_LENGTH 256
enum log_level_t {
LOG_LEVEL_NOISY,
LOG_LEVEL_DEBUG,
@ -22,7 +24,7 @@ enum log_level_t {
LOG_LEVEL_FATAL
};
[[maybe_unused]] static const char * log_level_names[] = {
[[maybe_unused]] static const char * const log_level_names[] = {
"\033[37m[NOISY]\033[0m ",
"\033[37m[DEBUG]\033[0m ",
"\033[97m[INFO] \033[0m ",
@ -38,12 +40,11 @@ static inline bool __ITM_channel_enabled(uint32_t channel) {
// adapted from ITM_SendChar() in the CMSIS-Core
//
// channel should be between 0 and 31
__STATIC_INLINE uint32_t __swo_putc (uint32_t c, unsigned int channel) {
static inline uint32_t __swo_putc(uint32_t c, unsigned int channel) {
if (((ITM->TCR & ITM_TCR_ITMENA_Msk) != 0UL) && /* ITM enabled */
((ITM->TER & (1UL << channel)) != 0UL)) /* ITM Port enabled */
{
while (ITM->PORT[channel].u32 == 0UL)
{
while (ITM->PORT[channel].u32 == 0UL) {
__NOP();
}
ITM->PORT[channel].u8 = (uint8_t)c;
@ -51,30 +52,46 @@ __STATIC_INLINE uint32_t __swo_putc (uint32_t c, unsigned int channel) {
return (c);
}
static inline void __swo_print(const char *str, unsigned int channel) {
if (!__ITM_channel_enabled(channel))
{
#define DEBUG_CHANNEL_ENABLED(channel) ({ \
unsigned int ch = (channel); \
(ch < 32) ? __ITM_channel_enabled(ch) : false; \
})
[[gnu::nonnull(2), gnu::null_terminated_string_arg(2)]]
static inline void __swo_print(unsigned int channel, const char *str) {
if (!__ITM_channel_enabled(channel)) {
return;
}
while(*str)
{
while (*str) {
__swo_putc(*str++, channel);
}
}
//Print a message to the SWO interface
//
//Each log level is printed to a different ITM channel
static inline void debug_log(enum log_level_t level, const char *msg, ...) {
va_list args;
va_start(args, msg);
char buffer[256];
vsnprintf(buffer, sizeof(buffer), msg, args);
va_end(args);
__swo_print(log_level_names[level], level);
__swo_print(buffer, level);
__swo_putc('\n', level);
}
#define debug_log(level, msg, ...) \
do { \
if (DEBUG_CHANNEL_ENABLED(level)) { \
char buffer[MAX_MESSAGE_LENGTH]; \
size_t len = snprintf(buffer, sizeof(buffer), msg, ##__VA_ARGS__); \
__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)
#define debug_log_cont(level, msg, ...) \
do { \
if (DEBUG_CHANNEL_ENABLED(level)) { \
char buffer[MAX_MESSAGE_LENGTH]; \
size_t len = snprintf(buffer, sizeof(buffer), msg, ##__VA_ARGS__); \
__swo_print(level, buffer); \
if (len >= sizeof(buffer)) { \
__swo_print(level, " [message length exceeded] "); \
} \
__swo_putc('\n', level); \
} \
} while (0)
#endif /* __SWO_LOG_H */

View File

@ -24,25 +24,25 @@
#define mV_from_ADBMS6830(x) (((((int16_t) (x))) * 0.150) + 1500)
struct ADBMS6830_Internal_Status {
uint16 CS_FLT : 16; //ADC fault - mismatch between S- and C-ADC
uint16 : 3;
uint16 CCTS : 13; //Conversion counter
uint16 SMED : 1; //S-ADC multiple trim error (uncorrectable)
uint16 SED : 1; //S-ADC single trim error (correctable)
uint16 CMED : 1; //C-ADC multiple trim error (uncorrectable)
uint16 CED : 1; //C-ADC single trim error (correctable)
uint16 VD_UV : 1; //3V digital supply undervoltage
uint16 VD_OV : 1; //3V digital supply overvoltage
uint16 VA_UV : 1; //5V analog supply undervoltage
uint16 VA_OV : 1; //5V analog supply overvoltage
uint16 OSCCHK : 1; //Oscillator check
uint16 TMODCHK : 1; //Test mode check
uint16 THSD : 1; //Thermal shutdown
uint16 SLEEP : 1; //Sleep mode previously entered
uint16 SPIFLT : 1; //SPI fault
uint16 COMPARE : 1; //Comparasion between S- and C-ADC active
uint16 VDE : 1; //Supply voltage error
uint16 VDEL : 1; //Latent supply voltage error
uint16_t CS_FLT : 16; //ADC fault - mismatch between S- and C-ADC
uint16_t : 3;
uint16_t CCTS : 13; //Conversion counter
uint16_t SMED : 1; //S-ADC multiple trim error (uncorrectable)
uint16_t SED : 1; //S-ADC single trim error (correctable)
uint16_t CMED : 1; //C-ADC multiple trim error (uncorrectable)
uint16_t CED : 1; //C-ADC single trim error (correctable)
uint16_t VD_UV : 1; //3V digital supply undervoltage
uint16_t VD_OV : 1; //3V digital supply overvoltage
uint16_t VA_UV : 1; //5V analog supply undervoltage
uint16_t VA_OV : 1; //5V analog supply overvoltage
uint16_t OSCCHK : 1; //Oscillator check
uint16_t TMODCHK : 1; //Test mode check
uint16_t THSD : 1; //Thermal shutdown
uint16_t SLEEP : 1; //Sleep mode previously entered
uint16_t SPIFLT : 1; //SPI fault
uint16_t COMPARE : 1; //Comparasion between S- and C-ADC active
uint16_t VDE : 1; //Supply voltage error
uint16_t VDEL : 1; //Latent supply voltage error
};
typedef struct {
@ -50,57 +50,57 @@ typedef struct {
int16_t auxVoltages[MAXIMUM_AUX_VOLTAGES];
struct ADBMS6830_Internal_Status status;
uint16 internalDieTemp;
uint16 analogSupplyVoltage;
uint16 digitalSupplyVoltage;
uint16 sumOfCellMeasurements;
uint16 refVoltage;
uint16_t internalDieTemp;
uint16_t analogSupplyVoltage;
uint16_t digitalSupplyVoltage;
uint16_t sumOfCellMeasurements;
uint16_t refVoltage;
uint16 GPIO_Values[MAXIMUM_GPIO];
uint16_t GPIO_Values[MAXIMUM_GPIO];
uint32 overVoltage;
uint32 underVoltage;
uint32_t overVoltage;
uint32_t underVoltage;
} Cell_Module;
uint8 amsReset();
uint8_t amsReset();
uint8 initAMS(SPI_HandleTypeDef* hspi, uint8 numofcells, uint8 numofaux);
uint8 amsWakeUp();
uint8_t initAMS(SPI_HandleTypeDef* hspi);
uint8_t amsWakeUp();
uint8 amsCellMeasurement(Cell_Module* module);
uint8 amsConfigCellMeasurement(uint8 numberofChannels);
uint8_t amsCellMeasurement(Cell_Module* module);
uint8_t amsConfigCellMeasurement(uint8_t numberofChannels);
uint8 amsAuxAndStatusMeasurement(Cell_Module* module);
uint8 amsConfigAuxMeasurement(uint16 Channels);
uint8_t amsAuxAndStatusMeasurement(Cell_Module* module);
uint8_t amsConfigAuxMeasurement(uint16_t Channels);
uint8 amsConfigGPIO(uint16 gpios);
uint8 amsSetGPIO(uint16 gpios);
uint8 readGPIO(Cell_Module* module);
uint8_t amsConfigGPIO(uint16_t gpios);
uint8_t amsSetGPIO(uint16_t gpios);
uint8_t readGPIO(Cell_Module* module);
uint8 amsConfigBalancing(uint32 Channels, uint8 dutyCycle);
uint8 amsStartBalancing(uint8 dutyCycle);
uint8 amsStopBalancing();
uint8_t amsConfigBalancing(uint32_t Channels, uint8_t dutyCycle);
uint8_t amsStartBalancing(uint8_t dutyCycle);
uint8_t amsStopBalancing();
uint8 amsSelfTest();
uint8_t amsSelfTest();
uint8 amsConfigOverUnderVoltage(uint16 overVoltage, uint16 underVoltage);
uint8_t amsConfigOverUnderVoltage(uint16_t overVoltage, uint16_t underVoltage);
uint8 amsCheckUnderOverVoltage(Cell_Module* module);
uint8 amsConfigOverVoltage(uint16 overVoltage);
uint8_t amsCheckUnderOverVoltage(Cell_Module* module);
uint8_t amsConfigOverVoltage(uint16_t overVoltage);
uint8 amscheckOpenCellWire(Cell_Module* module);
uint8_t amscheckOpenCellWire(Cell_Module* module);
uint8 amsClearFlag();
uint8 amsClearAux();
uint8 amsClearCells();
uint8_t amsClearFlag();
uint8_t amsClearAux();
uint8_t amsClearCells();
uint8 amsSendWarning();
uint8 amsSendError();
uint8_t amsSendWarning();
uint8_t amsSendError();
uint8 amsClearWarning();
uint8 amsClearError();
uint8_t amsClearWarning();
uint8_t amsClearError();
uint8 amsReadCellVoltages(Cell_Module* module);
uint8_t amsReadCellVoltages(Cell_Module* module);
#endif /* INC_ADBMS_ABSTRACTION_H_ */

View File

@ -83,6 +83,8 @@
#define MUTE 0x0028 // Mute Discharge
#define UNMUTE 0x0029 // Unmute Discharge
#define RDSID 0x002C // Read Serial ID
/* GPIO Selection for ADC Converion
@ -168,4 +170,6 @@
#define PWM_GROUP_ID 17
#define PWM_S_CONTROL_GROUP_B_ID 18
#define SID_GROUP_SIZE 6
#endif /* INC_ADBMS_CMD_MAKROS_H_ */

View File

@ -8,26 +8,55 @@
#ifndef ADBMS_LL_DRIVER_H_
#define ADBMS_LL_DRIVER_H_
#include "config_ADBMS6830.h"
#include "stm32h7xx_hal.h"
#include <stdint.h>
#define TARGET_STM32
#ifdef TARGET_STM32
typedef uint8_t uint8;
typedef uint16_t uint16;
typedef uint32_t uint32;
#endif
uint8 adbmsDriverInit(SPI_HandleTypeDef* hspi);
uint8_t adbmsDriverInit(SPI_HandleTypeDef* hspi);
//2 command + 2 PEC + (data + 2 DPEC) per BMS
#define CMD_BUFFER_SIZE(datalen) (4 + (N_BMS * (datalen + 2)))
#define BUFFER_BMS_OFFSET(bms, datalen) (4 + (bms * (datalen + 2)))
#define CMD_EMPTY_BUFFER ((uint8_t[CMD_BUFFER_SIZE(0)]){0})
#define CMD_EMPTY_BUFFER_SIZE CMD_BUFFER_SIZE(0)
//macro to function for better type checking (access attribute)
[[gnu::access(read_only, 4, 1)]]
static inline void __modify_writeCMD_args(size_t arglen, uint8_t args[static restrict N_BMS * (arglen + 2)], uint8_t bms, uint8_t * restrict data) {
for (uint8_t i = 0; i < arglen; i++) {
args[(bms * (arglen + 2)) + i] = data[i];
}
}
#define modify_writeCMD_args(args, bms, data) \
static_assert(bms < N_BMS, "bms out of range"); \
__modify_writeCMD_args(args.arglen, args.args + 4, bms, data)
HAL_StatusTypeDef ___writeCMD(uint16_t command, uint8_t * args, size_t arglen);
[[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 __writeCMD(uint16_t command, uint8_t * args, size_t arglen, size_t _) {
return ___writeCMD(command, args, arglen);
}
#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);
uint8_t pollCMD(uint16_t command);
uint8 writeCMD(uint16 command, uint8* args, uint8 arglen);
uint8 readCMD(uint16 command, uint8* buffer, uint8 buflen);
uint8 pollCMD(uint16 command);
void mcuAdbmsCSLow();
void mcuAdbmsCSHigh();
uint8 wakeUpCmd();
static inline void mcuDelay(uint16 delay) { HAL_Delay(delay); };
uint8_t wakeUpCmd();
static inline void mcuDelay(uint16_t delay) { HAL_Delay(delay); };
#endif /* ADBMS_LL_DRIVER_H_ */

View File

@ -30,7 +30,6 @@ extern uint32_t balancedCells;
extern bool BalancingActive;
extern uint8_t numberofCells;
extern uint8_t numberofAux;
void AMS_Init(SPI_HandleTypeDef* hspi);

View File

@ -8,28 +8,44 @@
#include "ADBMS_Abstraction.h"
#include "ADBMS_CMD_MAKROS.h"
#include "ADBMS_LL_Driver.h"
#include "swo_log.h"
#include <stddef.h>
uint8 numberofcells;
uint8 numberofauxchannels;
extern uint8_t numberofCells;
#define CHECK_RETURN(x) \
{ \
uint8 status = x; \
uint8_t status = x; \
if (status != 0) \
return status; \
}
uint8 amsReset() {
uint8_t amsReset() {
amsWakeUp();
readCMD(SRST, NULL, 0);
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)));
debug_log(LOG_LEVEL_INFO, "BMS reset complete\n");
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);
}
debug_log_cont(LOG_LEVEL_INFO, "0x%llx ", id);
}
debug_log_cont(LOG_LEVEL_INFO, "\n");
}
mcuDelay(10);
amsWakeUp();
amsStopBalancing();
amsConfigOverUnderVoltage(DEFAULT_OV, DEFAULT_UV);
uint8 buffer[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
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
@ -38,32 +54,24 @@ uint8 amsReset() {
return 0;
}
uint8 initAMS(SPI_HandleTypeDef* hspi, uint8 numofcells, uint8 numofaux) {
uint8_t initAMS(SPI_HandleTypeDef* hspi) {
adbmsDriverInit(hspi);
numberofcells = numofcells;
numberofauxchannels = numofaux;
return amsReset();
}
uint8 amsWakeUp() {
uint8 buf[6];
return readCMD(RDCFGA, buf, 6);
uint8_t amsWakeUp() {
uint8_t buffer[CMD_BUFFER_SIZE(CFG_GROUP_A_SIZE)] = {0};
return readCMD(RDCFGA, buffer, CMD_BUFFER_SIZE(CFG_GROUP_A_SIZE));
}
uint8 amsCellMeasurement(Cell_Module* module) {
uint8_t 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 amsConfigCellMeasurement(uint8 numberofChannels) {
numberofcells = numberofChannels;
return 0;
}
uint8 amsAuxAndStatusMeasurement(Cell_Module* module) {
uint8 rxbuf[AUX_GROUP_A_SIZE] = {};
uint8_t amsAuxAndStatusMeasurement(Cell_Module* module) {
uint8_t rxbuf[AUX_GROUP_A_SIZE] = {};
CHECK_RETURN(readCMD(RDSTATC, rxbuf, STATUS_GROUP_C_SIZE));
@ -112,7 +120,7 @@ uint8 amsAuxAndStatusMeasurement(Cell_Module* module) {
module->auxVoltages[9] = mV_from_ADBMS6830(rxbuf[0] | (rxbuf[1] << 8));
uint8 rxbuffer[STATUS_GROUP_A_SIZE];
uint8_t rxbuffer[STATUS_GROUP_A_SIZE];
CHECK_RETURN(readCMD(RDSTATA, rxbuffer, STATUS_GROUP_A_SIZE));
@ -128,9 +136,9 @@ uint8 amsAuxAndStatusMeasurement(Cell_Module* module) {
return 0;
}
uint8 amsConfigBalancing(uint32 channels, uint8 dutyCycle) {
uint8 buffer_a[PWM_GROUP_A_SIZE] = {};
uint8 buffer_b[PWM_GROUP_B_SIZE] = {};
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));
@ -156,14 +164,14 @@ uint8 amsConfigBalancing(uint32 channels, uint8 dutyCycle) {
return 0;
}
uint8 amsStartBalancing(uint8 dutyCycle) { return writeCMD(UNMUTE, NULL, 0); }
uint8_t amsStartBalancing(uint8_t dutyCycle) { return writeCMD(UNMUTE, NULL, 0); }
uint8 amsStopBalancing() { return writeCMD(MUTE, NULL, 0); }
uint8_t amsStopBalancing() { return writeCMD(MUTE, NULL, 0); }
uint8 amsSelfTest() { return 0; }
uint8_t amsSelfTest() { return 0; }
uint8 amsConfigOverUnderVoltage(uint16 overVoltage, uint16 underVoltage) {
uint8 buffer[CFG_GROUP_A_SIZE];
uint8_t amsConfigOverUnderVoltage(uint16_t overVoltage, uint16_t underVoltage) {
uint8_t buffer[CFG_GROUP_A_SIZE];
if (underVoltage & 0xF000 || overVoltage & 0xF000) { // only 12 bits allowed
return 1;
@ -172,21 +180,21 @@ uint8 amsConfigOverUnderVoltage(uint16 overVoltage, uint16 underVoltage) {
CHECK_RETURN(readCMD(RDCFGB, buffer, CFG_GROUP_A_SIZE));
//UV
buffer[0] = (uint8) (underVoltage & 0xFF);
buffer[0] = (uint8_t) (underVoltage & 0xFF);
buffer[1] &= 0xF0;
buffer[1] |= (uint8) ((underVoltage >> 8) & 0x0F);
buffer[1] |= (uint8_t) ((underVoltage >> 8) & 0x0F);
//OV
buffer[1] &= 0x0F;
buffer[1] |= (uint8) (overVoltage << 4);
buffer[2] = (uint8) (overVoltage >> 4);
buffer[1] |= (uint8_t) (overVoltage << 4);
buffer[2] = (uint8_t) (overVoltage >> 4);
return writeCMD(WRCFGB, buffer, CFG_GROUP_A_SIZE);
}
uint8 amsCheckUnderOverVoltage(Cell_Module* module) {
uint8 regbuffer[STATUS_GROUP_D_SIZE];
uint32 ov_uv_data = 0;
uint8_t amsCheckUnderOverVoltage(Cell_Module* module) {
uint8_t regbuffer[STATUS_GROUP_D_SIZE];
uint32_t ov_uv_data = 0;
CHECK_RETURN(readCMD(RDSTATD, regbuffer, STATUS_GROUP_D_SIZE));
ov_uv_data = (regbuffer[0] << 0) | (regbuffer[1] << 8) |
(regbuffer[2] << 16) | (regbuffer[3] << 24);
@ -194,7 +202,7 @@ uint8 amsCheckUnderOverVoltage(Cell_Module* module) {
module->overVoltage = 0;
module->underVoltage = 0;
for (size_t i = 0; i < numberofcells; i++) { // ov/uv flags are 1-bit flags for each cell C0UV, C0OV, C1UV, C1OV, ...
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;
}
@ -202,23 +210,23 @@ uint8 amsCheckUnderOverVoltage(Cell_Module* module) {
return 0;
}
uint8 amsClearFlag() {
uint8 buffer[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
uint8_t amsClearFlag() {
uint8_t buffer[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
return writeCMD(CLRFLAG, buffer, 6);
}
uint8 amsClearAux() {
uint8 buffer[6];
uint8_t amsClearAux() {
uint8_t buffer[6];
return writeCMD(CLRAUX, buffer, 0);
}
uint8 amsClearCells() {
uint8 buffer[6];
uint8_t amsClearCells() {
uint8_t buffer[6];
return writeCMD(CLRCELL, buffer, 0);
}
uint8 amsReadCellVoltages(Cell_Module* module) {
uint8 rxbuffer[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));

View File

@ -8,8 +8,11 @@
#include "ADBMS_LL_Driver.h"
#include "ADBMS_CMD_MAKROS.h"
#include "config_ADBMS6830.h"
#include "stm32h7xx_hal.h"
#include "swo_log.h"
#include <stdbool.h>
#include <stdint.h>
#include <strings.h>
#define INITIAL_COMMAND_PEC 0x0010
#define INITIAL_DATA_PEC 0x0010
@ -19,7 +22,7 @@
SPI_HandleTypeDef* adbmsspi;
uint8_t command_queue[N_BMS][12] = {0};
uint8 adbmsDriverInit(SPI_HandleTypeDef* hspi) {
uint8_t adbmsDriverInit(SPI_HandleTypeDef* hspi) {
mcuAdbmsCSLow();
HAL_Delay(1);
mcuAdbmsCSHigh();
@ -27,44 +30,36 @@ uint8 adbmsDriverInit(SPI_HandleTypeDef* hspi) {
return 0;
}
uint8 mcuSPITransmit(uint8* buffer, uint8 buffersize) {
static HAL_StatusTypeDef mcuSPITransmit(uint8_t* buffer, uint8_t buffersize) {
HAL_StatusTypeDef status;
uint8 rxbuf[buffersize];
status = HAL_SPI_TransmitReceive(adbmsspi, buffer, rxbuf, buffersize,
ADBMS_SPI_TIMEOUT);
status = HAL_SPI_Transmit(adbmsspi, buffer, buffersize, ADBMS_SPI_TIMEOUT);
__HAL_SPI_CLEAR_OVRFLAG(adbmsspi);
return status;
}
uint8 mcuSPIReceive(uint8* buffer, uint8 buffersize) {
HAL_StatusTypeDef status;
status = HAL_SPI_Receive(adbmsspi, buffer, buffersize, ADBMS_SPI_TIMEOUT);
return status;
static HAL_StatusTypeDef mcuSPIReceive(uint8_t* buffer, uint8_t buffersize) {
return HAL_SPI_Receive(adbmsspi, buffer, buffersize, ADBMS_SPI_TIMEOUT);
}
uint8 mcuSPITransmitReceive(uint8* rxbuffer, uint8* txbuffer,
uint8 buffersize) {
HAL_StatusTypeDef status;
status = HAL_SPI_TransmitReceive(adbmsspi, txbuffer, rxbuffer, buffersize,
ADBMS_SPI_TIMEOUT);
return status;
static HAL_StatusTypeDef mcuSPITransmitReceive(uint8_t* rxbuffer, uint8_t* txbuffer, uint8_t buffersize) {
return HAL_SPI_TransmitReceive(adbmsspi, txbuffer, rxbuffer, buffersize, ADBMS_SPI_TIMEOUT);
}
//command PEC calculation
//CRC-15
//x^15 + x^14 + x^10 + x^8 + x^7 + x^4 + x^3 + 1
static uint16 updateCommandPEC(uint16 currentPEC, uint8 din) {
static uint16_t updateCommandPEC(uint16_t currentPEC, uint8_t din) {
din = (din >> 7) & 0x01;
uint8 in0 = din ^ ((currentPEC >> 14) & 0x01);
uint8 in3 = in0 ^ ((currentPEC >> 2) & 0x01);
uint8 in4 = in0 ^ ((currentPEC >> 3) & 0x01);
uint8 in7 = in0 ^ ((currentPEC >> 6) & 0x01);
uint8 in8 = in0 ^ ((currentPEC >> 7) & 0x01);
uint8 in10 = in0 ^ ((currentPEC >> 9) & 0x01);
uint8 in14 = in0 ^ ((currentPEC >> 13) & 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 newPEC = 0;
uint16_t newPEC = 0;
newPEC |= in14 << 14;
newPEC |= (currentPEC & (0x01 << 12)) << 1;
@ -85,12 +80,12 @@ static uint16 updateCommandPEC(uint16 currentPEC, uint8 din) {
return newPEC;
}
static uint8 calculateCommandPEC(uint8_t* data, uint8_t datalen) {
uint16 currentpec = INITIAL_COMMAND_PEC;
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 din = data[i] << (n);
uint8_t din = data[i] << (n);
currentpec = updateCommandPEC(currentpec, din);
}
}
@ -103,22 +98,22 @@ static uint8 calculateCommandPEC(uint8_t* data, uint8_t datalen) {
}
}
static uint8 checkCommandPEC(uint8* data, uint8 datalen) {
static uint8_t checkCommandPEC(uint8_t* data, uint8_t datalen) {
if (datalen <= 3) {
return 255;
}
uint16 currentpec = INITIAL_COMMAND_PEC;
uint16_t currentpec = INITIAL_COMMAND_PEC;
for (int i = 0; i < (datalen - 2); i++) {
for (int n = 0; n < 8; n++) {
uint8 din = data[i] << (n);
uint8_t din = data[i] << (n);
currentpec = updateCommandPEC(currentpec, din);
}
}
uint8 pechigh = (currentpec >> 7) & 0xFF;
uint8 peclow = (currentpec << 1) & 0xFF;
uint8_t pechigh = (currentpec >> 7) & 0xFF;
uint8_t peclow = (currentpec << 1) & 0xFF;
if ((pechigh == data[datalen - 2]) && (peclow == data[datalen - 1])) {
return 0;
@ -174,7 +169,7 @@ static uint16_t pec10_calc(bool rx_cmd, int len, uint8_t* data) {
typedef uint16_t crc;
static crc F_CRC_CalculaCheckSum(uint8_t const AF_Datos[], uint16_t VF_nBytes);
static uint8 calculateDataPEC(uint8_t* data, uint8_t datalen) {
static uint8_t calculateDataPEC(uint8_t* data, uint8_t datalen) {
if (datalen >= 3) {
@ -185,7 +180,7 @@ static uint8 calculateDataPEC(uint8_t* data, uint8_t datalen) {
data[datalen - 2] = (currentpec >> 8) & 0xFF;
data[datalen - 1] = currentpec & 0xFF;
volatile uint8 result = pec10_calc(true, datalen, data);
volatile uint8_t result = pec10_calc(true, datalen, data);
return 0;
} else {
@ -193,7 +188,7 @@ static uint8 calculateDataPEC(uint8_t* data, uint8_t datalen) {
}
}
static uint8 checkDataPEC(uint8* data, uint8 len) {
static uint8_t checkDataPEC(uint8_t* data, uint8_t len) {
if (len <= 2) {
return 255;
}
@ -238,14 +233,14 @@ static crc F_CRC_CalculaCheckSum(uint8_t const AF_Datos[], uint16_t VF_nBytes) {
return (VP_CRCTableValue ^ 0x0000);
}
static uint16 updateDataPEC(uint16 currentPEC, uint8 din) {
static uint16_t updateDataPEC(uint16_t currentPEC, uint8_t din) {
din = (din >> 7) & 0x01;
uint8 in0 = din ^ ((currentPEC >> 9) & 0x01);
uint8 in2 = in0 ^ ((currentPEC >> 1) & 0x01);
uint8 in3 = in0 ^ ((currentPEC >> 2) & 0x01);
uint8 in7 = in0 ^ ((currentPEC >> 6) & 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 newPEC = 0;
uint16_t newPEC = 0;
newPEC |= (currentPEC & (0x01 << 8)) << 1;
newPEC |= (currentPEC & (0x01 << 7)) << 1;
@ -260,77 +255,92 @@ static uint16 updateDataPEC(uint16 currentPEC, uint8 din) {
return newPEC;
}
uint8 writeCMD(uint16 command, uint8* args, uint8 arglen) {
uint8 ret;
HAL_StatusTypeDef ___writeCMD(uint16_t command, uint8_t * args, size_t arglen) {
HAL_StatusTypeDef ret = HAL_OK;
if (arglen > 0) {
uint8 buffer[6 + arglen]; //command + PEC (2 bytes) + data + DPEC (2 bytes)
buffer[0] = (command >> 8) & 0xFF;
buffer[1] = (command) & 0xFF;
args[0] = (command >> 8) & 0xFF;
args[1] = (command) & 0xFF;
calculateCommandPEC(buffer, 4);
if (DEBUG_CHANNEL_ENABLED(LOG_LEVEL_NOISY)) {
debug_log(LOG_LEVEL_NOISY, "%lu W | %x %x ", HAL_GetTick(), args[0], args[1]);
for (uint8 i = 0; i < arglen; i++) {
buffer[4 + i] = args[i];
//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 < arglen; j++) {
debug_log_cont(LOG_LEVEL_NOISY, "%x ", args[4 + (i * (arglen + 2)) + j]);
}
}
calculateDataPEC(&buffer[4], arglen + 2); //DPEC is calculated over the data, not the command, and placed at the end of the data
debug_log_cont(LOG_LEVEL_NOISY, "\n");
}
calculateCommandPEC(args, 4);
for (size_t i = 0; i < N_BMS; i++) {
calculateDataPEC(&args[4 + (i * (arglen + 2))], arglen + 2); //DPEC is calculated over the data, not the command, and placed at the end of the data
}
mcuAdbmsCSLow();
ret = mcuSPITransmit(buffer, 6 + arglen);
ret = mcuSPITransmit(args, CMD_BUFFER_SIZE(arglen));
mcuAdbmsCSHigh();
} else {
uint8 buffer[4];
buffer[0] = (command >> 8) & 0xFF;
buffer[1] = (command) & 0xFF;
calculateCommandPEC(buffer, 4);
args[0] = (command >> 8) & 0xFF;
args[1] = (command) & 0xFF;
calculateCommandPEC(args, 4);
mcuAdbmsCSLow();
ret = mcuSPITransmit(buffer, 4);
ret = mcuSPITransmit(args, 4);
mcuAdbmsCSHigh();
}
return ret;
}
uint8 readCMD(uint16 command, uint8* buffer, uint8 buflen) {
uint8 txbuffer[6 + buflen];
uint8 rxbuffer[6 + buflen];
txbuffer[0] = (command >> 8) & 0xFF;
txbuffer[1] = (command)&0xFF;
calculateCommandPEC(txbuffer, 4);
HAL_StatusTypeDef readCMD(uint16_t command, uint8_t * buffer, size_t buflen) {
buffer[0] = (command >> 8) & 0xFF;
buffer[1] = (command)&0xFF;
calculateCommandPEC(buffer, 4);
mcuAdbmsCSLow();
uint8 status = mcuSPITransmitReceive(rxbuffer, txbuffer, 6 + buflen);
HAL_StatusTypeDef status = mcuSPITransmitReceive(buffer, buffer, buflen);
mcuAdbmsCSHigh();
if (status != 0) {
return status;
}
if (status != HAL_OK) return status;
for (uint8 i = 0; i < buflen; i++) {
buffer[i] = rxbuffer[i + 4];
}
[[maybe_unused]] uint8 commandCounter = rxbuffer[sizeof(rxbuffer) - 2] & 0xFC; //command counter is bits 7-2
//[[maybe_unused]] uint8_t commandCounter = buffer[sizeof(buffer) - 2] & 0xFC; //command counter is bits 7-2
//TODO: check command counter?
return checkDataPEC(&rxbuffer[4], buflen + 2);
if (DEBUG_CHANNEL_ENABLED(LOG_LEVEL_NOISY)) {
debug_log(LOG_LEVEL_NOISY, "%lu R | %x %x ", HAL_GetTick(), command >> 8, command & 0xFF);
//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]);
}
}
debug_log_cont(LOG_LEVEL_NOISY, "\n");
}
return checkDataPEC(&buffer[4], buflen + 2);
}
//check poll command - no data PEC sent back
uint8 pollCMD(uint16 command) {
uint8 txbuffer[5] = {};
uint8 rxbuffer[5] = {};
uint8_t pollCMD(uint16_t command) {
uint8_t txbuffer[5] = {};
uint8_t rxbuffer[5] = {};
txbuffer[0] = (command >> 8) & 0xFF;
txbuffer[1] = (command)&0xFF;
calculateCommandPEC(txbuffer, 4);
mcuAdbmsCSLow();
uint8 status = mcuSPITransmitReceive(rxbuffer, txbuffer, 5);
uint8_t status = mcuSPITransmitReceive(rxbuffer, txbuffer, 5);
mcuAdbmsCSHigh();
if (status != 0) {

View File

@ -8,8 +8,10 @@
#include "AMS_HighLevel.h"
#include "ADBMS_Abstraction.h"
#include "ADBMS_LL_Driver.h"
#include "config_ADBMS6830.h"
#include "errors.h"
#include "stm32h7xx_hal.h"
#include "swo_log.h"
#include <stdint.h>
#include <string.h>
@ -17,11 +19,7 @@ Cell_Module module = {};
uint32_t balancedCells = 0;
bool balancingActive = false;
uint16_t amsuv = 0;
uint16_t amsov = 0;
uint8_t numberofCells = 15;
uint8_t numberofAux = 0;
uint8_t packetChecksumFails = 0;
#define MAX_PACKET_CHECKSUM_FAILS 5
@ -29,9 +27,6 @@ uint8_t packetChecksumFails = 0;
uint8_t deviceSleeps = 0;
#define MAX_DEVICE_SLEEP 3 //TODO: change to correct value
amsState currentAMSState = AMSDEACTIVE;
amsState lastAMSState = AMSDEACTIVE;
struct pollingTimes {
uint32_t S_ADC_OW_CHECK;
uint32_t TMP1075;
@ -40,13 +35,10 @@ struct pollingTimes {
struct pollingTimes pollingTimes = {0, 0};
void AMS_Init(SPI_HandleTypeDef* hspi) {
initAMS(hspi, numberofCells, numberofAux);
amsov = DEFAULT_OV;
amsuv = DEFAULT_UV;
debug_log(LOG_LEVEL_INFO, "ADBMS6830B HAL - configured for %d controllers and %d cells per controller...", N_BMS, numberofCells);
initAMS(hspi);
pollingTimes = (struct pollingTimes) {HAL_GetTick(), HAL_GetTick()};
currentAMSState = AMSIDLE;
}
uint8_t AMS_Idle_Loop() {