mv-bms/Core/Src/ADBMS_Abstraction.c

247 lines
8.9 KiB
C

/*
* ADBMS_Abstraction.c
*
* Created on: 14.07.2022
* Author: max
*/
#include "ADBMS_Abstraction.h"
#include "ADBMS_CMD_MAKROS.h"
#include "ADBMS_LL_Driver.h"
#include <stddef.h>
uint8 numberofcells;
uint8 numberofauxchannels;
#define CHECK_RETURN(x) \
{ \
uint8 status = x; \
if (status != 0) \
return status; \
}
uint8 amsReset() {
amsWakeUp();
readCMD(SRST, NULL, 0);
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
CHECK_RETURN(writeCMD(ADAX | ADAX_CONV_ALL, NULL, 0)); //start aux measurement
return 0;
}
uint8 initAMS(SPI_HandleTypeDef* hspi, uint8 numofcells, uint8 numofaux) {
adbmsDriverInit(hspi);
numberofcells = numofcells;
numberofauxchannels = numofaux;
return amsReset();
}
uint8 amsWakeUp() {
uint8 buf[6];
return readCMD(RDCFGA, buf, 6);
}
uint8 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] = {};
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(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 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;
}
uint8 amsConfigBalancing(uint32 channels, uint8 dutyCycle) {
uint8 buffer_a[PWM_GROUP_A_SIZE] = {};
uint8 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;
}
#warning fixme
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);
} else {
buffer_b[(i - 12) / 2] = ((channels & (1 << (i + 1))) ? (dutyCycle << 4) : 0) |
((channels & (1 << i)) ? dutyCycle : 0);
}
}
CHECK_RETURN(writeCMD(WRPWMA, buffer_a, CFG_GROUP_A_SIZE));
CHECK_RETURN(writeCMD(WRPWMB, buffer_b, CFG_GROUP_B_SIZE));
return 0;
}
uint8 amsStartBalancing(uint8 dutyCycle) { return writeCMD(UNMUTE, NULL, 0); }
uint8 amsStopBalancing() { return writeCMD(MUTE, NULL, 0); }
uint8 amsSelfTest() { return 0; }
uint8 amsConfigOverUnderVoltage(uint16 overVoltage, uint16 underVoltage) {
uint8 buffer[CFG_GROUP_A_SIZE];
if (underVoltage & 0xF000 || overVoltage & 0xF000) { // only 12 bits allowed
return 1;
}
CHECK_RETURN(readCMD(RDCFGB, buffer, CFG_GROUP_A_SIZE));
//UV
buffer[0] = (uint8) (underVoltage & 0xFF);
buffer[1] &= 0xF0;
buffer[1] |= (uint8) ((underVoltage >> 8) & 0x0F);
//OV
buffer[1] &= 0x0F;
buffer[1] |= (uint8) (overVoltage << 4);
buffer[2] = (uint8) (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;
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 < 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;
}
return 0;
}
uint8 amsClearAux() {
uint8 buffer[6];
return writeCMD(CLRAUX, buffer, 0);
}
uint8 amsClearCells() {
uint8 buffer[6];
return writeCMD(CLRCELL, buffer, 0);
}
uint8 amsReadCellVoltages(Cell_Module* module) {
uint8 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));
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));
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));
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));
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));
CHECK_RETURN(readCMD(RDCVF, rxbuffer, CV_GROUP_A_SIZE));
module->cellVoltages[15] = mV_from_ADBMS6830(rxbuffer[0] | (rxbuffer[1] << 8));
return 0;
}