diff --git a/AMS_Master_Code/Core/Lib/ADBMS6830B_Driver/Core/Inc/ADBMS_CMD_MAKROS.h b/AMS_Master_Code/Core/Lib/ADBMS6830B_Driver/Core/Inc/ADBMS_CMD_MAKROS.h index 2cfdee9..84221c6 100755 --- a/AMS_Master_Code/Core/Lib/ADBMS6830B_Driver/Core/Inc/ADBMS_CMD_MAKROS.h +++ b/AMS_Master_Code/Core/Lib/ADBMS6830B_Driver/Core/Inc/ADBMS_CMD_MAKROS.h @@ -77,9 +77,23 @@ #define SRST 0x0027 //Soft reset #define DIAGN 0x0715 // Diagnos MUX and Poll Status + + #define WRCOMM 0x0721 // Write COMM Register Group #define RDCOMM 0x0722 // Read COMM Register Group #define STCOMM 0x0723 // Start I2C/SPI Communication +#define I2C_SEND_START 0b0110 << 4 +#define I2C_SEND_STOP 0b0001 << 4 +#define I2C_SEND 0b0000 << 4 +#define I2C_SEND_NOTRANSFER 0b0111 << 4 +#define I2C_SEND_ACK 0b0000 +#define I2C_SEND_NACK 0b1000 +#define I2C_SEND_NACK_STOP 0b1001 +#define I2C_RECV_ACK 0b0111 +#define I2C_RECV_NACK 0b1111 +#define I2C_RECV_ACK_STOP 0b0001 +#define I2C_RECV_NACK_STOP 0b1001 + #define MUTE 0x0028 // Mute Discharge #define UNMUTE 0x0029 // Unmute Discharge diff --git a/AMS_Master_Code/Core/Lib/ADBMS6830B_Driver/Core/Inc/ADBMS_LL_Driver.h b/AMS_Master_Code/Core/Lib/ADBMS6830B_Driver/Core/Inc/ADBMS_LL_Driver.h index 09a1b07..0beea4d 100755 --- a/AMS_Master_Code/Core/Lib/ADBMS6830B_Driver/Core/Inc/ADBMS_LL_Driver.h +++ b/AMS_Master_Code/Core/Lib/ADBMS6830B_Driver/Core/Inc/ADBMS_LL_Driver.h @@ -57,7 +57,10 @@ static inline HAL_StatusTypeDef __readCMD(uint16_t command, uint8_t * buffer, si #define readCMD(command, buffer, buflen) \ __readCMD(command, buffer, buflen, CMD_BUFFER_SIZE(buflen)) -HAL_StatusTypeDef pollCMD(uint16_t command); +HAL_StatusTypeDef __pollCMD(uint16_t command, uint8_t waitTime); + +#define pollCMD(command) \ + __pollCMD(command, (N_BMS * 2) + 1) //poll is only valid after 2 * N_BMS clock cycles, +1 for safety, see datasheet page 55 void mcuAdbmsCSLow(); diff --git a/AMS_Master_Code/Core/Lib/ADBMS6830B_Driver/Core/Src/ADBMS_Abstraction.c b/AMS_Master_Code/Core/Lib/ADBMS6830B_Driver/Core/Src/ADBMS_Abstraction.c index 5ca14d2..36efa2a 100755 --- a/AMS_Master_Code/Core/Lib/ADBMS6830B_Driver/Core/Src/ADBMS_Abstraction.c +++ b/AMS_Master_Code/Core/Lib/ADBMS6830B_Driver/Core/Src/ADBMS_Abstraction.c @@ -316,3 +316,75 @@ HAL_StatusTypeDef amsReadCellVoltages(Cell_Module (*module)[N_BMS]) { return HAL_OK; } + +//Each selected BMS must have a corresponding address, and the data array for that BMS must be at least datalens[i] bytes long +HAL_StatusTypeDef amsSendI2C(uint8_t addresses[static N_BMS], uint8_t * data[static N_BMS], uint8_t datalens[static N_BMS], uint32_t bms_mask) { + uint8_t buffer[CMD_BUFFER_SIZE(COMM_GROUP_SIZE)] = {}; + + //COMM register works in 3 bytes max per go, interleaved with control information + + uint8_t max_datalen = 0; + for (size_t i = 0; i < N_BMS; i++) { + if (datalens[i] > max_datalen) { + max_datalen = datalens[i]; + } + } + + for (size_t i = 0; i < N_BMS; i++) { + size_t offset = BUFFER_BMS_OFFSET(i, COMM_GROUP_SIZE); + + if (!(bms_mask & (1 << i))) { + buffer[offset + 0] = I2C_SEND_NOTRANSFER; + buffer[offset + 2] = I2C_SEND_NOTRANSFER; + buffer[offset + 4] = I2C_SEND_NOTRANSFER; + continue; + } + } + + size_t packet_count = ((max_datalen + 1) / 3) + ((max_datalen + 1) % 3 != 0); //number of 3 byte packets needed to send all data + + for (size_t i = 0; i < (packet_count * 3); i++) { //i - 1 is the number of data bytes sent so far (1 byte for the address) + for (size_t j = 0; j < N_BMS; j++) { + size_t offset = BUFFER_BMS_OFFSET(j, COMM_GROUP_SIZE); + if (!(bms_mask & (1 << j))) continue; //skip BMS that are not selected + + if (i == 0) { + buffer[offset + 0] = I2C_SEND_START; + buffer[offset + 1] = addresses[j]; + continue; + } + + //add data to the buffer + + //case 1: the last group of 3 bytes contained the last data byte, so we need to send a stop + if (datalens[j] - (int)i == -1) { + buffer[offset + ((i % 3) * 2)] = I2C_SEND_STOP; + continue; + } + + //case 2: we are more than one byte past the end, so we don't need to send any data + if (datalens[j] - (int)i < -1) { + buffer[offset + ((i % 3) * 2)] = I2C_SEND_NOTRANSFER; + continue; + } + + //case 3: we are still sending data + buffer[offset + ((i % 3) * 2)] = I2C_SEND; + buffer[offset + ((i % 3) * 2) + 1] = data[j][i - 1]; + } + + //send the data + if (i % 3 == 0 && i != 0) { + CHECK_RETURN(writeCMD(WRCOMM, buffer, COMM_GROUP_SIZE)); + + __pollCMD(STCOMM, 72); //wait 72 cycles for the I2C transfer to complete (datasheet page 43) + //TODO: not sure if this is correct for a daisy chain + } + } + + //send the last packet + CHECK_RETURN(writeCMD(WRCOMM, buffer, COMM_GROUP_SIZE)); + __pollCMD(STCOMM, 72); + + return HAL_OK; +} diff --git a/AMS_Master_Code/Core/Lib/ADBMS6830B_Driver/Core/Src/ADBMS_LL_Driver.c b/AMS_Master_Code/Core/Lib/ADBMS6830B_Driver/Core/Src/ADBMS_LL_Driver.c index b573d1a..33e5e46 100755 --- a/AMS_Master_Code/Core/Lib/ADBMS6830B_Driver/Core/Src/ADBMS_LL_Driver.c +++ b/AMS_Master_Code/Core/Lib/ADBMS6830B_Driver/Core/Src/ADBMS_LL_Driver.c @@ -212,17 +212,15 @@ HAL_StatusTypeDef ___readCMD(uint16_t command, uint8_t * buffer, size_t arglen) return HAL_OK; } -//check poll command - no data PEC sent back -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 - +//check poll command - no data PEC sent back, waitTime is in SPI clock cycles +HAL_StatusTypeDef __pollCMD(uint16_t command, uint8_t waitTime) { + uint8_t buffer[4 + (waitTime / 8) + 1] = {}; //8 cycles per byte, +1 as we round up buffer[0] = (command >> 8) & 0xFF; buffer[1] = (command) & 0xFF; calculateCommandPEC(buffer, 4); mcuAdbmsCSLow(); - HAL_StatusTypeDef status = mcuSPITransmitReceive(buffer, buffer, 4 + (N_BMS * 2) + 1); + HAL_StatusTypeDef status = mcuSPITransmitReceive(buffer, buffer, sizeof buffer); mcuAdbmsCSHigh(); if (status != HAL_OK) return status;