Compare commits

...

2 Commits

Author SHA1 Message Date
468ba1d7e7
make SPI reads/writes a interrupt-free 2025-05-26 14:26:47 +02:00
f910f899a4
reformat 2025-05-20 16:52:41 +02:00
27 changed files with 760 additions and 768 deletions

View File

@ -14,7 +14,7 @@
#define VREF 3000.0f // 3V #define VREF 3000.0f // 3V
#define TEMP_CONV 100.0f // 655.35°C max #define TEMP_CONV 100.0f // 655.35°C max
#define CELSIUS_TO_KELVIN 273.15f #define CELSIUS_TO_KELVIN 273.15f
#define CELSIUS_TO_KELVIN_SCALED CELSIUS_TO_KELVIN * TEMP_CONV #define CELSIUS_TO_KELVIN_SCALED (CELSIUS_TO_KELVIN * TEMP_CONV)
// More efficient (?) calc using: // More efficient (?) calc using:
// R_T = R_Pullup / (V_REF / ADC - 1) // R_T = R_Pullup / (V_REF / ADC - 1)
@ -24,7 +24,8 @@
[[gnu::optimize("fast-math")]] [[gnu::optimize("fast-math")]]
static inline uint16_t ntc_mv_to_celsius(int16_t adc) { static inline uint16_t ntc_mv_to_celsius(int16_t adc) {
const float log_ohms = logf(1 / ((VREF / adc) - 1)); const float log_ohms = logf(1 / ((VREF / adc) - 1));
return (uint16_t) (TEMP_CONV / (NTC_A1 + NTC_B1 * log_ohms + NTC_C1 * log_ohms * log_ohms + NTC_D1 * log_ohms * log_ohms * log_ohms) - CELSIUS_TO_KELVIN_SCALED); return (uint16_t)(TEMP_CONV / (NTC_A1 + NTC_B1 * log_ohms + NTC_C1 * log_ohms * log_ohms +
NTC_D1 * log_ohms * log_ohms * log_ohms) - CELSIUS_TO_KELVIN_SCALED);
} }
#else #else
// Lookup Table coming soon; not really needed but fun? // Lookup Table coming soon; not really needed but fun?

View File

@ -12,7 +12,7 @@
#define CAN_ID_SLAVE_STATUS_BASE 0x080 #define CAN_ID_SLAVE_STATUS_BASE 0x080
#define CAN_ID_AMS_SIGNALS 0x090 #define CAN_ID_AMS_SIGNALS 0x090
//TEMPORARY!! // TEMPORARY!!
#define CAN_ID_AMS_DETAILS 0x091 #define CAN_ID_AMS_DETAILS 0x091
#define CAN_ID_AMS_DETAILS_FC 0x092 #define CAN_ID_AMS_DETAILS_FC 0x092

View File

@ -22,7 +22,7 @@
#define __STM32H7xx_IT_H #define __STM32H7xx_IT_H
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
/* Private includes ----------------------------------------------------------*/ /* Private includes ----------------------------------------------------------*/

View File

@ -3,8 +3,8 @@
#include "stm32h7xx_hal.h" #include "stm32h7xx_hal.h"
#include <stdint.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h>
// Minimum vehicle side voltage to exit precharge // Minimum vehicle side voltage to exit precharge
#define MIN_VEHICLE_SIDE_VOLTAGE 150000 // mV #define MIN_VEHICLE_SIDE_VOLTAGE 150000 // mV
@ -22,15 +22,7 @@
// Time to wait between closing relays // Time to wait between closing relays
#define RELAY_CLOSE_WAIT 10 // ms #define RELAY_CLOSE_WAIT 10 // ms
typedef enum { typedef enum { TS_INACTIVE, TS_ACTIVE, TS_PRECHARGE, TS_DISCHARGE, TS_ERROR, TS_CHARGING_CHECK, TS_CHARGING } TSState;
TS_INACTIVE,
TS_ACTIVE,
TS_PRECHARGE,
TS_DISCHARGE,
TS_ERROR,
TS_CHARGING_CHECK,
TS_CHARGING
} TSState;
static inline const char *TSStateToString(TSState state) { static inline const char *TSStateToString(TSState state) {
switch (state) { switch (state) {
@ -62,10 +54,7 @@ typedef enum {
TS_ERRORKIND_SHUNT_OVERTEMP = 0x05 TS_ERRORKIND_SHUNT_OVERTEMP = 0x05
} TSErrorKind; } TSErrorKind;
typedef enum { typedef enum { TS_ERROR_SOURCE_SHUNT = (1 << 0), TS_ERROR_SOURCE_SLAVES = (1 << 1) } TSErrorSource;
TS_ERROR_SOURCE_SHUNT = (1 << 0),
TS_ERROR_SOURCE_SLAVES = (1 << 1)
} TSErrorSource;
typedef struct { typedef struct {
TSState current_state; TSState current_state;

View File

@ -27,7 +27,7 @@ ADBMS_Internal_Status amsStopBalancing();
ADBMS_Internal_Status amsSelfTest(); ADBMS_Internal_Status amsSelfTest();
ADBMS_Internal_Status amsConfigOverUnderVoltage(uint16_t overVoltage, uint16_t underVoltage); //arguments in mV ADBMS_Internal_Status amsConfigOverUnderVoltage(uint16_t overVoltage, uint16_t underVoltage); // arguments in mV
ADBMS_Internal_Status amsCheckUnderOverVoltage(BMS_Chip (*module)[N_BMS]); ADBMS_Internal_Status amsCheckUnderOverVoltage(BMS_Chip (*module)[N_BMS]);

View File

@ -66,11 +66,10 @@
#define PLADC 0x0718 // Poll ADC Conversion Status #define PLADC 0x0718 // Poll ADC Conversion Status
#define PLAUX 0x071E // Poll AUX Conversion Status #define PLAUX 0x071E // Poll AUX Conversion Status
#define SRST 0x0027 //Soft reset #define SRST 0x0027 // Soft reset
#define DIAGN 0x0715 // Diagnos MUX and Poll Status #define DIAGN 0x0715 // Diagnos MUX and Poll Status
#define WRCOMM 0x0721 // Write COMM Register Group #define WRCOMM 0x0721 // Write COMM Register Group
#define RDCOMM 0x0722 // Read COMM Register Group #define RDCOMM 0x0722 // Read COMM Register Group
#define STCOMM 0x0723 // Start I2C/SPI Communication #define STCOMM 0x0723 // Start I2C/SPI Communication
@ -91,8 +90,6 @@
#define RDSID 0x002C // Read Serial ID #define RDSID 0x002C // Read Serial ID
/* GPIO Selection for ADC Converion /* GPIO Selection for ADC Converion
* 000: GPIO1 to 5, 2nd Reference, GPIO 6 to 9 * 000: GPIO1 to 5, 2nd Reference, GPIO 6 to 9
* 001: GPIO1 and GPIO6 * 001: GPIO1 and GPIO6

View File

@ -19,8 +19,7 @@ typedef enum : uint16_t {
NUM_ERROR_KINDS NUM_ERROR_KINDS
} ADBMS_Status; } ADBMS_Status;
static const char* ADBMS_Status_Names[NUM_ERROR_KINDS] = { static const char *ADBMS_Status_Names[NUM_ERROR_KINDS] = {"ADBMS_NO_ERROR",
"ADBMS_NO_ERROR",
"ADBMS_OVERTEMP", "ADBMS_OVERTEMP",
"ADBMS_UNDERTEMP", "ADBMS_UNDERTEMP",
"ADBMS_OVERVOLT", "ADBMS_OVERVOLT",
@ -29,8 +28,7 @@ static const char* ADBMS_Status_Names[NUM_ERROR_KINDS] = {
"ADBMS_INTERNAL_BMS_TIMEOUT", "ADBMS_INTERNAL_BMS_TIMEOUT",
"ADBMS_INTERNAL_BMS_CHECKSUM_FAIL", "ADBMS_INTERNAL_BMS_CHECKSUM_FAIL",
"ADBMS_INTERNAL_BMS_OVERTEMP", "ADBMS_INTERNAL_BMS_OVERTEMP",
"ADBMS_INTERNAL_BMS_FAULT" "ADBMS_INTERNAL_BMS_FAULT"};
};
static inline const char* ADBMS_Status_ToString(ADBMS_Status status) { static inline const char* ADBMS_Status_ToString(ADBMS_Status status) {
return (status < NUM_ERROR_KINDS) ? ADBMS_Status_Names[status] : "UNKNOWN"; return (status < NUM_ERROR_KINDS) ? ADBMS_Status_Names[status] : "UNKNOWN";

View File

@ -13,6 +13,16 @@ typedef enum {
ADBMS_TIMEOUT, ADBMS_TIMEOUT,
} ADBMS_Internal_Status; } ADBMS_Internal_Status;
#define CRITICAL_SECTION_VAR(counter) bool primask_##counter = (__get_PRIMASK() == 0)
#define CRITICAL_SECTION_ENTER(counter) do { __disable_irq(); } while(0)
#define CRITICAL_SECTION_EXIT(counter) ({do { if (primask_##counter) __enable_irq(); } while(0);})
#define CRITICAL_SECTION() \
CRITICAL_SECTION_VAR(__COUNTER__); \
asm volatile ("dmb"); \
CRITICAL_SECTION_ENTER(__COUNTER__); \
for(int _cs_flag_##__COUNTER__ = 1; _cs_flag_##__COUNTER__; _cs_flag_##__COUNTER__ = 0, CRITICAL_SECTION_EXIT(__COUNTER__))
[[maybe_unused, gnu::always_inline]] [[maybe_unused, gnu::always_inline]]
static inline void mcuAdbmsCSLow() { static inline void mcuAdbmsCSLow() {
HAL_GPIO_WritePin(AMS_CS_GPIO_Port, AMS_CS_Pin, GPIO_PIN_RESET); HAL_GPIO_WritePin(AMS_CS_GPIO_Port, AMS_CS_Pin, GPIO_PIN_RESET);
@ -29,20 +39,32 @@ static inline void mcuAdbmsCSHigh() {
[[maybe_unused, gnu::always_inline, gnu::access(read_only, 2, 3), gnu::nonnull(1)]] [[maybe_unused, gnu::always_inline, gnu::access(read_only, 2, 3), gnu::nonnull(1)]]
static inline ADBMS_Internal_Status mcuSPITransmit(USER_PTR_TYPE user_ptr, const uint8_t* buffer, uint8_t buffersize, uint32_t timeout) { static inline ADBMS_Internal_Status mcuSPITransmit(USER_PTR_TYPE user_ptr, const uint8_t* buffer, uint8_t buffersize, uint32_t timeout) {
ADBMS_Internal_Status adbms_status;
CRITICAL_SECTION() {
const HAL_StatusTypeDef status = HAL_SPI_Transmit(user_ptr, buffer, buffersize, timeout); const HAL_StatusTypeDef status = HAL_SPI_Transmit(user_ptr, buffer, buffersize, timeout);
return (status == HAL_OK) ? ADBMS_OK : ADBMS_ERROR; adbms_status = (status == HAL_OK) ? ADBMS_OK : ADBMS_ERROR;
}
return adbms_status;
} }
[[maybe_unused, gnu::always_inline, gnu::access(read_write, 2, 3), gnu::nonnull(1)]] [[maybe_unused, gnu::always_inline, gnu::access(read_write, 2, 3), gnu::nonnull(1)]]
static inline ADBMS_Internal_Status mcuSPIReceive(USER_PTR_TYPE user_ptr, uint8_t* buffer, uint8_t buffersize, uint32_t timeout) { static inline ADBMS_Internal_Status mcuSPIReceive(USER_PTR_TYPE user_ptr, uint8_t* buffer, uint8_t buffersize, uint32_t timeout) {
ADBMS_Internal_Status adbms_status;
CRITICAL_SECTION() {
const HAL_StatusTypeDef status = HAL_SPI_Receive(user_ptr, buffer, buffersize, timeout); const HAL_StatusTypeDef status = HAL_SPI_Receive(user_ptr, buffer, buffersize, timeout);
return (status == HAL_OK) ? ADBMS_OK : ADBMS_ERROR; adbms_status = (status == HAL_OK) ? ADBMS_OK : ADBMS_ERROR;
}
return adbms_status;
} }
[[maybe_unused, gnu::always_inline, gnu::access(read_write, 2, 4), gnu::access(read_only, 3, 4), gnu::nonnull(1, 2)]] [[maybe_unused, gnu::always_inline, gnu::access(read_write, 2, 4), gnu::access(read_only, 3, 4), gnu::nonnull(1, 2)]]
static inline ADBMS_Internal_Status mcuSPITransmitReceive(USER_PTR_TYPE user_ptr, uint8_t* rxbuffer, const uint8_t* txbuffer, uint8_t buffersize, uint32_t timeout) { static inline ADBMS_Internal_Status mcuSPITransmitReceive(USER_PTR_TYPE user_ptr, uint8_t* rxbuffer, const uint8_t* txbuffer, uint8_t buffersize, uint32_t timeout) {
ADBMS_Internal_Status adbms_status;
CRITICAL_SECTION() {
const HAL_StatusTypeDef status = HAL_SPI_TransmitReceive(user_ptr, txbuffer, rxbuffer, buffersize, timeout); const HAL_StatusTypeDef status = HAL_SPI_TransmitReceive(user_ptr, txbuffer, rxbuffer, buffersize, timeout);
return (status == HAL_OK) ? ADBMS_OK : ADBMS_ERROR; adbms_status = (status == HAL_OK) ? ADBMS_OK : ADBMS_ERROR;
}
return adbms_status;
} }
// Delay by `delay` milliseconds // Delay by `delay` milliseconds

View File

@ -1,12 +1,12 @@
#ifndef ADBMS_LL_DRIVER_H_ #ifndef ADBMS_LL_DRIVER_H_
#define ADBMS_LL_DRIVER_H_ #define ADBMS_LL_DRIVER_H_
#include "config_ADBMS6830.h"
#include "ADBMS_Intern.h" #include "ADBMS_Intern.h"
#include "config_ADBMS6830.h"
#include <stddef.h> #include <stddef.h>
#include <stdint.h> #include <stdint.h>
//2 command + 2 PEC + (data + 2 DPEC) per BMS // 2 command + 2 PEC + (data + 2 DPEC) per BMS
#define CMD_BUFFER_SIZE(datalen) (4 + (N_BMS * ((datalen) + 2))) #define CMD_BUFFER_SIZE(datalen) (4 + (N_BMS * ((datalen) + 2)))
#define BUFFER_BMS_OFFSET(bms, datalen) (4 + ((bms) * ((datalen) + 2))) #define BUFFER_BMS_OFFSET(bms, datalen) (4 + ((bms) * ((datalen) + 2)))
@ -14,30 +14,28 @@
#define CMD_EMPTY_BUFFER ((uint8_t[CMD_BUFFER_SIZE(0)]){0}) #define CMD_EMPTY_BUFFER ((uint8_t[CMD_BUFFER_SIZE(0)]){0})
#define CMD_EMPTY_BUFFER_SIZE CMD_BUFFER_SIZE(0) #define CMD_EMPTY_BUFFER_SIZE CMD_BUFFER_SIZE(0)
ADBMS_Internal_Status ___writeCMD(uint16_t command, uint8_t * args, size_t arglen); ADBMS_Internal_Status ___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 [[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 ADBMS_Internal_Status __writeCMD(uint16_t command, uint8_t * args, size_t arglen, size_t) { static inline ADBMS_Internal_Status __writeCMD(uint16_t command, uint8_t *args, size_t arglen, size_t) {
return ___writeCMD(command, args, arglen); return ___writeCMD(command, args, arglen);
} }
#define writeCMD(command, args, arglen) \ #define writeCMD(command, args, arglen) __writeCMD(command, args, arglen, CMD_BUFFER_SIZE(arglen))
__writeCMD(command, args, arglen, CMD_BUFFER_SIZE(arglen))
ADBMS_Internal_Status ___readCMD(uint16_t command, uint8_t * buffer, size_t arglen); ADBMS_Internal_Status ___readCMD(uint16_t command, uint8_t *buffer, 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 [[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 ADBMS_Internal_Status __readCMD(uint16_t command, uint8_t * buffer, size_t arglen, size_t) { static inline ADBMS_Internal_Status __readCMD(uint16_t command, uint8_t *buffer, size_t arglen, size_t) {
return ___readCMD(command, buffer, arglen); return ___readCMD(command, buffer, arglen);
} }
#define readCMD(command, buffer, buflen) \ #define readCMD(command, buffer, buflen) __readCMD(command, buffer, buflen, CMD_BUFFER_SIZE(buflen))
__readCMD(command, buffer, buflen, CMD_BUFFER_SIZE(buflen))
ADBMS_Internal_Status __pollCMD(uint16_t command, uint8_t waitTime); ADBMS_Internal_Status __pollCMD(uint16_t command, uint8_t waitTime);
#define pollCMD(command) \ // poll is only valid after 2 * N_BMS clock cycles, +1 for safety, see datasheet page 55
__pollCMD(command, (N_BMS * 2) + 1) //poll is only valid after 2 * N_BMS clock cycles, +1 for safety, see datasheet page 55 #define pollCMD(command) __pollCMD(command, (N_BMS * 2) + 1)
void initSPI(USER_PTR_TYPE ptr); void initSPI(USER_PTR_TYPE ptr);

View File

@ -1,8 +1,8 @@
#include "ADBMS_Abstraction.h" #include "ADBMS_Abstraction.h"
#include "ADBMS_CMD_Defines.h" #include "ADBMS_CMD_Defines.h"
#include "ADBMS_Intern.h"
#include "ADBMS_LL_Driver.h" #include "ADBMS_LL_Driver.h"
#include "config_ADBMS6830.h" #include "config_ADBMS6830.h"
#include "ADBMS_Intern.h"
#include <stddef.h> #include <stddef.h>
@ -12,9 +12,10 @@ static const char* const ADBMS_Statuses[] = {"ADBMS_OK", "ADBMS_ERROR", "ADBMS_B
do { \ do { \
ADBMS_Internal_Status status = x; \ ADBMS_Internal_Status status = x; \
if (status != 0) { \ if (status != 0) { \
debug_log(ADBMS_LOG_LEVEL_ERROR, "in %s:%d@%s: %s failed with status %d (%s)", __FILE_NAME__, __LINE__, __func__,\ debug_log(ADBMS_LOG_LEVEL_ERROR, "in %s:%d@%s: %s failed with status %d (%s)", __FILE_NAME__, __LINE__, \
#x, status, \ __func__, #x, status, \
(status < (sizeof(ADBMS_Statuses) / sizeof(ADBMS_Statuses[0]))) ? ADBMS_Statuses[status] : "Unknown"); \ (status < (sizeof(ADBMS_Statuses) / sizeof(ADBMS_Statuses[0]))) ? ADBMS_Statuses[status] \
: "Unknown"); \
return status; \ return status; \
} \ } \
} while (0) } while (0)
@ -328,7 +329,7 @@ ADBMS_Internal_Status amsReadCellVoltages(BMS_Chip (*module)[N_BMS]) {
// Each selected BMS must have a corresponding address, and the data array for that BMS must be at least datalens[i] // Each selected BMS must have a corresponding address, and the data array for that BMS must be at least datalens[i]
// bytes long // bytes long
ADBMS_Internal_Status amsSendI2C(const uint8_t addresses[static N_BMS], uint8_t* data[static N_BMS], ADBMS_Internal_Status amsSendI2C(const uint8_t addresses[static N_BMS], uint8_t *data[static N_BMS],
const uint8_t datalens[static N_BMS], uint32_t bms_mask) { const uint8_t datalens[static N_BMS], uint32_t bms_mask) {
uint8_t buffer[CMD_BUFFER_SIZE(COMM_GROUP_SIZE)] = {}; uint8_t buffer[CMD_BUFFER_SIZE(COMM_GROUP_SIZE)] = {};
@ -404,7 +405,7 @@ ADBMS_Internal_Status amsSendI2C(const uint8_t addresses[static N_BMS], uint8_t*
// Each selected BMS must have a corresponding address, and the data array for that BMS must be at least datalens[i] // Each selected BMS must have a corresponding address, and the data array for that BMS must be at least datalens[i]
// bytes long // bytes long
ADBMS_Internal_Status amsReadI2C(const uint8_t addresses[static N_BMS], uint8_t* data[static N_BMS], ADBMS_Internal_Status amsReadI2C(const uint8_t addresses[static N_BMS], uint8_t *data[static N_BMS],
const uint8_t datalens[static N_BMS], uint32_t bms_mask) { const uint8_t datalens[static N_BMS], uint32_t bms_mask) {
uint8_t buffer[CMD_BUFFER_SIZE(COMM_GROUP_SIZE)] = {}; uint8_t buffer[CMD_BUFFER_SIZE(COMM_GROUP_SIZE)] = {};

View File

@ -1,11 +1,10 @@
#include "ADBMS_Abstraction.h" #include "ADBMS_Abstraction.h"
#include "ADBMS_Driver.h" #include "ADBMS_Driver.h"
#include "config_ADBMS6830.h"
#include "ADBMS_Intern.h" #include "ADBMS_Intern.h"
#include "config_ADBMS6830.h"
#include <stdint.h> #include <stdint.h>
#include <string.h> #include <string.h>
BMS_Chip bms_data[N_BMS] = {}; BMS_Chip bms_data[N_BMS] = {};
uint8_t packetChecksumFails = 0; uint8_t packetChecksumFails = 0;
@ -24,8 +23,8 @@ struct pollingTimes pollingTimes = {0, 0};
static constexpr ADBMS_DetailedStatus NO_ERROR = {ADBMS_NO_ERROR}; static constexpr ADBMS_DetailedStatus NO_ERROR = {ADBMS_NO_ERROR};
ADBMS_DetailedStatus AMS_Init(USER_PTR_TYPE ptr) { ADBMS_DetailedStatus AMS_Init(USER_PTR_TYPE ptr) {
debug_log(ADBMS_LOG_LEVEL_INFO, "ADBMS6830B HAL - configured for %d controllers and %d cells per controller...", N_BMS, debug_log(ADBMS_LOG_LEVEL_INFO, "ADBMS6830B HAL - configured for %d controllers and %d cells per controller...",
N_CELLS); N_BMS, N_CELLS);
if (initAMS(ptr) != ADBMS_OK) { if (initAMS(ptr) != ADBMS_OK) {
debug_log(ADBMS_LOG_LEVEL_ERROR, "ADBMS6830B HAL - initialization failed"); debug_log(ADBMS_LOG_LEVEL_ERROR, "ADBMS6830B HAL - initialization failed");
return (ADBMS_DetailedStatus){ADBMS_INTERNAL_BMS_FAULT, -1}; return (ADBMS_DetailedStatus){ADBMS_INTERNAL_BMS_FAULT, -1};

View File

@ -1,6 +1,6 @@
#include "ADBMS_LL_Driver.h" #include "ADBMS_LL_Driver.h"
#include "config_ADBMS6830.h"
#include "ADBMS_Intern.h" #include "ADBMS_Intern.h"
#include "config_ADBMS6830.h"
#include <stdint.h> #include <stdint.h>
#include <strings.h> #include <strings.h>
@ -25,9 +25,9 @@ void initSPI(USER_PTR_TYPE ptr) {
#define CRC10_REMAINDER_MASK 0x200 #define CRC10_REMAINDER_MASK 0x200
#define CRC10_RESULT_MASK 0x3FF #define CRC10_RESULT_MASK 0x3FF
//command PEC calculation // command PEC calculation
//CRC-15 // CRC-15
//x^15 + x^14 + x^10 + x^8 + x^7 + x^4 + x^3 + 1 // x^15 + x^14 + x^10 + x^8 + x^7 + x^4 + x^3 + 1
static uint16_t computeCRC15(const uint8_t* data, size_t length) { static uint16_t computeCRC15(const uint8_t* data, size_t length) {
uint16_t remainder = INITIAL_COMMAND_PEC; uint16_t remainder = INITIAL_COMMAND_PEC;
@ -61,11 +61,11 @@ static uint8_t checkCommandPEC(const uint8_t* data, uint8_t datalen) {
return ((pech == data[datalen - 2]) && (pecl == data[datalen - 1])) ? 0 : 1; return ((pech == data[datalen - 2]) && (pecl == data[datalen - 1])) ? 0 : 1;
} }
//data PEC calculation // data PEC calculation
//CRC-10 // CRC-10
//x^10 + x^7 + x^3 + x^2 + x + 1 // x^10 + x^7 + x^3 + x^2 + x + 1
static uint16_t computeCRC10(const uint8_t* data, size_t length, bool rx_cmd) { static uint16_t computeCRC10(const uint8_t *data, size_t length, bool rx_cmd) {
uint16_t remainder = INITIAL_DATA_PEC; uint16_t remainder = INITIAL_DATA_PEC;
for (size_t i = 0; i < length; i++) { for (size_t i = 0; i < length; i++) {
@ -147,7 +147,6 @@ static void print_spi_details() {
} }
#endif #endif
ADBMS_Internal_Status ___writeCMD(uint16_t command, uint8_t * args, size_t arglen) { ADBMS_Internal_Status ___writeCMD(uint16_t command, uint8_t * args, size_t arglen) {
ADBMS_Internal_Status ret; ADBMS_Internal_Status ret;
if (arglen > 0) { if (arglen > 0) {
@ -199,7 +198,7 @@ ADBMS_Internal_Status ___writeCMD(uint16_t command, uint8_t * args, size_t argle
ADBMS_Internal_Status ___readCMD(uint16_t command, uint8_t * buffer, size_t arglen) { ADBMS_Internal_Status ___readCMD(uint16_t command, uint8_t * buffer, size_t arglen) {
buffer[0] = (command >> 8) & 0xFF; buffer[0] = (command >> 8) & 0xFF;
buffer[1] = (command)&0xFF; buffer[1] = (command) & 0xFF;
calculateCommandPEC(buffer, 4); calculateCommandPEC(buffer, 4);
mcuAdbmsCSLow(); mcuAdbmsCSLow();

View File

@ -1,6 +1,6 @@
#include "isotp_log_backend.h" #include "isotp_log_backend.h"
#include "log.h"
#include "isotp.h" #include "isotp.h"
#include "log.h"
#include <string.h> #include <string.h>

View File

@ -9,7 +9,7 @@
/* ISO-TP CAN ID configuration */ /* ISO-TP CAN ID configuration */
#ifndef ISOTP_LOG_CAN_ID //TEMPORARY!!!!! #ifndef ISOTP_LOG_CAN_ID // TEMPORARY!!!!!
#define ISOTP_LOG_CAN_ID 0x123 // CAN ID to use for ISO-TP log messages #define ISOTP_LOG_CAN_ID 0x123 // CAN ID to use for ISO-TP log messages
#endif #endif
#ifndef ISOTP_LOG_FC_CAN_ID #ifndef ISOTP_LOG_FC_CAN_ID

View File

@ -10,10 +10,10 @@
#ifndef __LOG_H #ifndef __LOG_H
#define __LOG_H #define __LOG_H
#include <stdint.h>
#include <stdarg.h> #include <stdarg.h>
#include <stdio.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
/* Configuration */ /* Configuration */
#define MAX_MESSAGE_LENGTH 384 #define MAX_MESSAGE_LENGTH 384
@ -43,10 +43,10 @@ typedef struct {
/* Log backend interface */ /* Log backend interface */
typedef struct { typedef struct {
const char* name; const char *name;
void (*init)(void); void (*init)(void);
bool (*is_enabled)(log_level_t level); bool (*is_enabled)(log_level_t level);
void (*write)(const log_message_t* message); void (*write)(const log_message_t *message);
void (*flush)(void); void (*flush)(void);
void (*clear)(void); void (*clear)(void);
} log_backend_t; } log_backend_t;

View File

@ -85,7 +85,8 @@ static void swo_backend_write(const log_message_t* message) {
return; return;
} }
// Assuming message->message is ensured to be non-NULL by the logger core if message itself is not NULL. // Assuming message->message is ensured to be non-NULL by the logger core if message itself is not NULL.
// Or, if message->message can be NULL, the caller of swo_util_puts should handle it or swo_util_puts should be robust to it. // Or, if message->message can be NULL, the caller of swo_util_puts should handle it or swo_util_puts should be
// robust to it.
#if USE_MULTIPLE_CHANNELS #if USE_MULTIPLE_CHANNELS
swo_util_puts(message->message, message->level); swo_util_puts(message->message, message->level);

View File

@ -1,7 +1,7 @@
#include "swo_util.h" #include "swo_util.h"
#include "stm32h7xx.h" // For ITM registers, __NOP() and ITM_TCR_ITMENA_Msk, ITM_TER_TER_Msk #include "stm32h7xx.h" // For ITM registers, __NOP() and ITM_TCR_ITMENA_Msk, ITM_TER_TER_Msk
#include <stdint.h> // For uint32_t
#include <stddef.h> // For NULL #include <stddef.h> // For NULL
#include <stdint.h> // For uint32_t
// Core function to send a character to a specific SWO ITM port // Core function to send a character to a specific SWO ITM port
// Adapted from ITM_SendChar() in the CMSIS-Core // Adapted from ITM_SendChar() in the CMSIS-Core

View File

@ -4,10 +4,10 @@
#include "NTC.h" #include "NTC.h"
#include "can.h" #include "can.h"
#include "config_ADBMS6830.h" #include "config_ADBMS6830.h"
#include "ts_state_machine.h"
#include <string.h>
#include <math.h>
#include "main.h" #include "main.h"
#include "ts_state_machine.h"
#include <math.h>
#include <string.h>
#define SWO_LOG_PREFIX "[BATTERY] " #define SWO_LOG_PREFIX "[BATTERY] "
#include "swo_log.h" #include "swo_log.h"
@ -73,21 +73,18 @@ HAL_StatusTypeDef battery_init(SPI_HandleTypeDef *hspi) {
HAL_StatusTypeDef battery_update() { HAL_StatusTypeDef battery_update() {
auto const ret = AMS_Idle_Loop(); auto const ret = AMS_Idle_Loop();
if (ret.status != ADBMS_NO_ERROR) { if (ret.status != ADBMS_NO_ERROR) {
debug_log(LOG_LEVEL_ERROR, "Error while updating battery data: %s", debug_log(LOG_LEVEL_ERROR, "Error while updating battery data: %s", ADBMS_Status_ToString(ret.status));
ADBMS_Status_ToString(ret.status));
if (ret.bms_id != -1) { if (ret.bms_id != -1) {
debug_log_cont(LOG_LEVEL_ERROR, " (on BMS ID: %hd)", ret.bms_id); debug_log_cont(LOG_LEVEL_ERROR, " (on BMS ID: %hd)", ret.bms_id);
} }
if (ret.status == ADBMS_OVERVOLT || ret.status == ADBMS_UNDERVOLT) { if (ret.status == ADBMS_OVERVOLT || ret.status == ADBMS_UNDERVOLT) {
if (ret.bms_id != -1 && ret.bms_id < N_BMS) { if (ret.bms_id != -1 && ret.bms_id < N_BMS) {
const char* error_type = (ret.status == ADBMS_OVERVOLT) ? "overvoltage" : "undervoltage"; const char *error_type = (ret.status == ADBMS_OVERVOLT) ? "overvoltage" : "undervoltage";
const uint32_t voltage_flags = (ret.status == ADBMS_OVERVOLT) ? const uint32_t voltage_flags = (ret.status == ADBMS_OVERVOLT) ? bms_data[ret.bms_id].overVoltage
bms_data[ret.bms_id].overVoltage : : bms_data[ret.bms_id].underVoltage;
bms_data[ret.bms_id].underVoltage;
debug_log(LOG_LEVEL_ERROR, "Cell %s detected on module %d, affected cells: ", debug_log(LOG_LEVEL_ERROR, "Cell %s detected on module %d, affected cells: ", error_type, ret.bms_id);
error_type, ret.bms_id);
for (size_t cell = 0; cell < N_CELLS; cell++) { for (size_t cell = 0; cell < N_CELLS; cell++) {
if (voltage_flags & (1UL << cell)) { if (voltage_flags & (1UL << cell)) {
@ -138,10 +135,9 @@ HAL_StatusTypeDef battery_update() {
} }
// Process temperature values // Process temperature values
for (size_t j = 0; j < 10; j++) { //10 GPIOs for (size_t j = 0; j < 10; j++) { // 10 GPIOs
battery.module[i].cellTemps[j] = ntc_mv_to_celsius(bms_data[i].auxVoltages[j]); battery.module[i].cellTemps[j] = ntc_mv_to_celsius(bms_data[i].auxVoltages[j]);
// For new battery struct // For new battery struct
if (battery.module[i].cellTemps[j] > battery.pack.max_temp) { if (battery.module[i].cellTemps[j] > battery.pack.max_temp) {
battery.pack.max_temp = battery.module[i].cellTemps[j]; battery.pack.max_temp = battery.module[i].cellTemps[j];

View File

@ -1,14 +1,14 @@
#include "can.h" #include "can.h"
#include "ADBMS_Driver.h" #include "ADBMS_Driver.h"
#include "battery.h"
#include "imd_monitoring.h" #include "imd_monitoring.h"
#include "isotp.h" #include "isotp.h"
#include "isotp_user_defs.h"
#include "isotp_log_backend.h" #include "isotp_log_backend.h"
#include "isotp_user_defs.h"
#include "log.h" #include "log.h"
#include "main.h" #include "main.h"
#include "shunt_monitoring.h" #include "shunt_monitoring.h"
#include "battery.h"
#include "soc_estimation.h" #include "soc_estimation.h"
#include "ts_state_machine.h" #include "ts_state_machine.h"
@ -24,9 +24,7 @@ bool isotp_transmit(uint16_t id, const uint8_t *data, size_t datalen) {
return ftcan_transmit(id, data, datalen) == HAL_OK; return ftcan_transmit(id, data, datalen) == HAL_OK;
} }
uint32_t isotp_get_time() { uint32_t isotp_get_time() { return HAL_GetTick(); }
return HAL_GetTick();
}
void can_init(FDCAN_HandleTypeDef *handle) { void can_init(FDCAN_HandleTypeDef *handle) {
ftcan_init(handle); ftcan_init(handle);
@ -62,15 +60,14 @@ HAL_StatusTypeDef can_send_status() {
if (ret != HAL_OK) { if (ret != HAL_OK) {
return ret; return ret;
} }
data[0] = (sdc_closed_nodelay << 0) | (ts_error << 1) | (hv_active << 2) | data[0] = (sdc_closed_nodelay << 0) | (ts_error << 1) | (hv_active << 2) | (neg_air_closed << 3) |
(neg_air_closed << 3) | (pos_air_closed << 4) | (pos_air_closed << 4) | (precharge_closed << 5) | (pre_and_air_open << 6);
(precharge_closed << 5) | (pre_and_air_open << 6);
return ftcan_transmit(CAN_ID_AMS_SIGNALS, data, 1); return ftcan_transmit(CAN_ID_AMS_SIGNALS, data, 1);
} }
HAL_StatusTypeDef can_send_details() { HAL_StatusTypeDef can_send_details() {
static uint8_t module_index = 0; static uint8_t module_index = 0;
static uint8_t data[103] = {}; //sizeof(BMS_Chip) + 10 + 1 static uint8_t data[103] = {}; // sizeof(BMS_Chip) + 10 + 1
auto const module = &bms_data[module_index]; auto const module = &bms_data[module_index];
auto data_ptr = &data[1]; auto data_ptr = &data[1];

View File

@ -44,28 +44,23 @@ void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *handle) {
imd_data.duty_cycle = (100 * high_time) / period; imd_data.duty_cycle = (100 * high_time) / period;
// Check PWM frequency for state determination // Check PWM frequency for state determination
if (imd_data.freq > FREQ_NORMAL - FREQ_TOLERANCE && if (imd_data.freq > FREQ_NORMAL - FREQ_TOLERANCE && imd_data.freq < FREQ_NORMAL + FREQ_TOLERANCE) {
imd_data.freq < FREQ_NORMAL + FREQ_TOLERANCE) {
imd_data.state = IMD_STATE_NORMAL; imd_data.state = IMD_STATE_NORMAL;
} else if (imd_data.freq > FREQ_UNDERVOLTAGE - FREQ_TOLERANCE && } else if (imd_data.freq > FREQ_UNDERVOLTAGE - FREQ_TOLERANCE &&
imd_data.freq < FREQ_UNDERVOLTAGE + FREQ_TOLERANCE) { imd_data.freq < FREQ_UNDERVOLTAGE + FREQ_TOLERANCE) {
imd_data.state = IMD_STATE_UNDERVOLTAGE; imd_data.state = IMD_STATE_UNDERVOLTAGE;
} else if (imd_data.freq > FREQ_SST - FREQ_TOLERANCE && } else if (imd_data.freq > FREQ_SST - FREQ_TOLERANCE && imd_data.freq < FREQ_SST + FREQ_TOLERANCE) {
imd_data.freq < FREQ_SST + FREQ_TOLERANCE) {
imd_data.state = IMD_STATE_SST; imd_data.state = IMD_STATE_SST;
} else if (imd_data.freq > FREQ_DEV_ERROR - FREQ_TOLERANCE && } else if (imd_data.freq > FREQ_DEV_ERROR - FREQ_TOLERANCE && imd_data.freq < FREQ_DEV_ERROR + FREQ_TOLERANCE) {
imd_data.freq < FREQ_DEV_ERROR + FREQ_TOLERANCE) {
imd_data.state = IMD_STATE_DEV_ERROR; imd_data.state = IMD_STATE_DEV_ERROR;
} else if (imd_data.freq > FREQ_GND_FAULT - FREQ_TOLERANCE && } else if (imd_data.freq > FREQ_GND_FAULT - FREQ_TOLERANCE && imd_data.freq < FREQ_GND_FAULT + FREQ_TOLERANCE) {
imd_data.freq < FREQ_GND_FAULT + FREQ_TOLERANCE) {
imd_data.state = IMD_STATE_GND_FAULT; imd_data.state = IMD_STATE_GND_FAULT;
} else { } else {
imd_data.state = IMD_STATE_UNKNOWN; imd_data.state = IMD_STATE_UNKNOWN;
} }
// Calculate R_iso // Calculate R_iso
if (imd_data.state == IMD_STATE_NORMAL || if (imd_data.state == IMD_STATE_NORMAL || imd_data.state == IMD_STATE_UNDERVOLTAGE) {
imd_data.state == IMD_STATE_UNDERVOLTAGE) {
if (imd_data.duty_cycle < RISO_MIN_DUTY_CYCLE) { if (imd_data.duty_cycle < RISO_MIN_DUTY_CYCLE) {
imd_data.r_iso = RISO_MAX; imd_data.r_iso = RISO_MAX;
} else { } else {

View File

@ -79,8 +79,7 @@ void soc_update() {
current_was_flowing = 0; current_was_flowing = 0;
} }
if (now - last_current_time >= SOC_ESTIMATION_NO_CURRENT_TIME || if (now - last_current_time >= SOC_ESTIMATION_NO_CURRENT_TIME || last_current_time == 0) {
last_current_time == 0) {
// Assume we're measuring OCV if there's been no current for a while (or // Assume we're measuring OCV if there's been no current for a while (or
// we've just turned on the battery). // we've just turned on the battery).
battery.pack.soc = soc_for_ocv(battery.pack.min_voltage); battery.pack.soc = soc_for_ocv(battery.pack.min_voltage);