Add cellvoltage reading for BMW i3

This commit is contained in:
Daniel Öster 2024-07-15 22:48:38 +03:00
parent 36d06e85f2
commit a7fd4099e1

View file

@ -27,7 +27,7 @@ unsigned long turnOnTime; // Variables to store timestamps
enum State { POWERON, STATE_ON, STATE_OFF }; enum State { POWERON, STATE_ON, STATE_OFF };
static State WUPState = POWERON; static State WUPState = POWERON;
enum CmdState { SOH, CELL_VOLTAGE, SOC, CELL_VOLTAGE_AVG }; enum CmdState { SOH, CELL_VOLTAGE_MINMAX, SOC, CELL_VOLTAGE_AVG, CELL_VOLTAGE_CELLNO };
static CmdState cmdState = SOH; static CmdState cmdState = SOH;
const unsigned char crc8_table[256] = const unsigned char crc8_table[256] =
@ -302,6 +302,13 @@ CAN_frame_t BMW_6F1_CELL_VOLTAGE_AVG = {.FIR = {.B =
}}, }},
.MsgID = 0x6F1, .MsgID = 0x6F1,
.data = {0x07, 0x03, 0x22, 0xDF, 0xA0}}; .data = {0x07, 0x03, 0x22, 0xDF, 0xA0}};
CAN_frame_t BMW_6F1_CELL_VOLTAGE_CELLNO = {.FIR = {.B =
{
.DLC = 7,
.FF = CAN_frame_std,
}},
.MsgID = 0x6F1,
.data = {0x07, 0x05, 0x31, 0x01, 0xAD, 0x6E, 0x01}};
CAN_frame_t BMW_6F1_CONTINUE = {.FIR = {.B = CAN_frame_t BMW_6F1_CONTINUE = {.FIR = {.B =
{ {
@ -310,6 +317,13 @@ CAN_frame_t BMW_6F1_CONTINUE = {.FIR = {.B =
}}, }},
.MsgID = 0x6F1, .MsgID = 0x6F1,
.data = {0x07, 0x30, 0x00, 0x02}}; .data = {0x07, 0x30, 0x00, 0x02}};
CAN_frame_t BMW_6F1_CELL_CONTINUE = {.FIR = {.B =
{
.DLC = 6,
.FF = CAN_frame_std,
}},
.MsgID = 0x6F1,
.data = {0x07, 0x04, 0x31, 0x03, 0xAD, 0x6E}};
//The above CAN messages need to be sent towards the battery to keep it alive //The above CAN messages need to be sent towards the battery to keep it alive
static uint8_t startup_counter_contactor = 0; static uint8_t startup_counter_contactor = 0;
@ -397,6 +411,7 @@ static uint8_t battery_soh = 99;
static uint8_t message_data[50]; static uint8_t message_data[50];
static uint8_t next_data = 0; static uint8_t next_data = 0;
static uint8_t current_cell_polled = 1;
static uint8_t calculateCRC(CAN_frame_t rx_frame, uint8_t length, uint8_t initial_value) { static uint8_t calculateCRC(CAN_frame_t rx_frame, uint8_t length, uint8_t initial_value) {
uint8_t crc = initial_value; uint8_t crc = initial_value;
@ -441,11 +456,6 @@ void update_values_battery() { //This function maps all the values fetched via
datalayer.battery.status.temperature_max_dC = battery_temperature_max * 10; // Add a decimal datalayer.battery.status.temperature_max_dC = battery_temperature_max * 10; // Add a decimal
if (datalayer.battery.status.cell_voltages_mV[0] > 0 && datalayer.battery.status.cell_voltages_mV[2] > 0) {
datalayer.battery.status.cell_min_voltage_mV = datalayer.battery.status.cell_voltages_mV[0];
datalayer.battery.status.cell_max_voltage_mV = datalayer.battery.status.cell_voltages_mV[2];
}
if (battery_info_available) { if (battery_info_available) {
// Start checking safeties. First up, cellvoltages! // Start checking safeties. First up, cellvoltages!
if (detectedBattery == BATTERY_60AH) { if (detectedBattery == BATTERY_60AH) {
@ -631,6 +641,16 @@ void receive_can_battery(CAN_frame_t rx_frame) {
battery_ID2 = rx_frame.data.u8[0]; battery_ID2 = rx_frame.data.u8[0];
break; break;
case 0x607: //BMS - responses to message requests on 0x615 case 0x607: //BMS - responses to message requests on 0x615
if ((cmdState == CELL_VOLTAGE_CELLNO) && (rx_frame.data.u8[0] == 0xF4)) {
if (rx_frame.FIR.B.DLC == 6) {
ESP32Can.CANWriteFrame(&BMW_6F1_CELL_CONTINUE); // tell battery to send the cellvoltage
}
if (rx_frame.FIR.B.DLC == 8) { // We have the full value, map it
datalayer.battery.status.cell_voltages_mV[current_cell_polled - 1] =
(rx_frame.data.u8[6] << 8 | rx_frame.data.u8[7]);
}
}
if (rx_frame.FIR.B.DLC > 6 && next_data == 0 && rx_frame.data.u8[0] == 0xf1) { if (rx_frame.FIR.B.DLC > 6 && next_data == 0 && rx_frame.data.u8[0] == 0xf1) {
uint8_t count = 6; uint8_t count = 6;
while (count < rx_frame.FIR.B.DLC && next_data < 49) { while (count < rx_frame.FIR.B.DLC && next_data < 49) {
@ -646,15 +666,15 @@ void receive_can_battery(CAN_frame_t rx_frame) {
} }
switch (cmdState) { switch (cmdState) {
case CELL_VOLTAGE: case CELL_VOLTAGE_MINMAX:
if (next_data >= 4) { if (next_data >= 4) {
datalayer.battery.status.cell_voltages_mV[0] = (message_data[0] << 8 | message_data[1]); datalayer.battery.status.cell_min_voltage_mV = (message_data[0] << 8 | message_data[1]);
datalayer.battery.status.cell_voltages_mV[2] = (message_data[2] << 8 | message_data[3]); datalayer.battery.status.cell_max_voltage_mV = (message_data[2] << 8 | message_data[3]);
} }
break; break;
case CELL_VOLTAGE_AVG: case CELL_VOLTAGE_AVG:
if (next_data >= 30) { if (next_data >= 30) { //AVG not used
datalayer.battery.status.cell_voltages_mV[1] = (message_data[10] << 8 | message_data[11]) / 10; //datalayer.battery.status.cell_voltages_mV[1] = (message_data[10] << 8 | message_data[11]) / 10;
battery_capacity_cah = (message_data[4] << 8 | message_data[5]); battery_capacity_cah = (message_data[4] << 8 | message_data[5]);
} }
break; break;
@ -800,9 +820,9 @@ void send_can_battery() {
switch (cmdState) { switch (cmdState) {
case SOC: case SOC:
ESP32Can.CANWriteFrame(&BMW_6F1_CELL); ESP32Can.CANWriteFrame(&BMW_6F1_CELL);
cmdState = CELL_VOLTAGE; cmdState = CELL_VOLTAGE_MINMAX;
break; break;
case CELL_VOLTAGE: case CELL_VOLTAGE_MINMAX:
ESP32Can.CANWriteFrame(&BMW_6F1_SOH); ESP32Can.CANWriteFrame(&BMW_6F1_SOH);
cmdState = SOH; cmdState = SOH;
break; break;
@ -811,6 +831,15 @@ void send_can_battery() {
cmdState = CELL_VOLTAGE_AVG; cmdState = CELL_VOLTAGE_AVG;
break; break;
case CELL_VOLTAGE_AVG: case CELL_VOLTAGE_AVG:
ESP32Can.CANWriteFrame(&BMW_6F1_CELL_VOLTAGE_CELLNO);
cmdState = CELL_VOLTAGE_CELLNO;
current_cell_polled++;
if (current_cell_polled > 96) {
current_cell_polled = 1;
}
BMW_6F1_CELL_VOLTAGE_CELLNO.data.u8[6] = current_cell_polled;
break;
case CELL_VOLTAGE_CELLNO:
ESP32Can.CANWriteFrame(&BMW_6F1_SOC); ESP32Can.CANWriteFrame(&BMW_6F1_SOC);
cmdState = SOC; cmdState = SOC;
break; break;