Skip to content

Commit

Permalink
Add support for Sono Motors Battery
Browse files Browse the repository at this point in the history
  • Loading branch information
dalathegreat committed Jan 6, 2025
1 parent 6944561 commit e387ab9
Show file tree
Hide file tree
Showing 4 changed files with 205 additions and 0 deletions.
1 change: 1 addition & 0 deletions Software/USER_SETTINGS.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
//#define RENAULT_TWIZY_BATTERY
//#define RENAULT_ZOE_GEN1_BATTERY
//#define RENAULT_ZOE_GEN2_BATTERY
//#define SONO_BATTERY
//#define SANTA_FE_PHEV_BATTERY
//#define STELLANTIS_ECMP_BATTERY
//#define TESLA_MODEL_3Y_BATTERY
Expand Down
4 changes: 4 additions & 0 deletions Software/src/battery/BATTERIES.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@ void setup_can_shunt();
#include "CHADEMO-SHUNTS.h"
#endif

#ifdef SONO_BATTERY
#include "SONO-BATTERY.h"
#endif

#ifdef STELLANTIS_ECMP_BATTERY
#include "ECMP-BATTERY.h"
#endif
Expand Down
183 changes: 183 additions & 0 deletions Software/src/battery/SONO-BATTERY.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
#include "../include.h"
#ifdef SONO_BATTERY
#include "../datalayer/datalayer.h"
#include "../devboard/utils/events.h"
#include "SONO-BATTERY.h"

/* Do not change code below unless you are sure what you are doing */
static unsigned long previousMillis100 = 0; // will store last time a 100ms CAN Message was send
static unsigned long previousMillis1000 = 0; // will store last time a 1000ms CAN Message was send

static uint8_t seconds = 0;
static uint8_t functionalsafetybitmask = 0;
static uint16_t batteryVoltage = 3700;
static uint16_t allowedDischargePower = 0;
static uint16_t allowedChargePower = 0;
static uint16_t CellVoltMax_mV = 0;
static uint16_t CellVoltMin_mV = 0;
static int16_t batteryAmps = 0;
static int16_t temperatureMin = 0;
static int16_t temperatureMax = 0;
static uint8_t batterySOH = 99;
static uint8_t realSOC = 99;

CAN_frame SONO_400 = {.FD = false, //Message of Vehicle Command, 100ms
.ext_ID = false,
.DLC = 8,
.ID = 0x400,
.data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
CAN_frame SONO_401 = {.FD = false, //Message of Vehicle Date, 1000ms
.ext_ID = false,
.DLC = 8,
.ID = 0x400,
.data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};

void update_values_battery() { //This function maps all the values fetched via CAN to the correct parameters used for modbus

datalayer.battery.status.real_soc = (realSOC * 100); //increase SOC range from 0-100 -> 100.00

datalayer.battery.status.soh_pptt = (batterySOH * 100); //Increase decimals from 100% -> 100.00%

datalayer.battery.status.voltage_dV = batteryVoltage;

datalayer.battery.status.current_dA = batteryAmps;

datalayer.battery.info.total_capacity_Wh = 54000;

datalayer.battery.status.remaining_capacity_Wh = static_cast<uint32_t>(
(static_cast<double>(datalayer.battery.status.real_soc) / 10000) * datalayer.battery.info.total_capacity_Wh);

datalayer.battery.status.max_discharge_power_W = allowedDischargePower * 100;

datalayer.battery.status.max_charge_power_W = allowedChargePower * 100;

datalayer.battery.status.cell_max_voltage_mV = CellVoltMax_mV;

datalayer.battery.status.cell_min_voltage_mV = CellVoltMin_mV;

datalayer.battery.status.temperature_min_dC = temperatureMin;

datalayer.battery.status.temperature_max_dC = temperatureMax;
}

void handle_incoming_can_frame_battery(CAN_frame rx_frame) {
switch (rx_frame.ID) {
case 0x100:
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
break;
case 0x101:
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
break;
case 0x102:
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
functionalsafetybitmask = rx_frame.data.u8[0]; //If any bits are high here, battery has a HSD fault active.
break;
case 0x200:
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
break;
case 0x220:
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
allowedChargePower = (rx_frame.data.u8[0] << 8) + rx_frame.data.u8[1];
allowedDischargePower = (rx_frame.data.u8[2] << 8) + rx_frame.data.u8[3];
break;
case 0x221:
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
break;
case 0x300:
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
batteryVoltage = (rx_frame.data.u8[4] << 8) + rx_frame.data.u8[5];
break;
case 0x301:
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
CellVoltMax_mV = (rx_frame.data.u8[1] << 8) + rx_frame.data.u8[2];
CellVoltMin_mV = (rx_frame.data.u8[4] << 8) + rx_frame.data.u8[5];
break;
case 0x310:
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
break;
case 0x311:
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
batteryAmps = ((rx_frame.data.u8[4] << 8) + rx_frame.data.u8[5]) - 1000;
break;
case 0x320:
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
temperatureMax = ((rx_frame.data.u8[1] << 8) + rx_frame.data.u8[2]) - 400;
temperatureMin = ((rx_frame.data.u8[4] << 8) + rx_frame.data.u8[5]) - 400;
break;
case 0x321:
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
batterySOH = rx_frame.data.u8[4];
break;
case 0x330:
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
break;
case 0x331:
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
break;
case 0x601:
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
realSOC = rx_frame.data.u8[0];
break;
case 0x610:
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
break;
case 0x611:
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
break;
case 0x613:
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
break;
case 0x614:
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
break;
case 0x615:
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
break;
default:
break;
}
}
void transmit_can_battery() {
unsigned long currentMillis = millis();

// Send 100ms CAN Message
if (currentMillis - previousMillis100 >= INTERVAL_100_MS) {
previousMillis100 = currentMillis;
//VCU Command message
SONO_400.data.u8[0] = 0x15; //Charging enabled bit01, dischargign enabled bit23, dc charging bit45

if (datalayer.battery.status.bms_status == FAULT) {
SONO_400.data.u8[0] = 0x14; //Charging DISABLED
}
transmit_can_frame(&SONO_400, can_config.battery);
}
// Send 1000ms CAN Message
if (currentMillis - previousMillis1000 >= INTERVAL_1_S) {
previousMillis1000 = currentMillis;

//Time and date
//Let's see if the battery is happy with just getting seconds incrementing
SONO_401.data.u8[0] = 2025; //Year
SONO_401.data.u8[1] = 1; //Month
SONO_401.data.u8[2] = 1; //Day
SONO_401.data.u8[3] = 12; //Hour
SONO_401.data.u8[4] = 15; //Minute
SONO_401.data.u8[5] = seconds; //Second
seconds = (seconds + 1) % 61;
transmit_can_frame(&SONO_401, can_config.battery);
}
}

void setup_battery(void) { // Performs one time setup at startup
strncpy(datalayer.system.info.battery_protocol, "Sono Motors Sion 64kWh LFP ", 63);
datalayer.system.info.battery_protocol[63] = '\0';
datalayer.battery.info.number_of_cells = 96;
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.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;
datalayer.battery.info.chemistry = battery_chemistry_enum::LFP;
}

#endif
17 changes: 17 additions & 0 deletions Software/src/battery/SONO-BATTERY.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#ifndef SONO_BATTERY_H
#define SONO_BATTERY_H
#include <Arduino.h>
#include "../include.h"

#define BATTERY_SELECTED
#define MAX_PACK_VOLTAGE_DV 5000 //5000 = 500.0V
#define MIN_PACK_VOLTAGE_DV 2500
#define MAX_CELL_DEVIATION_MV 250
#define MAX_CELL_VOLTAGE_MV 3800 //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

uint8_t CalculateCRC8(CAN_frame rx_frame);
void setup_battery(void);
void transmit_can_frame(CAN_frame* tx_frame, int interface);

#endif

0 comments on commit e387ab9

Please sign in to comment.