add daisy chain isospi
This commit is contained in:
parent
7f3eac554e
commit
96b069a5a5
@ -52,6 +52,12 @@ static inline uint32_t __swo_putc(uint32_t c, unsigned int channel) {
|
||||
return (c);
|
||||
}
|
||||
|
||||
#define DEBUG_CHANNEL_ENABLED(channel) ({ \
|
||||
unsigned int ch = (channel); \
|
||||
(ch < 32) ? __ITM_channel_enabled(ch) : false; \
|
||||
})
|
||||
|
||||
[[gnu::nonnull(1), gnu::null_terminated_string_arg(1)]]
|
||||
static inline void __swo_print(const char *str, unsigned int channel) {
|
||||
if (!__ITM_channel_enabled(channel)) {
|
||||
return;
|
||||
@ -61,22 +67,18 @@ static inline void __swo_print(const char *str, unsigned int channel) {
|
||||
}
|
||||
}
|
||||
|
||||
// Print a message to the SWO interface
|
||||
//
|
||||
// Each log level is printed to a different ITM channel
|
||||
[[gnu::format(printf, 2, 3)]]
|
||||
static inline void debug_log(enum log_level_t level, const char *msg, ...) {
|
||||
va_list args;
|
||||
va_start(args, msg);
|
||||
char buffer[MAX_MESSAGE_LENGTH];
|
||||
size_t len = vsnprintf(buffer, sizeof(buffer), msg, args);
|
||||
va_end(args);
|
||||
__swo_print(log_level_names[level], level);
|
||||
__swo_print(buffer, level);
|
||||
if (len >= sizeof(buffer)) {
|
||||
__swo_print(" [message length exceeded] ", 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(log_level_names[level], level); \
|
||||
__swo_print(buffer, level); \
|
||||
if (len >= sizeof(buffer)) { \
|
||||
__swo_print(" [message length exceeded] ", level); \
|
||||
} \
|
||||
__swo_putc('\n', level); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#endif /* __SWO_LOG_H */
|
||||
|
@ -8,6 +8,7 @@
|
||||
#ifndef ADBMS_LL_DRIVER_H_
|
||||
#define ADBMS_LL_DRIVER_H_
|
||||
|
||||
#include "config_ADBMS6830.h"
|
||||
#include "stm32h7xx_hal.h"
|
||||
#include <stdint.h>
|
||||
#define TARGET_STM32
|
||||
@ -20,14 +21,48 @@ typedef uint32_t uint32;
|
||||
|
||||
uint8 adbmsDriverInit(SPI_HandleTypeDef* hspi);
|
||||
|
||||
uint8 writeCMD(uint16 command, uint8* args, uint8 arglen);
|
||||
uint8 readCMD(uint16 command, uint8* buffer, uint8 buflen);
|
||||
uint8 pollCMD(uint16 command);
|
||||
//2 command + 2 PEC + (data + 2 DPEC) per BMS
|
||||
#define CMD_BUFFER_SIZE(datalen) (4 + (N_BMS * (datalen + 2)))
|
||||
|
||||
//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);
|
||||
|
||||
#define readCMD(command, buffer, buflen) ({ \
|
||||
HAL_StatusTypeDef status = __readCMD(command, buffer, buflen); \
|
||||
buffer += 4; /* skip command and PEC */ \
|
||||
status; \
|
||||
})
|
||||
|
||||
uint8_t pollCMD(uint16_t command);
|
||||
|
||||
|
||||
void mcuAdbmsCSLow();
|
||||
void mcuAdbmsCSHigh();
|
||||
|
||||
uint8 wakeUpCmd();
|
||||
static inline void mcuDelay(uint16 delay) { HAL_Delay(delay); };
|
||||
static inline void mcuDelay(uint16_t delay) { HAL_Delay(delay); };
|
||||
|
||||
#endif /* ADBMS_LL_DRIVER_H_ */
|
||||
|
@ -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,42 +30,34 @@ uint8 adbmsDriverInit(SPI_HandleTypeDef* hspi) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8 mcuSPITransmit(uint8* buffer, uint8 buffersize) {
|
||||
HAL_StatusTypeDef status;
|
||||
uint8 rxbuf[buffersize];
|
||||
status = HAL_SPI_TransmitReceive(adbmsspi, buffer, rxbuf, buffersize,
|
||||
ADBMS_SPI_TIMEOUT);
|
||||
__HAL_SPI_CLEAR_OVRFLAG(adbmsspi);
|
||||
return status;
|
||||
static HAL_StatusTypeDef mcuSPITransmit(uint8_t* buffer, uint8_t buffersize) {
|
||||
HAL_StatusTypeDef status;
|
||||
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 updateCommandPEC(uint16 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;
|
||||
|
||||
@ -85,12 +80,12 @@ static uint16 updateCommandPEC(uint16 currentPEC, uint8 din) {
|
||||
return newPEC;
|
||||
}
|
||||
|
||||
static uint8 calculateCommandPEC(uint8_t* data, uint8_t datalen) {
|
||||
static uint8_t calculateCommandPEC(uint8_t* data, uint8_t datalen) {
|
||||
uint16 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,7 +98,7 @@ 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;
|
||||
}
|
||||
@ -112,13 +107,13 @@ static uint8 checkCommandPEC(uint8* data, uint8 datalen) {
|
||||
|
||||
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,12 +233,12 @@ 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 updateDataPEC(uint16 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;
|
||||
|
||||
@ -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, "%d 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(LOG_LEVEL_NOISY, "%d: ", i);
|
||||
for (size_t j = 0; j < arglen; j++) {
|
||||
debug_log(LOG_LEVEL_NOISY, "%x ", args[4 + (i * (arglen + 2)) + j]);
|
||||
}
|
||||
}
|
||||
|
||||
debug_log(LOG_LEVEL_NOISY, "\n");
|
||||
}
|
||||
|
||||
calculateDataPEC(&buffer[4], arglen + 2); //DPEC is calculated over the data, not the command, and placed at the end of the data
|
||||
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, "%d R | %x %x ", HAL_GetTick(), command >> 8, command & 0xFF);
|
||||
|
||||
//print out data bytes
|
||||
for (size_t i = 0; i < N_BMS; i++) {
|
||||
debug_log(LOG_LEVEL_NOISY, "%d: ", i);
|
||||
for (size_t j = 0; j < buflen; j++) {
|
||||
debug_log(LOG_LEVEL_NOISY, "%x ", buffer[4 + (i * (buflen + 2)) + j]);
|
||||
}
|
||||
}
|
||||
|
||||
debug_log(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) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user