mirror of
https://github.com/dalathegreat/Battery-Emulator.git
synced 2025-10-03 17:59:27 +02:00
Merge branch 'main' into feature/foxess-inverter
This commit is contained in:
commit
adcf145109
49 changed files with 584 additions and 294 deletions
|
@ -11,6 +11,7 @@
|
||||||
#include "freertos/FreeRTOS.h"
|
#include "freertos/FreeRTOS.h"
|
||||||
#include "freertos/task.h"
|
#include "freertos/task.h"
|
||||||
#include "src/charger/CHARGERS.h"
|
#include "src/charger/CHARGERS.h"
|
||||||
|
#include "src/datalayer/datalayer.h"
|
||||||
#include "src/devboard/utils/events.h"
|
#include "src/devboard/utils/events.h"
|
||||||
#include "src/devboard/utils/led_handler.h"
|
#include "src/devboard/utils/led_handler.h"
|
||||||
#include "src/devboard/utils/value_mapping.h"
|
#include "src/devboard/utils/value_mapping.h"
|
||||||
|
@ -23,8 +24,6 @@
|
||||||
#include "src/lib/miwagner-ESP32-Arduino-CAN/CAN_config.h"
|
#include "src/lib/miwagner-ESP32-Arduino-CAN/CAN_config.h"
|
||||||
#include "src/lib/miwagner-ESP32-Arduino-CAN/ESP32CAN.h"
|
#include "src/lib/miwagner-ESP32-Arduino-CAN/ESP32CAN.h"
|
||||||
|
|
||||||
#include "src/datalayer/datalayer.h"
|
|
||||||
|
|
||||||
#ifdef WIFI
|
#ifdef WIFI
|
||||||
#include "src/devboard/wifi/wifi.h"
|
#include "src/devboard/wifi/wifi.h"
|
||||||
#ifdef WEBSERVER
|
#ifdef WEBSERVER
|
||||||
|
@ -48,9 +47,13 @@
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef EQUIPMENT_STOP_BUTTON
|
||||||
|
#include "src/devboard/utils/debounce_button.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
Preferences settings; // Store user settings
|
Preferences settings; // Store user settings
|
||||||
// The current software version, shown on webserver
|
// The current software version, shown on webserver
|
||||||
const char* version_number = "7.4.0";
|
const char* version_number = "7.5.dev";
|
||||||
|
|
||||||
// Interval settings
|
// Interval settings
|
||||||
uint16_t intervalUpdateValues = INTERVAL_5_S; // Interval at which to update inverter values / Modbus registers
|
uint16_t intervalUpdateValues = INTERVAL_5_S; // Interval at which to update inverter values / Modbus registers
|
||||||
|
@ -64,7 +67,7 @@ volatile bool send_ok = 0;
|
||||||
|
|
||||||
#ifdef DUAL_CAN
|
#ifdef DUAL_CAN
|
||||||
#include "src/lib/pierremolinaro-acan2515/ACAN2515.h"
|
#include "src/lib/pierremolinaro-acan2515/ACAN2515.h"
|
||||||
static const uint32_t QUARTZ_FREQUENCY = 8UL * 1000UL * 1000UL; // 8 MHz
|
static const uint32_t QUARTZ_FREQUENCY = CRYSTAL_FREQUENCY_MHZ * 1000000UL; //MHZ configured in USER_SETTINGS.h
|
||||||
ACAN2515 can(MCP2515_CS, SPI, MCP2515_INT);
|
ACAN2515 can(MCP2515_CS, SPI, MCP2515_INT);
|
||||||
static ACAN2515_Buffer16 gBuffer;
|
static ACAN2515_Buffer16 gBuffer;
|
||||||
#endif
|
#endif
|
||||||
|
@ -135,6 +138,14 @@ unsigned long negativeStartTime = 0;
|
||||||
unsigned long timeSpentInFaultedMode = 0;
|
unsigned long timeSpentInFaultedMode = 0;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef EQUIPMENT_STOP_BUTTON
|
||||||
|
const unsigned long equipment_button_long_press_duration =
|
||||||
|
15000; // 15 seconds for long press in case of MOMENTARY_SWITCH
|
||||||
|
const unsigned long equipment_button_debounce_duration = 200; // 250ms for debouncing the button
|
||||||
|
unsigned long timeSincePress = 0; // Variable to store the time since the last press
|
||||||
|
DebouncedButton equipment_stop_button; // Debounced button object
|
||||||
|
#endif
|
||||||
|
|
||||||
TaskHandle_t main_loop_task;
|
TaskHandle_t main_loop_task;
|
||||||
TaskHandle_t connectivity_loop_task;
|
TaskHandle_t connectivity_loop_task;
|
||||||
|
|
||||||
|
@ -163,6 +174,9 @@ void setup() {
|
||||||
|
|
||||||
init_battery();
|
init_battery();
|
||||||
|
|
||||||
|
#ifdef EQUIPMENT_STOP_BUTTON
|
||||||
|
init_equipment_stop_button();
|
||||||
|
#endif
|
||||||
// BOOT button at runtime is used as an input for various things
|
// BOOT button at runtime is used as an input for various things
|
||||||
pinMode(0, INPUT_PULLUP);
|
pinMode(0, INPUT_PULLUP);
|
||||||
|
|
||||||
|
@ -235,6 +249,10 @@ void core_loop(void* task_time_us) {
|
||||||
while (true) {
|
while (true) {
|
||||||
START_TIME_MEASUREMENT(all);
|
START_TIME_MEASUREMENT(all);
|
||||||
START_TIME_MEASUREMENT(comm);
|
START_TIME_MEASUREMENT(comm);
|
||||||
|
#ifdef EQUIPMENT_STOP_BUTTON
|
||||||
|
monitor_equipment_stop_button();
|
||||||
|
#endif
|
||||||
|
|
||||||
// Input, Runs as fast as possible
|
// Input, Runs as fast as possible
|
||||||
receive_can_native(); // Receive CAN messages from native CAN port
|
receive_can_native(); // Receive CAN messages from native CAN port
|
||||||
#ifdef CAN_FD
|
#ifdef CAN_FD
|
||||||
|
@ -334,10 +352,21 @@ void init_serial() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void init_stored_settings() {
|
void init_stored_settings() {
|
||||||
|
static uint32_t temp = 0;
|
||||||
settings.begin("batterySettings", false);
|
settings.begin("batterySettings", false);
|
||||||
|
|
||||||
|
// Always get the equipment stop status
|
||||||
|
datalayer.system.settings.equipment_stop_active = settings.getBool("EQUIPMENT_STOP", false);
|
||||||
|
if (datalayer.system.settings.equipment_stop_active) {
|
||||||
|
set_event(EVENT_EQUIPMENT_STOP, 1);
|
||||||
|
}
|
||||||
|
|
||||||
#ifndef LOAD_SAVED_SETTINGS_ON_BOOT
|
#ifndef LOAD_SAVED_SETTINGS_ON_BOOT
|
||||||
settings.clear(); // If this clear function is executed, no settings will be read from storage
|
settings.clear(); // If this clear function is executed, no settings will be read from storage
|
||||||
|
|
||||||
|
//always save the equipment stop status
|
||||||
|
settings.putBool("EQUIPMENT_STOP", datalayer.system.settings.equipment_stop_active);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef WIFI
|
#ifdef WIFI
|
||||||
|
@ -356,7 +385,6 @@ void init_stored_settings() {
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static uint32_t temp = 0;
|
|
||||||
temp = settings.getUInt("BATTERY_WH_MAX", false);
|
temp = settings.getUInt("BATTERY_WH_MAX", false);
|
||||||
if (temp != 0) {
|
if (temp != 0) {
|
||||||
datalayer.battery.info.total_capacity_Wh = temp;
|
datalayer.battery.info.total_capacity_Wh = temp;
|
||||||
|
@ -547,6 +575,43 @@ void init_battery() {
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef EQUIPMENT_STOP_BUTTON
|
||||||
|
|
||||||
|
void monitor_equipment_stop_button() {
|
||||||
|
|
||||||
|
ButtonState changed_state = debounceButton(equipment_stop_button, timeSincePress);
|
||||||
|
|
||||||
|
if (equipment_stop_behavior == LATCHING_SWITCH) {
|
||||||
|
if (changed_state == PRESSED) {
|
||||||
|
// Changed to ON – initiating equipment stop.
|
||||||
|
setBatteryPause(true, true, true);
|
||||||
|
} else if (changed_state == RELEASED) {
|
||||||
|
// Changed to OFF – ending equipment stop.
|
||||||
|
setBatteryPause(false, false, false);
|
||||||
|
}
|
||||||
|
} else if (equipment_stop_behavior == MOMENTARY_SWITCH) {
|
||||||
|
if (changed_state == RELEASED) { // button is released
|
||||||
|
|
||||||
|
if (timeSincePress < equipment_button_long_press_duration) {
|
||||||
|
// Short press detected, trigger equipment stop
|
||||||
|
setBatteryPause(true, true, true);
|
||||||
|
} else {
|
||||||
|
// Long press detected, reset equipment stop state
|
||||||
|
setBatteryPause(false, false, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void init_equipment_stop_button() {
|
||||||
|
//using external pullup resistors NC
|
||||||
|
pinMode(EQUIPMENT_STOP_PIN, INPUT);
|
||||||
|
// Initialize the debounced button with NC switch type and equipment_button_debounce_duration debounce time
|
||||||
|
initDebouncedButton(equipment_stop_button, EQUIPMENT_STOP_PIN, NC, equipment_button_debounce_duration);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef CAN_FD
|
#ifdef CAN_FD
|
||||||
// Functions
|
// Functions
|
||||||
#ifdef DEBUG_CANFD_DATA
|
#ifdef DEBUG_CANFD_DATA
|
||||||
|
@ -581,6 +646,7 @@ void receive_canfd() { // This section checks if we have a complete CAN-FD mess
|
||||||
}
|
}
|
||||||
//message incoming, pass it on to the handler
|
//message incoming, pass it on to the handler
|
||||||
receive_can(&rx_frame, CAN_ADDON_FD_MCP2518);
|
receive_can(&rx_frame, CAN_ADDON_FD_MCP2518);
|
||||||
|
receive_can(&rx_frame, CANFD_NATIVE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -672,9 +738,14 @@ void handle_contactors() {
|
||||||
timeSpentInFaultedMode = 0;
|
timeSpentInFaultedMode = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (timeSpentInFaultedMode > MAX_ALLOWED_FAULT_TICKS) {
|
//handle contactor control SHUTDOWN_REQUESTED vs DISCONNECTED
|
||||||
|
if (timeSpentInFaultedMode > MAX_ALLOWED_FAULT_TICKS ||
|
||||||
|
(datalayer.system.settings.equipment_stop_active && contactorStatus != SHUTDOWN_REQUESTED)) {
|
||||||
contactorStatus = SHUTDOWN_REQUESTED;
|
contactorStatus = SHUTDOWN_REQUESTED;
|
||||||
}
|
}
|
||||||
|
if (contactorStatus == SHUTDOWN_REQUESTED && !datalayer.system.settings.equipment_stop_active) {
|
||||||
|
contactorStatus = DISCONNECTED;
|
||||||
|
}
|
||||||
if (contactorStatus == SHUTDOWN_REQUESTED) {
|
if (contactorStatus == SHUTDOWN_REQUESTED) {
|
||||||
digitalWrite(PRECHARGE_PIN, LOW);
|
digitalWrite(PRECHARGE_PIN, LOW);
|
||||||
#ifndef PWM_CONTACTOR_CONTROL
|
#ifndef PWM_CONTACTOR_CONTROL
|
||||||
|
@ -846,6 +917,12 @@ void init_serialDataLink() {
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void store_settings_equipment_stop() {
|
||||||
|
settings.begin("batterySettings", false);
|
||||||
|
settings.putBool("EQUIPMENT_STOP", datalayer.system.settings.equipment_stop_active);
|
||||||
|
settings.end();
|
||||||
|
}
|
||||||
|
|
||||||
void storeSettings() {
|
void storeSettings() {
|
||||||
settings.begin("batterySettings", false);
|
settings.begin("batterySettings", false);
|
||||||
#ifdef WIFI
|
#ifdef WIFI
|
||||||
|
|
|
@ -48,6 +48,13 @@ const char* mqtt_password = "REDACTED"; // Set NULL for no password
|
||||||
#endif // USE_MQTT
|
#endif // USE_MQTT
|
||||||
#endif // WIFI
|
#endif // WIFI
|
||||||
|
|
||||||
|
#ifdef EQUIPMENT_STOP_BUTTON
|
||||||
|
// Equipment stop button behavior. Use NC button for safety reasons.
|
||||||
|
//LATCHING_SWITCH - Normally closed (NC), latching switch. When pressed it activates e-stop
|
||||||
|
//MOMENTARY_SWITCH - Short press to activate e-stop, long 15s press to deactivate. E-stop is persistent between reboots
|
||||||
|
volatile STOP_BUTTON_BEHAVIOR equipment_stop_behavior = LATCHING_SWITCH;
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Charger settings (Optional, when using generator charging) */
|
/* Charger settings (Optional, when using generator charging) */
|
||||||
volatile float CHARGER_SET_HV = 384; // Reasonably appropriate 4.0v per cell charging of a 96s pack
|
volatile float CHARGER_SET_HV = 384; // Reasonably appropriate 4.0v per cell charging of a 96s pack
|
||||||
volatile float CHARGER_MAX_HV = 420; // Max permissible output (VDC) of charger
|
volatile float CHARGER_MAX_HV = 420; // Max permissible output (VDC) of charger
|
||||||
|
|
|
@ -53,6 +53,7 @@
|
||||||
//#define CONTACTOR_CONTROL //Enable this line to have pins 25,32,33 handle automatic precharge/contactor+/contactor- closing sequence
|
//#define CONTACTOR_CONTROL //Enable this line to have pins 25,32,33 handle automatic precharge/contactor+/contactor- closing sequence
|
||||||
//#define PWM_CONTACTOR_CONTROL //Enable this line to use PWM for CONTACTOR_CONTROL, which lowers power consumption and heat generation. CONTACTOR_CONTROL must be enabled.
|
//#define PWM_CONTACTOR_CONTROL //Enable this line to use PWM for CONTACTOR_CONTROL, which lowers power consumption and heat generation. CONTACTOR_CONTROL must be enabled.
|
||||||
//#define DUAL_CAN //Enable this line to activate an isolated secondary CAN Bus using add-on MCP2515 chip (Needed for some inverters / double battery)
|
//#define DUAL_CAN //Enable this line to activate an isolated secondary CAN Bus using add-on MCP2515 chip (Needed for some inverters / double battery)
|
||||||
|
#define CRYSTAL_FREQUENCY_MHZ 8 //DUAL_CAN option, what is your MCP2515 add-on boards crystal frequency?
|
||||||
//#define CAN_FD //Enable this line to activate an isolated secondary CAN-FD bus using add-on MCP2518FD chip / Native CANFD on Stark board
|
//#define CAN_FD //Enable this line to activate an isolated secondary CAN-FD bus using add-on MCP2518FD chip / Native CANFD on Stark board
|
||||||
//#define USE_CANFD_INTERFACE_AS_CLASSIC_CAN // Enable this line if you intend to use the CANFD as normal CAN
|
//#define USE_CANFD_INTERFACE_AS_CLASSIC_CAN // Enable this line if you intend to use the CANFD as normal CAN
|
||||||
//#define SERIAL_LINK_RECEIVER //Enable this line to receive battery data over RS485 pins from another Lilygo (This LilyGo interfaces with inverter)
|
//#define SERIAL_LINK_RECEIVER //Enable this line to receive battery data over RS485 pins from another Lilygo (This LilyGo interfaces with inverter)
|
||||||
|
@ -61,11 +62,12 @@
|
||||||
//#define WIFICONFIG //Enable this line to set a static IP address / gateway /subnet mask for the device. see USER_SETTINGS.cpp for the settings
|
//#define WIFICONFIG //Enable this line to set a static IP address / gateway /subnet mask for the device. see USER_SETTINGS.cpp for the settings
|
||||||
#define WEBSERVER //Enable this line to enable WiFi, and to run the webserver. See USER_SETTINGS.cpp for the Wifi settings.
|
#define WEBSERVER //Enable this line to enable WiFi, and to run the webserver. See USER_SETTINGS.cpp for the Wifi settings.
|
||||||
#define WEBSERVER_AUTH_REQUIRED \
|
#define WEBSERVER_AUTH_REQUIRED \
|
||||||
false //Enable this line to enable webserver authentication. See USER_SETTINGS.cpp setting the credentials.
|
false //Set this line to true to activate webserver authentication (this line must not be commented). Refer to USER_SETTINGS.cpp for setting the credentials.
|
||||||
#define WIFIAP //Disable this line to permanently disable WIFI AP mode (make sure to hardcode ssid and password of you home wifi network). When enabled WIFI AP can still be disabled by a setting in the future.
|
#define WIFIAP //Disable this line to permanently disable WIFI AP mode (make sure to hardcode ssid and password of you home wifi network). When enabled WIFI AP can still be disabled by a setting in the future.
|
||||||
#define MDNSRESPONDER //Enable this line to enable MDNS, allows battery monitor te be found by .local address. Requires WEBSERVER to be enabled.
|
#define MDNSRESPONDER //Enable this line to enable MDNS, allows battery monitor te be found by .local address. Requires WEBSERVER to be enabled.
|
||||||
#define LOAD_SAVED_SETTINGS_ON_BOOT //Enable this line to read settings stored via the webserver on boot (overrides Wifi/battery settings set below)
|
#define LOAD_SAVED_SETTINGS_ON_BOOT //Enable this line to read settings stored via the webserver on boot (overrides Wifi/battery settings set below)
|
||||||
//#define FUNCTION_TIME_MEASUREMENT // Enable this to record execution times and present them in the web UI (WARNING, raises CPU load, do not use for production)
|
//#define FUNCTION_TIME_MEASUREMENT // Enable this to record execution times and present them in the web UI (WARNING, raises CPU load, do not use for production)
|
||||||
|
//#define EQUIPMENT_STOP_BUTTON // Enable this to allow an equipment stop button connected to the Battery-Emulator to disengage the battery
|
||||||
|
|
||||||
/* MQTT options */
|
/* MQTT options */
|
||||||
// #define MQTT // Enable this line to enable MQTT
|
// #define MQTT // Enable this line to enable MQTT
|
||||||
|
@ -120,6 +122,11 @@ extern volatile float CHARGER_END_A;
|
||||||
extern bool charger_HV_enabled;
|
extern bool charger_HV_enabled;
|
||||||
extern bool charger_aux12V_enabled;
|
extern bool charger_aux12V_enabled;
|
||||||
|
|
||||||
|
#ifdef EQUIPMENT_STOP_BUTTON
|
||||||
|
typedef enum { LATCHING_SWITCH = 0, MOMENTARY_SWITCH = 1 } STOP_BUTTON_BEHAVIOR;
|
||||||
|
extern volatile STOP_BUTTON_BEHAVIOR equipment_stop_behavior;
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef WIFICONFIG
|
#ifdef WIFICONFIG
|
||||||
extern IPAddress local_IP;
|
extern IPAddress local_IP;
|
||||||
// Set your Gateway IP address
|
// Set your Gateway IP address
|
||||||
|
|
|
@ -395,8 +395,37 @@ void update_values_battery2() { //This function maps all the values fetched via
|
||||||
|
|
||||||
datalayer.battery2.status.temperature_max_dC = battery2_temperature_max * 10; // Add a decimal
|
datalayer.battery2.status.temperature_max_dC = battery2_temperature_max * 10; // Add a decimal
|
||||||
|
|
||||||
datalayer.battery2.status.cell_min_voltage_mV = datalayer.battery2.status.cell_voltages_mV[0];
|
if (battery2_info_available) {
|
||||||
datalayer.battery2.status.cell_max_voltage_mV = datalayer.battery2.status.cell_voltages_mV[1];
|
// Start checking safeties. First up, cellvoltages!
|
||||||
|
if (detectedBattery == BATTERY_60AH) {
|
||||||
|
datalayer.battery2.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_60AH;
|
||||||
|
datalayer.battery2.info.min_design_voltage_dV = MIN_PACK_VOLTAGE_60AH;
|
||||||
|
datalayer.battery2.info.max_cell_voltage_mV = MAX_CELL_VOLTAGE_60AH;
|
||||||
|
datalayer.battery2.info.min_cell_voltage_mV = MIN_CELL_VOLTAGE_60AH;
|
||||||
|
} else if (detectedBattery == BATTERY_94AH) {
|
||||||
|
datalayer.battery2.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_94AH;
|
||||||
|
datalayer.battery2.info.min_design_voltage_dV = MIN_PACK_VOLTAGE_94AH;
|
||||||
|
datalayer.battery2.info.max_cell_voltage_mV = MAX_CELL_VOLTAGE_94AH;
|
||||||
|
datalayer.battery2.info.min_cell_voltage_mV = MIN_CELL_VOLTAGE_94AH;
|
||||||
|
} else { // BATTERY_120AH
|
||||||
|
datalayer.battery2.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_120AH;
|
||||||
|
datalayer.battery2.info.min_design_voltage_dV = MIN_PACK_VOLTAGE_120AH;
|
||||||
|
datalayer.battery2.info.max_cell_voltage_mV = MAX_CELL_VOLTAGE_120AH;
|
||||||
|
datalayer.battery2.info.min_cell_voltage_mV = MIN_CELL_VOLTAGE_120AH;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Perform other safety checks
|
||||||
|
if (battery2_status_error_locking == 2) { // HVIL seated?
|
||||||
|
set_event(EVENT_HVIL_FAILURE, 2);
|
||||||
|
} else {
|
||||||
|
clear_event(EVENT_HVIL_FAILURE);
|
||||||
|
}
|
||||||
|
if (battery2_status_precharge_locked == 2) { // Capacitor seated?
|
||||||
|
set_event(EVENT_PRECHARGE_FAILURE, 2);
|
||||||
|
} else {
|
||||||
|
clear_event(EVENT_PRECHARGE_FAILURE);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void update_values_battery() { //This function maps all the values fetched via CAN to the battery datalayer
|
void update_values_battery() { //This function maps all the values fetched via CAN to the battery datalayer
|
||||||
|
@ -433,30 +462,18 @@ void update_values_battery() { //This function maps all the values fetched via
|
||||||
if (detectedBattery == BATTERY_60AH) {
|
if (detectedBattery == BATTERY_60AH) {
|
||||||
datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_60AH;
|
datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_60AH;
|
||||||
datalayer.battery.info.min_design_voltage_dV = MIN_PACK_VOLTAGE_60AH;
|
datalayer.battery.info.min_design_voltage_dV = MIN_PACK_VOLTAGE_60AH;
|
||||||
if (datalayer.battery.status.cell_max_voltage_mV >= MAX_CELL_VOLTAGE_60AH) {
|
datalayer.battery.info.max_cell_voltage_mV = MAX_CELL_VOLTAGE_60AH;
|
||||||
set_event(EVENT_CELL_OVER_VOLTAGE, 0);
|
datalayer.battery.info.min_cell_voltage_mV = MIN_CELL_VOLTAGE_60AH;
|
||||||
}
|
|
||||||
if (datalayer.battery.status.cell_min_voltage_mV <= MIN_CELL_VOLTAGE_60AH) {
|
|
||||||
set_event(EVENT_CELL_UNDER_VOLTAGE, 0);
|
|
||||||
}
|
|
||||||
} else if (detectedBattery == BATTERY_94AH) {
|
} else if (detectedBattery == BATTERY_94AH) {
|
||||||
datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_94AH;
|
datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_94AH;
|
||||||
datalayer.battery.info.min_design_voltage_dV = MIN_PACK_VOLTAGE_94AH;
|
datalayer.battery.info.min_design_voltage_dV = MIN_PACK_VOLTAGE_94AH;
|
||||||
if (datalayer.battery.status.cell_max_voltage_mV >= MAX_CELL_VOLTAGE_94AH) {
|
datalayer.battery.info.max_cell_voltage_mV = MAX_CELL_VOLTAGE_94AH;
|
||||||
set_event(EVENT_CELL_OVER_VOLTAGE, 0);
|
datalayer.battery.info.min_cell_voltage_mV = MIN_CELL_VOLTAGE_94AH;
|
||||||
}
|
|
||||||
if (datalayer.battery.status.cell_min_voltage_mV <= MIN_CELL_VOLTAGE_94AH) {
|
|
||||||
set_event(EVENT_CELL_UNDER_VOLTAGE, 0);
|
|
||||||
}
|
|
||||||
} else { // BATTERY_120AH
|
} else { // BATTERY_120AH
|
||||||
datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_120AH;
|
datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_120AH;
|
||||||
datalayer.battery.info.min_design_voltage_dV = MIN_PACK_VOLTAGE_120AH;
|
datalayer.battery.info.min_design_voltage_dV = MIN_PACK_VOLTAGE_120AH;
|
||||||
if (datalayer.battery.status.cell_max_voltage_mV >= MAX_CELL_VOLTAGE_120AH) {
|
datalayer.battery.info.max_cell_voltage_mV = MAX_CELL_VOLTAGE_120AH;
|
||||||
set_event(EVENT_CELL_OVER_VOLTAGE, 0);
|
datalayer.battery.info.min_cell_voltage_mV = MIN_CELL_VOLTAGE_120AH;
|
||||||
}
|
|
||||||
if (datalayer.battery.status.cell_min_voltage_mV <= MIN_CELL_VOLTAGE_120AH) {
|
|
||||||
set_event(EVENT_CELL_UNDER_VOLTAGE, 0);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1124,13 +1141,14 @@ void setup_battery(void) { // Performs one time setup at startup
|
||||||
//Before we have started up and detected which battery is in use, use 60AH values
|
//Before we have started up and detected which battery is in use, use 60AH values
|
||||||
datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_60AH;
|
datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_60AH;
|
||||||
datalayer.battery.info.min_design_voltage_dV = MIN_PACK_VOLTAGE_60AH;
|
datalayer.battery.info.min_design_voltage_dV = MIN_PACK_VOLTAGE_60AH;
|
||||||
|
datalayer.battery.info.max_cell_voltage_deviation_mV = MAX_CELL_DEVIATION_MV;
|
||||||
datalayer.system.status.battery_allows_contactor_closing = true;
|
datalayer.system.status.battery_allows_contactor_closing = true;
|
||||||
|
|
||||||
#ifdef DOUBLE_BATTERY
|
#ifdef DOUBLE_BATTERY
|
||||||
Serial.println("Another BMW i3 battery also selected!");
|
Serial.println("Another BMW i3 battery also selected!");
|
||||||
datalayer.battery2.info.max_design_voltage_dV = datalayer.battery.info.max_design_voltage_dV;
|
datalayer.battery2.info.max_design_voltage_dV = datalayer.battery.info.max_design_voltage_dV;
|
||||||
datalayer.battery2.info.min_design_voltage_dV = datalayer.battery.info.min_design_voltage_dV;
|
datalayer.battery2.info.min_design_voltage_dV = datalayer.battery.info.min_design_voltage_dV;
|
||||||
|
datalayer.battery2.info.max_cell_voltage_deviation_mV = datalayer.battery.info.max_cell_voltage_deviation_mV;
|
||||||
datalayer.battery2.status.voltage_dV =
|
datalayer.battery2.status.voltage_dV =
|
||||||
0; //Init voltage to 0 to allow contactor check to operate without fear of default values colliding
|
0; //Init voltage to 0 to allow contactor check to operate without fear of default values colliding
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -135,14 +135,14 @@ void update_values_battery() { //This function maps all the values fetched via
|
||||||
}
|
}
|
||||||
|
|
||||||
void receive_can_battery(CAN_frame rx_frame) {
|
void receive_can_battery(CAN_frame rx_frame) {
|
||||||
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
|
||||||
switch (rx_frame.ID) { //Log values taken with 422V from battery
|
switch (rx_frame.ID) { //Log values taken with 422V from battery
|
||||||
case 0x244: //00,00,00,04,41,0F,20,8B - Static, values never changes between logs
|
case 0x244: //00,00,00,04,41,0F,20,8B - Static, values never changes between logs
|
||||||
break;
|
break;
|
||||||
case 0x245: //01,00,02,19,3A,25,90,F4 Seems to have a mux in frame0
|
case 0x245: //01,00,02,19,3A,25,90,F4 Seems to have a mux in frame0
|
||||||
//02,00,90,01,79,79,90,EA // Point of interest, went from 7E,75 to 7B,7C when discharging
|
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||||
//03,C6,88,12,FD,48,90,5C
|
//02,00,90,01,79,79,90,EA // Point of interest, went from 7E,75 to 7B,7C when discharging
|
||||||
//04,00,FF,FF,00,00,90,6D
|
//03,C6,88,12,FD,48,90,5C
|
||||||
|
//04,00,FF,FF,00,00,90,6D
|
||||||
if (rx_frame.data.u8[0] == 0x01) {
|
if (rx_frame.data.u8[0] == 0x01) {
|
||||||
temperature_ambient = (rx_frame.data.u8[4] - 40); // TODO, check if this is actually temperature_ambient
|
temperature_ambient = (rx_frame.data.u8[4] - 40); // TODO, check if this is actually temperature_ambient
|
||||||
}
|
}
|
||||||
|
@ -371,9 +371,13 @@ void setup_battery(void) { // Performs one time setup at startup
|
||||||
#ifdef DEBUG_VIA_USB
|
#ifdef DEBUG_VIA_USB
|
||||||
Serial.println("BYD Atto 3 battery selected");
|
Serial.println("BYD Atto 3 battery selected");
|
||||||
#endif
|
#endif
|
||||||
|
datalayer.battery.info.number_of_cells = 126;
|
||||||
datalayer.battery.info.max_design_voltage_dV = 4410; // Over this charging is not possible
|
datalayer.battery.info.chemistry = battery_chemistry_enum::LFP;
|
||||||
datalayer.battery.info.min_design_voltage_dV = 3800; // Under this discharging is disabled
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -4,7 +4,11 @@
|
||||||
#include "../include.h"
|
#include "../include.h"
|
||||||
|
|
||||||
#define BATTERY_SELECTED
|
#define BATTERY_SELECTED
|
||||||
|
#define MAX_PACK_VOLTAGE_DV 4410 //5000 = 500.0V
|
||||||
|
#define MIN_PACK_VOLTAGE_DV 3800
|
||||||
#define MAX_CELL_DEVIATION_MV 150
|
#define MAX_CELL_DEVIATION_MV 150
|
||||||
|
#define MAX_CELL_VOLTAGE_MV 3800 //Battery is put into emergency stop if one cell goes over this value
|
||||||
|
#define MIN_CELL_VOLTAGE_MV 2800 //Battery is put into emergency stop if one cell goes below this value
|
||||||
|
|
||||||
void setup_battery(void);
|
void setup_battery(void);
|
||||||
void transmit_can(CAN_frame* tx_frame, int interface);
|
void transmit_can(CAN_frame* tx_frame, int interface);
|
||||||
|
|
|
@ -4,7 +4,6 @@
|
||||||
#include "../include.h"
|
#include "../include.h"
|
||||||
|
|
||||||
#define BATTERY_SELECTED
|
#define BATTERY_SELECTED
|
||||||
#define MAX_CELL_DEVIATION_MV 9999
|
|
||||||
|
|
||||||
//Contactor control is required for CHADEMO support
|
//Contactor control is required for CHADEMO support
|
||||||
#define CONTACTOR_CONTROL
|
#define CONTACTOR_CONTROL
|
||||||
|
|
|
@ -8,8 +8,6 @@
|
||||||
//Figure out if CAN messages need to be sent to keep the system happy?
|
//Figure out if CAN messages need to be sent to keep the system happy?
|
||||||
|
|
||||||
/* Do not change code below unless you are sure what you are doing */
|
/* Do not change code below unless you are sure what you are doing */
|
||||||
#define MAX_CELL_VOLTAGE 4150
|
|
||||||
#define MIN_CELL_VOLTAGE 2750
|
|
||||||
static uint8_t errorCode = 0; //stores if we have an error code active from battery control logic
|
static uint8_t errorCode = 0; //stores if we have an error code active from battery control logic
|
||||||
static uint8_t BMU_Detected = 0;
|
static uint8_t BMU_Detected = 0;
|
||||||
static uint8_t CMU_Detected = 0;
|
static uint8_t CMU_Detected = 0;
|
||||||
|
@ -106,14 +104,6 @@ void update_values_battery() { //This function maps all the values fetched via
|
||||||
datalayer.battery.status.temperature_max_dC = (int16_t)(max_temp_cel * 10);
|
datalayer.battery.status.temperature_max_dC = (int16_t)(max_temp_cel * 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
//Check safeties
|
|
||||||
if (datalayer.battery.status.cell_max_voltage_mV >= MAX_CELL_VOLTAGE) {
|
|
||||||
set_event(EVENT_CELL_OVER_VOLTAGE, datalayer.battery.status.cell_max_voltage_mV);
|
|
||||||
}
|
|
||||||
if (datalayer.battery.status.cell_min_voltage_mV <= MIN_CELL_VOLTAGE) {
|
|
||||||
set_event(EVENT_CELL_UNDER_VOLTAGE, datalayer.battery.status.cell_min_voltage_mV);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!BMU_Detected) {
|
if (!BMU_Detected) {
|
||||||
#ifdef DEBUG_VIA_USB
|
#ifdef DEBUG_VIA_USB
|
||||||
Serial.println("BMU not detected, check wiring!");
|
Serial.println("BMU not detected, check wiring!");
|
||||||
|
@ -239,9 +229,11 @@ void setup_battery(void) { // Performs one time setup at startup
|
||||||
#ifdef DEBUG_VIA_USB
|
#ifdef DEBUG_VIA_USB
|
||||||
Serial.println("Mitsubishi i-MiEV / Citroen C-Zero / Peugeot Ion battery selected");
|
Serial.println("Mitsubishi i-MiEV / Citroen C-Zero / Peugeot Ion battery selected");
|
||||||
#endif
|
#endif
|
||||||
|
datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_DV;
|
||||||
datalayer.battery.info.max_design_voltage_dV = 3696; // 369.6V
|
datalayer.battery.info.min_design_voltage_dV = MIN_PACK_VOLTAGE_DV;
|
||||||
datalayer.battery.info.min_design_voltage_dV = 3160; // 316.0V
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -4,7 +4,11 @@
|
||||||
#include "../include.h"
|
#include "../include.h"
|
||||||
|
|
||||||
#define BATTERY_SELECTED
|
#define BATTERY_SELECTED
|
||||||
|
#define MAX_PACK_VOLTAGE_DV 3696 //5000 = 500.0V
|
||||||
|
#define MIN_PACK_VOLTAGE_DV 3160
|
||||||
#define MAX_CELL_DEVIATION_MV 500
|
#define MAX_CELL_DEVIATION_MV 500
|
||||||
|
#define MAX_CELL_VOLTAGE_MV 4150 //Battery is put into emergency stop if one cell goes over this value
|
||||||
|
#define MIN_CELL_VOLTAGE_MV 2750 //Battery is put into emergency stop if one cell goes below this value
|
||||||
|
|
||||||
void setup_battery(void);
|
void setup_battery(void);
|
||||||
void transmit_can(CAN_frame* tx_frame, int interface);
|
void transmit_can(CAN_frame* tx_frame, int interface);
|
||||||
|
|
|
@ -263,8 +263,11 @@ void setup_battery(void) { // Performs one time setup at startup
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
datalayer.battery.info.number_of_cells = 108;
|
datalayer.battery.info.number_of_cells = 108;
|
||||||
datalayer.battery.info.max_design_voltage_dV = 4546;
|
datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_DV;
|
||||||
datalayer.battery.info.min_design_voltage_dV = 3370;
|
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.system.status.battery_allows_contactor_closing = true;
|
datalayer.system.status.battery_allows_contactor_closing = true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,11 @@
|
||||||
#include "../include.h"
|
#include "../include.h"
|
||||||
|
|
||||||
#define BATTERY_SELECTED
|
#define BATTERY_SELECTED
|
||||||
#define MAX_CELL_DEVIATION_MV 9999 // TODO is this ok ?
|
#define MAX_PACK_VOLTAGE_DV 4546 //5000 = 500.0V
|
||||||
|
#define MIN_PACK_VOLTAGE_DV 3370
|
||||||
|
#define MAX_CELL_DEVIATION_MV 500
|
||||||
|
#define MAX_CELL_VOLTAGE_MV 4250 //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
|
||||||
|
|
||||||
void setup_battery(void);
|
void setup_battery(void);
|
||||||
void transmit_can(CAN_frame* tx_frame, int interface);
|
void transmit_can(CAN_frame* tx_frame, int interface);
|
||||||
|
|
|
@ -15,9 +15,6 @@ static unsigned long previousMillis500ms = 0; // will store last time a 500ms C
|
||||||
static unsigned long previousMillis1s = 0; // will store last time a 1s CAN Message was send
|
static unsigned long previousMillis1s = 0; // will store last time a 1s CAN Message was send
|
||||||
static unsigned long previousMillis10s = 0; // will store last time a 10s CAN Message was send
|
static unsigned long previousMillis10s = 0; // will store last time a 10s CAN Message was send
|
||||||
|
|
||||||
#define MAX_CELL_VOLTAGE 4250 //Battery is put into emergency stop if one cell goes over this value
|
|
||||||
#define MIN_CELL_VOLTAGE 2950 //Battery is put into emergency stop if one cell goes below this value
|
|
||||||
|
|
||||||
const unsigned char crc8_table[256] =
|
const unsigned char crc8_table[256] =
|
||||||
{ // CRC8_SAE_J1850_ZER0 formula,0x1D Poly,initial value 0x3F,Final XOR value varies
|
{ // CRC8_SAE_J1850_ZER0 formula,0x1D Poly,initial value 0x3F,Final XOR value varies
|
||||||
0x00, 0x1D, 0x3A, 0x27, 0x74, 0x69, 0x4E, 0x53, 0xE8, 0xF5, 0xD2, 0xCF, 0x9C, 0x81, 0xA6, 0xBB, 0xCD, 0xD0,
|
0x00, 0x1D, 0x3A, 0x27, 0x74, 0x69, 0x4E, 0x53, 0xE8, 0xF5, 0xD2, 0xCF, 0x9C, 0x81, 0xA6, 0xBB, 0xCD, 0xD0,
|
||||||
|
@ -864,14 +861,6 @@ void update_values_battery() { //This function maps all the values fetched via
|
||||||
set_event(EVENT_12V_LOW, leadAcidBatteryVoltage);
|
set_event(EVENT_12V_LOW, leadAcidBatteryVoltage);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if cell voltages are within allowed range
|
|
||||||
if (CellVoltMax_mV >= MAX_CELL_VOLTAGE) {
|
|
||||||
set_event(EVENT_CELL_OVER_VOLTAGE, 0);
|
|
||||||
}
|
|
||||||
if (CellVoltMin_mV <= MIN_CELL_VOLTAGE) {
|
|
||||||
set_event(EVENT_CELL_UNDER_VOLTAGE, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Safeties verified. Perform USB serial printout if configured to do so */
|
/* Safeties verified. Perform USB serial printout if configured to do so */
|
||||||
|
|
||||||
#ifdef DEBUG_VIA_USB
|
#ifdef DEBUG_VIA_USB
|
||||||
|
@ -1239,11 +1228,10 @@ void setup_battery(void) { // Performs one time setup at startup
|
||||||
datalayer.system.status.battery_allows_contactor_closing = true;
|
datalayer.system.status.battery_allows_contactor_closing = true;
|
||||||
|
|
||||||
datalayer.battery.info.number_of_cells = 192; // TODO: will vary depending on battery
|
datalayer.battery.info.number_of_cells = 192; // TODO: will vary depending on battery
|
||||||
|
datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_DV;
|
||||||
datalayer.battery.info.max_design_voltage_dV =
|
datalayer.battery.info.min_design_voltage_dV = MIN_PACK_VOLTAGE_DV;
|
||||||
8064; // TODO: define when battery is known, charging is not possible (goes into forced discharge)
|
datalayer.battery.info.max_cell_voltage_mV = MAX_CELL_VOLTAGE_MV;
|
||||||
datalayer.battery.info.min_design_voltage_dV =
|
datalayer.battery.info.min_cell_voltage_mV = MIN_CELL_VOLTAGE_MV;
|
||||||
4320; // TODO: define when battery is known. discharging further is disabled
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -7,7 +7,11 @@
|
||||||
extern ACAN2517FD canfd;
|
extern ACAN2517FD canfd;
|
||||||
|
|
||||||
#define BATTERY_SELECTED
|
#define BATTERY_SELECTED
|
||||||
|
#define MAX_PACK_VOLTAGE_DV 8064 //5000 = 500.0V
|
||||||
|
#define MIN_PACK_VOLTAGE_DV 4320
|
||||||
#define MAX_CELL_DEVIATION_MV 150
|
#define MAX_CELL_DEVIATION_MV 150
|
||||||
|
#define MAX_CELL_VOLTAGE_MV 4250 //Battery is put into emergency stop if one cell goes over this value
|
||||||
|
#define MIN_CELL_VOLTAGE_MV 2950 //Battery is put into emergency stop if one cell goes below this value
|
||||||
#define MAXCHARGEPOWERALLOWED 10000
|
#define MAXCHARGEPOWERALLOWED 10000
|
||||||
#define MAXDISCHARGEPOWERALLOWED 10000
|
#define MAXDISCHARGEPOWERALLOWED 10000
|
||||||
|
|
||||||
|
|
|
@ -8,9 +8,6 @@
|
||||||
static unsigned long previousMillis100 = 0; // will store last time a 100ms CAN Message was send
|
static unsigned long previousMillis100 = 0; // will store last time a 100ms CAN Message was send
|
||||||
static unsigned long previousMillis10 = 0; // will store last time a 10s CAN Message was send
|
static unsigned long previousMillis10 = 0; // will store last time a 10s CAN Message was send
|
||||||
|
|
||||||
#define MAX_CELL_VOLTAGE 4250 //Battery is put into emergency stop if one cell goes over this value
|
|
||||||
#define MIN_CELL_VOLTAGE 2950 //Battery is put into emergency stop if one cell goes below this value
|
|
||||||
|
|
||||||
static uint16_t soc_calculated = 0;
|
static uint16_t soc_calculated = 0;
|
||||||
static uint16_t SOC_BMS = 0;
|
static uint16_t SOC_BMS = 0;
|
||||||
static uint16_t SOC_Display = 0;
|
static uint16_t SOC_Display = 0;
|
||||||
|
@ -147,14 +144,6 @@ void update_values_battery() { //This function maps all the values fetched via
|
||||||
set_event(EVENT_12V_LOW, leadAcidBatteryVoltage);
|
set_event(EVENT_12V_LOW, leadAcidBatteryVoltage);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if cell voltages are within allowed range
|
|
||||||
if (CellVoltMax_mV >= MAX_CELL_VOLTAGE) {
|
|
||||||
set_event(EVENT_CELL_OVER_VOLTAGE, 0);
|
|
||||||
}
|
|
||||||
if (CellVoltMin_mV <= MIN_CELL_VOLTAGE) {
|
|
||||||
set_event(EVENT_CELL_UNDER_VOLTAGE, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Safeties verified. Perform USB serial printout if configured to do so */
|
/* Safeties verified. Perform USB serial printout if configured to do so */
|
||||||
|
|
||||||
#ifdef DEBUG_VIA_USB
|
#ifdef DEBUG_VIA_USB
|
||||||
|
@ -223,12 +212,12 @@ void update_number_of_cells() {
|
||||||
// Check if we have 98S or 90S battery
|
// Check if we have 98S or 90S battery
|
||||||
if (datalayer.battery.status.cell_voltages_mV[97] > 0) {
|
if (datalayer.battery.status.cell_voltages_mV[97] > 0) {
|
||||||
datalayer.battery.info.number_of_cells = 98;
|
datalayer.battery.info.number_of_cells = 98;
|
||||||
datalayer.battery.info.max_design_voltage_dV = 4040;
|
datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_98S_DV;
|
||||||
datalayer.battery.info.min_design_voltage_dV = 3100;
|
datalayer.battery.info.min_design_voltage_dV = MIN_PACK_VOLTAGE_98S_DV;
|
||||||
} else {
|
} else {
|
||||||
datalayer.battery.info.number_of_cells = 90;
|
datalayer.battery.info.number_of_cells = 90;
|
||||||
datalayer.battery.info.max_design_voltage_dV = 3870;
|
datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_90S_DV;
|
||||||
datalayer.battery.info.min_design_voltage_dV = 2250;
|
datalayer.battery.info.min_design_voltage_dV = MIN_PACK_VOLTAGE_90S_DV;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -550,9 +539,10 @@ void setup_battery(void) { // Performs one time setup at startup
|
||||||
#ifdef DEBUG_VIA_USB
|
#ifdef DEBUG_VIA_USB
|
||||||
Serial.println("Kia Niro / Hyundai Kona 64kWh battery selected");
|
Serial.println("Kia Niro / Hyundai Kona 64kWh battery selected");
|
||||||
#endif
|
#endif
|
||||||
|
datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_98S_DV; //Start with 98S value. Precised later
|
||||||
datalayer.battery.info.max_design_voltage_dV = 4040; // 404.0V
|
datalayer.battery.info.min_design_voltage_dV = MIN_PACK_VOLTAGE_90S_DV; //Start with 90S value. Precised later
|
||||||
datalayer.battery.info.min_design_voltage_dV = 3100; // 310.0V
|
datalayer.battery.info.max_cell_voltage_mV = MAX_CELL_VOLTAGE_MV;
|
||||||
|
datalayer.battery.info.min_cell_voltage_mV = MIN_CELL_VOLTAGE_MV;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -4,7 +4,13 @@
|
||||||
#include "../include.h"
|
#include "../include.h"
|
||||||
|
|
||||||
#define BATTERY_SELECTED
|
#define BATTERY_SELECTED
|
||||||
|
#define MAX_PACK_VOLTAGE_98S_DV 4070 //5000 = 500.0V
|
||||||
|
#define MIN_PACK_VOLTAGE_98S_DV 2800
|
||||||
|
#define MAX_PACK_VOLTAGE_90S_DV 3870
|
||||||
|
#define MIN_PACK_VOLTAGE_90S_DV 2250
|
||||||
#define MAX_CELL_DEVIATION_MV 150
|
#define MAX_CELL_DEVIATION_MV 150
|
||||||
|
#define MAX_CELL_VOLTAGE_MV 4250 //Battery is put into emergency stop if one cell goes over this value
|
||||||
|
#define MIN_CELL_VOLTAGE_MV 2950 //Battery is put into emergency stop if one cell goes below this value
|
||||||
|
|
||||||
void setup_battery(void);
|
void setup_battery(void);
|
||||||
void update_number_of_cells();
|
void update_number_of_cells();
|
||||||
|
|
|
@ -264,9 +264,11 @@ void setup_battery(void) { // Performs one time setup at startup
|
||||||
#ifdef DEBUG_VIA_USB
|
#ifdef DEBUG_VIA_USB
|
||||||
Serial.println("Kia/Hyundai Hybrid battery selected");
|
Serial.println("Kia/Hyundai Hybrid battery selected");
|
||||||
#endif
|
#endif
|
||||||
datalayer.battery.info.number_of_cells = 56; // HEV , TODO: Make dynamic according to HEV/PHEV
|
datalayer.battery.info.number_of_cells = 56; // HEV , TODO: Make dynamic according to HEV/PHEV
|
||||||
datalayer.battery.info.max_design_voltage_dV = 2550; //TODO: Values OK?
|
datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_DV;
|
||||||
datalayer.battery.info.min_design_voltage_dV = 1700;
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -4,7 +4,11 @@
|
||||||
#include "../include.h"
|
#include "../include.h"
|
||||||
|
|
||||||
#define BATTERY_SELECTED
|
#define BATTERY_SELECTED
|
||||||
|
#define MAX_PACK_VOLTAGE_DV 2550 //5000 = 500.0V
|
||||||
|
#define MIN_PACK_VOLTAGE_DV 1700
|
||||||
#define MAX_CELL_DEVIATION_MV 100
|
#define MAX_CELL_DEVIATION_MV 100
|
||||||
|
#define MAX_CELL_VOLTAGE_MV 4250 //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
|
||||||
|
|
||||||
void setup_battery(void);
|
void setup_battery(void);
|
||||||
void transmit_can(CAN_frame* tx_frame, int interface);
|
void transmit_can(CAN_frame* tx_frame, int interface);
|
||||||
|
|
|
@ -141,8 +141,10 @@ void setup_battery(void) { // Performs one time setup at startup
|
||||||
Serial.println("MG 5 battery selected");
|
Serial.println("MG 5 battery selected");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
datalayer.battery.info.max_design_voltage_dV = 4040; // Over this charging is not possible
|
datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_DV;
|
||||||
datalayer.battery.info.min_design_voltage_dV = 3100; // Under this discharging is disabled
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -4,7 +4,11 @@
|
||||||
#include "../include.h"
|
#include "../include.h"
|
||||||
|
|
||||||
#define BATTERY_SELECTED
|
#define BATTERY_SELECTED
|
||||||
|
#define MAX_PACK_VOLTAGE_DV 4040 //5000 = 500.0V
|
||||||
|
#define MIN_PACK_VOLTAGE_DV 3100
|
||||||
#define MAX_CELL_DEVIATION_MV 150
|
#define MAX_CELL_DEVIATION_MV 150
|
||||||
|
#define MAX_CELL_VOLTAGE_MV 4250 //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
|
||||||
|
|
||||||
void setup_battery(void);
|
void setup_battery(void);
|
||||||
void transmit_can(CAN_frame* tx_frame, int interface);
|
void transmit_can(CAN_frame* tx_frame, int interface);
|
||||||
|
|
|
@ -75,9 +75,7 @@ static uint8_t crctable[256] = {
|
||||||
#define ZE1_BATTERY 2
|
#define ZE1_BATTERY 2
|
||||||
static uint8_t LEAF_battery_Type = ZE0_BATTERY;
|
static uint8_t LEAF_battery_Type = ZE0_BATTERY;
|
||||||
static bool battery_can_alive = false;
|
static bool battery_can_alive = false;
|
||||||
#define MAX_CELL_VOLTAGE 4250 //Battery is put into emergency stop if one cell goes over this value
|
#define WH_PER_GID 77 //One GID is this amount of Watt hours
|
||||||
#define MIN_CELL_VOLTAGE 2700 //Battery is put into emergency stop if one cell goes below this value
|
|
||||||
#define WH_PER_GID 77 //One GID is this amount of Watt hours
|
|
||||||
static uint16_t battery_Discharge_Power_Limit = 0; //Limit in kW
|
static uint16_t battery_Discharge_Power_Limit = 0; //Limit in kW
|
||||||
static uint16_t battery_Charge_Power_Limit = 0; //Limit in kW
|
static uint16_t battery_Charge_Power_Limit = 0; //Limit in kW
|
||||||
static int16_t battery_MAX_POWER_FOR_CHARGER = 0; //Limit in kW
|
static int16_t battery_MAX_POWER_FOR_CHARGER = 0; //Limit in kW
|
||||||
|
@ -634,12 +632,6 @@ void receive_can_battery2(CAN_frame rx_frame) {
|
||||||
datalayer.battery2.status.cell_max_voltage_mV = battery2_min_max_voltage[1];
|
datalayer.battery2.status.cell_max_voltage_mV = battery2_min_max_voltage[1];
|
||||||
datalayer.battery2.status.cell_min_voltage_mV = battery2_min_max_voltage[0];
|
datalayer.battery2.status.cell_min_voltage_mV = battery2_min_max_voltage[0];
|
||||||
|
|
||||||
if (battery2_min_max_voltage[1] >= MAX_CELL_VOLTAGE) {
|
|
||||||
set_event(EVENT_CELL_OVER_VOLTAGE, 0);
|
|
||||||
}
|
|
||||||
if (battery2_min_max_voltage[0] <= MIN_CELL_VOLTAGE) {
|
|
||||||
set_event(EVENT_CELL_UNDER_VOLTAGE, 0);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -884,12 +876,6 @@ void receive_can_battery(CAN_frame rx_frame) {
|
||||||
datalayer.battery.status.cell_max_voltage_mV = battery_min_max_voltage[1];
|
datalayer.battery.status.cell_max_voltage_mV = battery_min_max_voltage[1];
|
||||||
datalayer.battery.status.cell_min_voltage_mV = battery_min_max_voltage[0];
|
datalayer.battery.status.cell_min_voltage_mV = battery_min_max_voltage[0];
|
||||||
|
|
||||||
if (battery_min_max_voltage[1] >= MAX_CELL_VOLTAGE) {
|
|
||||||
set_event(EVENT_CELL_OVER_VOLTAGE, 0);
|
|
||||||
}
|
|
||||||
if (battery_min_max_voltage[0] <= MIN_CELL_VOLTAGE) {
|
|
||||||
set_event(EVENT_CELL_UNDER_VOLTAGE, 0);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1221,13 +1207,19 @@ void setup_battery(void) { // Performs one time setup at startup
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
datalayer.battery.info.number_of_cells = 96;
|
datalayer.battery.info.number_of_cells = 96;
|
||||||
datalayer.battery.info.max_design_voltage_dV = 4040; // 404.4V
|
datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_DV;
|
||||||
datalayer.battery.info.min_design_voltage_dV = 2600; // 260.0V
|
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;
|
||||||
|
|
||||||
#ifdef DOUBLE_BATTERY
|
#ifdef DOUBLE_BATTERY
|
||||||
datalayer.battery2.info.number_of_cells = datalayer.battery.info.number_of_cells;
|
datalayer.battery2.info.number_of_cells = datalayer.battery.info.number_of_cells;
|
||||||
datalayer.battery2.info.max_design_voltage_dV = datalayer.battery.info.max_design_voltage_dV;
|
datalayer.battery2.info.max_design_voltage_dV = datalayer.battery.info.max_design_voltage_dV;
|
||||||
datalayer.battery2.info.min_design_voltage_dV = datalayer.battery.info.min_design_voltage_dV;
|
datalayer.battery2.info.min_design_voltage_dV = datalayer.battery.info.min_design_voltage_dV;
|
||||||
|
datalayer.battery2.info.max_cell_voltage_mV = datalayer.battery.info.max_cell_voltage_mV;
|
||||||
|
datalayer.battery2.info.min_cell_voltage_mV = datalayer.battery.info.min_cell_voltage_mV;
|
||||||
|
datalayer.battery2.info.max_cell_voltage_deviation_mV = datalayer.battery.info.max_cell_voltage_deviation_mV;
|
||||||
#endif //DOUBLE_BATTERY
|
#endif //DOUBLE_BATTERY
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,11 @@
|
||||||
#include "../include.h"
|
#include "../include.h"
|
||||||
|
|
||||||
#define BATTERY_SELECTED
|
#define BATTERY_SELECTED
|
||||||
|
#define MAX_PACK_VOLTAGE_DV 4040 //5000 = 500.0V
|
||||||
|
#define MIN_PACK_VOLTAGE_DV 2600
|
||||||
#define MAX_CELL_DEVIATION_MV 500
|
#define MAX_CELL_DEVIATION_MV 500
|
||||||
|
#define MAX_CELL_VOLTAGE_MV 4250 //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
|
||||||
|
|
||||||
uint16_t Temp_fromRAW_to_F(uint16_t temperature);
|
uint16_t Temp_fromRAW_to_F(uint16_t temperature);
|
||||||
bool is_message_corrupt(CAN_frame rx_frame);
|
bool is_message_corrupt(CAN_frame rx_frame);
|
||||||
|
|
|
@ -4,10 +4,6 @@
|
||||||
#include "../devboard/utils/events.h"
|
#include "../devboard/utils/events.h"
|
||||||
#include "PYLON-BATTERY.h"
|
#include "PYLON-BATTERY.h"
|
||||||
|
|
||||||
/* Change the following to suit your battery */
|
|
||||||
#define MAX_PACK_VOLTAGE 5000 //5000 = 500.0V
|
|
||||||
#define MIN_PACK_VOLTAGE 1500
|
|
||||||
|
|
||||||
/* Do not change code below unless you are sure what you are doing */
|
/* Do not change code below unless you are sure what you are doing */
|
||||||
static unsigned long previousMillis1000 = 0; // will store last time a 1s CAN Message was sent
|
static unsigned long previousMillis1000 = 0; // will store last time a 1s CAN Message was sent
|
||||||
|
|
||||||
|
@ -183,8 +179,10 @@ void setup_battery(void) { // Performs one time setup at startup
|
||||||
Serial.println("Pylon battery selected");
|
Serial.println("Pylon battery selected");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE;
|
datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_DV;
|
||||||
datalayer.battery.info.min_design_voltage_dV = MIN_PACK_VOLTAGE;
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -4,7 +4,13 @@
|
||||||
#include "../include.h"
|
#include "../include.h"
|
||||||
|
|
||||||
#define BATTERY_SELECTED
|
#define BATTERY_SELECTED
|
||||||
#define MAX_CELL_DEVIATION_MV 9999
|
|
||||||
|
/* Change the following to suit your battery */
|
||||||
|
#define MAX_PACK_VOLTAGE_DV 5000 //5000 = 500.0V
|
||||||
|
#define MIN_PACK_VOLTAGE_DV 1500
|
||||||
|
#define MAX_CELL_VOLTAGE_MV 4250 //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
|
||||||
|
#define MAX_CELL_DEVIATION_MV 500
|
||||||
|
|
||||||
void setup_battery(void);
|
void setup_battery(void);
|
||||||
void transmit_can(CAN_frame* tx_frame, int interface);
|
void transmit_can(CAN_frame* tx_frame, int interface);
|
||||||
|
|
|
@ -106,13 +106,6 @@ void update_values_battery() { //This function maps all the values fetched via
|
||||||
|
|
||||||
datalayer.battery.status.cell_max_voltage_mV = LB_Cell_Max_Voltage;
|
datalayer.battery.status.cell_max_voltage_mV = LB_Cell_Max_Voltage;
|
||||||
|
|
||||||
if (LB_Cell_Max_Voltage >= ABSOLUTE_CELL_MAX_VOLTAGE) {
|
|
||||||
set_event(EVENT_CELL_OVER_VOLTAGE, (LB_Cell_Max_Voltage / 20));
|
|
||||||
}
|
|
||||||
if (LB_Cell_Min_Voltage <= ABSOLUTE_CELL_MIN_VOLTAGE) {
|
|
||||||
set_event(EVENT_CELL_UNDER_VOLTAGE, (LB_Cell_Min_Voltage / 20));
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef DEBUG_VIA_USB
|
#ifdef DEBUG_VIA_USB
|
||||||
Serial.println("Values going to inverter:");
|
Serial.println("Values going to inverter:");
|
||||||
Serial.print("SOH%: ");
|
Serial.print("SOH%: ");
|
||||||
|
@ -248,9 +241,11 @@ void setup_battery(void) { // Performs one time setup at startup
|
||||||
Serial.println("Renault Kangoo battery selected");
|
Serial.println("Renault Kangoo battery selected");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
datalayer.battery.info.max_design_voltage_dV =
|
datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_DV;
|
||||||
4040; // 404.0V, over this, charging is not possible (goes into forced discharge)
|
datalayer.battery.info.min_design_voltage_dV = MIN_PACK_VOLTAGE_DV;
|
||||||
datalayer.battery.info.min_design_voltage_dV = 3100; // 310.0V under this, discharging further is disabled
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -4,11 +4,12 @@
|
||||||
#include "../include.h"
|
#include "../include.h"
|
||||||
|
|
||||||
#define BATTERY_SELECTED
|
#define BATTERY_SELECTED
|
||||||
|
#define MAX_PACK_VOLTAGE_DV 4150 //5000 = 500.0V
|
||||||
#define ABSOLUTE_CELL_MAX_VOLTAGE 4150 // If cellvoltage goes over this mV, we go into FAULT mode
|
#define MIN_PACK_VOLTAGE_DV 2500
|
||||||
#define ABSOLUTE_CELL_MIN_VOLTAGE 2500 // If cellvoltage goes under this mV, we go into FAULT mode
|
#define MAX_CELL_DEVIATION_MV 500
|
||||||
#define MAX_CELL_DEVIATION_MV 500 // If cell mV delta exceeds this, we go into WARNING mode
|
#define MAX_CELL_VOLTAGE_MV 4250 //Battery is put into emergency stop if one cell goes over this value
|
||||||
#define MAX_CHARGE_POWER_W 5000 // Battery can be charged with this amount of power
|
#define MIN_CELL_VOLTAGE_MV 2700 //Battery is put into emergency stop if one cell goes below this value
|
||||||
|
#define MAX_CHARGE_POWER_W 5000 // Battery can be charged with this amount of power
|
||||||
|
|
||||||
void setup_battery(void);
|
void setup_battery(void);
|
||||||
void transmit_can(CAN_frame* tx_frame, int interface);
|
void transmit_can(CAN_frame* tx_frame, int interface);
|
||||||
|
|
|
@ -148,15 +148,7 @@ void update_values_battery() { //This function maps all the values fetched via
|
||||||
|
|
||||||
datalayer.battery.status.cell_min_voltage_mV = min_cell_mv_value;
|
datalayer.battery.status.cell_min_voltage_mV = min_cell_mv_value;
|
||||||
datalayer.battery.status.cell_max_voltage_mV = max_cell_mv_value;
|
datalayer.battery.status.cell_max_voltage_mV = max_cell_mv_value;
|
||||||
datalayer.battery.status.voltage_dV =
|
datalayer.battery.status.voltage_dV = static_cast<uint32_t>((calculated_total_pack_voltage_mV / 100)); // mV to dV
|
||||||
static_cast<uint32_t>((calculated_total_pack_voltage_mV / 100)); // Convert from mV to dV
|
|
||||||
|
|
||||||
if (datalayer.battery.status.cell_max_voltage_mV >= ABSOLUTE_CELL_MAX_VOLTAGE) {
|
|
||||||
set_event(EVENT_CELL_OVER_VOLTAGE, 0);
|
|
||||||
}
|
|
||||||
if (datalayer.battery.status.cell_min_voltage_mV <= ABSOLUTE_CELL_MIN_VOLTAGE) {
|
|
||||||
set_event(EVENT_CELL_UNDER_VOLTAGE, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef DEBUG_VIA_USB
|
#ifdef DEBUG_VIA_USB
|
||||||
|
|
||||||
|
@ -535,8 +527,11 @@ void setup_battery(void) { // Performs one time setup at startup
|
||||||
#endif
|
#endif
|
||||||
datalayer.system.status.battery_allows_contactor_closing = true;
|
datalayer.system.status.battery_allows_contactor_closing = true;
|
||||||
datalayer.battery.info.number_of_cells = 96;
|
datalayer.battery.info.number_of_cells = 96;
|
||||||
datalayer.battery.info.max_design_voltage_dV = 4040;
|
datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_DV;
|
||||||
datalayer.battery.info.min_design_voltage_dV = 2700;
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -3,10 +3,12 @@
|
||||||
#include "../include.h"
|
#include "../include.h"
|
||||||
|
|
||||||
#define BATTERY_SELECTED
|
#define BATTERY_SELECTED
|
||||||
|
|
||||||
#define ABSOLUTE_CELL_MAX_VOLTAGE 4200
|
|
||||||
#define ABSOLUTE_CELL_MIN_VOLTAGE 3000
|
|
||||||
#define MAX_CELL_DEVIATION_MV 500
|
#define MAX_CELL_DEVIATION_MV 500
|
||||||
|
#define MAX_PACK_VOLTAGE_DV 4200 //5000 = 500.0V
|
||||||
|
#define MIN_PACK_VOLTAGE_DV 3000
|
||||||
|
#define MAX_CELL_DEVIATION_MV 500
|
||||||
|
#define MAX_CELL_VOLTAGE_MV 4250 //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
|
||||||
|
|
||||||
void setup_battery(void);
|
void setup_battery(void);
|
||||||
void transmit_can(CAN_frame* tx_frame, int interface);
|
void transmit_can(CAN_frame* tx_frame, int interface);
|
||||||
|
|
|
@ -59,13 +59,6 @@ void update_values_battery() { //This function maps all the values fetched via
|
||||||
|
|
||||||
datalayer.battery.status.cell_max_voltage_mV;
|
datalayer.battery.status.cell_max_voltage_mV;
|
||||||
|
|
||||||
if (LB_Cell_Max_Voltage >= ABSOLUTE_CELL_MAX_VOLTAGE) {
|
|
||||||
set_event(EVENT_CELL_OVER_VOLTAGE, 0);
|
|
||||||
}
|
|
||||||
if (LB_Cell_Min_Voltage <= ABSOLUTE_CELL_MIN_VOLTAGE) {
|
|
||||||
set_event(EVENT_CELL_UNDER_VOLTAGE, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef DEBUG_VIA_USB
|
#ifdef DEBUG_VIA_USB
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -99,9 +92,13 @@ void setup_battery(void) { // Performs one time setup at startup
|
||||||
#ifdef DEBUG_VIA_USB
|
#ifdef DEBUG_VIA_USB
|
||||||
Serial.println("Renault Zoe 50kWh battery selected");
|
Serial.println("Renault Zoe 50kWh battery selected");
|
||||||
#endif
|
#endif
|
||||||
|
datalayer.system.status.battery_allows_contactor_closing = true;
|
||||||
datalayer.battery.info.max_design_voltage_dV = 4040;
|
datalayer.battery.info.number_of_cells = 96;
|
||||||
datalayer.battery.info.min_design_voltage_dV = 3100;
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -3,10 +3,11 @@
|
||||||
#include "../include.h"
|
#include "../include.h"
|
||||||
|
|
||||||
#define BATTERY_SELECTED
|
#define BATTERY_SELECTED
|
||||||
|
#define MAX_PACK_VOLTAGE_DV 4100 //5000 = 500.0V
|
||||||
#define ABSOLUTE_CELL_MAX_VOLTAGE 4100
|
#define MIN_PACK_VOLTAGE_DV 3000
|
||||||
#define ABSOLUTE_CELL_MIN_VOLTAGE 3000
|
|
||||||
#define MAX_CELL_DEVIATION_MV 500
|
#define MAX_CELL_DEVIATION_MV 500
|
||||||
|
#define MAX_CELL_VOLTAGE_MV 4250 //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
|
||||||
|
|
||||||
void setup_battery(void);
|
void setup_battery(void);
|
||||||
void transmit_can(CAN_frame* tx_frame, int interface);
|
void transmit_can(CAN_frame* tx_frame, int interface);
|
||||||
|
|
|
@ -545,8 +545,10 @@ void setup_battery(void) { // Performs one time setup at startup
|
||||||
Serial.println("RJXZS BMS selected");
|
Serial.println("RJXZS BMS selected");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
datalayer.battery.info.max_design_voltage_dV = 5000;
|
datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_DV;
|
||||||
datalayer.battery.info.min_design_voltage_dV = 1000;
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // RJXZS_BMS
|
#endif // RJXZS_BMS
|
||||||
|
|
|
@ -4,6 +4,10 @@
|
||||||
#include "../include.h"
|
#include "../include.h"
|
||||||
|
|
||||||
/* Tweak these according to your battery build */
|
/* Tweak these according to your battery build */
|
||||||
|
#define MAX_PACK_VOLTAGE_DV 5000 //5000 = 500.0V
|
||||||
|
#define MIN_PACK_VOLTAGE_DV 1500
|
||||||
|
#define MAX_CELL_VOLTAGE_MV 4250 //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
|
||||||
#define MAX_CELL_DEVIATION_MV 250
|
#define MAX_CELL_DEVIATION_MV 250
|
||||||
#define MAX_DISCHARGE_POWER_ALLOWED_W 5000
|
#define MAX_DISCHARGE_POWER_ALLOWED_W 5000
|
||||||
#define MAX_CHARGE_POWER_ALLOWED_W 5000
|
#define MAX_CHARGE_POWER_ALLOWED_W 5000
|
||||||
|
|
|
@ -410,8 +410,10 @@ void setup_battery(void) { // Performs one time setup at startup
|
||||||
Serial.println("Hyundai Santa Fe PHEV battery selected");
|
Serial.println("Hyundai Santa Fe PHEV battery selected");
|
||||||
#endif
|
#endif
|
||||||
datalayer.battery.info.number_of_cells = 96;
|
datalayer.battery.info.number_of_cells = 96;
|
||||||
datalayer.battery.info.max_design_voltage_dV = 4040;
|
datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_DV;
|
||||||
datalayer.battery.info.min_design_voltage_dV = 2880;
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -4,7 +4,11 @@
|
||||||
#include "../include.h"
|
#include "../include.h"
|
||||||
|
|
||||||
#define BATTERY_SELECTED
|
#define BATTERY_SELECTED
|
||||||
|
#define MAX_PACK_VOLTAGE_DV 4040 //5000 = 500.0V
|
||||||
|
#define MIN_PACK_VOLTAGE_DV 2880
|
||||||
#define MAX_CELL_DEVIATION_MV 250
|
#define MAX_CELL_DEVIATION_MV 250
|
||||||
|
#define MAX_CELL_VOLTAGE_MV 4250 //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);
|
uint8_t CalculateCRC8(CAN_frame rx_frame);
|
||||||
void setup_battery(void);
|
void setup_battery(void);
|
||||||
|
|
|
@ -4,9 +4,6 @@
|
||||||
#define SERIAL_LINK_RECEIVER_FROM_BATTERY_H
|
#define SERIAL_LINK_RECEIVER_FROM_BATTERY_H
|
||||||
|
|
||||||
#define BATTERY_SELECTED
|
#define BATTERY_SELECTED
|
||||||
#ifndef MAX_CELL_DEVIATION_MV
|
|
||||||
#define MAX_CELL_DEVIATION_MV 9999
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "../include.h"
|
#include "../include.h"
|
||||||
#include "../lib/mackelec-SerialDataLink/SerialDataLink.h"
|
#include "../lib/mackelec-SerialDataLink/SerialDataLink.h"
|
||||||
|
|
|
@ -253,16 +253,6 @@ static const char* hvilStatusState[] = {"NOT OK",
|
||||||
"UNKNOWN(14)",
|
"UNKNOWN(14)",
|
||||||
"UNKNOWN(15)"};
|
"UNKNOWN(15)"};
|
||||||
|
|
||||||
#define MAX_CELL_VOLTAGE_NCA_NCM 4250 //Battery is put into emergency stop if one cell goes over this value
|
|
||||||
#define MIN_CELL_VOLTAGE_NCA_NCM 2950 //Battery is put into emergency stop if one cell goes below this value
|
|
||||||
#define MAX_CELL_DEVIATION_NCA_NCM 500 //LED turns yellow on the board if mv delta exceeds this value
|
|
||||||
|
|
||||||
#define MAX_CELL_VOLTAGE_LFP 3550 //Battery is put into emergency stop if one cell goes over this value
|
|
||||||
#define MIN_CELL_VOLTAGE_LFP 2800 //Battery is put into emergency stop if one cell goes below this value
|
|
||||||
#define MAX_CELL_DEVIATION_LFP 200 //LED turns yellow on the board if mv delta exceeds this value
|
|
||||||
|
|
||||||
#define REASONABLE_ENERGYAMOUNT 20 //When the BMS stops making sense on some values, they are always <20
|
|
||||||
|
|
||||||
void update_values_battery() { //This function maps all the values fetched via CAN to the correct parameters used for modbus
|
void update_values_battery() { //This function maps all the values fetched via CAN to the correct parameters used for modbus
|
||||||
//After values are mapped, we perform some safety checks, and do some serial printouts
|
//After values are mapped, we perform some safety checks, and do some serial printouts
|
||||||
|
|
||||||
|
@ -316,6 +306,8 @@ void update_values_battery() { //This function maps all the values fetched via
|
||||||
|
|
||||||
datalayer.battery.status.cell_min_voltage_mV = battery_cell_min_v;
|
datalayer.battery.status.cell_min_voltage_mV = battery_cell_min_v;
|
||||||
|
|
||||||
|
battery_cell_deviation_mV = (battery_cell_max_v - battery_cell_min_v);
|
||||||
|
|
||||||
/* Value mapping is completed. Start to check all safeties */
|
/* Value mapping is completed. Start to check all safeties */
|
||||||
|
|
||||||
if (battery_hvil_status ==
|
if (battery_hvil_status ==
|
||||||
|
@ -325,8 +317,6 @@ void update_values_battery() { //This function maps all the values fetched via
|
||||||
clear_event(EVENT_INTERNAL_OPEN_FAULT);
|
clear_event(EVENT_INTERNAL_OPEN_FAULT);
|
||||||
}
|
}
|
||||||
|
|
||||||
battery_cell_deviation_mV = (battery_cell_max_v - battery_cell_min_v);
|
|
||||||
|
|
||||||
#ifdef TESLA_MODEL_3Y_BATTERY
|
#ifdef TESLA_MODEL_3Y_BATTERY
|
||||||
// Autodetect algoritm for chemistry on 3/Y packs.
|
// Autodetect algoritm for chemistry on 3/Y packs.
|
||||||
// NCM/A batteries have 96s, LFP has 102-106s
|
// NCM/A batteries have 96s, LFP has 102-106s
|
||||||
|
@ -339,49 +329,18 @@ void update_values_battery() { //This function maps all the values fetched via
|
||||||
if (datalayer.battery.info.chemistry == battery_chemistry_enum::LFP) {
|
if (datalayer.battery.info.chemistry == battery_chemistry_enum::LFP) {
|
||||||
datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_3Y_LFP;
|
datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_3Y_LFP;
|
||||||
datalayer.battery.info.min_design_voltage_dV = MIN_PACK_VOLTAGE_3Y_LFP;
|
datalayer.battery.info.min_design_voltage_dV = MIN_PACK_VOLTAGE_3Y_LFP;
|
||||||
|
datalayer.battery.info.max_cell_voltage_mV = MAX_CELL_VOLTAGE_LFP;
|
||||||
|
datalayer.battery.info.min_cell_voltage_mV = MIN_CELL_VOLTAGE_LFP;
|
||||||
|
datalayer.battery.info.max_cell_voltage_deviation_mV = MAX_CELL_DEVIATION_LFP;
|
||||||
} else { // NCM/A chemistry
|
} else { // NCM/A chemistry
|
||||||
datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_3Y_NCMA;
|
datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_3Y_NCMA;
|
||||||
datalayer.battery.info.min_design_voltage_dV = MIN_PACK_VOLTAGE_3Y_NCMA;
|
datalayer.battery.info.min_design_voltage_dV = MIN_PACK_VOLTAGE_3Y_NCMA;
|
||||||
|
datalayer.battery.info.max_cell_voltage_mV = MAX_CELL_VOLTAGE_NCA_NCM;
|
||||||
|
datalayer.battery.info.min_cell_voltage_mV = MIN_CELL_VOLTAGE_NCA_NCM;
|
||||||
|
datalayer.battery.info.max_cell_voltage_deviation_mV = MAX_CELL_DEVIATION_NCA_NCM;
|
||||||
}
|
}
|
||||||
#endif // TESLA_MODEL_3Y_BATTERY
|
#endif // TESLA_MODEL_3Y_BATTERY
|
||||||
|
|
||||||
//Check if SOC% is plausible
|
|
||||||
if (datalayer.battery.status.voltage_dV >
|
|
||||||
(datalayer.battery.info.max_design_voltage_dV -
|
|
||||||
20)) { // When pack voltage is close to max, and SOC% is still low, raise FAULT
|
|
||||||
if (datalayer.battery.status.real_soc < 5000) { //When SOC is less than 50.00% when approaching max voltage
|
|
||||||
set_event(EVENT_SOC_PLAUSIBILITY_ERROR, datalayer.battery.status.real_soc / 100);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (datalayer.battery.info.chemistry == battery_chemistry_enum::LFP) { //LFP limits used for voltage safeties
|
|
||||||
if (battery_cell_max_v >= MAX_CELL_VOLTAGE_LFP) {
|
|
||||||
set_event(EVENT_CELL_OVER_VOLTAGE, (battery_cell_max_v - MAX_CELL_VOLTAGE_LFP));
|
|
||||||
}
|
|
||||||
if (battery_cell_min_v <= MIN_CELL_VOLTAGE_LFP) {
|
|
||||||
set_event(EVENT_CELL_UNDER_VOLTAGE, (MIN_CELL_VOLTAGE_LFP - battery_cell_min_v));
|
|
||||||
}
|
|
||||||
if (battery_cell_deviation_mV > MAX_CELL_DEVIATION_LFP) {
|
|
||||||
set_event(EVENT_CELL_DEVIATION_HIGH, battery_cell_deviation_mV);
|
|
||||||
} else {
|
|
||||||
clear_event(EVENT_CELL_DEVIATION_HIGH);
|
|
||||||
}
|
|
||||||
} else { //NCA/NCM limits used
|
|
||||||
if (battery_cell_max_v >= MAX_CELL_VOLTAGE_NCA_NCM) {
|
|
||||||
set_event(EVENT_CELL_OVER_VOLTAGE, (battery_cell_max_v - MAX_CELL_VOLTAGE_NCA_NCM));
|
|
||||||
}
|
|
||||||
if (battery_cell_min_v <= MIN_CELL_VOLTAGE_NCA_NCM) {
|
|
||||||
set_event(EVENT_CELL_UNDER_VOLTAGE, (MIN_CELL_VOLTAGE_NCA_NCM - battery_cell_min_v));
|
|
||||||
}
|
|
||||||
if (battery_cell_deviation_mV > MAX_CELL_DEVIATION_NCA_NCM) {
|
|
||||||
set_event(EVENT_CELL_DEVIATION_HIGH, battery_cell_deviation_mV);
|
|
||||||
} else {
|
|
||||||
clear_event(EVENT_CELL_DEVIATION_HIGH);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Safeties verified. Perform USB serial printout if configured to do so */
|
|
||||||
|
|
||||||
#ifdef DEBUG_VIA_USB
|
#ifdef DEBUG_VIA_USB
|
||||||
|
|
||||||
printFaultCodesIfActive();
|
printFaultCodesIfActive();
|
||||||
|
@ -898,6 +857,8 @@ void update_values_battery2() { //This function maps all the values fetched via
|
||||||
|
|
||||||
datalayer.battery2.status.cell_min_voltage_mV = battery2_cell_min_v;
|
datalayer.battery2.status.cell_min_voltage_mV = battery2_cell_min_v;
|
||||||
|
|
||||||
|
battery2_cell_deviation_mV = (battery2_cell_max_v - battery2_cell_min_v);
|
||||||
|
|
||||||
/* Value mapping is completed. Start to check all safeties */
|
/* Value mapping is completed. Start to check all safeties */
|
||||||
|
|
||||||
if (battery2_hvil_status ==
|
if (battery2_hvil_status ==
|
||||||
|
@ -907,8 +868,6 @@ void update_values_battery2() { //This function maps all the values fetched via
|
||||||
clear_event(EVENT_INTERNAL_OPEN_FAULT);
|
clear_event(EVENT_INTERNAL_OPEN_FAULT);
|
||||||
}
|
}
|
||||||
|
|
||||||
battery2_cell_deviation_mV = (battery2_cell_max_v - battery2_cell_min_v);
|
|
||||||
|
|
||||||
#ifdef TESLA_MODEL_3Y_BATTERY
|
#ifdef TESLA_MODEL_3Y_BATTERY
|
||||||
// Autodetect algoritm for chemistry on 3/Y packs.
|
// Autodetect algoritm for chemistry on 3/Y packs.
|
||||||
// NCM/A batteries have 96s, LFP has 102-106s
|
// NCM/A batteries have 96s, LFP has 102-106s
|
||||||
|
@ -921,57 +880,18 @@ void update_values_battery2() { //This function maps all the values fetched via
|
||||||
if (datalayer.battery2.info.chemistry == battery_chemistry_enum::LFP) {
|
if (datalayer.battery2.info.chemistry == battery_chemistry_enum::LFP) {
|
||||||
datalayer.battery2.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_3Y_LFP;
|
datalayer.battery2.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_3Y_LFP;
|
||||||
datalayer.battery2.info.min_design_voltage_dV = MIN_PACK_VOLTAGE_3Y_LFP;
|
datalayer.battery2.info.min_design_voltage_dV = MIN_PACK_VOLTAGE_3Y_LFP;
|
||||||
|
datalayer.battery2.info.max_cell_voltage_mV = MAX_CELL_VOLTAGE_LFP;
|
||||||
|
datalayer.battery2.info.min_cell_voltage_mV = MIN_CELL_VOLTAGE_LFP;
|
||||||
|
datalayer.battery2.info.max_cell_voltage_deviation_mV = MAX_CELL_DEVIATION_LFP;
|
||||||
} else { // NCM/A chemistry
|
} else { // NCM/A chemistry
|
||||||
datalayer.battery2.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_3Y_NCMA;
|
datalayer.battery2.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_3Y_NCMA;
|
||||||
datalayer.battery2.info.min_design_voltage_dV = MIN_PACK_VOLTAGE_3Y_NCMA;
|
datalayer.battery2.info.min_design_voltage_dV = MIN_PACK_VOLTAGE_3Y_NCMA;
|
||||||
|
datalayer.battery2.info.max_cell_voltage_mV = MAX_CELL_VOLTAGE_NCA_NCM;
|
||||||
|
datalayer.battery2.info.min_cell_voltage_mV = MIN_CELL_VOLTAGE_NCA_NCM;
|
||||||
|
datalayer.battery2.info.max_cell_voltage_deviation_mV = MAX_CELL_DEVIATION_NCA_NCM;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // TESLA_MODEL_3Y_BATTERY
|
#endif // TESLA_MODEL_3Y_BATTERY
|
||||||
|
|
||||||
//Check if SOC% is plausible
|
|
||||||
if (datalayer.battery2.status.voltage_dV >
|
|
||||||
(datalayer.battery2.info.max_design_voltage_dV -
|
|
||||||
20)) { // When pack voltage is close to max, and SOC% is still low, raise FAULT
|
|
||||||
if (datalayer.battery2.status.real_soc < 5000) { //When SOC is less than 50.00% when approaching max voltage
|
|
||||||
set_event(EVENT_SOC_PLAUSIBILITY_ERROR, datalayer.battery2.status.real_soc / 100);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//Check if BMS is in need of recalibration
|
|
||||||
if (battery2_nominal_full_pack_energy > 1 && battery2_nominal_full_pack_energy < REASONABLE_ENERGYAMOUNT) {
|
|
||||||
set_event(EVENT_KWH_PLAUSIBILITY_ERROR, battery2_nominal_full_pack_energy);
|
|
||||||
} else if (battery2_nominal_full_pack_energy <= 1) {
|
|
||||||
set_event(EVENT_KWH_PLAUSIBILITY_ERROR, battery2_nominal_full_pack_energy);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (datalayer.battery2.info.chemistry == battery_chemistry_enum::LFP) { //LFP limits used for voltage safeties
|
|
||||||
if (battery2_cell_max_v >= MAX_CELL_VOLTAGE_LFP) {
|
|
||||||
set_event(EVENT_CELL_OVER_VOLTAGE, (battery2_cell_max_v - MAX_CELL_VOLTAGE_LFP));
|
|
||||||
}
|
|
||||||
if (battery2_cell_min_v <= MIN_CELL_VOLTAGE_LFP) {
|
|
||||||
set_event(EVENT_CELL_UNDER_VOLTAGE, (MIN_CELL_VOLTAGE_LFP - battery2_cell_min_v));
|
|
||||||
}
|
|
||||||
if (battery2_cell_deviation_mV > MAX_CELL_DEVIATION_LFP) {
|
|
||||||
set_event(EVENT_CELL_DEVIATION_HIGH, battery2_cell_deviation_mV);
|
|
||||||
} else {
|
|
||||||
clear_event(EVENT_CELL_DEVIATION_HIGH);
|
|
||||||
}
|
|
||||||
} else { //NCA/NCM limits used
|
|
||||||
if (battery2_cell_max_v >= MAX_CELL_VOLTAGE_NCA_NCM) {
|
|
||||||
set_event(EVENT_CELL_OVER_VOLTAGE, (battery2_cell_max_v - MAX_CELL_VOLTAGE_NCA_NCM));
|
|
||||||
}
|
|
||||||
if (battery2_cell_min_v <= MIN_CELL_VOLTAGE_NCA_NCM) {
|
|
||||||
set_event(EVENT_CELL_UNDER_VOLTAGE, (MIN_CELL_VOLTAGE_NCA_NCM - battery2_cell_min_v));
|
|
||||||
}
|
|
||||||
if (battery2_cell_deviation_mV > MAX_CELL_DEVIATION_NCA_NCM) {
|
|
||||||
set_event(EVENT_CELL_DEVIATION_HIGH, battery2_cell_deviation_mV);
|
|
||||||
} else {
|
|
||||||
clear_event(EVENT_CELL_DEVIATION_HIGH);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Safeties verified. Perform USB serial printout if configured to do so */
|
|
||||||
|
|
||||||
#ifdef DEBUG_VIA_USB
|
#ifdef DEBUG_VIA_USB
|
||||||
|
|
||||||
printFaultCodesIfActive_battery2();
|
printFaultCodesIfActive_battery2();
|
||||||
|
@ -1254,9 +1174,15 @@ void setup_battery(void) { // Performs one time setup at startup
|
||||||
#ifdef TESLA_MODEL_SX_BATTERY // Always use NCM/A mode on S/X packs
|
#ifdef TESLA_MODEL_SX_BATTERY // Always use NCM/A mode on S/X packs
|
||||||
datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_SX_NCMA;
|
datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_SX_NCMA;
|
||||||
datalayer.battery.info.min_design_voltage_dV = MIN_PACK_VOLTAGE_SX_NCMA;
|
datalayer.battery.info.min_design_voltage_dV = MIN_PACK_VOLTAGE_SX_NCMA;
|
||||||
|
datalayer.battery.info.max_cell_voltage_mV = MAX_CELL_VOLTAGE_NCA_NCM;
|
||||||
|
datalayer.battery.info.min_cell_voltage_mV = MIN_CELL_VOLTAGE_NCA_NCM;
|
||||||
|
datalayer.battery.info.max_cell_voltage_deviation_mV = MAX_CELL_DEVIATION_NCA_NCM;
|
||||||
#ifdef DOUBLE_BATTERY
|
#ifdef DOUBLE_BATTERY
|
||||||
datalayer.battery2.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_SX_NCMA;
|
datalayer.battery2.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_SX_NCMA;
|
||||||
datalayer.battery2.info.min_design_voltage_dV = MIN_PACK_VOLTAGE_SX_NCMA;
|
datalayer.battery2.info.min_design_voltage_dV = MIN_PACK_VOLTAGE_SX_NCMA;
|
||||||
|
datalayer.battery2.info.max_cell_voltage_mV = MAX_CELL_VOLTAGE_NCA_NCM;
|
||||||
|
datalayer.battery2.info.min_cell_voltage_mV = MIN_CELL_VOLTAGE_NCA_NCM;
|
||||||
|
datalayer.battery2.info.max_cell_voltage_deviation_mV = MAX_CELL_DEVIATION_NCA_NCM;
|
||||||
#endif // DOUBLE_BATTERY
|
#endif // DOUBLE_BATTERY
|
||||||
#endif // TESLA_MODEL_SX_BATTERY
|
#endif // TESLA_MODEL_SX_BATTERY
|
||||||
|
|
||||||
|
@ -1265,17 +1191,29 @@ void setup_battery(void) { // Performs one time setup at startup
|
||||||
datalayer.battery.info.chemistry = battery_chemistry_enum::LFP;
|
datalayer.battery.info.chemistry = battery_chemistry_enum::LFP;
|
||||||
datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_3Y_LFP;
|
datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_3Y_LFP;
|
||||||
datalayer.battery.info.min_design_voltage_dV = MIN_PACK_VOLTAGE_3Y_LFP;
|
datalayer.battery.info.min_design_voltage_dV = MIN_PACK_VOLTAGE_3Y_LFP;
|
||||||
|
datalayer.battery.info.max_cell_voltage_mV = MAX_CELL_VOLTAGE_LFP;
|
||||||
|
datalayer.battery.info.min_cell_voltage_mV = MIN_CELL_VOLTAGE_LFP;
|
||||||
|
datalayer.battery.info.max_cell_voltage_deviation_mV = MAX_CELL_DEVIATION_LFP;
|
||||||
#ifdef DOUBLE_BATTERY
|
#ifdef DOUBLE_BATTERY
|
||||||
datalayer.battery2.info.chemistry = battery_chemistry_enum::LFP;
|
datalayer.battery2.info.chemistry = battery_chemistry_enum::LFP;
|
||||||
datalayer.battery2.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_3Y_LFP;
|
datalayer.battery2.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_3Y_LFP;
|
||||||
datalayer.battery2.info.min_design_voltage_dV = MIN_PACK_VOLTAGE_3Y_LFP;
|
datalayer.battery2.info.min_design_voltage_dV = MIN_PACK_VOLTAGE_3Y_LFP;
|
||||||
|
datalayer.battery2.info.max_cell_voltage_mV = MAX_CELL_VOLTAGE_LFP;
|
||||||
|
datalayer.battery2.info.min_cell_voltage_mV = MIN_CELL_VOLTAGE_LFP;
|
||||||
|
datalayer.battery2.info.max_cell_voltage_deviation_mV = MAX_CELL_DEVIATION_LFP;
|
||||||
#endif // DOUBLE_BATTERY
|
#endif // DOUBLE_BATTERY
|
||||||
#else // Startup in NCM/A mode
|
#else // Startup in NCM/A mode
|
||||||
datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_3Y_NCMA;
|
datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_3Y_NCMA;
|
||||||
datalayer.battery.info.min_design_voltage_dV = MIN_PACK_VOLTAGE_3Y_NCMA;
|
datalayer.battery.info.min_design_voltage_dV = MIN_PACK_VOLTAGE_3Y_NCMA;
|
||||||
|
datalayer.battery.info.max_cell_voltage_mV = MAX_CELL_VOLTAGE_NCA_NCM;
|
||||||
|
datalayer.battery.info.min_cell_voltage_mV = MIN_CELL_VOLTAGE_NCA_NCM;
|
||||||
|
datalayer.battery.info.max_cell_voltage_deviation_mV = MAX_CELL_DEVIATION_NCA_NCM;
|
||||||
#ifdef DOUBLE_BATTERY
|
#ifdef DOUBLE_BATTERY
|
||||||
datalayer.battery2.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_3Y_NCMA;
|
datalayer.battery2.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_3Y_NCMA;
|
||||||
datalayer.battery2.info.min_design_voltage_dV = MIN_PACK_VOLTAGE_3Y_NCMA;
|
datalayer.battery2.info.min_design_voltage_dV = MIN_PACK_VOLTAGE_3Y_NCMA;
|
||||||
|
datalayer.battery2.info.max_cell_voltage_mV = MAX_CELL_VOLTAGE_NCA_NCM;
|
||||||
|
datalayer.battery2.info.min_cell_voltage_mV = MIN_CELL_VOLTAGE_NCA_NCM;
|
||||||
|
datalayer.battery2.info.max_cell_voltage_deviation_mV = MAX_CELL_DEVIATION_NCA_NCM;
|
||||||
#endif // DOUBLE_BATTERY
|
#endif // DOUBLE_BATTERY
|
||||||
#endif // !LFP_CHEMISTRY
|
#endif // !LFP_CHEMISTRY
|
||||||
#endif // TESLA_MODEL_3Y_BATTERY
|
#endif // TESLA_MODEL_3Y_BATTERY
|
||||||
|
|
|
@ -15,13 +15,18 @@
|
||||||
#define FLOAT_MAX_POWER_W 200 // W, what power to allow for top balancing battery
|
#define FLOAT_MAX_POWER_W 200 // W, what power to allow for top balancing battery
|
||||||
#define FLOAT_START_MV 20 // mV, how many mV under overvoltage to start float charging
|
#define FLOAT_START_MV 20 // mV, how many mV under overvoltage to start float charging
|
||||||
|
|
||||||
#define MAX_PACK_VOLTAGE_SX_NCMA 4600 // V+1, if pack voltage goes over this, charge stops
|
#define MAX_PACK_VOLTAGE_SX_NCMA 4600 // V+1, if pack voltage goes over this, charge stops
|
||||||
#define MIN_PACK_VOLTAGE_SX_NCMA 3100 // V+1, if pack voltage goes over this, charge stops
|
#define MIN_PACK_VOLTAGE_SX_NCMA 3100 // V+1, if pack voltage goes over this, charge stops
|
||||||
#define MAX_PACK_VOLTAGE_3Y_NCMA 4030 // V+1, if pack voltage goes over this, charge stops
|
#define MAX_PACK_VOLTAGE_3Y_NCMA 4030 // V+1, if pack voltage goes over this, charge stops
|
||||||
#define MIN_PACK_VOLTAGE_3Y_NCMA 3100 // V+1, if pack voltage goes below this, discharge stops
|
#define MIN_PACK_VOLTAGE_3Y_NCMA 3100 // V+1, if pack voltage goes below this, discharge stops
|
||||||
#define MAX_PACK_VOLTAGE_3Y_LFP 3880 // V+1, if pack voltage goes over this, charge stops
|
#define MAX_PACK_VOLTAGE_3Y_LFP 3880 // V+1, if pack voltage goes over this, charge stops
|
||||||
#define MIN_PACK_VOLTAGE_3Y_LFP 2968 // V+1, if pack voltage goes below this, discharge stops
|
#define MIN_PACK_VOLTAGE_3Y_LFP 2968 // V+1, if pack voltage goes below this, discharge stops
|
||||||
#define MAX_CELL_DEVIATION_MV 9999 // Handled inside the Tesla.cpp file, just for compilation
|
#define MAX_CELL_DEVIATION_NCA_NCM 500 //LED turns yellow on the board if mv delta exceeds this value
|
||||||
|
#define MAX_CELL_DEVIATION_LFP 200 //LED turns yellow on the board if mv delta exceeds this value
|
||||||
|
#define MAX_CELL_VOLTAGE_NCA_NCM 4250 //Battery is put into emergency stop if one cell goes over this value
|
||||||
|
#define MIN_CELL_VOLTAGE_NCA_NCM 2950 //Battery is put into emergency stop if one cell goes below this value
|
||||||
|
#define MAX_CELL_VOLTAGE_LFP 3550 //Battery is put into emergency stop if one cell goes over this value
|
||||||
|
#define MIN_CELL_VOLTAGE_LFP 2800 //Battery is put into emergency stop if one cell goes below this value
|
||||||
|
|
||||||
void printFaultCodesIfActive();
|
void printFaultCodesIfActive();
|
||||||
void printDebugIfActive(uint8_t symbol, const char* message);
|
void printDebugIfActive(uint8_t symbol, const char* message);
|
||||||
|
|
|
@ -8,9 +8,6 @@
|
||||||
static unsigned long previousMillis100 = 0; // will store last time a 100ms CAN Message was send
|
static unsigned long previousMillis100 = 0; // will store last time a 100ms CAN Message was send
|
||||||
static unsigned long previousMillis60s = 0; // will store last time a 60s CAN Message was send
|
static unsigned long previousMillis60s = 0; // will store last time a 60s CAN Message was send
|
||||||
|
|
||||||
#define MAX_CELL_VOLTAGE 4210 //Battery is put into emergency stop if one cell goes over this value
|
|
||||||
#define MIN_CELL_VOLTAGE 2700 //Battery is put into emergency stop if one cell goes below this value
|
|
||||||
|
|
||||||
static float BATT_U = 0; //0x3A
|
static float BATT_U = 0; //0x3A
|
||||||
static float MAX_U = 0; //0x3A
|
static float MAX_U = 0; //0x3A
|
||||||
static float MIN_U = 0; //0x3A
|
static float MIN_U = 0; //0x3A
|
||||||
|
@ -22,8 +19,8 @@ static float BATT_T_MIN = 0; //0x413
|
||||||
static float BATT_T_AVG = 0; //0x413
|
static float BATT_T_AVG = 0; //0x413
|
||||||
static uint16_t SOC_BMS = 0; //0X37D
|
static uint16_t SOC_BMS = 0; //0X37D
|
||||||
static uint16_t SOC_CALC = 0;
|
static uint16_t SOC_CALC = 0;
|
||||||
static uint16_t CELL_U_MAX = 0; //0x37D
|
static uint16_t CELL_U_MAX = 3700; //0x37D
|
||||||
static uint16_t CELL_U_MIN = 0; //0x37D
|
static uint16_t CELL_U_MIN = 3700; //0x37D
|
||||||
static uint8_t CELL_ID_U_MAX = 0; //0x37D
|
static uint8_t CELL_ID_U_MAX = 0; //0x37D
|
||||||
static uint16_t HvBattPwrLimDchaSoft = 0; //0x369
|
static uint16_t HvBattPwrLimDchaSoft = 0; //0x369
|
||||||
static uint8_t batteryModuleNumber = 0x10; // First battery module
|
static uint8_t batteryModuleNumber = 0x10; // First battery module
|
||||||
|
@ -288,12 +285,6 @@ void receive_can_battery(CAN_frame rx_frame) {
|
||||||
min_max_voltage[1] = cell_voltages[cellcounter];
|
min_max_voltage[1] = cell_voltages[cellcounter];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (min_max_voltage[1] >= MAX_CELL_VOLTAGE) {
|
|
||||||
set_event(EVENT_CELL_OVER_VOLTAGE, 0);
|
|
||||||
}
|
|
||||||
if (min_max_voltage[0] <= MIN_CELL_VOLTAGE) {
|
|
||||||
set_event(EVENT_CELL_UNDER_VOLTAGE, 0);
|
|
||||||
}
|
|
||||||
transmit_can(&VOLVO_SOH_Req, can_config.battery); //Send SOH read request
|
transmit_can(&VOLVO_SOH_Req, can_config.battery); //Send SOH read request
|
||||||
}
|
}
|
||||||
rxConsecutiveFrames = 0;
|
rxConsecutiveFrames = 0;
|
||||||
|
@ -347,8 +338,10 @@ void setup_battery(void) { // Performs one time setup at startup
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
datalayer.battery.info.number_of_cells = 108;
|
datalayer.battery.info.number_of_cells = 108;
|
||||||
datalayer.battery.info.max_design_voltage_dV =
|
datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_DV;
|
||||||
4540; // 454.0V, over this, charging is not possible (goes into forced discharge)
|
datalayer.battery.info.min_design_voltage_dV = MIN_PACK_VOLTAGE_DV;
|
||||||
datalayer.battery.info.min_design_voltage_dV = 2938; // 293.8V under this, discharging further is disabled
|
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;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -4,7 +4,11 @@
|
||||||
#include "../include.h"
|
#include "../include.h"
|
||||||
|
|
||||||
#define BATTERY_SELECTED
|
#define BATTERY_SELECTED
|
||||||
|
#define MAX_PACK_VOLTAGE_DV 4540 //5000 = 500.0V
|
||||||
|
#define MIN_PACK_VOLTAGE_DV 2938
|
||||||
#define MAX_CELL_DEVIATION_MV 250
|
#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
|
||||||
|
|
||||||
void setup_battery(void);
|
void setup_battery(void);
|
||||||
void transmit_can(CAN_frame* tx_frame, int interface);
|
void transmit_can(CAN_frame* tx_frame, int interface);
|
||||||
|
|
|
@ -13,6 +13,12 @@ typedef struct {
|
||||||
uint16_t max_design_voltage_dV = 5000;
|
uint16_t max_design_voltage_dV = 5000;
|
||||||
/** The minimum intended packvoltage, in deciVolt. 3300 = 330.0 V */
|
/** The minimum intended packvoltage, in deciVolt. 3300 = 330.0 V */
|
||||||
uint16_t min_design_voltage_dV = 2500;
|
uint16_t min_design_voltage_dV = 2500;
|
||||||
|
/** The maximum cellvoltage before shutting down, in milliVolt. 4300 = 4.250 V */
|
||||||
|
uint16_t max_cell_voltage_mV = 4300;
|
||||||
|
/** The minimum cellvoltage before shutting down, in milliVolt. 2700 = 2.700 V */
|
||||||
|
uint16_t min_cell_voltage_mV = 2700;
|
||||||
|
/** The maxumum allowed deviation between cells, in milliVolt. 500 = 0.500 V */
|
||||||
|
uint16_t max_cell_voltage_deviation_mV = 500;
|
||||||
/** BYD CAN specific setting, max charge in deciAmpere. 300 = 30.0 A */
|
/** BYD CAN specific setting, max charge in deciAmpere. 300 = 30.0 A */
|
||||||
uint16_t max_charge_amp_dA = BATTERY_MAX_CHARGE_AMP;
|
uint16_t max_charge_amp_dA = BATTERY_MAX_CHARGE_AMP;
|
||||||
/** BYD CAN specific setting, max discharge in deciAmpere. 300 = 30.0 A */
|
/** BYD CAN specific setting, max discharge in deciAmpere. 300 = 30.0 A */
|
||||||
|
@ -172,6 +178,7 @@ typedef struct {
|
||||||
} DATALAYER_SYSTEM_STATUS_TYPE;
|
} DATALAYER_SYSTEM_STATUS_TYPE;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
bool equipment_stop_active = false;
|
||||||
} DATALAYER_SYSTEM_SETTINGS_TYPE;
|
} DATALAYER_SYSTEM_SETTINGS_TYPE;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
|
|
@ -65,6 +65,9 @@
|
||||||
#define LED_PIN 4
|
#define LED_PIN 4
|
||||||
#define LED_MAX_BRIGHTNESS 40
|
#define LED_MAX_BRIGHTNESS 40
|
||||||
|
|
||||||
|
// Equipment stop pin
|
||||||
|
#define EQUIPMENT_STOP_PIN 35
|
||||||
|
|
||||||
/* ----- Error checks below, don't change (can't be moved to separate file) ----- */
|
/* ----- Error checks below, don't change (can't be moved to separate file) ----- */
|
||||||
#ifndef HW_CONFIGURED
|
#ifndef HW_CONFIGURED
|
||||||
#define HW_CONFIGURED
|
#define HW_CONFIGURED
|
||||||
|
@ -78,6 +81,18 @@
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef EQUIPMENT_STOP_BUTTON
|
||||||
|
#ifdef DUAL_CAN
|
||||||
|
#error EQUIPMENT_STOP_BUTTON and DUAL_CAN cannot coexist due to overlapping GPIO pin usage
|
||||||
|
#endif
|
||||||
|
#ifdef CAN_FD
|
||||||
|
#error EQUIPMENT_STOP_BUTTON and CAN_FD cannot coexist due to overlapping GPIO pin usage
|
||||||
|
#endif
|
||||||
|
#ifdef CHADEMO_BATTERY
|
||||||
|
#error EQUIPMENT_STOP_BUTTON and CHADEMO_BATTERY cannot coexist due to overlapping GPIO pin usage
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef BMW_I3_BATTERY
|
#ifdef BMW_I3_BATTERY
|
||||||
#ifdef CONTACTOR_CONTROL
|
#ifdef CONTACTOR_CONTROL
|
||||||
#error GPIO PIN 25 cannot be used for both BMWi3 Wakeup and contactor control. Disable CONTACTOR_CONTROL
|
#error GPIO PIN 25 cannot be used for both BMWi3 Wakeup and contactor control. Disable CONTACTOR_CONTROL
|
||||||
|
|
|
@ -58,6 +58,9 @@ GPIOs on extra header
|
||||||
#define LED_PIN 4
|
#define LED_PIN 4
|
||||||
#define LED_MAX_BRIGHTNESS 40
|
#define LED_MAX_BRIGHTNESS 40
|
||||||
|
|
||||||
|
// Equipment stop pin
|
||||||
|
#define EQUIPMENT_STOP_PIN 2
|
||||||
|
|
||||||
/* ----- Error checks below, don't change (can't be moved to separate file) ----- */
|
/* ----- Error checks below, don't change (can't be moved to separate file) ----- */
|
||||||
#ifndef HW_CONFIGURED
|
#ifndef HW_CONFIGURED
|
||||||
#define HW_CONFIGURED
|
#define HW_CONFIGURED
|
||||||
|
|
|
@ -54,6 +54,15 @@ void update_machineryprotection() {
|
||||||
clear_event(EVENT_BATTERY_UNDERVOLTAGE);
|
clear_event(EVENT_BATTERY_UNDERVOLTAGE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Cell overvoltage, critical latching error without automatic reset. Requires user action.
|
||||||
|
if (datalayer.battery.status.cell_max_voltage_mV >= datalayer.battery.info.max_cell_voltage_mV) {
|
||||||
|
set_event(EVENT_CELL_OVER_VOLTAGE, 0);
|
||||||
|
}
|
||||||
|
// Cell undervoltage, critical latching error without automatic reset. Requires user action.
|
||||||
|
if (datalayer.battery.status.cell_min_voltage_mV <= datalayer.battery.info.min_cell_voltage_mV) {
|
||||||
|
set_event(EVENT_CELL_UNDER_VOLTAGE, 0);
|
||||||
|
}
|
||||||
|
|
||||||
// Battery is fully charged. Dont allow any more power into it
|
// Battery is fully charged. Dont allow any more power into it
|
||||||
// Normally the BMS will send 0W allowed, but this acts as an additional layer of safety
|
// Normally the BMS will send 0W allowed, but this acts as an additional layer of safety
|
||||||
if (datalayer.battery.status.reported_soc == 10000) //Scaled SOC% value is 100.00%
|
if (datalayer.battery.status.reported_soc == 10000) //Scaled SOC% value is 100.00%
|
||||||
|
@ -103,7 +112,7 @@ void update_machineryprotection() {
|
||||||
|
|
||||||
// Check diff between highest and lowest cell
|
// Check diff between highest and lowest cell
|
||||||
cell_deviation_mV = (datalayer.battery.status.cell_max_voltage_mV - datalayer.battery.status.cell_min_voltage_mV);
|
cell_deviation_mV = (datalayer.battery.status.cell_max_voltage_mV - datalayer.battery.status.cell_min_voltage_mV);
|
||||||
if (cell_deviation_mV > MAX_CELL_DEVIATION_MV) {
|
if (cell_deviation_mV > datalayer.battery.info.max_cell_voltage_deviation_mV) {
|
||||||
set_event(EVENT_CELL_DEVIATION_HIGH, (cell_deviation_mV / 20));
|
set_event(EVENT_CELL_DEVIATION_HIGH, (cell_deviation_mV / 20));
|
||||||
} else {
|
} else {
|
||||||
clear_event(EVENT_CELL_DEVIATION_HIGH);
|
clear_event(EVENT_CELL_DEVIATION_HIGH);
|
||||||
|
@ -175,6 +184,23 @@ void update_machineryprotection() {
|
||||||
clear_event(EVENT_CAN_RX_WARNING);
|
clear_event(EVENT_CAN_RX_WARNING);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Cell overvoltage, critical latching error without automatic reset. Requires user action.
|
||||||
|
if (datalayer.battery2.status.cell_max_voltage_mV >= datalayer.battery2.info.max_cell_voltage_mV) {
|
||||||
|
set_event(EVENT_CELL_OVER_VOLTAGE, 0);
|
||||||
|
}
|
||||||
|
// Cell undervoltage, critical latching error without automatic reset. Requires user action.
|
||||||
|
if (datalayer.battery2.status.cell_min_voltage_mV <= datalayer.battery2.info.min_cell_voltage_mV) {
|
||||||
|
set_event(EVENT_CELL_UNDER_VOLTAGE, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check diff between highest and lowest cell
|
||||||
|
cell_deviation_mV = (datalayer.battery2.status.cell_max_voltage_mV - datalayer.battery2.status.cell_min_voltage_mV);
|
||||||
|
if (cell_deviation_mV > datalayer.battery2.info.max_cell_voltage_deviation_mV) {
|
||||||
|
set_event(EVENT_CELL_DEVIATION_HIGH, (cell_deviation_mV / 20));
|
||||||
|
} else {
|
||||||
|
clear_event(EVENT_CELL_DEVIATION_HIGH);
|
||||||
|
}
|
||||||
|
|
||||||
// Check if SOH% between the packs is too large
|
// Check if SOH% between the packs is too large
|
||||||
if ((datalayer.battery.status.soh_pptt != 9900) && (datalayer.battery2.status.soh_pptt != 9900)) {
|
if ((datalayer.battery.status.soh_pptt != 9900) && (datalayer.battery2.status.soh_pptt != 9900)) {
|
||||||
// Both values available, check diff
|
// Both values available, check diff
|
||||||
|
@ -196,7 +222,23 @@ void update_machineryprotection() {
|
||||||
}
|
}
|
||||||
|
|
||||||
//battery pause status begin
|
//battery pause status begin
|
||||||
void setBatteryPause(bool pause_battery, bool pause_CAN) {
|
void setBatteryPause(bool pause_battery, bool pause_CAN, bool equipment_stop, bool store_settings) {
|
||||||
|
|
||||||
|
// First handle equipment stop / resume
|
||||||
|
if (equipment_stop && !datalayer.system.settings.equipment_stop_active) {
|
||||||
|
datalayer.system.settings.equipment_stop_active = true;
|
||||||
|
if (store_settings) {
|
||||||
|
store_settings_equipment_stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
set_event(EVENT_EQUIPMENT_STOP, 1);
|
||||||
|
} else if (!equipment_stop && datalayer.system.settings.equipment_stop_active) {
|
||||||
|
datalayer.system.settings.equipment_stop_active = false;
|
||||||
|
if (store_settings) {
|
||||||
|
store_settings_equipment_stop();
|
||||||
|
}
|
||||||
|
clear_event(EVENT_EQUIPMENT_STOP);
|
||||||
|
}
|
||||||
|
|
||||||
emulator_pause_CAN_send_ON = pause_CAN;
|
emulator_pause_CAN_send_ON = pause_CAN;
|
||||||
|
|
||||||
|
@ -228,6 +270,7 @@ void setBatteryPause(bool pause_battery, bool pause_CAN) {
|
||||||
/// @brief handle emulator pause status
|
/// @brief handle emulator pause status
|
||||||
/// @return true if CAN messages should be sent to battery, false if not
|
/// @return true if CAN messages should be sent to battery, false if not
|
||||||
void emulator_pause_state_send_CAN_battery() {
|
void emulator_pause_state_send_CAN_battery() {
|
||||||
|
bool previous_allowed_to_send_CAN = allowed_to_send_CAN;
|
||||||
|
|
||||||
if (emulator_pause_status == NORMAL) {
|
if (emulator_pause_status == NORMAL) {
|
||||||
allowed_to_send_CAN = true;
|
allowed_to_send_CAN = true;
|
||||||
|
@ -245,6 +288,14 @@ void emulator_pause_state_send_CAN_battery() {
|
||||||
}
|
}
|
||||||
|
|
||||||
allowed_to_send_CAN = (!emulator_pause_CAN_send_ON || emulator_pause_status == NORMAL);
|
allowed_to_send_CAN = (!emulator_pause_CAN_send_ON || emulator_pause_status == NORMAL);
|
||||||
|
|
||||||
|
if (previous_allowed_to_send_CAN && !allowed_to_send_CAN) {
|
||||||
|
//completely force stop the CAN communication
|
||||||
|
ESP32Can.CANStop();
|
||||||
|
} else if (!previous_allowed_to_send_CAN && allowed_to_send_CAN) {
|
||||||
|
//resume CAN communication
|
||||||
|
ESP32Can.CANInit();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string get_emulator_pause_status() {
|
std::string get_emulator_pause_status() {
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
#define SAFETY_H
|
#define SAFETY_H
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include "../../lib/miwagner-ESP32-Arduino-CAN/ESP32CAN.h"
|
||||||
|
|
||||||
#define MAX_CAN_FAILURES 50
|
#define MAX_CAN_FAILURES 50
|
||||||
|
|
||||||
|
@ -15,10 +16,12 @@ extern battery_pause_status emulator_pause_status;
|
||||||
extern bool allowed_to_send_CAN;
|
extern bool allowed_to_send_CAN;
|
||||||
//battery pause status end
|
//battery pause status end
|
||||||
|
|
||||||
|
extern void store_settings_equipment_stop();
|
||||||
|
|
||||||
void update_machineryprotection();
|
void update_machineryprotection();
|
||||||
|
|
||||||
//battery pause status begin
|
//battery pause status begin
|
||||||
void setBatteryPause(bool pause_battery, bool pause_CAN);
|
void setBatteryPause(bool pause_battery, bool pause_CAN, bool equipment_stop = false, bool store_settings = true);
|
||||||
void emulator_pause_state_send_CAN_battery();
|
void emulator_pause_state_send_CAN_battery();
|
||||||
std::string get_emulator_pause_status();
|
std::string get_emulator_pause_status();
|
||||||
//battery pause status end
|
//battery pause status end
|
||||||
|
|
56
Software/src/devboard/utils/debounce_button.cpp
Normal file
56
Software/src/devboard/utils/debounce_button.cpp
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
#include "debounce_button.h"
|
||||||
|
|
||||||
|
// Function to initialize the debounced button with pin, switch type, and debounce delay
|
||||||
|
void initDebouncedButton(DebouncedButton& button, int pin, SwitchType type, unsigned long debounceDelay) {
|
||||||
|
button.pin = pin;
|
||||||
|
button.debounceDelay = debounceDelay;
|
||||||
|
button.lastDebounceTime = 0;
|
||||||
|
button.lastButtonState = (type == NC) ? HIGH : LOW; // NC starts HIGH, NO starts LOW
|
||||||
|
button.buttonState = button.lastButtonState;
|
||||||
|
button.switchType = type;
|
||||||
|
pinMode(pin, INPUT); // Setup pin mode
|
||||||
|
}
|
||||||
|
|
||||||
|
ButtonState debounceButton(DebouncedButton& button, unsigned long& timeSincePress) {
|
||||||
|
int reading = digitalRead(button.pin);
|
||||||
|
|
||||||
|
// If the button state has changed due to noise or a press
|
||||||
|
if (reading != button.lastButtonState) {
|
||||||
|
// Reset debounce timer
|
||||||
|
button.lastDebounceTime = millis();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the state change is stable for the debounce delay
|
||||||
|
if ((millis() - button.lastDebounceTime) > button.debounceDelay) {
|
||||||
|
if (reading != button.buttonState) {
|
||||||
|
button.buttonState = reading;
|
||||||
|
|
||||||
|
// Adjust button logic based on switch type (NC or NO)
|
||||||
|
if (button.switchType == NC) {
|
||||||
|
if (button.buttonState == LOW) {
|
||||||
|
// Button pressed for NC, record the press time
|
||||||
|
button.ulPressTime = millis();
|
||||||
|
return PRESSED;
|
||||||
|
} else {
|
||||||
|
// Button released for NC, calculate the time since last press
|
||||||
|
timeSincePress = millis() - button.ulPressTime;
|
||||||
|
return RELEASED;
|
||||||
|
}
|
||||||
|
} else { // NO type
|
||||||
|
if (button.buttonState == HIGH) {
|
||||||
|
// Button pressed for NO, record the press time
|
||||||
|
button.ulPressTime = millis();
|
||||||
|
return PRESSED;
|
||||||
|
} else {
|
||||||
|
// Button released for NO, calculate the time since last press
|
||||||
|
timeSincePress = millis() - button.ulPressTime;
|
||||||
|
return RELEASED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remember the last button state
|
||||||
|
button.lastButtonState = reading;
|
||||||
|
return NONE; // No change in button state
|
||||||
|
}
|
36
Software/src/devboard/utils/debounce_button.h
Normal file
36
Software/src/devboard/utils/debounce_button.h
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
#ifndef DEBOUNCE_H
|
||||||
|
#define DEBOUNCE_H
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
|
||||||
|
// Enum to define switch type (Normally Closed - NC, Normally Open - NO)
|
||||||
|
enum SwitchType {
|
||||||
|
NC, // Normally Closed
|
||||||
|
NO // Normally Open
|
||||||
|
};
|
||||||
|
|
||||||
|
// Enum to define button state
|
||||||
|
enum ButtonState {
|
||||||
|
NONE, // No change in button state
|
||||||
|
PRESSED, // Button is pressed down
|
||||||
|
RELEASED // Button is released
|
||||||
|
};
|
||||||
|
|
||||||
|
// Struct to hold button state and debounce parameters
|
||||||
|
struct DebouncedButton {
|
||||||
|
int pin; // GPIO pin number
|
||||||
|
unsigned long lastDebounceTime; // Time of last state change
|
||||||
|
unsigned long debounceDelay; // Debounce delay time
|
||||||
|
unsigned long ulPressTime; // Time when the button was last pressed
|
||||||
|
bool lastButtonState; // Previous button state
|
||||||
|
bool buttonState; // Current button state
|
||||||
|
SwitchType switchType; // Switch type (NC or NO)
|
||||||
|
};
|
||||||
|
|
||||||
|
// Function to initialize the debounced button
|
||||||
|
void initDebouncedButton(DebouncedButton& button, int pin, SwitchType type, unsigned long debounceDelay = 50);
|
||||||
|
|
||||||
|
// Function to debounce button and return the button state (PRESSED, RELEASED, or NONE)
|
||||||
|
ButtonState debounceButton(DebouncedButton& button, unsigned long& timeSincePress);
|
||||||
|
|
||||||
|
#endif // DEBOUNCE_H
|
|
@ -149,7 +149,7 @@ void init_events(void) {
|
||||||
events.entries[EVENT_CANFD_RX_FAILURE].level = EVENT_LEVEL_ERROR;
|
events.entries[EVENT_CANFD_RX_FAILURE].level = EVENT_LEVEL_ERROR;
|
||||||
events.entries[EVENT_CAN_RX_WARNING].level = EVENT_LEVEL_WARNING;
|
events.entries[EVENT_CAN_RX_WARNING].level = EVENT_LEVEL_WARNING;
|
||||||
events.entries[EVENT_CAN_TX_FAILURE].level = EVENT_LEVEL_ERROR;
|
events.entries[EVENT_CAN_TX_FAILURE].level = EVENT_LEVEL_ERROR;
|
||||||
events.entries[EVENT_CAN_INVERTER_MISSING].level = EVENT_LEVEL_ERROR;
|
events.entries[EVENT_CAN_INVERTER_MISSING].level = EVENT_LEVEL_WARNING;
|
||||||
events.entries[EVENT_WATER_INGRESS].level = EVENT_LEVEL_ERROR;
|
events.entries[EVENT_WATER_INGRESS].level = EVENT_LEVEL_ERROR;
|
||||||
events.entries[EVENT_CHARGE_LIMIT_EXCEEDED].level = EVENT_LEVEL_INFO;
|
events.entries[EVENT_CHARGE_LIMIT_EXCEEDED].level = EVENT_LEVEL_INFO;
|
||||||
events.entries[EVENT_DISCHARGE_LIMIT_EXCEEDED].level = EVENT_LEVEL_INFO;
|
events.entries[EVENT_DISCHARGE_LIMIT_EXCEEDED].level = EVENT_LEVEL_INFO;
|
||||||
|
@ -215,6 +215,7 @@ void init_events(void) {
|
||||||
events.entries[EVENT_WIFI_DISCONNECT].level = EVENT_LEVEL_INFO;
|
events.entries[EVENT_WIFI_DISCONNECT].level = EVENT_LEVEL_INFO;
|
||||||
events.entries[EVENT_MQTT_CONNECT].level = EVENT_LEVEL_INFO;
|
events.entries[EVENT_MQTT_CONNECT].level = EVENT_LEVEL_INFO;
|
||||||
events.entries[EVENT_MQTT_DISCONNECT].level = EVENT_LEVEL_INFO;
|
events.entries[EVENT_MQTT_DISCONNECT].level = EVENT_LEVEL_INFO;
|
||||||
|
events.entries[EVENT_EQUIPMENT_STOP].level = EVENT_LEVEL_ERROR;
|
||||||
|
|
||||||
events.entries[EVENT_EEPROM_WRITE].log = false; // Don't log the logger...
|
events.entries[EVENT_EEPROM_WRITE].log = false; // Don't log the logger...
|
||||||
|
|
||||||
|
@ -278,7 +279,7 @@ const char* get_event_message_string(EVENTS_ENUM_TYPE event) {
|
||||||
case EVENT_CAN_TX_FAILURE:
|
case EVENT_CAN_TX_FAILURE:
|
||||||
return "ERROR: CAN messages failed to transmit, or no one on the bus to ACK the message!";
|
return "ERROR: CAN messages failed to transmit, or no one on the bus to ACK the message!";
|
||||||
case EVENT_CAN_INVERTER_MISSING:
|
case EVENT_CAN_INVERTER_MISSING:
|
||||||
return "ERROR: Inverter missing on CAN bus! Check wiring!";
|
return "Warning: Inverter not sending messages on CAN bus. Check wiring!";
|
||||||
case EVENT_CHARGE_LIMIT_EXCEEDED:
|
case EVENT_CHARGE_LIMIT_EXCEEDED:
|
||||||
return "Info: Inverter is charging faster than battery is allowing.";
|
return "Info: Inverter is charging faster than battery is allowing.";
|
||||||
case EVENT_DISCHARGE_LIMIT_EXCEEDED:
|
case EVENT_DISCHARGE_LIMIT_EXCEEDED:
|
||||||
|
@ -417,6 +418,8 @@ const char* get_event_message_string(EVENTS_ENUM_TYPE event) {
|
||||||
return "Info: MQTT connected.";
|
return "Info: MQTT connected.";
|
||||||
case EVENT_MQTT_DISCONNECT:
|
case EVENT_MQTT_DISCONNECT:
|
||||||
return "Info: MQTT disconnected.";
|
return "Info: MQTT disconnected.";
|
||||||
|
case EVENT_EQUIPMENT_STOP:
|
||||||
|
return "ERROR: EQUIPMENT STOP ACTIVATED!!!";
|
||||||
default:
|
default:
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
|
@ -103,6 +103,7 @@
|
||||||
XX(EVENT_WIFI_DISCONNECT) \
|
XX(EVENT_WIFI_DISCONNECT) \
|
||||||
XX(EVENT_MQTT_CONNECT) \
|
XX(EVENT_MQTT_CONNECT) \
|
||||||
XX(EVENT_MQTT_DISCONNECT) \
|
XX(EVENT_MQTT_DISCONNECT) \
|
||||||
|
XX(EVENT_EQUIPMENT_STOP) \
|
||||||
XX(EVENT_NOF_EVENTS)
|
XX(EVENT_NOF_EVENTS)
|
||||||
|
|
||||||
typedef enum { EVENTS_ENUM_TYPE(GENERATE_ENUM) } EVENTS_ENUM_TYPE;
|
typedef enum { EVENTS_ENUM_TYPE(GENERATE_ENUM) } EVENTS_ENUM_TYPE;
|
||||||
|
|
|
@ -166,6 +166,23 @@ void init_webserver() {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Route for equipment stop/resume
|
||||||
|
server.on("/equipmentStop", HTTP_GET, [](AsyncWebServerRequest* request) {
|
||||||
|
if (WEBSERVER_AUTH_REQUIRED && !request->authenticate(http_username, http_password))
|
||||||
|
return request->requestAuthentication();
|
||||||
|
if (request->hasParam("stop")) {
|
||||||
|
String valueStr = request->getParam("stop")->value();
|
||||||
|
if (valueStr == "true" || valueStr == "1") {
|
||||||
|
setBatteryPause(true, true, true);
|
||||||
|
} else {
|
||||||
|
setBatteryPause(false, false, false);
|
||||||
|
}
|
||||||
|
request->send(200, "text/plain", "Updated successfully");
|
||||||
|
} else {
|
||||||
|
request->send(400, "text/plain", "Bad Request");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// Route for editing SOCMin
|
// Route for editing SOCMin
|
||||||
server.on("/updateSocMin", HTTP_GET, [](AsyncWebServerRequest* request) {
|
server.on("/updateSocMin", HTTP_GET, [](AsyncWebServerRequest* request) {
|
||||||
if (WEBSERVER_AUTH_REQUIRED && !request->authenticate(http_username, http_password))
|
if (WEBSERVER_AUTH_REQUIRED && !request->authenticate(http_username, http_password))
|
||||||
|
@ -327,7 +344,10 @@ void init_webserver() {
|
||||||
if (WEBSERVER_AUTH_REQUIRED && !request->authenticate(http_username, http_password))
|
if (WEBSERVER_AUTH_REQUIRED && !request->authenticate(http_username, http_password))
|
||||||
return request->requestAuthentication();
|
return request->requestAuthentication();
|
||||||
request->send(200, "text/plain", "Rebooting server...");
|
request->send(200, "text/plain", "Rebooting server...");
|
||||||
//TODO: Should we handle contactors gracefully? Ifdef CONTACTOR_CONTROL then what?
|
|
||||||
|
//Equipment STOP without persisting the equipment state before restart
|
||||||
|
// Max Charge/Discharge = 0; CAN = stop; contactors = open
|
||||||
|
setBatteryPause(true, true, true, false);
|
||||||
delay(1000);
|
delay(1000);
|
||||||
ESP.restart();
|
ESP.restart();
|
||||||
});
|
});
|
||||||
|
@ -834,7 +854,10 @@ String processor(const String& var) {
|
||||||
if (emulator_pause_request_ON)
|
if (emulator_pause_request_ON)
|
||||||
content += "<button onclick='PauseBattery(false)'>Resume charge/discharge</button>";
|
content += "<button onclick='PauseBattery(false)'>Resume charge/discharge</button>";
|
||||||
else
|
else
|
||||||
content += "<button onclick='PauseBattery(true)'>Pause charge/discharge</button>";
|
content +=
|
||||||
|
"<button onclick=\"if(confirm('Are you sure you want to pause charging and discharging? This will set the "
|
||||||
|
"maximum charge and discharge values to zero, preventing any further power flow.')) { PauseBattery(true); "
|
||||||
|
"}\">Pause charge/discharge</button>";
|
||||||
content += " ";
|
content += " ";
|
||||||
content += "<button onclick='OTA()'>Perform OTA update</button>";
|
content += "<button onclick='OTA()'>Perform OTA update</button>";
|
||||||
content += " ";
|
content += " ";
|
||||||
|
@ -847,6 +870,21 @@ String processor(const String& var) {
|
||||||
content += "<button onclick='askReboot()'>Reboot Emulator</button>";
|
content += "<button onclick='askReboot()'>Reboot Emulator</button>";
|
||||||
if (WEBSERVER_AUTH_REQUIRED)
|
if (WEBSERVER_AUTH_REQUIRED)
|
||||||
content += "<button onclick='logout()'>Logout</button>";
|
content += "<button onclick='logout()'>Logout</button>";
|
||||||
|
if (!datalayer.system.settings.equipment_stop_active)
|
||||||
|
content +=
|
||||||
|
"<br/><br/><button style=\"background:red;color:white;cursor:pointer;\""
|
||||||
|
" onclick=\""
|
||||||
|
"if(confirm('This action will open contactors on the battery and stop all CAN communications. Are you "
|
||||||
|
"sure?')) { estop(true); }\""
|
||||||
|
">Open Contactors</button><br/>";
|
||||||
|
else
|
||||||
|
content +=
|
||||||
|
"<br/><br/><button style=\"background:green;color:white;cursor:pointer;\""
|
||||||
|
"20px;font-size:16px;font-weight:bold;cursor:pointer;border-radius:5px; margin:10px;"
|
||||||
|
" onclick=\""
|
||||||
|
"if(confirm('This action will restore the battery state. Are you sure?')) { estop(false); }\""
|
||||||
|
">Close Contactors</button><br/>";
|
||||||
|
|
||||||
content += "<script>";
|
content += "<script>";
|
||||||
content += "function OTA() { window.location.href = '/update'; }";
|
content += "function OTA() { window.location.href = '/update'; }";
|
||||||
content += "function Cellmon() { window.location.href = '/cellmonitor'; }";
|
content += "function Cellmon() { window.location.href = '/cellmonitor'; }";
|
||||||
|
@ -875,7 +913,12 @@ String processor(const String& var) {
|
||||||
"XMLHttpRequest();xhr.onload=function() { "
|
"XMLHttpRequest();xhr.onload=function() { "
|
||||||
"window.location.reload();};xhr.open('GET','/pause?p='+pause,true);xhr.send();";
|
"window.location.reload();};xhr.open('GET','/pause?p='+pause,true);xhr.send();";
|
||||||
content += "}";
|
content += "}";
|
||||||
|
content += "function estop(stop){";
|
||||||
|
content +=
|
||||||
|
"var xhr=new "
|
||||||
|
"XMLHttpRequest();xhr.onload=function() { "
|
||||||
|
"window.location.reload();};xhr.open('GET','/equipmentStop?stop='+stop,true);xhr.send();";
|
||||||
|
content += "}";
|
||||||
content += "</script>";
|
content += "</script>";
|
||||||
|
|
||||||
//Script for refreshing page
|
//Script for refreshing page
|
||||||
|
@ -899,9 +942,6 @@ void onOTAStart() {
|
||||||
clear_event(EVENT_OTA_UPDATE_TIMEOUT);
|
clear_event(EVENT_OTA_UPDATE_TIMEOUT);
|
||||||
ota_active = true;
|
ota_active = true;
|
||||||
|
|
||||||
//completely force stop the CAN communication
|
|
||||||
ESP32Can.CANStop();
|
|
||||||
|
|
||||||
ota_timeout_timer.reset();
|
ota_timeout_timer.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -924,6 +964,9 @@ void onOTAEnd(bool success) {
|
||||||
|
|
||||||
// Log when OTA has finished
|
// Log when OTA has finished
|
||||||
if (success) {
|
if (success) {
|
||||||
|
//Equipment STOP without persisting the equipment state before restart
|
||||||
|
// Max Charge/Discharge = 0; CAN = stop; contactors = open
|
||||||
|
setBatteryPause(true, true, true, false);
|
||||||
// a reboot will be done by the OTA library. no need to do anything here
|
// a reboot will be done by the OTA library. no need to do anything here
|
||||||
#ifdef DEBUG_VIA_USB
|
#ifdef DEBUG_VIA_USB
|
||||||
Serial.println("OTA update finished successfully!");
|
Serial.println("OTA update finished successfully!");
|
||||||
|
@ -934,8 +977,6 @@ void onOTAEnd(bool success) {
|
||||||
#endif // DEBUG_VIA_USB
|
#endif // DEBUG_VIA_USB
|
||||||
//try to Resume the battery pause and CAN communication
|
//try to Resume the battery pause and CAN communication
|
||||||
setBatteryPause(false, false);
|
setBatteryPause(false, false);
|
||||||
//resume CAN communication
|
|
||||||
ESP32Can.CANInit();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,7 @@ static unsigned long LastFrameTime = 0;
|
||||||
static uint8_t number_of_batteries = 1;
|
static uint8_t number_of_batteries = 1;
|
||||||
static uint16_t capped_capacity_Wh;
|
static uint16_t capped_capacity_Wh;
|
||||||
static uint16_t capped_remaining_capacity_Wh;
|
static uint16_t capped_remaining_capacity_Wh;
|
||||||
|
static uint16_t inverter_missing_on_can = 0;
|
||||||
|
|
||||||
//CAN message translations from this amazing repository: https://github.com/rand12345/solax_can_bus
|
//CAN message translations from this amazing repository: https://github.com/rand12345/solax_can_bus
|
||||||
|
|
||||||
|
@ -88,6 +89,12 @@ void update_values_can_inverter() { //This function maps all the values fetched
|
||||||
if (millis() - LastFrameTime >= SolaxTimeout) {
|
if (millis() - LastFrameTime >= SolaxTimeout) {
|
||||||
datalayer.system.status.inverter_allows_contactor_closing = false;
|
datalayer.system.status.inverter_allows_contactor_closing = false;
|
||||||
STATE = BATTERY_ANNOUNCE;
|
STATE = BATTERY_ANNOUNCE;
|
||||||
|
inverter_missing_on_can++;
|
||||||
|
if (inverter_missing_on_can > CAN_STILL_ALIVE) {
|
||||||
|
set_event(EVENT_CAN_INVERTER_MISSING, 0);
|
||||||
|
} else {
|
||||||
|
clear_event(EVENT_CAN_INVERTER_MISSING);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
//Calculate the required values
|
//Calculate the required values
|
||||||
temperature_average =
|
temperature_average =
|
||||||
|
@ -129,6 +136,14 @@ void update_values_can_inverter() { //This function maps all the values fetched
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Cap the value according to user settings. Some inverters cannot handle large values.
|
||||||
|
if ((max_charge_rate_amp * 10) > datalayer.battery.info.max_charge_amp_dA) {
|
||||||
|
max_charge_rate_amp = (datalayer.battery.info.max_charge_amp_dA / 10);
|
||||||
|
}
|
||||||
|
if ((max_discharge_rate_amp * 10) > datalayer.battery.info.max_discharge_amp_dA) {
|
||||||
|
max_discharge_rate_amp = (datalayer.battery.info.max_discharge_amp_dA / 10);
|
||||||
|
}
|
||||||
|
|
||||||
// Batteries might be larger than uint16_t value can take
|
// Batteries might be larger than uint16_t value can take
|
||||||
if (datalayer.battery.info.total_capacity_Wh > 65000) {
|
if (datalayer.battery.info.total_capacity_Wh > 65000) {
|
||||||
capped_capacity_Wh = 65000;
|
capped_capacity_Wh = 65000;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue