This commit is contained in:
hamza 2024-07-08 18:52:09 +03:00
parent 17e8cee0ac
commit 1a6728f7c0
8 changed files with 165 additions and 13 deletions

View File

@ -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

View File

@ -4,6 +4,9 @@
#include "stm32f3xx_hal.h"
#include <stdint.h>
#include <main.h>
#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_

19
Core/Inc/soc_estimation.h Normal file
View File

@ -0,0 +1,19 @@
#ifndef INC_SOC_ESTIMATION_H
#define INC_SOC_ESTIMATION_H
#include <stdint.h>
#include <main.h>
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

View File

@ -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;

View File

@ -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);
}
}

View File

@ -1,7 +1,7 @@
#include "eeprom.h"
#include "errors.h"
#include "stm32f3xx_hal.h"
#include <stdint.h>
#include <string.h>
#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);
}
}

91
Core/Src/soc_estimation.c Normal file
View File

@ -0,0 +1,91 @@
#include "soc_estimation.h"
#include "state_machine.h"
#include "stm32f3xx_hal.h"
#include <stddef.h>
#include <stdint.h>
#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;
}

View File

@ -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) {