From 1a6728f7c097c0bfd641c5f41cd7b30fe7504d20 Mon Sep 17 00:00:00 2001 From: hamza Date: Mon, 8 Jul 2024 18:52:09 +0300 Subject: [PATCH] V1.7 --- CHANGELOG.txt | 7 +++ Core/Inc/eeprom.h | 6 +++ Core/Inc/soc_estimation.h | 19 ++++++++ Core/Src/AMS_HighLevel.c | 7 +-- Core/Src/can.c | 14 ++++-- Core/Src/eeprom.c | 24 ++++++++++- Core/Src/soc_estimation.c | 91 +++++++++++++++++++++++++++++++++++++++ Core/Src/state_machine.c | 10 ++--- 8 files changed, 165 insertions(+), 13 deletions(-) create mode 100644 Core/Inc/soc_estimation.h create mode 100644 Core/Src/soc_estimation.c diff --git a/CHANGELOG.txt b/CHANGELOG.txt index ff2eb0d..c75ba07 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -37,3 +37,10 @@ V1.6 - CAN messages are now correctly formated - minimum cell voltage is now set to 3200 mV - powerground calibration is now done in STATE_PRECHARGE (well yes but actually no) + +V1.7 +- added eeprom functions +- fixed(tm) voltage and CURRENT_MEASUREMENT +- changed the CAN message a bit +- added soc_estimation.c soc_estimation.h +- added MIN/MAX_CELL_VOLTAGE for AMS_HighLevel diff --git a/Core/Inc/eeprom.h b/Core/Inc/eeprom.h index 3d21c7a..d0b9439 100755 --- a/Core/Inc/eeprom.h +++ b/Core/Inc/eeprom.h @@ -4,6 +4,9 @@ #include "stm32f3xx_hal.h" #include +#include +#include "AMS_HighLevel.h" +#include "errors.h" __attribute__((packed)) typedef struct { uint8_t id; @@ -13,5 +16,8 @@ extern EEPROMConfig eeprom_config; void eeprom_init(I2C_HandleTypeDef* hi2c); void eeprom_config_save(); +void eeprom_write_status(); +void eeprom_read(int8_t* data); +void eeprom_write(uint8_t* data, uint8_t data_length); #endif // INC_EEPROM_H_ diff --git a/Core/Inc/soc_estimation.h b/Core/Inc/soc_estimation.h new file mode 100644 index 0000000..9903490 --- /dev/null +++ b/Core/Inc/soc_estimation.h @@ -0,0 +1,19 @@ +#ifndef INC_SOC_ESTIMATION_H +#define INC_SOC_ESTIMATION_H + +#include +#include + +extern float current_soc; + +void soc_init(); +void soc_update(); + +typedef struct { + uint16_t ocv; + float soc; +} ocv_soc_pair_t; +extern ocv_soc_pair_t OCV_SOC_PAIRS[]; +float soc_for_ocv(uint16_t ocv); + +#endif // INC_SOC_ESTIMATION_H diff --git a/Core/Src/AMS_HighLevel.c b/Core/Src/AMS_HighLevel.c index 3978263..cc4c8ae 100755 --- a/Core/Src/AMS_HighLevel.c +++ b/Core/Src/AMS_HighLevel.c @@ -28,7 +28,8 @@ uint8_t packetChecksumFails = 0; uint8_t deviceSleeps = 0; #define MAX_DEVICE_SLEEP 3 //TODO: change to correct value - +#define MAX_CELL_VOLTAGE 4100 //change to 4200 +#define MIN_CELL_VOLTAGE 3100 //change to 3100 amsState currentAMSState = AMSDEACTIVE; amsState lastAMSState = AMSDEACTIVE; @@ -136,13 +137,13 @@ uint8_t AMS_Idle_Loop() { int any_voltage_error = 0; for (size_t i = 0; i < numberofCells; i++) { - if (module.cellVoltages[i] < 3200) { + if (module.cellVoltages[i] < MIN_CELL_VOLTAGE) { any_voltage_error = 1; error_data.data_kind = SEK_UNDERVOLT; error_data.data[0] = i; uint8_t* ptr = &error_data.data[1]; ptr = ftcan_marshal_unsigned(ptr, module.cellVoltages[i], 2); - } else if (module.cellVoltages[i] > 4200) { + } else if (module.cellVoltages[i] > MAX_CELL_VOLTAGE) { any_voltage_error = 1; error_data.data_kind = SEK_OVERVOLT; error_data.data[0] = i; diff --git a/Core/Src/can.c b/Core/Src/can.c index 593c7e0..0020c59 100644 --- a/Core/Src/can.c +++ b/Core/Src/can.c @@ -65,12 +65,12 @@ void can_handle_send_status() { sm_check_battery_temperature(&id_highest_temp, &highest_temp); data[0] = ((state.current_state << 4) | (powerground_status >> 4)); // 1 bit emptyy | 3 bit state | 4 bit powerground - data[1] = ((powerground_status << 4) | (state.error_source >> 4)); // 4 bit powerground | 4 bit error + data[1] = ((powerground_status << 4) | (state.error_source >> 4)); // 4 bit powerground | 4 bit error data[2] = ((state.error_source << 4) | (0)); // 4 bit error | 4 bit state of charge - data[3] = ((RELAY_BAT_SIDE_VOLTAGE >> 8)); // 4 bit state of charge | 4 bit battery voltage + data[3] = ((RELAY_BAT_SIDE_VOLTAGE >> 8)); // 8 bit battery voltage data[4] = ((RELAY_BAT_SIDE_VOLTAGE >> 0)); - data[5] = ((CURRENT_MEASUREMENT >> 8)); - data[6] = ((CURRENT_MEASUREMENT & 0x000F) | (highest_temp >> 12)); + data[5] = ((CURRENT_MEASUREMENT) / 1000); + data[6] = (/*(CURRENT_MEASUREMENT & 0x000F) |*/ (highest_temp >> 12)); data[7] = ((highest_temp) >> 4); //data[7] = state.error_source; ftcan_transmit(CAN_ID_OUT, data, sizeof(data)); @@ -144,6 +144,12 @@ void can_handle_recieve_command(const uint8_t *data){ sm_handle_ams_in(data); } else if (data[0] == 0x02 && data[1] <= 100) { sm_handle_ams_in(data); + } else if (data[0] == 0xF0 && data[1] == 0x00) { + sm_handle_ams_in(data); + } else if (data[0] == 0xF1 && data[1] == 0) { + sm_handle_ams_in(data); + } else if (data[0] == 0xFF && data[1] == 0) { + sm_handle_ams_in(data); } } diff --git a/Core/Src/eeprom.c b/Core/Src/eeprom.c index c6853bb..717df8b 100755 --- a/Core/Src/eeprom.c +++ b/Core/Src/eeprom.c @@ -1,7 +1,7 @@ #include "eeprom.h" -#include "errors.h" #include "stm32f3xx_hal.h" +#include #include #define EEPROM_I2C_ADDR 0xA0 @@ -10,11 +10,13 @@ #define EEPROM_CONFIG_ECC_OFFSET 0x20 EEPROMConfig eeprom_config; +uint32_t current_address; static I2C_HandleTypeDef* hi2c; void eeprom_init(I2C_HandleTypeDef* handle) { hi2c = handle; + current_address = 0; uint8_t buf[sizeof(EEPROMConfig) * 3]; // Read 3 EEPROM config buffers at 32 byte offsets for (size_t ecc_i = 0; ecc_i < 3; ecc_i++) { @@ -58,3 +60,23 @@ void eeprom_config_save() { HAL_Delay(100); } } + +void eeprom_write_status(){ + uint8_t data_length = 16; + uint8_t data[data_length] = {}; + + + eeprom_write(data, data_length); +} + +void eeprom_read(int8_t* data){} + +void eeprom_write(uint8_t* data, uint8_t data_length){ + HAL_StatusTypeDef status = HAL_I2C_Mem_Write( + hi2c, EEPROM_I2C_ADDR, + current_address, 2, + (uint8_t*)&eeprom_config, sizeof(eeprom_config), 100); + if (status != HAL_OK) { + set_error_source(ERROR_SOURCE_EEPROM); + } +} diff --git a/Core/Src/soc_estimation.c b/Core/Src/soc_estimation.c new file mode 100644 index 0000000..32f3184 --- /dev/null +++ b/Core/Src/soc_estimation.c @@ -0,0 +1,91 @@ +#include "soc_estimation.h" + +#include "state_machine.h" +#include "stm32f3xx_hal.h" + +#include +#include + +#define SOC_ESTIMATION_NO_CURRENT_THRESH 200 // mA +#define SOC_ESTIMATION_NO_CURRENT_TIME 100000 // ms +#define SOC_ESTIMATION_BATTERY_CAPACITY 70300800 // mAs + +#define MIN_CELL_VOLTAGE 3000 +#define MAX_CELL_VOLTAGE 4200 + +ocv_soc_pair_t OCV_SOC_PAIRS[] = { + {25000, 0.00f}, {29900, 3.97f}, {32300, 9.36f}, {33200, 12.60f}, + {33500, 13.68f}, {34100, 20.15f}, {35300, 32.01f}, {38400, 66.53f}, + {40100, 83.79f}, {40200, 90.26f}, {40400, 94.58f}, {41000, 98.89f}, + {42000, 100.00f}}; + +float current_soc; + +int current_was_flowing; +uint32_t last_current_time; +float soc_before_current; +float mAs_before_current; + +void soc_init() { + current_soc = 0; + last_current_time = 0; + current_was_flowing = 1; +} + +void soc_update() { + uint32_t now = HAL_GetTick(); + if (CURRENT_MEASUREMENT >= SOC_ESTIMATION_NO_CURRENT_THRESH) { + last_current_time = now; + if (!current_was_flowing) { + soc_before_current = current_soc; + mAs_before_current = CURRENT_MEASUREMENT; + } + current_was_flowing = 1; + } else { + current_was_flowing = 0; + } + + if (now - last_current_time >= SOC_ESTIMATION_NO_CURRENT_TIME || + last_current_time == 0) { + // Assume we're measuring OCV if there's been no current for a while (or + // we've just turned on the battery). + current_soc = soc_for_ocv(min_voltage); + } else { + // Otherwise, use the current counter to update SoC + float as_delta = shunt_data.current_counter - mAs_before_current; + float soc_delta = as_delta / SOC_ESTIMATION_BATTERY_CAPACITY * 100; + current_soc = soc_before_current + soc_delta; + } +} + +float soc_for_ocv(uint16_t ocv) { + size_t i = 0; + size_t array_length = sizeof(OCV_SOC_PAIRS) / sizeof(*OCV_SOC_PAIRS); + // Find the index of the first element with OCV greater than the target OCV + while (i < array_length && OCV_SOC_PAIRS[i].ocv <= ocv) { + i++; + } + + // If the target OCV is lower than the smallest OCV in the array, return the + // first SOC value + if (i == 0) { + return OCV_SOC_PAIRS[0].soc; + } + + // If the target OCV is higher than the largest OCV in the array, return the + // last SOC value + if (i == array_length) { + return OCV_SOC_PAIRS[array_length - 1].soc; + } + + // Perform linear interpolation + uint16_t ocv1 = OCV_SOC_PAIRS[i - 1].ocv; + uint16_t ocv2 = OCV_SOC_PAIRS[i].ocv; + float soc1 = OCV_SOC_PAIRS[i - 1].soc; + float soc2 = OCV_SOC_PAIRS[i].soc; + + float slope = (soc2 - soc1) / (ocv2 - ocv1); + float interpolated_soc = soc1 + slope * (ocv - ocv1); + + return interpolated_soc; +} diff --git a/Core/Src/state_machine.c b/Core/Src/state_machine.c index 3017f26..e57791e 100644 --- a/Core/Src/state_machine.c +++ b/Core/Src/state_machine.c @@ -49,13 +49,13 @@ void sm_update(){ // state.current_state = state.target_state = STATE_ERROR; if (state.current_state == STATE_INACTIVE){ - base_offset = module.auxVoltages[0]; + CURRENT_MEASUREMENT = (module.auxVoltages[0] > 2494) ? (module.auxVoltages[0] - (2494.0)) * (300.0) : 0; + } else { + CURRENT_MEASUREMENT = (module.auxVoltages[0] > 2477) ? (module.auxVoltages[0] - (2477.0)) * (4600.0) : 0; } - - CURRENT_MEASUREMENT = roundf((module.auxVoltages[0] - base_offset) * 350); CURRENT_MEASUREMENT_ON = (module.auxVoltages[1] > 2400); - RELAY_ESC_SIDE_VOLTAGE = module.auxVoltages[2] * 11.711; - RELAY_BAT_SIDE_VOLTAGE = module.auxVoltages[3] * 11.711; // the calculation says the factor is 11. 11.711 yields the better result + RELAY_ESC_SIDE_VOLTAGE = module.auxVoltages[2] * 15.98; + RELAY_BAT_SIDE_VOLTAGE = module.auxVoltages[3] * 15.98; // the calculation says the factor is 11. 11.711 yields the better result switch (state.current_state) {