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 27eb9c4..b4194d9 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 @@ -1,53 +1,62 @@ #ifndef ADBMS_DRIVER_H #define ADBMS_DRIVER_H -#include #include "stm32h7xx_hal.h" +#include #define ERROR_TIME_THRESH 150 // ms -typedef enum { - SEK_OVERTEMP, - SEK_UNDERTEMP, - SEK_OVERVOLT, - SEK_UNDERVOLT, - SEK_TOO_FEW_TEMPS, - SEK_OPENWIRE, - SEK_EEPROM_ERR, - SEK_INTERNAL_BMS_TIMEOUT, - SEK_INTERNAL_BMS_CHECKSUM_FAIL, - SEK_INTERNAL_BMS_OVERTEMP, - SEK_INTERNAL_BMS_FAULT, - SEK_1WIRE_ERR, - SEK_DS18B20_TIMEOUT, - NUM_ERROR_KINDS -} SlaveErrorKind; +typedef enum : uint16_t { + ADBMS_OK = 0x00, // same as STM32 HAL status + ADBMS_ERROR = 0x01, // + ADBMS_BUSY = 0x02, // + ADBMS_TIMEOUT = 0x03 // +} ADBMS_StatusTypeDef; + +typedef enum : uint16_t { + ADBMS_NONE = 0, + ADBMS_OVERTEMP, + ADBMS_UNDERTEMP, + ADBMS_OVERVOLT, + ADBMS_UNDERVOLT, + ADBMS_OPENWIRE, + ADBMS_INTERNAL_BMS_TIMEOUT, + ADBMS_INTERNAL_BMS_CHECKSUM_FAIL, + ADBMS_INTERNAL_BMS_OVERTEMP, + ADBMS_INTERNAL_BMS_FAULT, + NUM_ERROR_KINDS +} ADBMS_ErrorKind; typedef struct { - uint8_t data[4]; - uint32_t errors_since; + ADBMS_StatusTypeDef status : 16; + ADBMS_ErrorKind error : 16; // zero if status is ADBMS_OK +} ADBMS_DetailedStatus; + +typedef struct { + uint8_t data[4]; + uint32_t errors_since; } SlaveErrorData; struct ADBMS6830_Internal_Status { - uint16_t CS_FLT : 16; //ADC fault - mismatch between S- and C-ADC + uint16_t CS_FLT : 16; // ADC fault - mismatch between S- and C-ADC uint16_t : 3; - uint16_t CCTS : 13; //Conversion counter - uint16_t SMED : 1; //S-ADC multiple trim error (uncorrectable) - uint16_t SED : 1; //S-ADC single trim error (correctable) - uint16_t CMED : 1; //C-ADC multiple trim error (uncorrectable) - uint16_t CED : 1; //C-ADC single trim error (correctable) - uint16_t VD_UV : 1; //3V digital supply undervoltage - uint16_t VD_OV : 1; //3V digital supply overvoltage - uint16_t VA_UV : 1; //5V analog supply undervoltage - uint16_t VA_OV : 1; //5V analog supply overvoltage - uint16_t OSCCHK : 1; //Oscillator check - uint16_t TMODCHK : 1; //Test mode check - uint16_t THSD : 1; //Thermal shutdown - uint16_t SLEEP : 1; //Sleep mode previously entered - uint16_t SPIFLT : 1; //SPI fault - uint16_t COMPARE : 1; //Comparasion between S- and C-ADC active - uint16_t VDE : 1; //Supply voltage error - uint16_t VDEL : 1; //Latent supply voltage error + uint16_t CCTS : 13; // Conversion counter + uint16_t SMED : 1; // S-ADC multiple trim error (uncorrectable) + uint16_t SED : 1; // S-ADC single trim error (correctable) + uint16_t CMED : 1; // C-ADC multiple trim error (uncorrectable) + uint16_t CED : 1; // C-ADC single trim error (correctable) + uint16_t VD_UV : 1; // 3V digital supply undervoltage + uint16_t VD_OV : 1; // 3V digital supply overvoltage + uint16_t VA_UV : 1; // 5V analog supply undervoltage + uint16_t VA_OV : 1; // 5V analog supply overvoltage + uint16_t OSCCHK : 1; // Oscillator check + uint16_t TMODCHK : 1; // Test mode check + uint16_t THSD : 1; // Thermal shutdown + uint16_t SLEEP : 1; // Sleep mode previously entered + uint16_t SPIFLT : 1; // SPI fault + uint16_t COMPARE : 1; // Comparasion between S- and C-ADC active + uint16_t VDE : 1; // Supply voltage error + uint16_t VDEL : 1; // Latent supply voltage error }; #define MAXIMUM_CELL_VOLTAGES 16 @@ -75,10 +84,9 @@ typedef struct { extern uint32_t error_sources; // Bitfield of error sources extern SlaveErrorData error_data[NUM_ERROR_KINDS]; -[[gnu::nonnull]] -void AMS_Init(SPI_HandleTypeDef* hspi); +[[gnu::nonnull]] ADBMS_DetailedStatus AMS_Init(SPI_HandleTypeDef* hspi); -uint8_t AMS_Idle_Loop(); +ADBMS_DetailedStatus AMS_Idle_Loop(); #undef MAXIMUM_CELL_VOLTAGES #undef MAXIMUM_AUX_VOLTAGES diff --git a/AMS_Master_Code/Core/Lib/ADBMS6830B_Driver/Core/Inc/ADBMS_Error.h b/AMS_Master_Code/Core/Lib/ADBMS6830B_Driver/Core/Inc/ADBMS_Error.h index 4d2a8d5..2e37f99 100644 --- a/AMS_Master_Code/Core/Lib/ADBMS6830B_Driver/Core/Inc/ADBMS_Error.h +++ b/AMS_Master_Code/Core/Lib/ADBMS6830B_Driver/Core/Inc/ADBMS_Error.h @@ -11,8 +11,8 @@ static_assert(sizeof(error_sources) * CHAR_BIT >= NUM_ERROR_KINDS, "error_sources is too small to hold all error sources"); -void set_error_source(SlaveErrorKind source); -void clear_error_source(SlaveErrorKind source); +void set_error_source(ADBMS_ErrorKind source); +void clear_error_source(ADBMS_ErrorKind source); #endif //AMS_MASTER_CODE_ADBMS_ERROR_H diff --git a/AMS_Master_Code/Core/Lib/ADBMS6830B_Driver/Core/Src/ADBMS_Error.c b/AMS_Master_Code/Core/Lib/ADBMS6830B_Driver/Core/Src/ADBMS_Error.c index 6b94b28..04554bc 100644 --- a/AMS_Master_Code/Core/Lib/ADBMS6830B_Driver/Core/Src/ADBMS_Error.c +++ b/AMS_Master_Code/Core/Lib/ADBMS6830B_Driver/Core/Src/ADBMS_Error.c @@ -4,14 +4,14 @@ SlaveErrorData error_data[NUM_ERROR_KINDS] = {}; uint32_t error_sources = 0; -void set_error_source(SlaveErrorKind source) { +void set_error_source(ADBMS_ErrorKind source) { if (!(error_sources & (1 << source))) { error_data[source].errors_since = HAL_GetTick(); } error_sources |= (1 << source); } -void clear_error_source(SlaveErrorKind source) { +void clear_error_source(ADBMS_ErrorKind source) { error_data[source].errors_since = 0; error_sources &= ~(1 << source); } 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 ce26e53..49cbadf 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 @@ -7,10 +7,10 @@ #include "ADBMS_HighLevel.h" #include "ADBMS_Abstraction.h" +#include "ADBMS_Driver.h" +#include "ADBMS_Error.h" #include "ADBMS_LL_Driver.h" #include "config_ADBMS6830.h" -#include "ADBMS_Error.h" -#include "ADBMS_Driver.h" #include "stm32h7xx_hal.h" #include "swo_log.h" #include @@ -26,115 +26,119 @@ uint8_t packetChecksumFails = 0; #define MAX_PACKET_CHECKSUM_FAILS 5 uint8_t deviceSleeps = 0; -#define MAX_DEVICE_SLEEP 3 //TODO: change to correct value +#define MAX_DEVICE_SLEEP 3 // TODO: change to correct value struct pollingTimes { - uint32_t S_ADC_OW_CHECK; - uint32_t TMP1075; + uint32_t S_ADC_OW_CHECK; + uint32_t TMP1075; }; struct pollingTimes pollingTimes = {0, 0}; -void AMS_Init(SPI_HandleTypeDef* hspi) { - debug_log(LOG_LEVEL_INFO, "ADBMS6830B HAL - configured for %d controllers and %d cells per controller...", N_BMS, numberofCells); - if (initAMS(hspi) != HAL_OK) { - debug_log(LOG_LEVEL_ERROR, "ADBMS6830B HAL - initialization failed"); - } +static constexpr ADBMS_DetailedStatus NO_ERROR = {ADBMS_OK, ADBMS_NONE}; - pollingTimes = (struct pollingTimes) {HAL_GetTick(), HAL_GetTick()}; +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); + if (initAMS(hspi) != HAL_OK) { + debug_log(LOG_LEVEL_ERROR, "ADBMS6830B HAL - initialization failed"); + return (ADBMS_DetailedStatus){ADBMS_ERROR, ADBMS_INTERNAL_BMS_FAULT}; + } + + pollingTimes = (struct pollingTimes){HAL_GetTick(), HAL_GetTick()}; + return NO_ERROR; } -#define any(x) ({ \ - bool any = false; \ - for (size_t __any_intern_i = 0; __any_intern_i < N_BMS; __any_intern_i++) { \ - Cell_Module module = modules[__any_intern_i]; \ - any |= (x); \ - } \ - any; \ -}) +#define any(x) \ + ({ \ + uint32_t any = false; \ + static_assert(sizeof(any) * CHAR_BIT >= N_BMS, "any datatype needs to be larger!"); \ + for (size_t __any_intern_i = 0; __any_intern_i < N_BMS; __any_intern_i++) { \ + Cell_Module module = modules[__any_intern_i]; \ + any |= ((x) ? 1 : 0) << __any_intern_i; \ + } \ + any; \ + }) +ADBMS_DetailedStatus AMS_Idle_Loop() { + if (!amsWakeUp()) { + // error_data.data_kind = SEK_INTERNAL_BMS_TIMEOUT; //we don't receive data for the wakeup command + // set_error_source(ERROR_SOURCE_INTERNAL); //so we can't tell if we timed out + } -uint8_t AMS_Idle_Loop() { - if (!amsWakeUp()) { - //error_data.data_kind = SEK_INTERNAL_BMS_TIMEOUT; //we don't receive data for the wakeup command - //set_error_source(ERROR_SOURCE_INTERNAL); //so we can't tell if we timed out - } - - packetChecksumFails += amsAuxAndStatusMeasurement(&modules); + packetChecksumFails += amsAuxAndStatusMeasurement(&modules); - if (any(module.status.SLEEP)) { - deviceSleeps++; - if (deviceSleeps > MAX_DEVICE_SLEEP) { - set_error_source(SEK_INTERNAL_BMS_TIMEOUT); + if (any(module.status.SLEEP)) { + deviceSleeps++; + if (deviceSleeps > MAX_DEVICE_SLEEP) { + return (ADBMS_DetailedStatus){ADBMS_ERROR, ADBMS_INTERNAL_BMS_TIMEOUT}; + } else { + amsReset(); + } + } + + if (any(module.status.CS_FLT || module.status.SPIFLT || module.status.CMED || module.status.SMED || + module.status.VDE || module.status.VDEL || module.status.OSCCHK || module.status.TMODCHK)) { + + const uint8_t* ptr = ((uint8_t*)&modules[0].status) + 4; // skip conversion counter + error_data[ADBMS_INTERNAL_BMS_FAULT].data[2] = ptr[1]; + error_data[ADBMS_INTERNAL_BMS_FAULT].data[3] = ptr[0]; + + // Fault bits are latched -- clear them so we can check again next + // iteration. + amsClearFlag(); + + return (ADBMS_DetailedStatus){ADBMS_ERROR, ADBMS_INTERNAL_BMS_FAULT}; } else { - amsReset(); + // clear_error_source(SEK_INTERNAL_BMS_FAULT); } - } - if (any(module.status.CS_FLT || module.status.SPIFLT || module.status.CMED || module.status.SMED || - module.status.VDE || module.status.VDEL || module.status.OSCCHK || module.status.TMODCHK)) { + packetChecksumFails += amsCellMeasurement(&modules); + packetChecksumFails += amsCheckUnderOverVoltage(&modules); - // TODO: handle errors - - // ftcan_marshal_unsigned(&error_data[SEK_INTERNAL_BMS_FAULT].data[0], module.status.CS_FLT, 2); - /* const uint8_t* ptr = ((uint8_t*)&modules.status) + 4; //skip conversion counter - error_data[SEK_INTERNAL_BMS_FAULT].data[2] = ptr[1]; - error_data[SEK_INTERNAL_BMS_FAULT].data[3] = ptr[0]; - set_error_source(SEK_INTERNAL_BMS_FAULT); */ - - // Fault bits are latched -- clear them so we can check again next - // iteration. - amsClearFlag(); - } else { - clear_error_source(SEK_INTERNAL_BMS_FAULT); - } - - packetChecksumFails += amsCellMeasurement(&modules); - packetChecksumFails += amsCheckUnderOverVoltage(&modules); - - if (packetChecksumFails > MAX_PACKET_CHECKSUM_FAILS) { - set_error_source(SEK_INTERNAL_BMS_CHECKSUM_FAIL); - } - - //TODO: temperature measurement - - bool overvolt = false; - bool undervolt = false; - for (size_t i = 0; i < numberofCells; i++) { - if (any(module.cellVoltages[i] < 2500)) { - undervolt = true; - error_data[SEK_UNDERVOLT].data[0] = i; - uint8_t* ptr = &error_data[SEK_UNDERVOLT].data[1]; - //ftcan_marshal_unsigned(ptr, module.cellVoltages[i], 2); - } else if (any(module.cellVoltages[i] > 4200)) { - overvolt = true; - error_data[SEK_OVERVOLT].data[0] = i; - uint8_t* ptr = &error_data[SEK_OVERVOLT].data[1]; - //ftcan_marshal_unsigned(ptr, module.cellVoltages[i], 2); + if (packetChecksumFails > MAX_PACKET_CHECKSUM_FAILS) { + set_error_source(ADBMS_INTERNAL_BMS_CHECKSUM_FAIL); } - } - if (any(module.internalDieTemp > 28000 || module.status.THSD)) { //TODO: change to correct value - //ftcan_marshal_unsigned(&error_data[SEK_INTERNAL_BMS_OVERTEMP].data[0], module.internalDieTemp, 2); + // TODO: temperature measurement - set_error_source(SEK_INTERNAL_BMS_OVERTEMP); - } else { - clear_error_source(SEK_INTERNAL_BMS_OVERTEMP); - } + bool overvolt = false; + bool undervolt = false; + for (size_t i = 0; i < numberofCells; i++) { + if (any(module.cellVoltages[i] < 2500)) { + undervolt = true; + error_data[ADBMS_UNDERVOLT].data[0] = i; + uint8_t* ptr = &error_data[ADBMS_UNDERVOLT].data[1]; + // ftcan_marshal_unsigned(ptr, module.cellVoltages[i], 2); + } else if (any(module.cellVoltages[i] > 4200)) { + overvolt = true; + error_data[ADBMS_OVERVOLT].data[0] = i; + uint8_t* ptr = &error_data[ADBMS_OVERVOLT].data[1]; + // ftcan_marshal_unsigned(ptr, module.cellVoltages[i], 2); + } + } - if (overvolt) { - set_error_source(SEK_OVERVOLT); - } else { - clear_error_source(SEK_OVERVOLT); - } + if (any(module.internalDieTemp > 28000 || module.status.THSD)) { // TODO: change to correct value + // ftcan_marshal_unsigned(&error_data[SEK_INTERNAL_BMS_OVERTEMP].data[0], module.internalDieTemp, 2); - if (undervolt) { - set_error_source(SEK_UNDERVOLT); - } else { - clear_error_source(SEK_UNDERVOLT); - } + set_error_source(ADBMS_INTERNAL_BMS_OVERTEMP); + } else { + clear_error_source(ADBMS_INTERNAL_BMS_OVERTEMP); + } - mcuDelay(10); + if (overvolt) { + set_error_source(ADBMS_OVERVOLT); + } else { + clear_error_source(ADBMS_OVERVOLT); + } - return 0; + if (undervolt) { + set_error_source(ADBMS_UNDERVOLT); + } else { + clear_error_source(ADBMS_UNDERVOLT); + } + + mcuDelay(10); + + return NO_ERROR; }