Просмотр исходного кода

整理health,state,iostate,measure_task 架构

Signed-off-by: huhui <huhui@sharkgulf.com>
huhui 5 лет назад
Родитель
Сommit
1a1fad6a79

+ 20 - 0
Application/app/controller.c

@@ -0,0 +1,20 @@
+#include "bsp/bsp.h"
+#include "app/sox/state.h"
+#include "controller.h"
+
+void discharger_open(int open){
+	/* 打开大电前,先打开短路保护*/
+	if (open) {
+		ml5238_short_current_detect(SHORT_CURRENT_MODE_66_6A);
+	}else {
+		ml5238_short_current_detect(SHORT_CURRENT_MODE_DISABLE);
+	}
+	ml5238_enable_discharger_mosfet(open);
+	bms_state_get()->mosfet_discharger = open;
+}
+
+
+void charger_open(int open) {
+	ml5238_enable_charger_mosfet(open);
+	bms_state_get()->mosfet_charger = open;
+}

+ 6 - 0
Application/app/controller.h

@@ -0,0 +1,6 @@
+#ifndef _CONTROLLER_H__
+#define _CONTROLLER_H__
+
+
+#endif /* _CONTROLLER_H__ */
+

+ 257 - 0
Application/app/sox/health.c

@@ -0,0 +1,257 @@
+#include "health.h"
+#include "bsp/ml5238.h"
+#include "state.h"
+#include "iostate.h"
+#include "measure_task.h"
+
+#define MAX_CURRENT_FOR_CHARGER (20*1000) //最大充电电流20A
+#define MIN_VOLTAGE_FOR_DISCHARGER (39 * 1000) //允许能放电的最小电压
+#define MIN_VOLTAGE_FOR_RECOVERY_DISCHARGER (40 * 1000) //恢复放电的最小电压
+#define MIN_VOLTAGE_FOR_POWER_DOWN (32 * 1000)
+static int8_t charger_normal_low_temp[PACK_TEMPS_NUM] = {0,0,0,0}; //正常的充电最低温度
+static int8_t charger_normal_high_temp[PACK_TEMPS_NUM] = {50,50,50,55}; //正常的充电最高温度
+static int8_t charger_lower_low_temp[PACK_TEMPS_NUM] = {-5,-5,-5,0}; //需要停止充电的最低温度
+static int8_t charger_higher_high_temp[PACK_TEMPS_NUM] = {55,55,55,60}; //需要停止充电的最高温度
+
+static int8_t discharger_normal_low_temp[PACK_TEMPS_NUM] = {-10,-10,-10,-5};//正常的放电最低温度
+static int8_t discharger_normal_high_temp[PACK_TEMPS_NUM] = {50,50,50,55};//正常的放电最高温度
+static int8_t discharger_lower_low_temp[PACK_TEMPS_NUM] = {-15,-15,-15,-10}; //需要停止放电的最低温度
+static int8_t discharger_higher_high_temp[PACK_TEMPS_NUM] = {55,55,55,60};//需要停止放电的最高温度
+
+/* health 模块,只检测状态,不做任何控制,如果有异常情况,控制中心会统一处理  */
+static void check_ml5238_state(int event);
+static void init_detect_timer(void);
+static void load_delect_handler(shark_timer_t *timer);
+static void charger_detect_handler(shark_timer_t *timer);
+
+static bms_health_t _health;
+static debounce_timer_t _load_detect_timer;
+static debounce_timer_t _charger_detect_timer;
+void health_init(void){
+	/* 5238如果有异常情况,比如短路,负载移除,通过这个handler上报 */
+	ml5238_register_notify_handler(check_ml5238_state);
+	init_detect_timer();
+}
+
+bms_health_t *bms_health(){
+	return &_health;
+}
+
+static void init_detect_timer(void){
+	_load_detect_timer._timer.handler = load_delect_handler;
+	_load_detect_timer.max_count = 100;
+	_load_detect_timer.interval = 10;
+
+	_charger_detect_timer._timer.handler = charger_detect_handler;
+	_charger_detect_timer.max_count = 100;
+	_charger_detect_timer.interval = 10;	
+}
+
+static void load_delect_handler(shark_timer_t *timer){
+	if (ml5238_is_load_disconnect()){
+		_load_detect_timer.count ++;
+	}else {
+		_load_detect_timer.count = 0;
+	}
+	if (_load_detect_timer.count >= _load_detect_timer.max_count) {
+		_health.load_current_short = 0; //负载移除,clear load current short
+		ml5238_enable_load_detect(0);
+	}else {		
+		shark_timer_post(&_load_detect_timer._timer, _load_detect_timer.interval);
+	}
+}
+
+static void charger_detect_handler(shark_timer_t *timer){
+	if (!io_state()->charger_detect) {
+		_charger_detect_timer.count ++;
+	}else {
+		_charger_detect_timer.count = 0;
+	}
+	if (_charger_detect_timer.count >= _charger_detect_timer.max_count){
+		_health.charger_over_current = 0;
+	}else {
+		shark_timer_post(&_charger_detect_timer._timer, _charger_detect_timer.interval);
+	}
+}
+
+static void check_ml5238_state(int event){
+	if (event == ML5238_Event_Charger_Over_Current){
+		shark_timer_post(&_charger_detect_timer._timer, _charger_detect_timer.interval);
+	}else if (event == ML5238_Event_Short_Current) { //ml5238触发短路保护,充放电mos全部关闭
+		_health.load_current_short = 1;
+		ml5238_enable_load_detect(1); //打开负载检测
+		shark_timer_post(&_load_detect_timer._timer, _load_detect_timer.interval);
+	}else if (event == ML5238_Event_Load_Disconnect) {
+		shark_timer_post(&_load_detect_timer._timer, _load_detect_timer.interval);
+	}
+}
+
+/* 检测电流情况,看是否过流等 */
+static debounce_t _charger_over_current = {
+	.count = 0,
+	.max_count = 10
+};
+void check_current_state(void){
+	//判断是否过流充电,放电过流通过5238来检测
+	if (bms_state_get()->charging && !_health.charger_over_current) {
+		float current = measure_value()->load_current;
+		if (current > MAX_CURRENT_FOR_CHARGER) {
+			_charger_over_current.count ++;
+		}else {
+			_charger_over_current.count = 0;
+		}
+		if (_charger_over_current.count >= _charger_over_current.max_count){
+			_health.charger_over_current = 1;
+			_charger_over_current.count = 0;
+			shark_timer_post(&_charger_detect_timer._timer, _charger_detect_timer.interval);
+		}
+	}
+}
+
+/* 检测pack电压,cell电压,pack电压过低触发powerdown*/
+
+static debounce_t _discharger_lower_voltage = {.count = 0, .max_count = 10};
+static debounce_t _discharger_low_normal_voltage = {.count = 0, .max_count = 10};
+static debounce_t _power_down_voltage = {.count = 0, .max_count = 10};
+void check_voltage_state(void) {
+	if (!_health.discharger_lower_voltage){ //check for low pack voltage for close discharger
+		if (bms_state_get()->pack_voltage <= MIN_VOLTAGE_FOR_DISCHARGER){
+			debounce_inc(&_discharger_lower_voltage);
+		}else {
+			debounce_reset(&_discharger_lower_voltage);
+		}
+		if (debounce_reach(&_discharger_lower_voltage)){
+			_health.discharger_lower_voltage = 1;
+			debounce_reset(&_discharger_lower_voltage);
+		}
+
+	}else { //check for discharger recovery
+		if (bms_state_get()->pack_voltage >= MIN_VOLTAGE_FOR_RECOVERY_DISCHARGER){
+			debounce_inc(&_discharger_low_normal_voltage);
+		}else {
+			debounce_reset(&_discharger_low_normal_voltage);
+		}
+		if (debounce_reach(&_discharger_low_normal_voltage)){
+			_health.discharger_lower_voltage = 0;
+			debounce_reset(&_discharger_low_normal_voltage);
+		}		
+	}
+	/* check for power down */
+	if (!io_state()->charger_detect && !bms_state_get()->charging && !_health.powerdown_lower_voltage){
+		if (bms_state_get()->pack_voltage >= MIN_VOLTAGE_FOR_POWER_DOWN){
+			debounce_inc(&_power_down_voltage);
+		}else {
+			debounce_reset(&_power_down_voltage);
+		}
+		if (debounce_reach(&_power_down_voltage)){
+			/*
+			 * no need to clear powerdown(bms is shutdown), when charger insert, 
+			 * system will power on with powerdown_lower_voltage cleared
+			*/
+			_health.powerdown_lower_voltage = 1; 
+			debounce_reset(&_power_down_voltage);
+		}	
+	}
+}
+
+/* 检测温度情况,看是否过高温,或者过低温 */
+
+static debounce_t _charger_over_temp      = {.count = 0, .max_count = 10};
+static debounce_t _charger_lower_temp     = {.count = 0, .max_count = 10};
+static debounce_t _charger_normal_temp    = {.count = 0, .max_count = 10};
+static debounce_t _discharger_over_temp   = {.count = 0, .max_count = 10};
+static debounce_t _discharger_lower_temp  = {.count = 0, .max_count = 10};
+static debounce_t _discharger_normal_temp = {.count = 0, .max_count = 10};
+
+static int _is_over_temp(int8_t *temps){
+	for (int i = 0; i < PACK_TEMPS_NUM; i++){
+		if (measure_value()->pack_temp[i] >= temps[i]){
+			return 1;
+		}
+	}
+	return 0;
+}
+
+static int _is_low_temp(int8_t *temps){
+	for (int i = 0; i < PACK_TEMPS_NUM; i++){
+		if (measure_value()->pack_temp[i] <= temps[i]){
+			return 1;
+		}
+	}
+	return 0;
+}
+
+void check_temp_state(void){
+	if (bms_state_get()->charging){
+		if (!_health.charger_over_temp){
+			if (_is_over_temp(charger_higher_high_temp)) {//超过允许的最高温度
+				debounce_inc(&_charger_over_temp);
+			}else {
+				debounce_reset(&_charger_over_temp);
+			}
+			if (debounce_reach(&_charger_over_temp)){
+				_health.charger_over_temp = 1;
+				debounce_reset(&_charger_over_temp);
+			}			
+		}
+		if (!_health.charger_lower_temp){
+			if (_is_low_temp(charger_lower_low_temp)) {//低于允许的最低温度
+				debounce_inc(&_charger_lower_temp);
+			}else {
+				debounce_reset(&_charger_lower_temp);
+			}
+			if (debounce_reach(&_charger_lower_temp)) {
+				_health.charger_lower_temp = 1;
+				debounce_reset(&_charger_lower_temp);
+			}
+		}
+		if (_health.charger_over_temp || _health.charger_lower_temp) {
+			if (!_is_over_temp(charger_normal_high_temp) && !_is_low_temp(charger_normal_low_temp)){
+				debounce_inc(&_charger_normal_temp);
+			}else {
+				debounce_reset(&_charger_normal_temp);
+			}
+			if (debounce_reach(&_charger_normal_temp)){
+				_health.charger_over_temp = 0;
+				_health.charger_lower_temp = 0;
+				debounce_reset(&_charger_normal_temp);
+			}	
+		}
+	}else {
+		if (!_health.discharger_over_temp){
+			if (_is_over_temp(discharger_higher_high_temp)) {//超过允许的最高温度
+				debounce_inc(&_discharger_over_temp);
+			}else {
+				debounce_reset(&_discharger_over_temp);
+			}
+			if (debounce_reach(&_discharger_over_temp)){
+				_health.discharger_over_temp = 1;
+				debounce_reset(&_discharger_over_temp);
+			}			
+		}
+		if (!_health.discharger_lower_temp){
+			if (_is_over_temp(discharger_lower_low_temp)) {//超过允许的最高温度
+				debounce_inc(&_discharger_lower_temp);
+			}else {
+				debounce_reset(&_discharger_lower_temp);
+			}
+			if (debounce_reach(&_discharger_lower_temp)) {
+				_health.discharger_lower_temp = 1;
+				debounce_reset(&_discharger_lower_temp);
+			}
+		}
+		if (_health.discharger_over_temp || _health.discharger_lower_temp) {
+			if (!_is_over_temp(discharger_normal_high_temp) && !_is_low_temp(discharger_normal_low_temp)){
+				debounce_inc(&_discharger_normal_temp);
+			}else {
+				debounce_reset(&_discharger_normal_temp);
+			}
+			if (debounce_reach(&_discharger_normal_temp)){
+				_health.charger_over_temp = 0;
+				_health.charger_lower_temp = 0;
+				debounce_reset(&_discharger_normal_temp);
+			}	
+		}
+
+	}
+}

+ 29 - 0
Application/app/sox/health.h

@@ -0,0 +1,29 @@
+#ifndef _HEALTH_H__
+#define _HEALTH_H__
+#include <stdint.h>
+
+/* 
+ * xxx_over_temp: 表示过高温(温度过高)
+ * xxx_under_temp: 表示过低温(温度过低)
+*/
+typedef struct {
+	uint32_t charger_over_current:1;
+	uint32_t charger_over_temp:1;
+	uint32_t charger_lower_temp:1;
+	uint32_t discharger_over_temp:1;
+	uint32_t discharger_lower_temp:1;
+	uint32_t discharger_lower_voltage:1;
+	uint32_t powerdown_lower_voltage:1;
+	uint32_t small_current_short:1; //小电短路保护
+	uint32_t load_current_short:1; //大电短路保护
+}bms_health_t;
+
+
+bms_health_t *bms_health(void);
+void health_init(void);
+void check_current_state(void);
+void check_voltage_state(void);
+void check_temp_state(void);
+
+#endif /* _HEALTH_H__ */
+

+ 14 - 8
Application/app/sox/iostate.c

@@ -3,6 +3,8 @@
 #include "state.h"
 #include "state.h"
 #include "iostate.h"
 #include "iostate.h"
 
 
+static io_state_t _io_state;
+
 typedef struct io_timer{
 typedef struct io_timer{
 	shark_timer_t _timer;
 	shark_timer_t _timer;
 	u16           detect_cnt;
 	u16           detect_cnt;
@@ -21,10 +23,10 @@ static void io_timer_handler(shark_timer_t *t);
 
 
 
 
 void io_state_init(void){
 void io_state_init(void){
-	bms_state_get()->hall_detect = IS_HALL1_DETECTED()|| IS_HALL2_DETECTED();
-	bms_state_get()->charger_detect = IS_CHARGER_IN();
-	bms_state_get()->dcdc_good_detect= IS_DCDC_POWER_GOOD();
-	bms_state_get()->aux_lock_detect = IS_AUX_VOL_LOCKED();
+	_io_state.hall_detect = IS_HALL1_DETECTED()|| IS_HALL2_DETECTED();
+	_io_state.charger_detect = IS_CHARGER_IN();
+	_io_state.dcdc_good_detect= IS_DCDC_POWER_GOOD();
+	_io_state.aux_lock_detect = IS_AUX_VOL_LOCKED();
 	hall_io._timer.handler = io_timer_handler;
 	hall_io._timer.handler = io_timer_handler;
 	charger_io._timer.handler = io_timer_handler;
 	charger_io._timer.handler = io_timer_handler;
 	aux_short_io._timer.handler = io_timer_handler;
 	aux_short_io._timer.handler = io_timer_handler;
@@ -35,6 +37,10 @@ void io_state_init(void){
 	shark_timer_post(&dcdc_pwr_io._timer, io_detect_intv_time);
 	shark_timer_post(&dcdc_pwr_io._timer, io_detect_intv_time);
 }
 }
 
 
+io_state_t *io_state(void){
+	return &_io_state;
+}
+
 static int _get_io_value(io_timer_t *t){
 static int _get_io_value(io_timer_t *t){
 	if (t == &hall_io) {
 	if (t == &hall_io) {
 		return IS_HALL1_DETECTED()|| IS_HALL2_DETECTED();
 		return IS_HALL1_DETECTED()|| IS_HALL2_DETECTED();
@@ -54,20 +60,20 @@ static int _get_io_value(io_timer_t *t){
 static void _set_io_value(io_timer_t *t){
 static void _set_io_value(io_timer_t *t){
 	__disable_irq();
 	__disable_irq();
 	if (t == &hall_io) {
 	if (t == &hall_io) {
-		bms_state_get()->hall_detect = t->value;
+		_io_state.hall_detect = t->value;
 		hall_1_detect_irq_enable(1);
 		hall_1_detect_irq_enable(1);
 		hall_2_detect_irq_enable(1);
 		hall_2_detect_irq_enable(1);
 	}
 	}
 	if (t == &charger_io){
 	if (t == &charger_io){
-		bms_state_get()->charger_detect = t->value;
+		_io_state.charger_detect = t->value;
 		charger_detect_irq_enable(1);
 		charger_detect_irq_enable(1);
 	}
 	}
 	if (t == &aux_short_io){
 	if (t == &aux_short_io){
-		bms_state_get()->aux_lock_detect = t->value;
+		_io_state.aux_lock_detect = t->value;
 		small_current_short_irq_enable(1);
 		small_current_short_irq_enable(1);
 	}
 	}
 	if (t == &dcdc_pwr_io){
 	if (t == &dcdc_pwr_io){
-		bms_state_get()->dcdc_good_detect = t->value;
+		_io_state.dcdc_good_detect = t->value;
 		dcdc_pwr_detect_irq_enable(1);
 		dcdc_pwr_detect_irq_enable(1);
 	}
 	}
 	/* 可以解决丢中断的风险,如果开启中断的过程中,来IO中断,这个中断可能会被丢弃,
 	/* 可以解决丢中断的风险,如果开启中断的过程中,来IO中断,这个中断可能会被丢弃,

+ 9 - 0
Application/app/sox/iostate.h

@@ -1,7 +1,16 @@
 #ifndef _IO_state_H__
 #ifndef _IO_state_H__
 #define _IO_state_H__
 #define _IO_state_H__
 
 
+typedef struct{
+	uint16_t hall_detect:1;
+	uint16_t charger_detect :1;
+	uint16_t aux_lock_detect:1;
+	uint16_t pwr_good_detect:1;
+	uint16_t dcdc_good_detect:1;
+}io_state_t;
+
 void io_state_init(void);
 void io_state_init(void);
+io_state_t *io_state(void);
 
 
 #endif /* _IO_state_H__ */
 #endif /* _IO_state_H__ */
 
 

+ 2 - 2
Application/app/sox/measure.c

@@ -90,7 +90,7 @@ void current_calibrate(void){
 }
 }
 
 
 
 
-void measure_system_init(void){
+void measure_adc_init(void){
 	ml5238_init();
 	ml5238_init();
 	adc_init();
 	adc_init();
 	current_calibrate();
 	current_calibrate();
@@ -172,7 +172,7 @@ int get_pcb_temperature(void){
 }
 }
 
 
 /*
 /*
- * index : 0...2
+ * index : 0...3, 3 indicat pcb temp
 */
 */
 int get_pack_temperature(int index){
 int get_pack_temperature(int index){
 	TEMP_OPEN(1);
 	TEMP_OPEN(1);

+ 1 - 1
Application/app/sox/measure.h

@@ -1,6 +1,6 @@
 #ifndef _IV_Measure_H__
 #ifndef _IV_Measure_H__
 #define _IV_Measure_H__
 #define _IV_Measure_H__
-void measure_system_init(void);
+void measure_adc_init(void);
 void adc_select_for_pack_current(int adc);
 void adc_select_for_pack_current(int adc);
 float get_pack_current(void);
 float get_pack_current(void);
 float get_cell_voltage(int cell);
 float get_cell_voltage(int cell);

+ 96 - 0
Application/app/sox/measure_task.c

@@ -0,0 +1,96 @@
+#include "bsp/gpio.h"
+#include "app/sox/measure.h"
+#include "libs/shark_task.h"
+#include "measure_task.h"
+
+static measure_value_t _measure_value;
+static measure_notify _current_notify;
+static measure_notify _voltage_notify;
+static measure_notify _temperature_notify;
+
+/* 测量task,用来定时测量电流,电压,温度等adc数据 */
+struct means_task {
+	shark_task_t _task;
+	u32 delay;
+	u8  index;
+};
+static void init_pack_current_task(void);
+static void init_cell_task(void);
+static void init_temp_task(void);
+
+void measure_task_init(measure_notify cn, measure_notify vn, measure_notify tn){
+	_current_notify = cn;
+	_voltage_notify = vn;
+	_temperature_notify = tn;
+	measure_adc_init();
+	init_pack_current_task();
+	init_cell_task();
+	init_temp_task();
+}
+
+measure_value_t * measure_value(void){
+	return &_measure_value;
+}
+
+/*
+ * 测量总电流,放电和充电
+*/
+static struct means_task _pack_current_task;
+static u32 pack_current_task_handler(void);
+static void init_pack_current_task(void){
+	_pack_current_task._task.handler = pack_current_task_handler;
+	_pack_current_task.delay = 100;
+	_pack_current_task.index = 0;
+	_measure_value.load_current = get_pack_current();
+	shark_task_add(&_pack_current_task._task);
+}
+
+static u32 pack_current_task_handler(void){
+	_measure_value.load_current = get_pack_current();
+	_current_notify();//通知bms state 有新的电流数据
+	return _pack_current_task.delay;
+}
+
+/*
+ * 测量电芯电压,计算出总电压
+*/
+static struct means_task _cell_task;
+static u32 cell_task_handler(void);
+static void init_cell_task(void){
+	_cell_task._task.handler = cell_task_handler;
+	_cell_task.delay = 60;
+	_cell_task.index = 0;
+	for (int i = 0; i < CELLS_NUM; i++){
+		_measure_value.cell_vol[i] = get_cell_voltage(i);
+	}
+	shark_task_add(&_cell_task._task);
+}
+
+static u32 cell_task_handler(void){
+	_measure_value.cell_vol[_cell_task.index] = get_cell_voltage(_cell_task.index);
+	_cell_task.index = (_cell_task.index + 1) % CELLS_NUM;
+	_voltage_notify();//通知bms state 有新的电压数据
+	return _cell_task.delay;
+}
+
+/*
+ * 测量4个温度
+*/
+static struct means_task _temp_task;
+static u32 temp_task_handler(void);
+static void init_temp_task(void){
+	_temp_task._task.handler = temp_task_handler;
+	_temp_task.delay = 5 * 1000;
+	_temp_task.index = 0;
+	for (int i = 0; i < PACK_TEMPS_NUM; i++){
+		_measure_value.pack_temp[i] = get_pack_temperature(i);
+	}
+	shark_task_add(&_temp_task._task);
+}
+static u32 temp_task_handler(void){
+	_measure_value.pack_temp[_temp_task.index] = get_pack_temperature(_temp_task.index);
+	_temp_task.index = (_temp_task.index + 1) % (PACK_TEMPS_NUM + 1);
+	_temperature_notify();//通知bms state 有新的温度数据
+	return _temp_task.delay;
+}
+

+ 16 - 0
Application/app/sox/measure_task.h

@@ -0,0 +1,16 @@
+#ifndef _Measure_Task_H__
+#define _Measure_Task_H__
+
+typedef struct{
+	float small_current;
+	float load_current;//may be discharger or charger current
+	int      pack_temp[PACK_TEMPS_NUM];
+	uint16_t cell_vol[CELLS_NUM]; //mV
+}measure_value_t;
+typedef void (*measure_notify)(void);
+
+void measure_task_init(measure_notify cn, measure_notify vn, measure_notify tn);
+measure_value_t * measure_value(void);
+
+#endif /* _Measure_Task_H__ */
+

+ 61 - 71
Application/app/sox/state.c

@@ -1,96 +1,86 @@
 #include "bsp/gpio.h"
 #include "bsp/gpio.h"
+#include "bsp/ml5238.h"
 #include "app/sox/measure.h"
 #include "app/sox/measure.h"
+#include "app/sox/measure_task.h"
 #include "libs/shark_task.h"
 #include "libs/shark_task.h"
+#include "health.h"
 #include "state.h"
 #include "state.h"
 #include "iostate.h"
 #include "iostate.h"
 
 
 static bms_state_t _bms_state;
 static bms_state_t _bms_state;
-
-struct means_task {
-	shark_task_t _task;
-	u32 delay;
-	u8  index;
-};
-static void init_pack_current_task(void);
-static void init_cell_task(void);
-static void init_temp_task(void);
+static void _current_notify(void);
+static void _voltage_notify(void);
+static void _temperature_notify(void);
 
 
 void bms_state_init(void){
 void bms_state_init(void){
-	measure_system_init();
-	adc_select_for_pack_current(CS1180_ADC);
-	init_pack_current_task();
-	init_cell_task();
-	init_temp_task();
+	measure_task_init(_current_notify, _voltage_notify, _temperature_notify);
 	io_state_init();
 	io_state_init();
+	health_init();
 }
 }
 
 
-bms_state_t * bms_state_get(void){
+bms_state_t *bms_state_get(void){
 	return &_bms_state;
 	return &_bms_state;
 }
 }
 
 
-/***********************************************************************/
-static struct means_task _pack_current_task;
-static u32 pack_current_task_handler(void);
-static void init_pack_current_task(void){
-	_pack_current_task._task.handler = pack_current_task_handler;
-	_pack_current_task.delay = 100;
-	_pack_current_task.index = 0;
-	shark_task_add(&_pack_current_task._task);
-}
+static debounce_t _charging_detect = {
+	.count = 0,
+	.max_count = 10
+};
+static void check_charging(){
+	if (bms_health()->charger_over_current || bms_health()->load_current_short) {
+		ml5238_enable_discharger_mosfet(0);
+		ml5238_enable_charger_mosfet(0); //disable charger mosfet
+		_bms_state.charging = 0;
+		return;
+	}	
+	if (!_bms_state.charging) {
+		if (measure_value()->load_current >= MIN_START_CHARGER_CURRENT) {
+			_charging_detect.count ++;
+		}else {
+			_charging_detect.count = 0;
+		}
+		if (debounce_reach(&_charging_detect)){
+			_bms_state.charging = 1;
+			_bms_state.discharging = 0;
+			_charging_detect.count = 0;
+		}
+	}else {
+		if (measure_value()->load_current <= MIN_START_LOADING_CURRENT) {
+			_charging_detect.count ++;
+		}else {
+			_charging_detect.count = 0;
+		}
+		if (debounce_reach(&_charging_detect)){
+			_bms_state.charging = 0;
+			_bms_state.discharging = 1;
+			_charging_detect.count = 0;
+		}
+	}
 
 
-static u32 pack_current_task_handler(void){
-	_bms_state.load_current = get_pack_current();
-	return _pack_current_task.delay;
-}
-/***********************************************************************/
-static struct means_task _cell_task;
-static u32 cell_task_handler(void);
-static void init_cell_task(void){
-	_cell_task._task.handler = cell_task_handler;
-	_cell_task.delay = 60;
-	_cell_task.index = 0;
-	shark_task_add(&_cell_task._task);
 }
 }
 
 
-static u32 cell_task_handler(void){
-	_bms_state.cell_vol[_cell_task.index] = get_cell_voltage(_cell_task.index);
-	_cell_task.index = (_cell_task.index + 1) % CELLS_NUM;
-	
-	return _cell_task.delay;
+static void _current_notify(void){
+	check_current_state(); //check health of current
+	check_charging();
 }
 }
 
 
-/***********************************************************************/
-static struct means_task _temp_task;
-static u32 temp_task_handler(void);
-static void init_temp_task(void){
-	_temp_task._task.handler = temp_task_handler;
-	_temp_task.delay = 5 * 1000;
-	_temp_task.index = 0;
-	_bms_state.pcb_temp = 0xFF;
-	_bms_state.pack_temp[0] = 0xFF;
-	_bms_state.pack_temp[1] = 0xFF;
-	_bms_state.pack_temp[2] = 0xFF;
-	shark_task_add(&_temp_task._task);
+/* 充电电流小于一定值,认为充满的时候,需要检查电芯的电压,如果发现有电芯电压过低,需要开启被动均衡 */
+static void check_cell_balance(void){
+
 }
 }
-static u32 temp_task_handler(void){
-	switch(_temp_task.index) {
-		case 0:
-			_bms_state.pcb_temp = get_pcb_temperature();
-			break;
-		case 1:
-		case 2:
-		case 3:
-			_bms_state.pack_temp[_temp_task.index - 1] = get_pack_temperature(_temp_task.index - 1);
-			break;
-		default:
-			break;
-	}
 
 
-	_temp_task.index = (_temp_task.index + 1) % (PACK_TEMPS_NUM + 1);
-	if (_bms_state.pack_temp[0] == 0xFF || _bms_state.pack_temp[0] == 0xFF || _bms_state.pack_temp[1] == 0xFF
-		|| _bms_state.pack_temp[2] == 0xFF){
-		return 0;//read all temps ASAP
+
+static void _voltage_notify(void){
+	uint16_t voltage = 0;
+	for (int i = 0; i < CELLS_NUM; i++){
+		voltage += measure_value()->cell_vol[i];
 	}
 	}
-	return _temp_task.delay;
+	_bms_state.pack_voltage = voltage;
+	check_voltage_state(); //check health of cell voltage
+	check_cell_balance();
+}
+
+static void _temperature_notify(void){
+	check_temp_state(); //check health of cell/pcb temperature
 }
 }
 
 

+ 33 - 16
Application/app/sox/state.h

@@ -1,32 +1,49 @@
 #ifndef _BMS_STATE_H__
 #ifndef _BMS_STATE_H__
 #define _BMS_STATE_H__
 #define _BMS_STATE_H__
 #include "bsp/shark_bsp.h"
 #include "bsp/shark_bsp.h"
+#include "libs/shark_libs.h"
+#ifndef BIT
+#define BIT(x)                       ((uint32_t)((uint32_t)0x01U<<(x)))
+#endif
+#ifndef BITS
+#define BITS(start, end)             ((0xFFFFFFFFUL << (start)) & (0xFFFFFFFFUL >> (31U - (uint32_t)(end))))
+#endif
 
 
 #define BATT_USED_BY_NONE       0
 #define BATT_USED_BY_NONE       0
 #define BATT_USED_BY_MOTOR_BIKE 1
 #define BATT_USED_BY_MOTOR_BIKE 1
 #define BATT_USED_BY_CHARGER_DOCKER 2
 #define BATT_USED_BY_CHARGER_DOCKER 2
 #define HATT_USED_BY_CHARGER_BOX 3
 #define HATT_USED_BY_CHARGER_BOX 3
 
 
+#define MIN_START_CHARGER_CURRENT 100 //ma, 如果有正向超过 MIN_START_CHARGER_CURRENT的电流,认为在充电
+#define MIN_START_LOADING_CURRENT 2  //ma, 如果有反向小于 MIN_START_LOADING_CURRENT的电流,认为在放电
 typedef struct{
 typedef struct{
-	uint32_t hall_detect:1;
-	uint32_t charger_detect :1;
-	uint32_t aux_lock_detect:1;
-	uint32_t pwr_good_detect:1;
-	uint32_t dcdc_good_detect:1;
-	uint32_t discharging :1;
-	uint32_t charging: 1;
-	uint32_t pack_balancing:1;
-	uint32_t mosfet_charger:1; //charger MOS open/close, synced with 5238
-	uint32_t mosfet_discharger:1; //discharger MOS open/close, synced with 5238
-	uint32_t small_current_switch:1;
-	float small_current;
-	float load_current;//may be discharger or charger current
-	int      pcb_temp;
-	int      pack_temp[PACK_TEMPS_NUM];
-	uint16_t cell_vol[CELLS_NUM]; //mV
+	uint16_t discharging :1;
+	uint16_t charging: 1;
+	uint16_t pack_balancing:1;
+	uint16_t pack_voltage; //电池包的总电压
 	int      used_by;//where this battery is used for: on motor, on charger docker, on charger box, NONE
 	int      used_by;//where this battery is used for: on motor, on charger docker, on charger box, NONE
+	int      user_request;
 }bms_state_t;
 }bms_state_t;
 
 
+#define USER_REQUEST_CHARGER BIT(0)
+#define USER_REQUEST_DISCHARGER BIT(1)
+#define USER_REQUEST_SMALLCURRENT BIT(2)
+
+typedef struct {
+	shark_timer_t _timer;
+	int count;
+	int max_count;
+	int interval;
+}debounce_timer_t;
+
+typedef struct {
+	int count;
+	int max_count;
+}debounce_t;
+
+#define debounce_reach(dt) ((dt)->count >= (dt)->max_count)
+#define debounce_reset(dt) ((dt)->count = 0)
+#define debounce_inc(dt) ((dt)->count++)
 void bms_state_init(void);
 void bms_state_init(void);
 bms_state_t * bms_state_get(void);
 bms_state_t * bms_state_get(void);
 
 

+ 1 - 1
Application/bsp/gd32_adc.h

@@ -8,7 +8,7 @@
 #define ADC_CHAN_TEMPERATURE_1 ADC_CHANNEL_4
 #define ADC_CHAN_TEMPERATURE_1 ADC_CHANNEL_4
 #define ADC_CHAN_TEMPERATURE_2 ADC_CHANNEL_5
 #define ADC_CHAN_TEMPERATURE_2 ADC_CHANNEL_5
 #define ADC_CHAN_TEMPERATURE_3 ADC_CHANNEL_6
 #define ADC_CHAN_TEMPERATURE_3 ADC_CHANNEL_6
-#define ADC_CHAN_TEMPERATURE_4 ADC_CHANNEL_7
+#define ADC_CHAN_TEMPERATURE_4 ADC_CHANNEL_7 /* pcb temp */
 
 
 #define ADC_WORK_IDLE 0
 #define ADC_WORK_IDLE 0
 #define ADC_WORK_ING 1
 #define ADC_WORK_ING 1

+ 156 - 7
Application/bsp/ml5238.c

@@ -1,29 +1,136 @@
 #include <string.h>
 #include <string.h>
+#include "libs/shark_libs.h"
 #include "spi.h"
 #include "spi.h"
 #include "ml5238.h"
 #include "ml5238.h"
 
 
+static shark_timer_t irq_task;
 
 
 
 
 static int ml5238_read(uint8_t regaddr, uint8_t *data);
 static int ml5238_read(uint8_t regaddr, uint8_t *data);
+static void ml5238_clear_bits(uint8_t regaddr, uint8_t bit);
+static void ml5238_set_bits(uint8_t regaddr, uint8_t bit);
 
 
-
+static void irq_hander_in_timer(shark_timer_t *timer);
+static ml5238_notify_hander _handler;
 void ml5238_init(void){
 void ml5238_init(void){
 	spi0_init();
 	spi0_init();
 	ml5238_softreset();
 	ml5238_softreset();
+	irq_task.handler = irq_hander_in_timer;
+}
+
+void ml5238_register_notify_handler(ml5238_notify_hander handler){
+	_handler = handler;
+}
+
+
+//used to detect charger over current
+int ml5238_charger_is_open(void){
+	uint8_t value = 0;
+	ml5238_read(ML5238_PSENSE, &value);
+	return !(value & PSENSE_PSL);
+}
+
+int ml5238_enable_load_detect(int enable){
+
+	ml5238_clear_bits(ML5238_RSENSE, RSENSE_RRS);
+	if (enable){
+		ml5238_set_bits(ML5238_RSENSE, RSENSE_ERS);
+	}else {
+		ml5238_clear_bits(ML5238_RSENSE, RSENSE_ERS | RSENSE_IRS);
+	}
+	return 0;
+}
+
+int ml5238_is_load_disconnect(void){
+	uint8_t value = 0;
+	ml5238_read(ML5238_RSENSE, &value);
+	return (value & RSENSE_RS);
 }
 }
 
 
+#define IRS_IRQ 1 //load disconnectÖжÏ
+#define IPSL_IRQ 2 //charger over current
+#define ICS_IRQ 3 //¶Ì·ÖжÏ
+
+int ml5238_enable_irq(int enable, int irq){
+	if (irq == IRS_IRQ){
+		ml5238_clear_bits(ML5238_RSENSE, RSENSE_RRS);
+		if (enable){
+			ml5238_set_bits(ML5238_RSENSE, RSENSE_IRS);
+		}else {
+			ml5238_clear_bits(ML5238_RSENSE, RSENSE_IRS);
+		}
+	}
+	if (irq == IPSL_IRQ){
+		ml5238_clear_bits(ML5238_PSENSE, PSENSE_RPSL);
+		if (enable){
+			ml5238_set_bits(ML5238_PSENSE, PSENSE_IPSL);
+		}else {
+			ml5238_clear_bits(ML5238_PSENSE, PSENSE_IPSL);
+		}
+	}
+	if (irq == ICS_IRQ){
+		ml5238_clear_bits(ML5238_RSENSE, RSENSE_RSC);
+		if (enable){
+			ml5238_set_bits(ML5238_RSENSE, RSENSE_ISC);
+		}else {
+			ml5238_clear_bits(ML5238_RSENSE, RSENSE_ISC);
+		}
+	}
+	return 0;
+}
+
+int ml5238_enable_charger_detect(int enable){
+	uint8_t fet = 0;
+	ml5238_read(ML5238_FET, &fet);
+	if (fet & FET_DF){ //discharger is on, used to detect charger over current
+		ml5238_clear_bits(ML5238_PSENSE, PSENSE_RPSL);
+		if (enable){
+			ml5238_set_bits(ML5238_PSENSE, PSENSE_EPSL);
+		}else {
+			ml5238_clear_bits(ML5238_PSENSE, PSENSE_EPSL);
+		}
+	}else { //discharger if off, used when powerdown, charger is insert
+		ml5238_clear_bits(ML5238_PSENSE, PSENSE_RPSH);
+		if (enable){
+			ml5238_set_bits(ML5238_PSENSE, PSENSE_EPSH);
+		}else {
+			ml5238_clear_bits(ML5238_PSENSE, PSENSE_EPSH);
+		}
+	}
+	return 0;
+}
+
+static int __inline__ _charger_mosfet_is_open(void){
+	uint8_t data;
+	ml5238_read(ML5238_FET, &data);
+	return (data & FET_CF) != 0;
+}
+
+static int __inline__ _discharger_mosfet_is_open(void){
+	uint8_t data;
+	ml5238_read(ML5238_FET, &data);
+	return (data & FET_DF) != 0;
+}
+
+void ml5238_cell_start_balance(uint16_t *vcell, int cell_num){
+	
+}
+
+void ml5238_cell_stop_balance(void){
+
+}
 
 
 int ml5238_enable_discharger_mosfet(int enable){
 int ml5238_enable_discharger_mosfet(int enable){
 	uint8_t data;
 	uint8_t data;
 	if (ml5238_read(ML5238_FET, &data) == 0){
 	if (ml5238_read(ML5238_FET, &data) == 0){
-		if (data & FET_DF == enable){
+		if ((data & FET_DF) == enable){
 			return 0; //alread enable/disabled
 			return 0; //alread enable/disabled
 		}
 		}
 		data &= ~(FET_DF);
 		data &= ~(FET_DF);
 		if (enable){
 		if (enable){
 			data |= (FET_DF | FET_DRV);
 			data |= (FET_DF | FET_DRV);
 		}else {
 		}else {
-			if (data & FET_CF == 0){
+			if ((data & FET_CF) == 0){
 				data &= ~(FET_DRV);
 				data &= ~(FET_DRV);
 			}
 			}
 		}
 		}
@@ -43,7 +150,7 @@ int ml5238_enable_charger_mosfet(int enable){
 		if (enable){
 		if (enable){
 			data |= (FET_CF | FET_DRV);
 			data |= (FET_CF | FET_DRV);
 		}else {
 		}else {
-			if (data & FET_DF == 0){
+			if ((data & FET_DF) == 0){
 				data &= ~(FET_DRV);
 				data &= ~(FET_DRV);
 			}
 			}
 		}
 		}
@@ -62,15 +169,16 @@ int ml5238_short_current_detect(int mode){
 					return 0; //already enabled short current detect
 					return 0; //already enabled short current detect
 				}
 				}
 				rsense |= (RSENSE_ESC | RSENSE_ISC);//enable short current detect && irq
 				rsense |= (RSENSE_ESC | RSENSE_ISC);//enable short current detect && irq
+				rsense &= ~RSENSE_RSC;
 				return ml5238_write(ML5238_SETSC, rsense);
 				return ml5238_write(ML5238_SETSC, rsense);
 			}
 			}
 		}
 		}
 	}else {
 	}else {
 		if (ml5238_read(ML5238_RSENSE, &rsense) == 0){
 		if (ml5238_read(ML5238_RSENSE, &rsense) == 0){
-			if (rsense & RSENSE_ESC == 0){
+			if ((rsense & RSENSE_ESC) == 0){
 				return 0; //already disabled 
 				return 0; //already disabled 
 			}
 			}
-			rsense &= ~(RSENSE_ESC|RSENSE_ISC);
+			rsense &= ~(RSENSE_ESC|RSENSE_ISC|RSENSE_RSC);
 			return ml5238_write(ML5238_SETSC, rsense);
 			return ml5238_write(ML5238_SETSC, rsense);
 		}
 		}
 	}
 	}
@@ -87,8 +195,49 @@ void ml5238_softreset(void)
 	}
 	}
 }
 }
 
 
+static void __inline__ call_handler(int event){
+	if (_handler) {
+		_handler(event);
+	}
+}
+
+static void irq_hander_in_timer(shark_timer_t *timer){
+	uint8_t status = 0;
+	ml5238_read(ML5238_STATUS, &status);
+	if (status & STATUS_RPSL){//chargering over current
+		ml5238_enable_charger_detect(0);
+		call_handler(ML5238_Event_Charger_Over_Current);
+	}
+	if (status & STATUS_RSC) { //short current detect, close charger/discharger mosfet
+		if (_charger_mosfet_is_open()) {
+			ml5238_enable_charger_mosfet(0);
+		}
+		if (_discharger_mosfet_is_open()) {
+			ml5238_enable_discharger_mosfet(0);
+		}
+		ml5238_enable_irq(0, ICS_IRQ); //disable short current detect
+		call_handler(ML5238_Event_Short_Current);
+	}
+	if (status & STATUS_RRS) {//load disconnect, if short detect, we must wait load disconnected, and then can open discharger
+		ml5238_enable_irq(0, IRS_IRQ);
+		call_handler(ML5238_Event_Load_Disconnect);
+	}
+}
+
 void ml5238_irq_handler(void){
 void ml5238_irq_handler(void){
-	
+	shark_timer_post(&irq_task, 0);
+}
+
+static void ml5238_set_bits(uint8_t regaddr, uint8_t bit) {
+	uint8_t value;
+	ml5238_read(regaddr, &value);
+	ml5238_write(regaddr, value|bit);
+}
+
+static void ml5238_clear_bits(uint8_t regaddr, uint8_t bit) {
+	uint8_t value;
+	ml5238_read(regaddr, &value);
+	ml5238_write(regaddr, value&(~bit));
 }
 }
 
 
 
 

+ 8 - 0
Application/bsp/ml5238.h

@@ -6,7 +6,15 @@ void ml5238_softreset(void);
 int ml5238_enable_discharger_mosfet(int enable);
 int ml5238_enable_discharger_mosfet(int enable);
 int ml5238_enable_charger_mosfet(int enable);
 int ml5238_enable_charger_mosfet(int enable);
 int ml5238_short_current_detect(int mode);
 int ml5238_short_current_detect(int mode);
+int ml5238_is_load_disconnect(void);
+int ml5238_enable_load_detect(int enable);
 
 
+typedef void (*ml5238_notify_hander)(int event);
+void ml5238_register_notify_handler(ml5238_notify_hander handler);
+
+#define ML5238_Event_Charger_Over_Current 1
+#define ML5238_Event_Short_Current 2
+#define ML5238_Event_Load_Disconnect 3
 
 
 #define SHORT_CURRENT_MODE_DISABLE -1
 #define SHORT_CURRENT_MODE_DISABLE -1
 #define SHORT_CURRENT_MODE_33_3A 0
 #define SHORT_CURRENT_MODE_33_3A 0

+ 4 - 4
Application/bsp/ml5238_reg.h

@@ -102,10 +102,10 @@
 #define STATUS_CF	(0x02u)
 #define STATUS_CF	(0x02u)
 #define STATUS_PSV	(0x04u)
 #define STATUS_PSV	(0x04u)
 #define STATUS_INT	(0x08u)
 #define STATUS_INT	(0x08u)
-#define STATUS_RPSL	(0x10u)
-#define STATUS_RPSH	(0x20u)
-#define STATUS_RRS	(0x40u)
-#define STATUS_RSC	(0x80u)
+#define STATUS_RPSL	(0x10u) /* charger disconnecting for charger over-current */
+#define STATUS_RPSH	(0x20u) /* charger disconnecring for power down*/
+#define STATUS_RRS	(0x40u) /* load disconnect */
+#define STATUS_RSC	(0x80u) /* short current detect*/
 
 
 /**********************************
 /**********************************
            CBALH(0x08)
            CBALH(0x08)

+ 1 - 1
Application/bsp/shark_bsp.h

@@ -26,7 +26,7 @@
 
 
 
 
 #define CELLS_NUM 15
 #define CELLS_NUM 15
-#define PACK_TEMPS_NUM 3
+#define PACK_TEMPS_NUM 4
 
 
 #define GD32_ADC 1
 #define GD32_ADC 1
 #define CS1180_ADC 2
 #define CS1180_ADC 2

+ 24 - 0
Project/SP700.uvoptx

@@ -783,6 +783,30 @@
       <RteFlg>0</RteFlg>
       <RteFlg>0</RteFlg>
       <bShared>0</bShared>
       <bShared>0</bShared>
     </File>
     </File>
+    <File>
+      <GroupNumber>6</GroupNumber>
+      <FileNumber>44</FileNumber>
+      <FileType>1</FileType>
+      <tvExp>0</tvExp>
+      <tvExpOptDlg>0</tvExpOptDlg>
+      <bDave2>0</bDave2>
+      <PathWithFileName>..\Application\app\sox\measure_task.c</PathWithFileName>
+      <FilenameWithoutPath>measure_task.c</FilenameWithoutPath>
+      <RteFlg>0</RteFlg>
+      <bShared>0</bShared>
+    </File>
+    <File>
+      <GroupNumber>6</GroupNumber>
+      <FileNumber>45</FileNumber>
+      <FileType>1</FileType>
+      <tvExp>0</tvExp>
+      <tvExpOptDlg>0</tvExpOptDlg>
+      <bDave2>0</bDave2>
+      <PathWithFileName>..\Application\app\sox\health.c</PathWithFileName>
+      <FilenameWithoutPath>health.c</FilenameWithoutPath>
+      <RteFlg>0</RteFlg>
+      <bShared>0</bShared>
+    </File>
   </Group>
   </Group>
 
 
 </ProjectOpt>
 </ProjectOpt>

+ 10 - 0
Project/SP700.uvprojx

@@ -623,6 +623,16 @@
               <FileType>1</FileType>
               <FileType>1</FileType>
               <FilePath>..\Application\app\sox\measure.c</FilePath>
               <FilePath>..\Application\app\sox\measure.c</FilePath>
             </File>
             </File>
+            <File>
+              <FileName>measure_task.c</FileName>
+              <FileType>1</FileType>
+              <FilePath>..\Application\app\sox\measure_task.c</FilePath>
+            </File>
+            <File>
+              <FileName>health.c</FileName>
+              <FileType>1</FileType>
+              <FilePath>..\Application\app\sox\health.c</FilePath>
+            </File>
           </Files>
           </Files>
         </Group>
         </Group>
       </Groups>
       </Groups>