diff --git a/AMS_Master_Code/.vscode/launch.json b/AMS_Master_Code/.vscode/launch.json index e713b61..4fa138f 100644 --- a/AMS_Master_Code/.vscode/launch.json +++ b/AMS_Master_Code/.vscode/launch.json @@ -40,7 +40,6 @@ "request": "attach", "type": "cortex-debug", "servertype": "openocd", - "preLaunchTask": "Build STM", "device": "stm32h7a3xxq.s", "configFiles": [ "openocd.cfg" diff --git a/AMS_Master_Code/Core/Inc/NTC.h b/AMS_Master_Code/Core/Inc/NTC.h index 7934f44..6c0d10b 100644 --- a/AMS_Master_Code/Core/Inc/NTC.h +++ b/AMS_Master_Code/Core/Inc/NTC.h @@ -1,4 +1,5 @@ #include <math.h> +#include <stdint.h> #define USE_CALC @@ -18,10 +19,10 @@ // With R_T/R_0 and R_0 = R_T@25C // R_T/R_0 = 1 / V_REF / ADC - 1 +[[gnu::optimize("fast-math")]] static inline uint16_t ntc_mv_to_celsius(int16_t adc) { - float log_ohms = logf(1/((VREF/adc)-1)); + 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); - } #else // Lookup Table coming soon; not really needed but fun? diff --git a/AMS_Master_Code/Core/Inc/config_ADBMS6830.h b/AMS_Master_Code/Core/Inc/config_ADBMS6830.h index 4b60e4c..2fdaa6a 100644 --- a/AMS_Master_Code/Core/Inc/config_ADBMS6830.h +++ b/AMS_Master_Code/Core/Inc/config_ADBMS6830.h @@ -4,13 +4,17 @@ #include "main.h" #define N_BMS 1 -#define ADBMS_SPI_TIMEOUT 100 // Timeout in ms +#define N_CELLS 16 +#define ADBMS_MAX_CHIP_TEMP 110 // max temperature of ADBMS6830B (not battery) in C +#define ADBMS_SPI_TIMEOUT 50 // Timeout in ms -[[maybe_unused]] static inline void mcuAdbmsCSLow() { +[[maybe_unused, gnu::always_inline]] +static inline void mcuAdbmsCSLow() { HAL_GPIO_WritePin(AMS_CS_GPIO_Port, AMS_CS_Pin, GPIO_PIN_RESET); } -[[maybe_unused]] static inline void mcuAdbmsCSHigh() { +[[maybe_unused, gnu::always_inline]] +static inline void mcuAdbmsCSHigh() { HAL_GPIO_WritePin(AMS_CS_GPIO_Port, AMS_CS_Pin, GPIO_PIN_SET); } diff --git a/AMS_Master_Code/Core/Inc/swo_log.h b/AMS_Master_Code/Core/Inc/swo_log.h index 1eb1e68..ed95e66 100644 --- a/AMS_Master_Code/Core/Inc/swo_log.h +++ b/AMS_Master_Code/Core/Inc/swo_log.h @@ -93,8 +93,7 @@ static inline void __swo_print(unsigned int channel, const char *str) { } } -[[maybe_unused]] -static void debug_clear_console() { +static inline void debug_clear_console() { for (int i = 0; i < LOG_LEVEL_NOISY; i++) { #if USE_ANSI_ESCAPE_CODES __swo_print(i, "\033[2J\033[;H"); // clear screen @@ -104,44 +103,58 @@ static void debug_clear_console() { } } -#define debug_log(level, msg, ...) \ - do { \ - if (DEBUG_CHANNEL_ENABLED(level)) { \ - char __swo_buffer[MAX_MESSAGE_LENGTH]; \ - size_t len = \ - snprintf(__swo_buffer, sizeof(__swo_buffer), msg, ##__VA_ARGS__); \ - __swo_putc('\n', level); \ - /* Print timestamp if enabled */ \ - if (PRINT_TIMESTAMP) { \ - char __time_buffer[16]; \ - if (USE_ANSI_ESCAPE_CODES) { \ - snprintf(__time_buffer, sizeof(__time_buffer), \ - "\033[90m[%lu]\033[0m ", HAL_GetTick()); \ - } else { \ - snprintf(__time_buffer, sizeof(__time_buffer), "[%lu] ", \ - HAL_GetTick()); \ - } \ - __swo_print(level, __time_buffer); \ - } \ - __swo_print(level, log_level_names[level]); \ - __swo_print(level, __swo_buffer); \ - if (len >= sizeof(__swo_buffer)) { \ - __swo_print(level, " [message length exceeded] "); \ - } \ - } \ - } while (0) +[[gnu::format(printf, 2, 3)]] +static inline void debug_log(enum log_level_t level, const char *msg, ...) { + if (!DEBUG_CHANNEL_ENABLED(level)) { + return; + } + + char __swo_buffer[MAX_MESSAGE_LENGTH]; + va_list args; + va_start(args, msg); + size_t len = vsnprintf(__swo_buffer, sizeof(__swo_buffer), msg, args); + va_end(args); + + __swo_putc('\n', level); + + /* Print timestamp if enabled */ + if (PRINT_TIMESTAMP) { + char __time_buffer[16]; + if (USE_ANSI_ESCAPE_CODES) { + snprintf(__time_buffer, sizeof(__time_buffer), + "\033[90m[%lu]\033[0m ", HAL_GetTick()); + } else { + snprintf(__time_buffer, sizeof(__time_buffer), "[%lu] ", + HAL_GetTick()); + } + __swo_print(level, __time_buffer); + } + + __swo_print(level, log_level_names[level]); + __swo_print(level, __swo_buffer); + + if (len >= sizeof(__swo_buffer)) { + __swo_print(level, " [message length exceeded] "); + } +} -#define debug_log_cont(level, msg, ...) \ - do { \ - if (DEBUG_CHANNEL_ENABLED(level)) { \ - char __swo_buffer[MAX_MESSAGE_LENGTH]; \ - size_t len = \ - snprintf(__swo_buffer, sizeof(__swo_buffer), msg, ##__VA_ARGS__); \ - __swo_print(level, __swo_buffer); \ - if (len >= sizeof(__swo_buffer)) { \ - __swo_print(level, " [message length exceeded] "); \ - } \ - } \ - } while (0) +[[gnu::format(printf, 2, 3)]] +static inline void debug_log_cont(enum log_level_t level, const char *msg, ...) { + if (!DEBUG_CHANNEL_ENABLED(level)) { + return; + } + + char __swo_buffer[MAX_MESSAGE_LENGTH]; + va_list args; + va_start(args, msg); + size_t len = vsnprintf(__swo_buffer, sizeof(__swo_buffer), msg, args); + va_end(args); + + __swo_print(level, __swo_buffer); + + if (len >= sizeof(__swo_buffer)) { + __swo_print(level, " [message length exceeded] "); + } +} #endif /* __SWO_LOG_H */ diff --git a/AMS_Master_Code/Core/Lib/ADBMS6830B_Driver/Core/Inc/ADBMS_Abstraction.h b/AMS_Master_Code/Core/Lib/ADBMS6830B_Driver/Core/Inc/ADBMS_Abstraction.h index 406e92c..8b1fdca 100644 --- a/AMS_Master_Code/Core/Lib/ADBMS6830B_Driver/Core/Inc/ADBMS_Abstraction.h +++ b/AMS_Master_Code/Core/Lib/ADBMS6830B_Driver/Core/Inc/ADBMS_Abstraction.h @@ -8,10 +8,7 @@ #ifndef INC_ADBMS_ABSTRACTION_H_ #define INC_ADBMS_ABSTRACTION_H_ -#include "ADBMS_CMD_MAKROS.h" #include "ADBMS_Driver.h" -#include "ADBMS_LL_Driver.h" -#include "main.h" #define mV_from_ADBMS6830(x) (((((int16_t)(x))) * 0.150) + 1500) diff --git a/AMS_Master_Code/Core/Lib/ADBMS6830B_Driver/Core/Inc/ADBMS_Driver.h b/AMS_Master_Code/Core/Lib/ADBMS6830B_Driver/Core/Inc/ADBMS_Driver.h index 6c8a037..020b3f1 100644 --- a/AMS_Master_Code/Core/Lib/ADBMS6830B_Driver/Core/Inc/ADBMS_Driver.h +++ b/AMS_Master_Code/Core/Lib/ADBMS6830B_Driver/Core/Inc/ADBMS_Driver.h @@ -83,7 +83,7 @@ typedef struct { uint32_t bmsID; struct ADBMS6830_Internal_Status status; - uint16_t internalDieTemp; + int16_t internalDieTemp; uint16_t analogSupplyVoltage; uint16_t digitalSupplyVoltage; uint16_t sumOfCellMeasurements; diff --git a/AMS_Master_Code/Core/Lib/ADBMS6830B_Driver/Core/Inc/ADBMS_HighLevel.h b/AMS_Master_Code/Core/Lib/ADBMS6830B_Driver/Core/Inc/ADBMS_HighLevel.h index 2222503..ced8255 100644 --- a/AMS_Master_Code/Core/Lib/ADBMS6830B_Driver/Core/Inc/ADBMS_HighLevel.h +++ b/AMS_Master_Code/Core/Lib/ADBMS6830B_Driver/Core/Inc/ADBMS_HighLevel.h @@ -30,6 +30,4 @@ extern Cell_Module modules[N_BMS]; extern uint32_t balancedCells; extern bool BalancingActive; -extern uint8_t numberofCells; - #endif /* INC_AMS_HIGHLEVEL_H_ */ 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 73a0156..cb785ce 100644 --- 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 @@ -9,9 +9,7 @@ #define ADBMS_LL_DRIVER_H_ #include "config_ADBMS6830.h" -#include "stm32h7xx_hal.h" #include <stdint.h> -#define TARGET_STM32 uint8_t adbmsDriverInit(SPI_HandleTypeDef* hspi); 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 93f794c..9a219cb 100644 --- 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 @@ -13,8 +13,6 @@ #include <stddef.h> #include "NTC.h" -extern uint8_t numberofCells; - static const char* const HAL_Statuses[] = {"HAL_OK", "HAL_ERROR", "HAL_BUSY", "HAL_TIMEOUT"}; #define CHECK_RETURN(x) \ @@ -91,8 +89,7 @@ HAL_StatusTypeDef initAMS(SPI_HandleTypeDef* hspi) { } HAL_StatusTypeDef amsWakeUp() { - uint8_t buffer[CMD_BUFFER_SIZE(CFG_GROUP_A_SIZE)] = {0}; - return readCMD(RDCFGA, buffer, CFG_GROUP_A_SIZE); + return __pollCMD(PLADC, 100); //wake up ADBMS6830, wait for T_wake = 200 us (100 cycles at 500 kHz) } HAL_StatusTypeDef amsCellMeasurement(Cell_Module (*module)[N_BMS]) { @@ -264,8 +261,7 @@ HAL_StatusTypeDef amsCheckUnderOverVoltage(Cell_Module (*module)[N_BMS]) { (*module)[i].overVoltage = 0; (*module)[i].underVoltage = 0; - for (size_t j = 0; j < numberofCells; - j++) { // ov/uv flags are 1-bit flags for each cell C0UV, C0OV, C1UV, C1OV, ... + for (size_t j = 0; j < N_CELLS; j++) { // ov/uv flags are 1-bit flags for each cell C0UV, C0OV, C1UV, C1OV, ... (*module)[i].underVoltage |= (ov_uv_data >> (j * 2)) & 0x01; (*module)[i].overVoltage |= (ov_uv_data >> (j * 2 + 1)) & 0x01; } diff --git a/AMS_Master_Code/Core/Lib/ADBMS6830B_Driver/Core/Src/ADBMS_HighLevel.c b/AMS_Master_Code/Core/Lib/ADBMS6830B_Driver/Core/Src/ADBMS_HighLevel.c index e30a1ed..afd150f 100644 --- a/AMS_Master_Code/Core/Lib/ADBMS6830B_Driver/Core/Src/ADBMS_HighLevel.c +++ b/AMS_Master_Code/Core/Lib/ADBMS6830B_Driver/Core/Src/ADBMS_HighLevel.c @@ -18,8 +18,6 @@ Cell_Module modules[N_BMS] = {}; uint32_t balancedCells = 0; bool balancingActive = false; -uint8_t numberofCells = 16; - uint8_t packetChecksumFails = 0; #define MAX_PACKET_CHECKSUM_FAILS 5 @@ -37,7 +35,7 @@ static constexpr ADBMS_DetailedStatus NO_ERROR = {ADBMS_NO_ERROR}; ADBMS_DetailedStatus AMS_Init(SPI_HandleTypeDef* hspi) { debug_log(LOG_LEVEL_INFO, "ADBMS6830B HAL - configured for %d controllers and %d cells per controller...", N_BMS, - numberofCells); + N_CELLS); if (initAMS(hspi) != HAL_OK) { debug_log(LOG_LEVEL_ERROR, "ADBMS6830B HAL - initialization failed"); return (ADBMS_DetailedStatus){ADBMS_INTERNAL_BMS_FAULT, -1}; @@ -106,8 +104,7 @@ ADBMS_DetailedStatus AMS_Idle_Loop() { return (ADBMS_DetailedStatus){ADBMS_UNDERVOLT, match - 1}; } - // TODO: replace with the correct threshold for the internal die temperature - if ((match = any(module.internalDieTemp > 28000 || module.status.THSD))) { + if ((match = any(module.internalDieTemp > ADBMS_MAX_CHIP_TEMP || module.status.THSD))) { return (ADBMS_DetailedStatus){ADBMS_INTERNAL_BMS_OVERTEMP, match - 1}; } 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 a35c61c..f951a04 100644 --- 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 @@ -15,6 +15,13 @@ #define INITIAL_COMMAND_PEC 0x0010 #define INITIAL_DATA_PEC 0x0010 +// CRC polynomial constants +#define CRC15_POLY 0xC599 +#define CRC10_POLY 0x8F +#define CRC15_REMAINDER_MASK 0x4000 +#define CRC10_REMAINDER_MASK 0x200 +#define CRC10_RESULT_MASK 0x3FF + SPI_HandleTypeDef* adbmsspi; uint8_t adbmsDriverInit(SPI_HandleTypeDef* hspi) { @@ -49,8 +56,8 @@ static uint16_t computeCRC15(const uint8_t* data, size_t length) { for (size_t i = 0; i < length; i++) { remainder ^= (data[i] << 7); for (int b = 0; b < 8; b++) { - if (remainder & 0x4000) { - remainder = (uint16_t)((remainder << 1) ^ 0xC599); + if (remainder & CRC15_REMAINDER_MASK) { + remainder = (uint16_t)((remainder << 1) ^ CRC15_POLY); } else { remainder <<= 1; } @@ -81,13 +88,12 @@ static uint8_t checkCommandPEC(uint8_t* data, uint8_t datalen) { static uint16_t computeCRC10(const uint8_t* data, size_t length, bool rx_cmd) { uint16_t remainder = INITIAL_DATA_PEC; - const uint16_t poly = 0x8F; for (size_t i = 0; i < length; i++) { remainder ^= (uint16_t)(data[i] << 2); for (int b = 0; b < 8; b++) { - if (remainder & 0x200) { - remainder = (uint16_t)((remainder << 1) ^ poly); + if (remainder & CRC10_REMAINDER_MASK) { + remainder = (uint16_t)((remainder << 1) ^ CRC10_POLY); } else { remainder <<= 1; } @@ -98,14 +104,14 @@ static uint16_t computeCRC10(const uint8_t* data, size_t length, bool rx_cmd) { if (rx_cmd) { remainder ^= (uint16_t)((data[length] & 0xFC) << 2); for (int b = 0; b < 6; b++) { - if (remainder & 0x200) { - remainder = (uint16_t)((remainder << 1) ^ poly); + if (remainder & CRC10_REMAINDER_MASK) { + remainder = (uint16_t)((remainder << 1) ^ CRC10_POLY); } else { remainder <<= 1; } } } - return (uint16_t)(remainder & 0x3FF); + return (uint16_t)(remainder & CRC10_RESULT_MASK); } static uint8_t calculateDataPEC(uint8_t* data, uint8_t datalen) { @@ -242,10 +248,27 @@ HAL_StatusTypeDef ___readCMD(uint16_t command, uint8_t * buffer, size_t arglen) } } + if (arglen == 0) { + return HAL_OK; //no data to check + } + //check data PEC for (size_t i = 0; i < N_BMS; i++) { size_t offset = BUFFER_BMS_OFFSET(i, arglen); if (checkDataPEC(&buffer[offset], arglen + 2) != 0) { + debug_log(LOG_LEVEL_ERROR, "Invalid data PEC when reading BMS %d", i); + debug_log(LOG_LEVEL_ERROR, "Received: "); + for (size_t j = 0; j < arglen + 2; j++) { + debug_log_cont(LOG_LEVEL_ERROR, "%02X ", buffer[offset + j]); + } + debug_log_cont(LOG_LEVEL_ERROR, "| %02X %02X ", buffer[offset + arglen], buffer[offset + arglen + 1]); //print out the DPEC + debug_log(LOG_LEVEL_ERROR, " DATA ^"); + //print out spaces until start of DPEC + for (size_t j = 0; j < arglen - 1; j++) { + debug_log_cont(LOG_LEVEL_ERROR, (arglen < 2) ? "" : "^^^"); + } + debug_log_cont(LOG_LEVEL_ERROR, "^^ "); + debug_log_cont(LOG_LEVEL_ERROR, " PEC ^"); return HAL_ERROR; } } @@ -271,5 +294,5 @@ HAL_StatusTypeDef __pollCMD(uint16_t command, uint8_t waitTime) { return status; } - return ((buffer[4 + (N_BMS * 2)] & 0x0F) == 0x0) ? HAL_BUSY : HAL_OK; //SDO goes high when data is ready + return ((buffer[sizeof buffer] & 0x0F) == 0x0) ? HAL_BUSY : HAL_OK; //SDO goes high when data is ready } \ No newline at end of file