From 84fb5bab158c51b199c7063ddf86a53ceac8993e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Mon, 3 Mar 2025 23:28:05 +0200 Subject: [PATCH 1/2] Add support for 96S 69kWh SPA battery --- Software/src/battery/VOLVO-SPA-BATTERY.cpp | 33 ++++++++++++++++------ Software/src/battery/VOLVO-SPA-BATTERY.h | 6 ++-- 2 files changed, 28 insertions(+), 11 deletions(-) diff --git a/Software/src/battery/VOLVO-SPA-BATTERY.cpp b/Software/src/battery/VOLVO-SPA-BATTERY.cpp index 86b16f09..4354db88 100644 --- a/Software/src/battery/VOLVO-SPA-BATTERY.cpp +++ b/Software/src/battery/VOLVO-SPA-BATTERY.cpp @@ -33,7 +33,6 @@ static uint8_t battery_request_idx = 0; static uint8_t rxConsecutiveFrames = 0; static uint16_t min_max_voltage[2]; //contains cell min[0] and max[1] values in mV static uint8_t cellcounter = 0; -static uint32_t remaining_capacity = 0; static uint16_t cell_voltages[108]; //array with all the cellvoltages static bool startedUp = false; static uint8_t DTC_reset_counter = 0; @@ -134,12 +133,12 @@ void update_values_battery() { //This function maps all the values fetched via datalayer_extended.VolvoPolestar.UserRequestDTCreadout = false; } - remaining_capacity = (78200 - CHARGE_ENERGY); + datalayer.battery.status.remaining_capacity_Wh = (datalayer.battery.info.total_capacity_Wh - CHARGE_ENERGY); //datalayer.battery.status.real_soc = SOC_BMS; // Use BMS reported SOC, havent figured out how to get the BMS to calibrate empty/full yet - SOC_CALC = remaining_capacity / 78; // Use calculated SOC based on remaining_capacity + SOC_CALC = (remaining_capacity_Wh / (total_capacity_Wh / 1000)); // Use calculated SOC based on remaining_capacity - datalayer.battery.status.real_soc = SOC_CALC * 10; + datalayer.battery.status.real_soc = SOC_CALC * 10; //Add one decimal to make it pptt if (BATT_U > MAX_U) // Protect if overcharged { @@ -151,7 +150,6 @@ void update_values_battery() { //This function maps all the values fetched via datalayer.battery.status.voltage_dV = BATT_U * 10; datalayer.battery.status.current_dA = BATT_I * 10; - datalayer.battery.status.remaining_capacity_Wh = remaining_capacity; datalayer.battery.status.max_discharge_power_W = HvBattPwrLimDchaSlowAgi * 1000; //kW to W datalayer.battery.status.max_charge_power_W = HvBattPwrLimChrgSlowAgi * 1000; //kW to W @@ -166,6 +164,22 @@ void update_values_battery() { //This function maps all the values fetched via datalayer.battery.status.cell_voltages_mV[i] = cell_voltages[i]; } + //If we have enough cell values populated (atleast 96 read) AND number_of_cells not initialized yet + if (cell_voltages[95] > 0 && datalayer.battery.info.number_of_cells == 0) { + // We can determine whether we have 96S or 108S battery + if (datalayer.battery.status.cell_voltages_mV[107] > 0) { + datalayer.battery.info.number_of_cells = 108; + datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_108S_DV; + datalayer.battery.info.min_design_voltage_dV = MIN_PACK_VOLTAGE_108S_DV; + datalayer.battery.info.total_capacity_Wh = 78200; + } else { + datalayer.battery.info.number_of_cells = 96; + datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_96S_DV; + datalayer.battery.info.min_design_voltage_dV = MIN_PACK_VOLTAGE_96S_DV; + datalayer.battery.info.total_capacity_Wh = 69511; + } + } + #ifdef DEBUG_LOG logging.print("BMS reported SOC%: "); logging.println(SOC_BMS); @@ -463,11 +477,12 @@ void transmit_can_battery() { } void setup_battery(void) { // Performs one time setup at startup - strncpy(datalayer.system.info.battery_protocol, "Volvo / Polestar 78kWh battery", 63); + strncpy(datalayer.system.info.battery_protocol, "Volvo / Polestar 69/78kWh SPA battery", 63); datalayer.system.info.battery_protocol[63] = '\0'; - datalayer.battery.info.number_of_cells = 108; - datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_DV; - datalayer.battery.info.min_design_voltage_dV = MIN_PACK_VOLTAGE_DV; + datalayer.battery.info.number_of_cells = 0; // Initializes when all cells have been read + datalayer.battery.info.total_capacity_Wh = 78200; //Startout in 78kWh mode (This value used for SOC calc) + datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_108S_DV; //Startout with max allowed range + datalayer.battery.info.min_design_voltage_dV = MIN_PACK_VOLTAGE_96S_DV; //Startout with min allowed range datalayer.battery.info.max_cell_voltage_mV = MAX_CELL_VOLTAGE_MV; datalayer.battery.info.min_cell_voltage_mV = MIN_CELL_VOLTAGE_MV; datalayer.battery.info.max_cell_voltage_deviation_mV = MAX_CELL_DEVIATION_MV; diff --git a/Software/src/battery/VOLVO-SPA-BATTERY.h b/Software/src/battery/VOLVO-SPA-BATTERY.h index 6dcda0e7..fb81ff10 100644 --- a/Software/src/battery/VOLVO-SPA-BATTERY.h +++ b/Software/src/battery/VOLVO-SPA-BATTERY.h @@ -4,8 +4,10 @@ #include "../include.h" #define BATTERY_SELECTED -#define MAX_PACK_VOLTAGE_DV 4540 //5000 = 500.0V -#define MIN_PACK_VOLTAGE_DV 2938 +#define MAX_PACK_VOLTAGE_108S_DV 4540 +#define MIN_PACK_VOLTAGE_108S_DV 2938 +#define MAX_PACK_VOLTAGE_96S_DV 4030 +#define MIN_PACK_VOLTAGE_96S_DV 2620 #define MAX_CELL_DEVIATION_MV 250 #define MAX_CELL_VOLTAGE_MV 4210 //Battery is put into emergency stop if one cell goes over this value #define MIN_CELL_VOLTAGE_MV 2700 //Battery is put into emergency stop if one cell goes below this value From 50014a8a0144f2891f16f105e762bda4a8991f36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Mon, 3 Mar 2025 23:33:59 +0200 Subject: [PATCH 2/2] Fix compilation error --- Software/src/battery/VOLVO-SPA-BATTERY.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Software/src/battery/VOLVO-SPA-BATTERY.cpp b/Software/src/battery/VOLVO-SPA-BATTERY.cpp index 4354db88..aaf33b63 100644 --- a/Software/src/battery/VOLVO-SPA-BATTERY.cpp +++ b/Software/src/battery/VOLVO-SPA-BATTERY.cpp @@ -136,7 +136,8 @@ void update_values_battery() { //This function maps all the values fetched via datalayer.battery.status.remaining_capacity_Wh = (datalayer.battery.info.total_capacity_Wh - CHARGE_ENERGY); //datalayer.battery.status.real_soc = SOC_BMS; // Use BMS reported SOC, havent figured out how to get the BMS to calibrate empty/full yet - SOC_CALC = (remaining_capacity_Wh / (total_capacity_Wh / 1000)); // Use calculated SOC based on remaining_capacity + // Use calculated SOC based on remaining_capacity + SOC_CALC = (datalayer.battery.status.remaining_capacity_Wh / (datalayer.battery.info.total_capacity_Wh / 1000)); datalayer.battery.status.real_soc = SOC_CALC * 10; //Add one decimal to make it pptt