|
|
@@ -1,8 +1,10 @@
|
|
|
+#include <string.h>
|
|
|
#include "bsp/gpio.h"
|
|
|
#include "bsp/ml5238.h"
|
|
|
#include "bsp/cs1180.h"
|
|
|
#include "bsp/uart.h"
|
|
|
#include "bsp/mcu_power_sleep.h"
|
|
|
+#include "bsp/cht8305.h"
|
|
|
#include "app/sox/measure.h"
|
|
|
#include "app/sox/measure_task.h"
|
|
|
#include "libs/shark_task.h"
|
|
|
@@ -12,6 +14,7 @@
|
|
|
#include "soc.h"
|
|
|
#include "state.h"
|
|
|
#include "iostate.h"
|
|
|
+#include "event_record.h"
|
|
|
|
|
|
#define ALLOW_DEEP_SLEEP 1
|
|
|
#define SLEEP_IGNORE_UNHEALTH 0
|
|
|
@@ -26,7 +29,8 @@ static void _temperature_notify(void);
|
|
|
static u32 _bms_main_task_handler(void);
|
|
|
static void _debug_timer_handler(shark_timer_t *t);
|
|
|
static void _process_power_down(void);
|
|
|
-static uint8_t calc_cell_voltage(void);
|
|
|
+static void calc_cell_voltage(void);
|
|
|
+static int _can_close_mos_no_hall(void);
|
|
|
|
|
|
static bms_state_t _bms_state;
|
|
|
static int pcb_temp = 100;
|
|
|
@@ -38,10 +42,30 @@ static int open_dfet = 0;
|
|
|
static int open_dfet_failt = 0;
|
|
|
static int close_dfet_reson = 0;
|
|
|
static int close_dfet_no_hall = 0;
|
|
|
+static int no_hall_time[5];
|
|
|
+static int no_hall_count = 0;
|
|
|
+u64 uart_frame_time = 0;
|
|
|
+static u32 uart_reinit_count = 0;
|
|
|
+static void put_no_hall_time(void){
|
|
|
+ no_hall_time[no_hall_count] = shark_get_seconds();
|
|
|
+ no_hall_count = (no_hall_count + 1) % 5;
|
|
|
+}
|
|
|
+
|
|
|
+static void log_no_hall_time(void){
|
|
|
+ state_debug("current time %d\n", shark_get_seconds());
|
|
|
+ for (int i = 0; i < 5; i++){
|
|
|
+ state_debug("no hall time[%d]:%d\n", i, no_hall_time[i]);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
void bms_state_init(void){
|
|
|
set_log_level(MOD_STATE, L_debug);
|
|
|
- state_debug("BMS System Starting......\n");
|
|
|
+ state_debug("BMS System Starting......\n");
|
|
|
+#if (CONFIG_BOARD_TYPE==SHARK_BOARD_SP700)
|
|
|
+ cht8305_reset();
|
|
|
+#endif
|
|
|
_bms_state.cell_index_of_max_vol = 0xff;
|
|
|
+ _bms_state.cell_index_of_min_vol = 0xff;
|
|
|
_bms_state.bms_addr = 0x30;
|
|
|
measure_task_init(_current_notify, _voltage_notify, _temperature_notify);
|
|
|
io_state_init();
|
|
|
@@ -54,6 +78,8 @@ void bms_state_init(void){
|
|
|
|
|
|
pcb_temp = measure_value()->pack_temp[PCB_TEMP_INDEX];
|
|
|
|
|
|
+ uart_frame_time = shark_get_mseconds();
|
|
|
+
|
|
|
set_log_all(L_disable);
|
|
|
}
|
|
|
|
|
|
@@ -103,13 +129,16 @@ int bms_is_ps_charger_in(void){
|
|
|
return _bms_state.ps_charger_mask && _bms_state.ps_charger_in;
|
|
|
}
|
|
|
void bms_state_log(void){
|
|
|
+ soc_log();
|
|
|
state_debug("Life Time: %d\n", shark_get_seconds());
|
|
|
state_debug("Sleep Time: %ds\n", get_system_sleep_time());
|
|
|
state_debug("ml5238 cali: %d\n", ml5238_cali_count);
|
|
|
- state_debug("ps charger mask:in %d, %d\n", _bms_state.ps_charger_mask, _bms_state.ps_charger_in);
|
|
|
- state_debug("open dfet %d - %d - %d - %d\n", open_dfet, open_dfet_failt, close_dfet_reson, close_dfet_no_hall);
|
|
|
+ state_debug("open dfet %d - %d - 0x%x - %d\n", open_dfet, open_dfet_failt, close_dfet_reson, close_dfet_no_hall);
|
|
|
state_debug("Reset Reson 0x%x\n", bsp_get_rst_reson());
|
|
|
state_debug("BackUp value 0x%x\n", bsp_get_backup());
|
|
|
+ state_debug("Debug: %d, %d. uart reinit=%d\n", shark_uart_timeout(), io_state()->hall_detect, uart_reinit_count);
|
|
|
+ log_no_hall_time();
|
|
|
+ nv_storage_log();
|
|
|
#if 0
|
|
|
state_debug("Charging: %d\n", _bms_state.charging);
|
|
|
state_debug("WorkMode %d\n", _bms_state.work_mode);
|
|
|
@@ -175,7 +204,13 @@ void discharger_open(int open){
|
|
|
|
|
|
|
|
|
void charger_open(int open) {
|
|
|
- ml5238_enable_charger_mosfet(open);
|
|
|
+ int retry = 10;
|
|
|
+ while( open != ml5238_is_charging()) {
|
|
|
+ ml5238_enable_charger_mosfet(open);
|
|
|
+ if (retry-- <= 0) {
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
|
|
|
@@ -202,28 +237,20 @@ static s32 _process_unheath(void){
|
|
|
u32 unhealth = Health_Success;
|
|
|
if (bms_health()->load_current_short) {//短路检测后,关闭充放电mos
|
|
|
discharger_open(0);
|
|
|
+ push_event_persit(Discharger_Operate_Off, 5);
|
|
|
charger_open(0); //disable charger mosfet
|
|
|
start_aux_power(0);
|
|
|
_bms_state.charging = 0;
|
|
|
close_dfet_reson = 2;
|
|
|
unhealth = (Health_Discharger_Failt | Health_charger_Fault);
|
|
|
}
|
|
|
- if (!bms_work_is_normal()){
|
|
|
- return unhealth; //测试模式只关注短路保护
|
|
|
- }
|
|
|
if (bms_health()->charger_over_current || bms_health()->charger_over_temp || bms_health()->charger_lower_temp ||
|
|
|
bms_health()->charger_over_voltage || bms_health()->sigle_cell_over_voltage){
|
|
|
- if (_bms_state.ps_charger_mask && !_bms_state.ps_charger_in){
|
|
|
-
|
|
|
- }else {
|
|
|
- charger_open(0); //disable charger mosfet
|
|
|
- unhealth |= Health_charger_Fault;
|
|
|
- }
|
|
|
+ charger_open(0); //disable charger mosfet
|
|
|
+ unhealth |= Health_charger_Fault;
|
|
|
}
|
|
|
if (bms_health()->over_temp_deny_charger|| bms_health()->lower_temp_deny_charger) {
|
|
|
- if (_bms_state.ps_charger_mask && !_bms_state.ps_charger_in){
|
|
|
-
|
|
|
- }else if (_bms_state.charging) {
|
|
|
+ if (_bms_state.charging) {
|
|
|
charger_open(0); //disable charger mosfet
|
|
|
unhealth |= Health_charger_Fault;
|
|
|
}
|
|
|
@@ -234,6 +261,7 @@ static s32 _process_unheath(void){
|
|
|
unhealth |= Health_aux_Fault;
|
|
|
}
|
|
|
discharger_open(0); //disable charger mosfet
|
|
|
+ push_event_persit(Discharger_Operate_Off, 4);
|
|
|
close_dfet_reson = (bms_health()->discharger_over_temp == 1)?3:4;
|
|
|
unhealth |= Health_Discharger_Failt;
|
|
|
}
|
|
|
@@ -246,6 +274,7 @@ static s32 _process_unheath(void){
|
|
|
start_aux_power(0);
|
|
|
if (ml5238_is_discharging()) {
|
|
|
close_dfet_reson = (bms_health()->sigle_cell_lower_voltage == 1) ?5:6;
|
|
|
+ push_event_persit(Discharger_Operate_Off, 3);
|
|
|
discharger_open(0);
|
|
|
}
|
|
|
}
|
|
|
@@ -254,23 +283,28 @@ static s32 _process_unheath(void){
|
|
|
if (bms_health()->over_temp_deny_discharger|| bms_health()->lower_temp_deny_discharger) {
|
|
|
if (!_bms_state.charging) {
|
|
|
close_dfet_reson = (bms_health()->over_temp_deny_discharger == 1)?7:8;
|
|
|
+ push_event_persit(Discharger_Operate_Off, 2);
|
|
|
discharger_open(0); //disable discharger mosfet
|
|
|
}
|
|
|
unhealth |= (Health_Discharger_Failt | Health_Fault_Can_Sleep);
|
|
|
}
|
|
|
- if (io_state()->aux_lock_detect || bms_health()->small_current_short) {
|
|
|
+ if (bms_health()->small_current_real_short) {
|
|
|
unhealth |= Health_aux_Fault;
|
|
|
if (bms_health()->small_current_real_short) {
|
|
|
unhealth |= Health_Discharger_Failt;
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
+ if (soc_is_force_full()) {
|
|
|
+ charger_open(0); //disable charger mosfet
|
|
|
+ unhealth |= (Health_charger_Fault |Health_Fault_Can_Sleep);
|
|
|
+ }
|
|
|
return unhealth;
|
|
|
}
|
|
|
|
|
|
|
|
|
//处理PS100/310/320/360,充电底座,充电柜的指令或者bms自己发给自己的指令
|
|
|
static void _process_user_request(s32 health){
|
|
|
+ bool mos_drv = false;
|
|
|
if (_bms_state.user_request & USER_REQUEST_PENDING){
|
|
|
//开关小电
|
|
|
if (_bms_state.user_request & USER_REQUEST_SMALLCURRENT_OFF){
|
|
|
@@ -278,6 +312,8 @@ static void _process_user_request(s32 health){
|
|
|
}
|
|
|
if (_bms_state.user_request & USER_REQUEST_DISCHARGER_OFF){
|
|
|
discharger_open(0);
|
|
|
+ push_event_persit(Discharger_Operate_Off, 1);
|
|
|
+ close_dfet_reson |= (3 << 24);
|
|
|
}
|
|
|
if (_bms_state.user_request & USER_REQUEST_CHARGER_OFF){
|
|
|
charger_open(0);
|
|
|
@@ -290,17 +326,31 @@ static void _process_user_request(s32 health){
|
|
|
}
|
|
|
if (_bms_state.user_request & USER_REQUEST_CHARGER_ON){
|
|
|
if (!(health & Health_charger_Fault)){
|
|
|
- charger_open(1);
|
|
|
+ if ((io_state()->hall_detect) || !_can_close_mos_no_hall()){
|
|
|
+ charger_open(1);
|
|
|
+ mos_drv = true;
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
if (_bms_state.user_request & USER_REQUEST_DISCHARGER_ON) {
|
|
|
open_dfet ++;
|
|
|
if (!(health & Health_Discharger_Failt)){
|
|
|
- discharger_open(1);
|
|
|
+ if ((io_state()->hall_detect || _bms_state.charging) || !_can_close_mos_no_hall()){
|
|
|
+ push_event_persit(Discharger_Operate_On, 10);
|
|
|
+ discharger_open(1);
|
|
|
+ mos_drv = true;
|
|
|
+ }else {
|
|
|
+ push_event_persit(Discharger_Operate_On, 20);
|
|
|
+ }
|
|
|
}else {
|
|
|
+ push_event_persit(Discharger_Operate_On, 30);
|
|
|
open_dfet_failt ++;
|
|
|
}
|
|
|
}
|
|
|
+ if (mos_drv && ml5238_is_mosdrv_strong()) {
|
|
|
+ task_udelay(3000);
|
|
|
+ ml5238_disable_mosdrv();
|
|
|
+ }
|
|
|
_bms_state.user_request &= ~USER_REQUEST_PENDING;//clear user request pending
|
|
|
}
|
|
|
}
|
|
|
@@ -308,6 +358,9 @@ static void _process_user_request(s32 health){
|
|
|
static void _process_power_down(void){
|
|
|
#if (ALLOW_POWER_DOWN==1)
|
|
|
if (bms_health()->powerdown_lower_voltage){
|
|
|
+ if (bms_work_is_normal() && (shark_get_seconds() < bms_health()->pd_time + 5)) {//超过5s powerdown
|
|
|
+ return;
|
|
|
+ }
|
|
|
state_debug("BMS System PowerDown!!\n");
|
|
|
|
|
|
if (bms_work_is_normal() && soc_update_by_ocv()) {
|
|
|
@@ -361,7 +414,8 @@ static void _process_deepsleep(s32 health){
|
|
|
if (!bms_work_is_normal()){
|
|
|
return; //测试模式下不休眠
|
|
|
}
|
|
|
- if (ml5238_is_charging() || ml5238_is_discharging() || io_state()->charger_detect_irq || _bms_state.charging){
|
|
|
+ if (ml5238_is_charging() || ml5238_is_discharging() || io_state()->charger_detect_irq || _bms_state.charging ||
|
|
|
+ _bms_state.pack_balancing){
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
@@ -379,11 +433,13 @@ static void _process_deepsleep(s32 health){
|
|
|
if (shark_get_mseconds() < (_sleep_time + 3 * 1000)){
|
|
|
return;
|
|
|
}
|
|
|
-
|
|
|
+ printf("SYSTEM: enter sleep\n");
|
|
|
+ shark_uart_flush();
|
|
|
nv_save_all_soc();
|
|
|
mcu_enter_deepsleep();
|
|
|
soc_update_for_deepsleep(mcu_get_sleeptime());//补偿休眠的功耗
|
|
|
_sleep_time = shark_get_mseconds();
|
|
|
+ uart_frame_time = shark_get_mseconds();
|
|
|
#endif
|
|
|
}
|
|
|
|
|
|
@@ -396,23 +452,30 @@ static int _can_close_mos_no_hall(void){
|
|
|
}
|
|
|
|
|
|
static void _process_iostate_changed(s32 unhealth){
|
|
|
- if (!(io_state()->hall_detect)&& _can_close_mos_no_hall()){
|
|
|
+ if (!(io_state()->hall_detect)){
|
|
|
bms_set_ps_charger_in(0, 0);
|
|
|
- if (ml5238_is_discharging() && (!_bms_state.charging)){
|
|
|
- discharger_open(0);
|
|
|
- close_dfet_no_hall ++;
|
|
|
- open_dfet = open_dfet_failt = 0; //clear open dfet count
|
|
|
+ if (bms_work_is_aging_test()) {
|
|
|
+ bms_work_mode_set(WORK_MODE_AGING_TEST, 0);//close aging test mode
|
|
|
}
|
|
|
- if (!AUX_VOL_IS_OPEN() && !bms_health()->load_current_short && !io_state()->aux_lock_detect && !bms_health()->small_current_short){
|
|
|
- start_aux_power(1);
|
|
|
- }
|
|
|
- if (!io_state()->charger_detect_irq && ml5238_is_charging() && (!_bms_state.charging)){
|
|
|
- charger_open(0);
|
|
|
+ if (_can_close_mos_no_hall()) {
|
|
|
+ if (ml5238_is_discharging() && (!_bms_state.charging)){
|
|
|
+ push_event_persit(Discharger_Operate_Off, 256);
|
|
|
+ discharger_open(0);
|
|
|
+ put_no_hall_time();
|
|
|
+ close_dfet_no_hall ++;
|
|
|
+ open_dfet = open_dfet_failt = 0; //clear open dfet count
|
|
|
+ }
|
|
|
+ if (!AUX_VOL_IS_OPEN() && !bms_health()->load_current_short && !io_state()->aux_lock_detect && !bms_health()->small_current_short){
|
|
|
+ start_aux_power(1);
|
|
|
+ }
|
|
|
+ if (!io_state()->charger_detect_irq && ml5238_is_charging() && (!_bms_state.charging)){
|
|
|
+ charger_open(0);
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
if (io_state()->charger_detect_irq && ((unhealth & Health_charger_Fault) == 0) && (_bms_state.cell_max_vol < SIGLE_CELL_MAX_CHARGER_VOLTAGE)) {
|
|
|
if (!ml5238_is_charging() && shark_uart_timeout()){//不在车上,底座上,充电柜上,检测到充电器插入,自动打开充电,否则的话,只能通过指令来打开充电mos
|
|
|
- if (!(bms_health()->over_temp_deny_charger|| bms_health()->lower_temp_deny_charger)) {
|
|
|
+ if (!(bms_health()->over_temp_deny_charger|| bms_health()->lower_temp_deny_charger)&& (get_soc()->capacity < 100)) {
|
|
|
charger_open(1);
|
|
|
}
|
|
|
}
|
|
|
@@ -426,34 +489,58 @@ static void _process_iostate_changed(s32 unhealth){
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+static void _bms_uart_workaround(void) {
|
|
|
+ if (io_state()->hall_detect != 1){
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ if (shark_get_mseconds() >= (uart_frame_time + 3000)){
|
|
|
+ UART0_IR_EN(0);
|
|
|
+ UART1_IR_EN(0);
|
|
|
+ task_udelay(50 * 1000);
|
|
|
+ UART0_IR_EN(1);
|
|
|
+ UART1_IR_EN(1);
|
|
|
+ uart_reinit_count++;
|
|
|
+ uart_frame_time = shark_get_mseconds();
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
static u32 _bms_main_task_handler(void){
|
|
|
s32 unhealth = _process_unheath();
|
|
|
_process_user_request(unhealth);
|
|
|
_process_deepsleep(unhealth);
|
|
|
_process_power_down();
|
|
|
_process_iostate_changed(unhealth);
|
|
|
+ _bms_uart_workaround();
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
extern void show_leds_for_charging(uint8_t charging);
|
|
|
static debounce_t _charging_detect = {.count = 0, .max_count = 10, .init_count = 0};
|
|
|
static int cs1180_may_error_count = 0;
|
|
|
+static bool _cs1180_may_error(void) {
|
|
|
+ //cs1180 not working
|
|
|
+ if (measure_value()->load_current == measure_value()->current_5238) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ //cs1180检测到充电电流,5238检测到负电流
|
|
|
+ if ((measure_value()->load_current >= MIN_START_CHARGER_CURRENT) && (measure_value()->current_5238 <= 0)) {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ //cs1180 和 5238的测量电流差超过阈值
|
|
|
+ if (abs(measure_value()->load_current - measure_value()->current_5238) >= MIN_DIFF_BT_5238_1180) {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ return false;
|
|
|
+}
|
|
|
static void check_charging(){
|
|
|
/* 解决cs1180可能出错,导致误判充电,离仓后无法休眠 */
|
|
|
- int may_error = 0;
|
|
|
- if (measure_value()->load_current >= MIN_START_CHARGER_CURRENT) {
|
|
|
- if (measure_value()->load_current != measure_value()->current_5238) {
|
|
|
- if (measure_value()->current_5238 <= 0) { //cs1180检测到充电电流,5238检测到负电流
|
|
|
- if (++cs1180_may_error_count >= _charging_detect.max_count/2) {
|
|
|
- measure_value()->load_current = measure_value()->current_5238;
|
|
|
- cs1180_adc_shutdown();
|
|
|
- cs1180_may_error_count = 0;
|
|
|
- }
|
|
|
- may_error = 1;
|
|
|
- }
|
|
|
+ if (_cs1180_may_error()) {
|
|
|
+ if (++cs1180_may_error_count >= _charging_detect.max_count/2) {
|
|
|
+ measure_value()->load_current = measure_value()->current_5238;
|
|
|
+ cs1180_adc_shutdown();
|
|
|
+ cs1180_may_error_count = 0;
|
|
|
}
|
|
|
- }
|
|
|
- if (may_error == 0) {
|
|
|
+ }else {
|
|
|
cs1180_may_error_count = 0;
|
|
|
}
|
|
|
if ((measure_value()->load_current >= MIN_START_CHARGER_CURRENT)) {
|
|
|
@@ -489,9 +576,12 @@ static void check_charging(){
|
|
|
static int _min_current_for_both_mos_count = 0;
|
|
|
static u32 _check_mos_time = 0;
|
|
|
static __INLINE u32 _open_all_mos_time(void){
|
|
|
- if (abs(measure_value()->load_current) >= MIN_CURRENT_FOR_BOTH_MOS_OPEN * 2){
|
|
|
+ if (abs(measure_value()->load_current) >= MIN_CURRENT_FOR_BOTH_MOS_OPEN * 11){
|
|
|
return 0;
|
|
|
}
|
|
|
+ if (abs(measure_value()->load_current) >= MIN_CURRENT_FOR_BOTH_MOS_OPEN * 6) {
|
|
|
+ return 5;
|
|
|
+ }
|
|
|
if (abs(measure_value()->load_current) >= MIN_CURRENT_FOR_BOTH_MOS_OPEN) {
|
|
|
return 10;
|
|
|
}
|
|
|
@@ -505,9 +595,11 @@ static void _check_mos_stat(void){
|
|
|
int cmos = ml5238_is_charging();
|
|
|
if (dmos + cmos == 0){
|
|
|
//state_error("current = %d, but all mos is closed\n", measure_value()->load_current);
|
|
|
+ _check_mos_time = shark_get_seconds();
|
|
|
return;
|
|
|
}
|
|
|
if (dmos == 1 && cmos == 1){
|
|
|
+ _check_mos_time = shark_get_seconds();
|
|
|
return;
|
|
|
}
|
|
|
if (shark_get_seconds() >= (_check_mos_time + _open_all_mos_time())) {
|
|
|
@@ -523,10 +615,16 @@ static void _check_mos_stat(void){
|
|
|
}
|
|
|
}else {
|
|
|
_min_current_for_both_mos_count = 0;
|
|
|
+ _check_mos_time = shark_get_seconds();
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
+#if (ALLOW_5238_BALANCE==1)
|
|
|
+static bool check_stop_balance(void) ;
|
|
|
+#endif
|
|
|
static void _current_notify(void){
|
|
|
+#if (ALLOW_5238_BALANCE==1)
|
|
|
+ check_stop_balance();
|
|
|
+#endif
|
|
|
check_charging();
|
|
|
check_current_state(); //check health of current
|
|
|
_check_mos_stat();
|
|
|
@@ -540,52 +638,166 @@ static void _current_notify(void){
|
|
|
* 木桶效应,目标是电压最高的那个cell,尽量压制,不让电压再升高,或者升高的尽量慢一些
|
|
|
*/
|
|
|
static void _balance_timer_handler(shark_timer_t *t);
|
|
|
-
|
|
|
static shark_timer_t _balance_timer = {.handler = _balance_timer_handler};
|
|
|
+static void _start_balance(uint16_t mask) {
|
|
|
+ int success = ml5238_cell_start_balance(mask);
|
|
|
+ if (success ) {
|
|
|
+ if (mask == 0) {
|
|
|
+ _bms_state.pack_balancing = 0;
|
|
|
+ }else {
|
|
|
+ _bms_state.pack_balancing = 1;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
|
|
|
-static debounce_t _cell_balance = {.count = 0, .max_count = 10, .init_count = 0};
|
|
|
+static void _stop_balance(void) {
|
|
|
+ _start_balance(0);
|
|
|
+}
|
|
|
|
|
|
static void _balance_timer_handler(shark_timer_t *t){
|
|
|
- ml5238_cell_start_balance(0);
|
|
|
- _bms_state.pack_balancing = 0;
|
|
|
+ _stop_balance();
|
|
|
+ if (_bms_state.pack_balancing) {
|
|
|
+ shark_timer_post(&_balance_timer, 1);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
-static uint32_t get_balance_mask(uint8_t current_max_index){
|
|
|
- return BIT(current_max_index);
|
|
|
-}
|
|
|
|
|
|
-static void check_cell_balance(uint8_t current_max_index){
|
|
|
- if (!_bms_state.charging){ //not charging, need not do balance
|
|
|
- if (_bms_state.pack_balancing){
|
|
|
- _bms_state.pack_balancing = 0;
|
|
|
- _cell_balance.count = 10;
|
|
|
- ml5238_cell_start_balance(0);
|
|
|
- shark_timer_cancel(&_balance_timer);
|
|
|
+static u16 _search_direct(u16 *delta_v, u8 current_cell, u8 *depth, u8 dir) {
|
|
|
+ u16 delta_next, delta_prev;
|
|
|
+ u8 idx_prev, idx_next;
|
|
|
+ u8 balance_idx = 255;
|
|
|
+
|
|
|
+ for (int i = 0; i < CELLS_NUM/2 + 1; i++) {
|
|
|
+ *depth ++;
|
|
|
+ //get the delta v of the prev and current
|
|
|
+ if (current_cell == 0) {
|
|
|
+ idx_prev = CELLS_NUM - 1;
|
|
|
+ }else {
|
|
|
+ idx_prev = current_cell - 1;
|
|
|
+ }
|
|
|
+ delta_prev = delta_v[idx_prev];
|
|
|
+
|
|
|
+ //get the delta v of the next and current
|
|
|
+#if 0
|
|
|
+ if (current_cell == CELLS_NUM - 1) {
|
|
|
+ idx_next = 0;
|
|
|
+ }else {
|
|
|
+ idx_next = current_cell + 1;
|
|
|
+ }
|
|
|
+#endif
|
|
|
+ idx_next = current_cell;
|
|
|
+ delta_next = delta_v[idx_next];
|
|
|
+
|
|
|
+ //use the max delta v of the prev and next
|
|
|
+ if (delta_prev >= delta_next) {
|
|
|
+ if(delta_prev >= MAX_DIFF_BETWEEN_MIN_MAX_CELL){
|
|
|
+ balance_idx = idx_prev; //balance with prev cell
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }else {
|
|
|
+ if(delta_next >= MAX_DIFF_BETWEEN_MIN_MAX_CELL){
|
|
|
+ balance_idx = idx_next; //balance with next cell
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (dir == 1) {//search forword
|
|
|
+ current_cell = (current_cell + 1) % CELLS_NUM;
|
|
|
+ }else { //search backwork
|
|
|
+ if (current_cell == 0) {
|
|
|
+ current_cell = CELLS_NUM - 1;
|
|
|
+ }else {
|
|
|
+ current_cell -= 1;
|
|
|
+ }
|
|
|
}
|
|
|
- return;
|
|
|
}
|
|
|
- if ((!_bms_state.pack_balancing && _bms_state.cell_max_vol < MAX_CELL_VOLTAGE_FOR_BALACNE) || _bms_state.pack_balancing){
|
|
|
+ return balance_idx;
|
|
|
+}
|
|
|
+static u32 get_balance_maskV2(void) {
|
|
|
+ u16 delta_v[CELLS_NUM];
|
|
|
+ u16 *pcellv = measure_value()->cell_vol;
|
|
|
+
|
|
|
+ //calc the delta v of the Neighboring cells
|
|
|
+ delta_v[CELLS_NUM - 1] = abs(pcellv[CELLS_NUM-1] - pcellv[0]);
|
|
|
+ for (int i = 0; i < CELLS_NUM - 1; i++) {
|
|
|
+ delta_v[i] = abs(pcellv[i] - pcellv[i + 1]);
|
|
|
+ }
|
|
|
+ u8 depth_next = 0, depth_prev = 0;
|
|
|
+ u8 idx_next = _search_direct(delta_v, _bms_state.cell_index_of_max_vol, &depth_next, 1);// search from max to next....
|
|
|
+ u8 idx_prev = _search_direct(delta_v, _bms_state.cell_index_of_max_vol, &depth_prev, 0);// search from max to prev
|
|
|
+ //chose the min depth whitch near from max voltage cell
|
|
|
+ if (depth_next < depth_prev) {
|
|
|
+ return BIT(idx_next);
|
|
|
+ }else if (depth_prev < depth_next) {
|
|
|
+ return BIT(idx_prev);
|
|
|
+ }else {
|
|
|
+ if (idx_next < CELLS_NUM) {
|
|
|
+ return BIT(idx_next);
|
|
|
+ }
|
|
|
+ if (idx_prev < CELLS_NUM) {
|
|
|
+ return BIT(idx_prev);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+#define BALANCE_TIME (10 * 60) //S
|
|
|
+static u8 g_is_charging = 0;
|
|
|
+static u8 can_do_balance(void) {
|
|
|
+ u8 balance = 0;
|
|
|
+ //when stop normal(not energy recovery) charging, need check balance
|
|
|
+ if (g_is_charging && (!_bms_state.charging && soc_is_normal_charging())) {
|
|
|
+ balance = 1;
|
|
|
+ }
|
|
|
+ g_is_charging = _bms_state.charging;
|
|
|
+ //if already balancing, do nothing
|
|
|
+ if (_bms_state.pack_balancing) {
|
|
|
+ balance = 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ return balance;
|
|
|
+}
|
|
|
+
|
|
|
+static u8 need_stop_balance(void) {
|
|
|
+ if (measure_value()->load_current < -100.0 || g_is_charging) {
|
|
|
+ return 1;
|
|
|
+ }
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static void check_cell_balance(void){
|
|
|
+ if (check_stop_balance()) {
|
|
|
return;
|
|
|
}
|
|
|
- if (_bms_state.cell_max_vol >= MAX_CELL_VOLTAGE_FOR_BALACNE){
|
|
|
- debounce_inc(_cell_balance);
|
|
|
- }else {
|
|
|
- debounce_reset(_cell_balance);
|
|
|
+ u16 mask = get_balance_maskV2();
|
|
|
+ if (mask) {
|
|
|
+ push_event(Cell_balance, mask);
|
|
|
+ _start_balance(mask);
|
|
|
+ shark_timer_post(&_balance_timer, BALANCE_TIME * 1000); //stop balance after BALANCE_TIME
|
|
|
}
|
|
|
- if (!_bms_state.pack_balancing && debounce_reach_max(_cell_balance)){
|
|
|
- _bms_state.pack_balancing = 1;
|
|
|
- ml5238_cell_start_balance(get_balance_mask(current_max_index));
|
|
|
- shark_timer_post(&_balance_timer, 30 * 1000); //stop balance after 30s
|
|
|
- debounce_reset(_cell_balance);
|
|
|
+ state_debug("Cell balance mask 0x%x\n", mask);
|
|
|
+}
|
|
|
+
|
|
|
+static bool check_stop_balance(void) {
|
|
|
+ if (!can_do_balance()) {
|
|
|
+ if (need_stop_balance()) {
|
|
|
+ if (_bms_state.pack_balancing){
|
|
|
+ _stop_balance();
|
|
|
+ push_event(Cell_balance, 0);
|
|
|
+ shark_timer_cancel(&_balance_timer);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return true;
|
|
|
}
|
|
|
- _bms_state.cell_index_of_max_vol = current_max_index;
|
|
|
+ return false;
|
|
|
}
|
|
|
+
|
|
|
#endif
|
|
|
-static uint8_t calc_cell_voltage(void){
|
|
|
+static void calc_cell_voltage(void){
|
|
|
uint16_t voltage = 0;
|
|
|
uint16_t max_cell = 0;
|
|
|
uint16_t min_cell = 0xf000;
|
|
|
uint8_t max_index = 0;
|
|
|
+ uint8_t min_index = 0;
|
|
|
for (int i = 0; i < CELLS_NUM; i++){
|
|
|
voltage += measure_value()->cell_vol[i];
|
|
|
if (max_cell < measure_value()->cell_vol[i]){
|
|
|
@@ -594,23 +806,26 @@ static uint8_t calc_cell_voltage(void){
|
|
|
}
|
|
|
if (min_cell > measure_value()->cell_vol[i]){
|
|
|
min_cell = measure_value()->cell_vol[i];
|
|
|
+ min_index = i;
|
|
|
}
|
|
|
}
|
|
|
_bms_state.pack_voltage = voltage;
|
|
|
_bms_state.cell_max_vol = max_cell;
|
|
|
- _bms_state.cell_min_vol = min_cell;
|
|
|
- return max_index;
|
|
|
+ _bms_state.cell_min_vol = min_cell;
|
|
|
+ _bms_state.cell_index_of_min_vol = min_index;
|
|
|
+ _bms_state.cell_index_of_max_vol = max_index;
|
|
|
}
|
|
|
|
|
|
static void _voltage_notify(void){
|
|
|
- uint8_t max_index = calc_cell_voltage();
|
|
|
+ calc_cell_voltage();
|
|
|
check_voltage_state(); //check health of cell voltage
|
|
|
#if (ALLOW_5238_BALANCE==1)
|
|
|
- check_cell_balance(max_index);
|
|
|
+ check_cell_balance();
|
|
|
#endif
|
|
|
}
|
|
|
|
|
|
static void _temperature_notify(void){
|
|
|
+ static uint8_t _bms_aging_test = 0;
|
|
|
int pcb_current_temp = measure_value()->pack_temp[PCB_TEMP_INDEX];
|
|
|
if (abs(pcb_temp - pcb_current_temp) >= 5){//pcb温度变化超过5度,需要重新校准ML5238
|
|
|
if (pcb_temp_count ++ >= 5) {
|
|
|
@@ -624,5 +839,31 @@ static void _temperature_notify(void){
|
|
|
pcb_temp_count = 0;
|
|
|
}
|
|
|
check_temp_state(); //check health of cell/pcb temperature
|
|
|
+ if (bms_work_is_aging_test()) {
|
|
|
+ if (abs(measure_value()->load_current) >= 2000) {
|
|
|
+ if (_bms_aging_test == 0) {
|
|
|
+ memcpy(_bms_state.aging_start_temp, measure_value()->pack_temp, PACK_TEMPS_NUM * sizeof(int));
|
|
|
+ memcpy(_bms_state.aging_max_temp, measure_value()->pack_temp, PACK_TEMPS_NUM * sizeof(int));
|
|
|
+ _bms_state.aging_real_start = 0;
|
|
|
+ _bms_state.agint_cost_time = 0;
|
|
|
+ _bms_aging_test = 1;
|
|
|
+ }
|
|
|
+ if (_bms_state.aging_real_start == 0) {
|
|
|
+ _bms_state.aging_real_start = shark_get_seconds();
|
|
|
+ }
|
|
|
+ for (int i = 0; i < PACK_TEMPS_NUM; i++) {
|
|
|
+ if (_bms_state.aging_max_temp[i] < measure_value()->pack_temp[i]) {
|
|
|
+ _bms_state.aging_max_temp[i] = measure_value()->pack_temp[i];
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }else {
|
|
|
+ if(_bms_state.aging_real_start > 0){
|
|
|
+ _bms_state.agint_cost_time += (shark_get_seconds() - _bms_state.aging_real_start);
|
|
|
+ _bms_state.aging_real_start = 0;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }else {
|
|
|
+ _bms_aging_test = 0;
|
|
|
+ }
|
|
|
}
|
|
|
|