measure.c 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  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. /* measure the temp & current & voltage for battery pack by using
  11. * ms5238 & cs1180(only used when bms is in small current loading)
  12. */
  13. /*
  14. 1. 小电流
  15. 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
  16. 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
  17. 2. 大电流
  18. cs1180(32x):1.861-2.082
  19. ml5238(50x):1.869-1.865-1.890
  20. */
  21. /* this is the inited gain set to the ms5238, but the really gain is calibrated
  22. * by measure_system_calibrate
  23. */
  24. static float imon_gain_10x = 10.0f;
  25. static float imon_gain_50x = 50.0f;
  26. static float imon_gain_now;
  27. static float vim0_10x = 0.0f;
  28. static float vim0_50x = 0.0f;
  29. static float vim0_now;
  30. #define gain_default_50x 1
  31. #define CS1180_MAX_CURRENT 4500 //MA, cs1180的最大电流,超过这个使用ML5238
  32. #define r_pcb_resistor 0.0f // pcb resistor
  33. static const float r_sense = r_resistor + r_pcb_resistor;
  34. static const float v_gd_ref = 3300.0f; //adc ref = 3.3v
  35. static const float max_gd_adc = 65535.0f;
  36. static const float v_cs1180_ref = 1235.0f;//cs1180 vref = 1.235v
  37. static const float max_cs1180_adc = 0x7FFFF;//
  38. static const float small_cur_r_sense = 360.0f;//欧姆
  39. static void __inline__ select_gain_10x(int select){
  40. if (select){
  41. ML5238_IMON_OUT_10X();
  42. imon_gain_now = imon_gain_10x;
  43. vim0_now = vim0_10x;
  44. }else {
  45. ML5238_IMON_OUT_50X();
  46. imon_gain_now = imon_gain_50x;
  47. vim0_now = vim0_50x;
  48. }
  49. }
  50. static int __inline__ _is_x10_gain(void){
  51. return imon_gain_now == imon_gain_10x;
  52. }
  53. static void current_10x_calibrate(void){
  54. /* calibrate the 10x gain */
  55. ML5238_IMON_OUT_ZERO_10X();
  56. vim0_10x = adc_sample_avg(ADC_CHAN_IMON, 10);
  57. ML5238_IMON_OUT_V2000_10X();
  58. float vim1 = adc_sample_avg(ADC_CHAN_IMON, 10);
  59. ML5238_IMON_OUT_V100_10X();
  60. float vr = adc_sample_avg(ADC_CHAN_IMON, 10);
  61. imon_gain_10x = ML5238_GAIN(vim0_10x, vim1, vr);
  62. }
  63. static void current_50x_calibrate(void){
  64. /* calibrate the 50x gain */
  65. ML5238_IMON_OUT_ZERO_50X();
  66. vim0_50x = adc_sample_avg(ADC_CHAN_IMON, 10);
  67. ML5238_IMON_OUT_V2000_50X();
  68. float vim1 = adc_sample_avg(ADC_CHAN_IMON, 10);
  69. ML5238_IMON_OUT_V100_50X();
  70. float vr = adc_sample_avg(ADC_CHAN_IMON, 10);
  71. imon_gain_50x = ML5238_GAIN(vim0_50x, vim1, vr);
  72. }
  73. /*calibrate when startup && temperature is changed more than 5? degree
  74. * calibrate the ms5238's IMON output voltage gain
  75. */
  76. void current_calibrate(void){
  77. #ifdef gain_default_50x
  78. current_50x_calibrate();
  79. select_gain_10x(0);
  80. #else
  81. current_10x_calibrate();
  82. select_gain_10x(1);
  83. #endif
  84. }
  85. void measure_adc_init(void){
  86. ml5238_init();
  87. gd32_adc_init();
  88. current_calibrate();
  89. cs1180_adc_init();
  90. set_log_level(MOD_SYSTEM, L_debug);
  91. }
  92. /* get battery pack's current (mA) */
  93. static float get_pack_current_by_gd(void){
  94. float adc = adc_sample_avg(ADC_CHAN_IMON, 10);
  95. if (adc >= 0xFFF0 && (!_is_x10_gain())){//overflow, use 10x gain
  96. current_10x_calibrate();
  97. select_gain_10x(1);
  98. adc = adc_sample_avg(ADC_CHAN_IMON, 10);
  99. }else if (adc <= 0x1F && (_is_x10_gain())){// is too small, select 50x gain
  100. current_50x_calibrate();
  101. select_gain_10x(0);
  102. adc = adc_sample_avg(ADC_CHAN_IMON, 10);
  103. }
  104. float cali_adc = ML5238_V_RSENSER(adc, vim0_now, imon_gain_now);
  105. return (int)((cali_adc / max_gd_adc) * v_gd_ref / r_sense * 1000);
  106. }
  107. static float get_pack_current_by_cs1180(void){
  108. float adc = cs1180_adc_sample();
  109. return (adc / max_cs1180_adc) * v_cs1180_ref / r_sense * 1000;
  110. }
  111. float get_pack_current(void){
  112. if (!cs1180_is_ready()){ //if cs1180 is not ready, just use gd adc
  113. return get_pack_current_by_gd();
  114. }
  115. float current = get_pack_current_by_cs1180();
  116. if (abs(current) >= CS1180_MAX_CURRENT){
  117. return get_pack_current_by_gd();
  118. }
  119. sys_debug("%f, %f\n", current, get_pack_current_by_gd());
  120. return current;
  121. }
  122. /* get cell's voltage (mV) */
  123. float get_cell_voltage(int cell){
  124. ML5238_SELECT_CELL(cell);
  125. delay_us(100);
  126. float adc = adc_sample_avg(ADC_CHAN_VMON, 10);
  127. return cell_real_vol((adc / max_gd_adc) * v_gd_ref);
  128. }
  129. /* get battery pack's aux current (MA) */
  130. float get_small_current(void){
  131. float adc = adc_sample_avg(ADC_CHAN_AUX_CURR, 10);
  132. return ((adc / max_gd_adc * v_gd_ref)) / small_cur_r_sense;
  133. }
  134. /* 用来判断小电流的情况下,电压小于某一个值认为小电流真正短路,比如16v*/
  135. float get_small_current_voltage(void){
  136. float s_current_a = get_small_current();//MA
  137. return s_current_a * (small_cur_r_sense + 28.0f);//28欧姆是mos的D极两个56的并联
  138. }
  139. int get_pcb_temperature(void){
  140. TEMP_OPEN(1);
  141. delay_us(100);
  142. uint16_t adc = adc_sample(ADC_CHAN_TEMPERATURE_4, TRUE);
  143. TEMP_OPEN(0);
  144. return get_temp_by_adc(adc);
  145. }
  146. /*
  147. * index : 0...3, 3 indicat pcb temp
  148. */
  149. int get_pack_temperature(int index){
  150. TEMP_OPEN(1);
  151. delay_us(100);
  152. uint16_t adc = adc_sample(ADC_CHAN_TEMPERATURE_1 + index, TRUE);
  153. TEMP_OPEN(0);
  154. return get_temp_by_adc(adc);
  155. }