#include "measure.h" #include "bsp/ml5238.h" #include "bsp/cs1180.h" #include "bsp/gd32_adc.h" #include "bsp/clock.h" #include "bsp/gpio.h" #include "bsp/temp_lookup_tab.h" #include "bsp/shark_bsp.h" #include "libs/logger.h" #include "Least_Square.h" #include "app/sox/state.h" /* measure the temp & current & voltage for battery pack by using * ms5238 & cs1180(only used when bms is in small current loading) */ /* 1. 小电流 cs1180(32x):0.305-0.315, 0.277-0.286, 0.255-0.264, 0.220-0.228, 0.184-0.190, 0.137-0.142, 0.062-0.064, 0.011-0.009:0.012 ml5289(50x):0.307-0.313:0.330,0.277-0.275:0.290,0.254-0.251:0.271,0.221-0.208:0.253,0.183-0.170:0.196,0.136-0.121:0.155,0.061-0.072:0.096, 0.011-0.033:0.060 2. 大电流 cs1180(32x):1.861-2.082 ml5238(50x):1.869-1.865-1.890 */ /* this is the inited gain set to the ms5238, but the really gain is calibrated * by measure_system_calibrate */ static float imon_gain_10x = 10.0f; static float imon_gain_50x = 50.0f; static float imon_gain_now; static float vim0_10x = 0.0f; static float vim0_50x = 0.0f; static float vim0_now; static linear_ceoff_t ml5238_10x_ceoff = {.Ka = 1.0f, .Cb = 0.0f}; static linear_ceoff_t ml5238_50x_ceoff = {.Ka = 1.0f, .Cb = 0.0f}; static linear_ceoff_t ml5238_now_ceoff; static linear_ceoff_t cs1180_ceoff = {.Ka = 1.0f, .Cb = 0.0f}; #define gain_default_50x 1 #define CS1180_MAX_CURRENT 4500 //MA, cs1180的最大电流,超过这个使用ML5238 #define r_pcb_resistor 0.0f // pcb resistor static const float r_sense = r_resistor + r_pcb_resistor; static const float v_gd_ref = 3300.0f; //adc ref = 3.3v static const float max_gd_adc = 4095.0f;//65536.0f; static const float v_cs1180_ref = 1235.0f;//cs1180 vref = 1.235v static const float max_cs1180_adc = 0x7FFFF;// static const float small_cur_r_sense = 0.360f;//欧姆 static least_square_t adc_cali[2]; // y = ax + b #define GD32_ADC_READ_TIMES 128 static void __inline__ select_gain_10x(int select){ if (select){ ML5238_IMON_OUT_10X(); imon_gain_now = imon_gain_10x; vim0_now = vim0_10x; ml5238_now_ceoff = ml5238_10x_ceoff; }else { ML5238_IMON_OUT_50X(); imon_gain_now = imon_gain_50x; vim0_now = vim0_50x; ml5238_now_ceoff = ml5238_50x_ceoff; } } static int __inline__ _is_x10_gain(void){ return imon_gain_now == imon_gain_10x; } float get_ml5238_gain(void){ return imon_gain_now; } float get_ml5238_vos(void){ return vim0_now; } static void current_10x_calibrate(void){ /* calibrate the 10x gain */ ML5238_IMON_OUT_ZERO_10X(); vim0_10x = adc_sample_avg(ADC_CHAN_IMON, GD32_ADC_READ_TIMES); #if 0 ML5238_IMON_OUT_V2000_10X(); float vim1 = adc_sample_avg(ADC_CHAN_IMON, GD32_ADC_READ_TIMES); ML5238_IMON_OUT_V100_10X(); float vr = adc_sample_avg(ADC_CHAN_IMON, GD32_ADC_READ_TIMES); imon_gain_10x = ML5238_GAIN(vim0_10x, vim1, vr); #else imon_gain_10x = 10.0f; #endif } static void current_50x_calibrate(void){ /* calibrate the 50x gain */ ML5238_IMON_OUT_ZERO_50X(); vim0_50x = adc_sample_avg(ADC_CHAN_IMON, GD32_ADC_READ_TIMES); #if 0 ML5238_IMON_OUT_V2000_50X(); float vim1 = adc_sample_avg(ADC_CHAN_IMON, GD32_ADC_READ_TIMES); ML5238_IMON_OUT_V20_50X(); float vr = adc_sample_avg(ADC_CHAN_IMON, GD32_ADC_READ_TIMES); imon_gain_50x = ML5238_GAIN(vim0_50x, vim1, vr) * 0.948f; #else imon_gain_50x = 50.0f; #endif } /*calibrate when startup && temperature is changed more than 5? degree * calibrate the ms5238's IMON output voltage gain */ void current_calibrate(void){ current_10x_calibrate(); current_50x_calibrate(); #ifdef gain_default_50x select_gain_10x(0); #else select_gain_10x(1); #endif } void measure_adc_init(void){ ml5238_init(); gd32_adc_init(); current_calibrate(); cs1180_adc_init(); } static float get_current_by_ml5238(void){ float adc = adc_sample_avg(ADC_CHAN_IMON, GD32_ADC_READ_TIMES); float cali_adc = ML5238_V_RSENSER(adc, vim0_now, imon_gain_now); return (int)((cali_adc / max_gd_adc) * v_gd_ref / r_sense * 1000); } /* get battery pack's current (mA) */ static float get_pack_current_by_gd(void){ float adc = adc_sample_avg(ADC_CHAN_IMON, GD32_ADC_READ_TIMES); if (adc >= (max_gd_adc - 255.0f) && (!_is_x10_gain())){//overflow, use 10x gain select_gain_10x(1); adc = adc_sample_avg(ADC_CHAN_IMON, GD32_ADC_READ_TIMES); }else if (abs(adc - vim0_now) <= 255.0f && (_is_x10_gain())){// is too small, select 50x gain select_gain_10x(0); adc = adc_sample_avg(ADC_CHAN_IMON, GD32_ADC_READ_TIMES); } float cali_adc = ML5238_V_RSENSER(adc, vim0_now, imon_gain_now); return (int)((cali_adc / max_gd_adc) * v_gd_ref / r_sense * 1000); } static float get_pack_current_by_cs1180(int *valid){ float adc = cs1180_adc_sample(valid); float vol = (adc / max_cs1180_adc) * v_cs1180_ref; return (vol / r_sense) * 1000 - 5.0f;//板子固定5MA,cs1180无法测量到 } static __inline__ float get_caliberated_current(linear_ceoff_t *cof, float x) { return (x * cof->Ka) + cof->Cb; } float get_pack_current(int *current_5238){ float current = get_pack_current_by_gd(); current = get_caliberated_current(&ml5238_now_ceoff, current); if (current_5238 != NULL){ *current_5238 = (int)current; } if (cs1180_change_gain(current) == 1) { int valid = 1; float cs1180_current = get_pack_current_by_cs1180(&valid); if (valid == 1) { current = get_caliberated_current(&cs1180_ceoff, cs1180_current); } } return current; } /* get cell's voltage (mV) */ float get_cell_voltage(int cell){ ML5238_SELECT_CELL(cell); delay_us(100); float adc = adc_sample_avg(ADC_CHAN_VMON, GD32_ADC_READ_TIMES); return cell_real_vol((adc / max_gd_adc) * v_gd_ref); } /* get battery pack's aux current (MA) */ float get_small_current(void){ float adc = adc_sample_avg(ADC_CHAN_AUX_CURR, 16); return ((adc / max_gd_adc * v_gd_ref)) / small_cur_r_sense; } /* 用来判断小电流的情况下,电压小于某一个值认为小电流真正短路,比如16v*/ float get_small_current_voltage(void){ float s_current_a = get_small_current();//MA return s_current_a * (small_cur_r_sense + SMALL_CURRENT_R);//28欧姆是mos的D极两个56的并联 } int get_pcb_temperature(void){ TEMP_OPEN(1); delay_us(100); uint16_t adc = adc_sample_avg(ADC_CHAN_TEMPERATURE_4, 1); TEMP_OPEN(0); return get_temp_by_adc(adc); } /* * index : 0...3, 3 indicat pcb temp */ int get_pack_temperature(int index){ TEMP_OPEN(1); delay_us(100); uint16_t adc = adc_sample_avg(ADC_CHAN_TEMPERATURE_1 + index, 1); TEMP_OPEN(0); return get_temp_by_adc((adc<<4)&0xFFFF); } int measure_start_cali(uint8_t adc, uint8_t gain, uint8_t samples){ bms_work_mode_set(WORK_MODE_CALIBRATE, 1); least_square_init(&adc_cali[adc], samples); sys_debug("start cali %d, %d, %d\n", adc, gain, samples); if (adc == GD32_ADC) { if (gain == 10) { select_gain_10x(1); }else if (gain == 50) { select_gain_10x(0); }else { return 0; } return 1; } return 1; } int measure_continue_cali(uint8_t adc, uint16_t voltage, int16_t current) { float x = 0; float y = current; sys_debug("continue cali %d, %d, %d\n", adc, voltage, current); if (adc == GD32_ADC) { x = get_current_by_ml5238(); }else { x = get_pack_current_by_cs1180(NULL); } least_square_put(&adc_cali[adc], x, y); return 1; } int measure_stop_cali(uint8_t adc, uint8_t gain){ bms_work_mode_set(WORK_MODE_CALIBRATE, 0); sys_debug("continue stop %d, %d\n", adc, gain); if (adc_cali[adc].finished ) { if (adc == GD32_ADC) { if (gain == 10) { ml5238_10x_ceoff = adc_cali[adc].coeff; }else if (gain == 50) { ml5238_50x_ceoff = adc_cali[adc].coeff; } }else { cs1180_ceoff = adc_cali[adc].coeff; } sys_debug("stop %f, %f\n", adc_cali[adc].coeff.Ka, adc_cali[adc].coeff.Cb); } select_gain_10x(0); return adc_cali[adc].finished; }