measure.c 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277
  1. #include "measure.h"
  2. #include "bsp/ml5238.h"
  3. #include "bsp/cs1180.h"
  4. #include "bsp/gd32_adc.h"
  5. #include "bsp/clock.h"
  6. #include "bsp/gpio.h"
  7. #include "bsp/temp_lookup_tab.h"
  8. #include "bsp/shark_bsp.h"
  9. #include "libs/logger.h"
  10. #include "Least_Square.h"
  11. #include "app/sox/state.h"
  12. /* measure the temp & current & voltage for battery pack by using
  13. * ms5238 & cs1180(only used when bms is in small current loading)
  14. */
  15. /*
  16. 1. 小电流
  17. 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
  18. 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
  19. 2. 大电流
  20. cs1180(32x):1.861-2.082
  21. ml5238(50x):1.869-1.865-1.890
  22. */
  23. /* this is the inited gain set to the ms5238, but the really gain is calibrated
  24. * by measure_system_calibrate
  25. */
  26. static float imon_gain_10x = 10.0f;
  27. static float imon_gain_50x = 50.0f;
  28. static float imon_gain_now;
  29. static float vim0_10x = 0.0f;
  30. static float vim0_50x = 0.0f;
  31. static float vim0_now;
  32. static float ml5238_10x_a = 1.0f;
  33. static float ml5238_50x_a = 1.0f;
  34. static float ml5238_10x_b = 0.0f;
  35. static float ml5238_50x_b = 0.0f;
  36. static float ml5238_now_a = 1.0f;
  37. static float ml5238_now_b = 0.0f;
  38. static float cs1180_a = 1.0f;
  39. static float cs1180_b = 0.0f;
  40. #define gain_default_50x 1
  41. #define CS1180_MAX_CURRENT 4500 //MA, cs1180的最大电流,超过这个使用ML5238
  42. #define r_pcb_resistor 0.0f // pcb resistor
  43. static const float r_sense = r_resistor + r_pcb_resistor;
  44. static const float v_gd_ref = 3300.0f; //adc ref = 3.3v
  45. static const float max_gd_adc = 4095.0f;//65536.0f;
  46. static const float v_cs1180_ref = 1235.0f;//cs1180 vref = 1.235v
  47. static const float max_cs1180_adc = 0x7FFFF;//
  48. static const float small_cur_r_sense = 360.0f;//欧姆
  49. static least_square_t adc_cali[2]; // y = ax + b
  50. #define GD32_ADC_READ_TIMES 128
  51. static void __inline__ select_gain_10x(int select){
  52. if (select){
  53. ML5238_IMON_OUT_10X();
  54. imon_gain_now = imon_gain_10x;
  55. vim0_now = vim0_10x;
  56. ml5238_now_a = ml5238_10x_a;
  57. ml5238_now_b = ml5238_10x_b;
  58. }else {
  59. ML5238_IMON_OUT_50X();
  60. imon_gain_now = imon_gain_50x;
  61. vim0_now = vim0_50x;
  62. ml5238_now_a = ml5238_50x_a;
  63. ml5238_now_b = ml5238_50x_b;
  64. }
  65. }
  66. static int __inline__ _is_x10_gain(void){
  67. return imon_gain_now == imon_gain_10x;
  68. }
  69. float get_ml5238_gain(void){
  70. return imon_gain_now;
  71. }
  72. float get_ml5238_vos(void){
  73. return vim0_now;
  74. }
  75. static void current_10x_calibrate(void){
  76. /* calibrate the 10x gain */
  77. ML5238_IMON_OUT_ZERO_10X();
  78. vim0_10x = adc_sample_avg(ADC_CHAN_IMON, GD32_ADC_READ_TIMES);
  79. #if 0
  80. ML5238_IMON_OUT_V2000_10X();
  81. float vim1 = adc_sample_avg(ADC_CHAN_IMON, GD32_ADC_READ_TIMES);
  82. ML5238_IMON_OUT_V100_10X();
  83. float vr = adc_sample_avg(ADC_CHAN_IMON, GD32_ADC_READ_TIMES);
  84. imon_gain_10x = ML5238_GAIN(vim0_10x, vim1, vr);
  85. #else
  86. imon_gain_10x = 10.0f;
  87. #endif
  88. }
  89. static void current_50x_calibrate(void){
  90. /* calibrate the 50x gain */
  91. ML5238_IMON_OUT_ZERO_50X();
  92. vim0_50x = adc_sample_avg(ADC_CHAN_IMON, GD32_ADC_READ_TIMES);
  93. #if 0
  94. ML5238_IMON_OUT_V2000_50X();
  95. float vim1 = adc_sample_avg(ADC_CHAN_IMON, GD32_ADC_READ_TIMES);
  96. ML5238_IMON_OUT_V20_50X();
  97. float vr = adc_sample_avg(ADC_CHAN_IMON, GD32_ADC_READ_TIMES);
  98. imon_gain_50x = ML5238_GAIN(vim0_50x, vim1, vr) * 0.948f;
  99. #else
  100. imon_gain_50x = 50.0f;
  101. #endif
  102. }
  103. /*calibrate when startup && temperature is changed more than 5? degree
  104. * calibrate the ms5238's IMON output voltage gain
  105. */
  106. void current_calibrate(void){
  107. current_10x_calibrate();
  108. current_50x_calibrate();
  109. #ifdef gain_default_50x
  110. select_gain_10x(0);
  111. #else
  112. select_gain_10x(1);
  113. #endif
  114. }
  115. void measure_adc_init(void){
  116. ml5238_init();
  117. gd32_adc_init();
  118. current_calibrate();
  119. cs1180_adc_init();
  120. set_log_level(MOD_SYSTEM, L_debug);
  121. }
  122. static float get_current_by_ml5238(void){
  123. float adc = adc_sample_avg(ADC_CHAN_IMON, GD32_ADC_READ_TIMES);
  124. float cali_adc = ML5238_V_RSENSER(adc, vim0_now, imon_gain_now);
  125. return (int)((cali_adc / max_gd_adc) * v_gd_ref / r_sense * 1000);
  126. }
  127. /* get battery pack's current (mA) */
  128. static float get_pack_current_by_gd(void){
  129. float adc = adc_sample_avg(ADC_CHAN_IMON, GD32_ADC_READ_TIMES);
  130. if (adc >= (max_gd_adc - 255.0f) && (!_is_x10_gain())){//overflow, use 10x gain
  131. select_gain_10x(1);
  132. adc = adc_sample_avg(ADC_CHAN_IMON, GD32_ADC_READ_TIMES);
  133. }else if (abs(adc - vim0_now) <= 255.0f && (_is_x10_gain())){// is too small, select 50x gain
  134. select_gain_10x(0);
  135. adc = adc_sample_avg(ADC_CHAN_IMON, GD32_ADC_READ_TIMES);
  136. }
  137. float cali_adc = ML5238_V_RSENSER(adc, vim0_now, imon_gain_now);
  138. return (int)((cali_adc / max_gd_adc) * v_gd_ref / r_sense * 1000);
  139. }
  140. static float get_pack_current_by_cs1180(int *valid){
  141. float adc = cs1180_adc_sample(valid);
  142. float vol = (adc / max_cs1180_adc) * v_cs1180_ref;
  143. return (vol / r_sense) * 1000 - 5.0f;//板子固定5MA,cs1180无法测量到
  144. }
  145. float get_pack_current(int *current_5238){
  146. float current = get_pack_current_by_gd();
  147. current = ml5238_now_a * current + ml5238_now_b;
  148. if (current_5238 != NULL){
  149. *current_5238 = (int)current;
  150. }
  151. if (cs1180_change_gain(current) == 0) {
  152. int valid = 1;
  153. float cs1180_current = get_pack_current_by_cs1180(&valid);
  154. if (valid == 1) {
  155. current = cs1180_current * cs1180_a + cs1180_b;
  156. }
  157. }
  158. return current;
  159. }
  160. /* get cell's voltage (mV) */
  161. float get_cell_voltage(int cell){
  162. ML5238_SELECT_CELL(cell);
  163. delay_us(100);
  164. float adc = adc_sample_avg(ADC_CHAN_VMON, GD32_ADC_READ_TIMES);
  165. return cell_real_vol((adc / max_gd_adc) * v_gd_ref);
  166. }
  167. /* get battery pack's aux current (MA) */
  168. float get_small_current(void){
  169. float adc = adc_sample_avg(ADC_CHAN_AUX_CURR, GD32_ADC_READ_TIMES);
  170. return ((adc / max_gd_adc * v_gd_ref)) / small_cur_r_sense;
  171. }
  172. /* 用来判断小电流的情况下,电压小于某一个值认为小电流真正短路,比如16v*/
  173. float get_small_current_voltage(void){
  174. float s_current_a = get_small_current();//MA
  175. return s_current_a * (small_cur_r_sense + 28.0f);//28欧姆是mos的D极两个56的并联
  176. }
  177. int get_pcb_temperature(void){
  178. TEMP_OPEN(1);
  179. delay_us(100);
  180. uint16_t adc = adc_sample_avg(ADC_CHAN_TEMPERATURE_4, 1);
  181. TEMP_OPEN(0);
  182. return get_temp_by_adc(adc);
  183. }
  184. /*
  185. * index : 0...3, 3 indicat pcb temp
  186. */
  187. int get_pack_temperature(int index){
  188. TEMP_OPEN(1);
  189. delay_us(100);
  190. uint16_t adc = adc_sample_avg(ADC_CHAN_TEMPERATURE_1 + index, 1);
  191. TEMP_OPEN(0);
  192. return get_temp_by_adc((adc<<4)&0xFFFF);
  193. }
  194. int measure_start_cali(uint8_t adc, uint8_t gain, uint8_t samples){
  195. bms_work_mode_set(WORK_MODE_CALIBRATE, 1);
  196. least_square_init(&adc_cali[adc], samples);
  197. sys_debug("start cali %d, %d, %d\n", adc, gain, samples);
  198. if (adc == GD32_ADC) {
  199. if (gain == 10) {
  200. select_gain_10x(1);
  201. }else if (gain == 50) {
  202. select_gain_10x(0);
  203. }else {
  204. return 0;
  205. }
  206. return 1;
  207. }
  208. return 1;
  209. }
  210. int measure_continue_cali(uint8_t adc, uint16_t voltage, int16_t current) {
  211. float x = 0;
  212. float y = current;
  213. sys_debug("continue cali %d, %d, %d\n", adc, voltage, current);
  214. if (adc == GD32_ADC) {
  215. x = get_current_by_ml5238();
  216. }else {
  217. x = get_pack_current_by_cs1180(NULL);
  218. }
  219. least_square_put(&adc_cali[adc], x, y);
  220. return 1;
  221. }
  222. int measure_stop_cali(uint8_t adc, uint8_t gain){
  223. bms_work_mode_set(WORK_MODE_CALIBRATE, 0);
  224. sys_debug("continue stop %d, %d\n", adc, gain);
  225. if (adc_cali[adc].finished ) {
  226. if (adc == GD32_ADC) {
  227. if (gain == 10) {
  228. ml5238_10x_a = adc_cali[adc].Cb;
  229. ml5238_10x_b = adc_cali[adc].Ka;
  230. }else if (gain == 50) {
  231. ml5238_50x_a = adc_cali[adc].Cb;
  232. ml5238_50x_b = adc_cali[adc].Ka;
  233. }
  234. }else {
  235. cs1180_a = adc_cali[adc].Cb;
  236. cs1180_b = adc_cali[adc].Ka;
  237. }
  238. sys_debug("stop %f, %f\n", adc_cali[adc].Cb, adc_cali[adc].Ka);
  239. }
  240. select_gain_10x(0);
  241. return adc_cali[adc].finished;
  242. }