ml5238.c 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307
  1. #include <string.h>
  2. #include "libs/shark_libs.h"
  3. #include "spi.h"
  4. #include "ml5238.h"
  5. #include "libs/logger.h"
  6. static int ml5238_read(uint8_t regaddr, uint8_t *data);
  7. static void ml5238_clear_bits(uint8_t regaddr, uint8_t bit);
  8. static void ml5238_set_bits(uint8_t regaddr, uint8_t bit);
  9. static void irq_hander_in_timer(shark_timer_t *timer);
  10. static ml5238_notify_hander _handler;
  11. static shark_timer_t irq_task = {.handler = irq_hander_in_timer};
  12. void ml5238_init(void){
  13. spi0_init();
  14. ml5238_softreset();
  15. ml5238_irq_enable(1);
  16. }
  17. void ml5238_register_notify_handler(ml5238_notify_hander handler){
  18. _handler = handler;
  19. }
  20. //小电流打开等效discharger mos打开
  21. int ml5238_charger_is_disconnect(int small_current_on){
  22. uint8_t value = 0;
  23. uint8_t fet = 0;
  24. ml5238_read(ML5238_FET, &fet);
  25. ml5238_read(ML5238_PSENSE, &value);
  26. if ((fet & FET_DF) || small_current_on){
  27. return (value & PSENSE_PSL);
  28. }
  29. return (value & PSENSE_PSH);
  30. }
  31. int ml5238_enable_load_detect(int enable){
  32. ml5238_clear_bits(ML5238_RSENSE, RSENSE_RRS);
  33. if (enable){
  34. ml5238_set_bits(ML5238_RSENSE, RSENSE_ERS);
  35. }else {
  36. ml5238_clear_bits(ML5238_RSENSE, RSENSE_ERS | RSENSE_IRS);
  37. }
  38. return 0;
  39. }
  40. int ml5238_is_load_disconnect(void){
  41. uint8_t value = 0;
  42. ml5238_read(ML5238_RSENSE, &value);
  43. return (value & RSENSE_RS);
  44. }
  45. #define IRS_IRQ 1 //load disconnect中断
  46. #define IPSL_IRQ 2 //charger over current
  47. #define ICS_IRQ 3 //短路中断
  48. int ml5238_enable_irq(int enable, int irq){
  49. if (irq == IRS_IRQ){
  50. ml5238_clear_bits(ML5238_RSENSE, RSENSE_RRS);
  51. if (enable){
  52. ml5238_set_bits(ML5238_RSENSE, RSENSE_IRS);
  53. }else {
  54. ml5238_clear_bits(ML5238_RSENSE, RSENSE_IRS);
  55. }
  56. }
  57. if (irq == IPSL_IRQ){
  58. ml5238_clear_bits(ML5238_PSENSE, PSENSE_RPSL);
  59. if (enable){
  60. ml5238_set_bits(ML5238_PSENSE, PSENSE_IPSL);
  61. }else {
  62. ml5238_clear_bits(ML5238_PSENSE, PSENSE_IPSL);
  63. }
  64. }
  65. if (irq == ICS_IRQ){
  66. ml5238_clear_bits(ML5238_RSENSE, RSENSE_RSC);
  67. if (enable){
  68. ml5238_set_bits(ML5238_RSENSE, RSENSE_ISC);
  69. }else {
  70. ml5238_clear_bits(ML5238_RSENSE, RSENSE_ISC);
  71. }
  72. }
  73. return 0;
  74. }
  75. //小电流打开等效discharger mos打开
  76. int ml5238_enable_charger_detect(int small_current_on, int enable){
  77. uint8_t fet = 0;
  78. ml5238_read(ML5238_FET, &fet);
  79. if ((fet & FET_DF) || small_current_on){ //discharger is on, used to detect charger over current
  80. ml5238_clear_bits(ML5238_PSENSE, PSENSE_RPSL);
  81. if (enable){
  82. ml5238_set_bits(ML5238_PSENSE, PSENSE_EPSL);
  83. }else {
  84. ml5238_clear_bits(ML5238_PSENSE, PSENSE_EPSL);
  85. }
  86. }else { //discharger if off, used when powerdown, charger is insert
  87. ml5238_clear_bits(ML5238_PSENSE, PSENSE_RPSH);
  88. if (enable){
  89. ml5238_set_bits(ML5238_PSENSE, PSENSE_EPSH);
  90. }else {
  91. ml5238_clear_bits(ML5238_PSENSE, PSENSE_EPSH);
  92. }
  93. }
  94. return 0;
  95. }
  96. static int __inline__ _charger_mosfet_is_open(void){
  97. uint8_t data;
  98. ml5238_read(ML5238_FET, &data);
  99. return (data & FET_CF) != 0;
  100. }
  101. static int __inline__ _discharger_mosfet_is_open(void){
  102. uint8_t data;
  103. ml5238_read(ML5238_FET, &data);
  104. return (data & FET_DF) != 0;
  105. }
  106. int ml5238_is_charging(void){
  107. return _charger_mosfet_is_open();
  108. }
  109. int ml5238_is_discharging(void){
  110. return _discharger_mosfet_is_open();
  111. }
  112. void ml5238_cell_start_balance(uint16_t balance_mask){
  113. ml5238_write(ML5238_CBALH, (balance_mask >> 8) & 0xFF);
  114. ml5238_write(ML5238_CBALL, balance_mask & 0xFF);
  115. }
  116. int ml5238_enable_discharger_mosfet(int enable){
  117. uint8_t data;
  118. if (ml5238_read(ML5238_FET, &data) == 0){
  119. if ((data & FET_DF) == enable){
  120. return 0; //alread enable/disabled
  121. }
  122. data &= ~(FET_DF);
  123. if (enable){
  124. data |= (FET_DF | FET_DRV);
  125. }else {
  126. if ((data & FET_CF) == 0){
  127. data &= ~(FET_DRV);
  128. }
  129. }
  130. return ml5238_write(ML5238_FET, data);
  131. }
  132. return -1;
  133. }
  134. /* when enable charger the discharger mosfet also must be enabled for charging */
  135. int ml5238_enable_charger_mosfet(int enable){
  136. uint8_t data;
  137. if (ml5238_read(ML5238_FET, &data) == 0){
  138. if (((data & FET_CF) >> 1) == enable){
  139. return 0; //alread enable/disabled
  140. }
  141. data &= ~(FET_CF);
  142. if (enable){
  143. data |= (FET_CF | FET_DRV);
  144. }else {
  145. if ((data & FET_DF) == 0){
  146. data &= ~(FET_DRV);
  147. }
  148. }
  149. return ml5238_write(ML5238_FET, data);
  150. }
  151. return -1;
  152. }
  153. int ml5238_short_current_detect(int mode){
  154. uint8_t rsense = 0;
  155. if (mode >= SHORT_CURRENT_MODE_50A_100A){
  156. if (ml5238_read(ML5238_RSENSE, &rsense) == 0){
  157. if (ml5238_write(ML5238_SETSC, mode) == 0){
  158. rsense |= (RSENSE_ESC | RSENSE_ISC);//enable short current detect && irq
  159. rsense &= ~RSENSE_RSC;
  160. return ml5238_write(ML5238_RSENSE, rsense);
  161. }
  162. }
  163. }else {
  164. if (ml5238_read(ML5238_RSENSE, &rsense) == 0){
  165. rsense &= ~(RSENSE_ESC|RSENSE_ISC|RSENSE_RSC);
  166. return ml5238_write(ML5238_RSENSE, rsense);
  167. }
  168. }
  169. return -1;
  170. }
  171. int ml5238_is_short_current_enabled(int mode){
  172. uint8_t value = 0;
  173. if (ml5238_read(ML5238_SETSC, &value) < 0){
  174. return 0;
  175. }
  176. if (value != mode) {
  177. return 0;
  178. }
  179. value = 0;
  180. if (ml5238_read(ML5238_RSENSE, &value) < 0){
  181. return 0;
  182. }
  183. if ((value & (RSENSE_ESC | RSENSE_ISC)) != (RSENSE_ESC | RSENSE_ISC)){
  184. return 0;
  185. }
  186. if (value & RSENSE_RSC){
  187. return 0;
  188. }
  189. return 1;
  190. }
  191. void ml5238_softreset(void)
  192. {
  193. unsigned char i;
  194. for(i=0u;i<0x0Au;i++)
  195. {
  196. ml5238_write((uint8_t)(ML5238_VMON + i), 0x00u);
  197. }
  198. }
  199. void ml5238_power_down(void){
  200. do {
  201. ml5238_write(ML5238_PSENSE, PSENSE_EPSH|PSENSE_IPSH); //before power down, we must enable charger detect
  202. ml5238_write(ML5238_POWER, POWER_PDWN);
  203. }while(1);
  204. }
  205. void ml5238_power_save(int save){
  206. if (save) {
  207. ml5238_write(ML5238_PSENSE, 0);
  208. ML5238_VMON_DISABLE();
  209. ML5238_IMON_DISABLE();
  210. ml5238_write(ML5238_POWER, POWER_PSV);
  211. ml5238_irq_enable(1); //enable charger detect irq, to wakeup bms when charger insert
  212. }else {
  213. ml5238_write(ML5238_POWER, 0);
  214. }
  215. }
  216. static void __inline__ call_handler(int event){
  217. if (_handler) {
  218. _handler(event);
  219. }
  220. }
  221. static void irq_hander_in_timer(shark_timer_t *timer){
  222. uint8_t status = 0;
  223. ml5238_read(ML5238_STATUS, &status);
  224. if (status & STATUS_RPSL){//chargering over current
  225. sys_error("charger over current\n");
  226. ml5238_enable_charger_detect(0, 0);
  227. ml5238_enable_charger_detect(1, 0);
  228. call_handler(ML5238_Event_Charger_Over_Current);
  229. }
  230. if (status & STATUS_RSC) { //short current detect, close charger/discharger mosfet
  231. sys_error("short current\n");
  232. if (_charger_mosfet_is_open()) {
  233. ml5238_enable_charger_mosfet(0);
  234. }
  235. if (_discharger_mosfet_is_open()) {
  236. ml5238_enable_discharger_mosfet(0);
  237. }
  238. ml5238_short_current_detect(SHORT_CURRENT_MODE_DISABLE);
  239. call_handler(ML5238_Event_Short_Current);
  240. }
  241. if (status & STATUS_RRS) {//load disconnect, if short detect, we must wait load disconnected, and then can open discharger
  242. ml5238_enable_irq(0, IRS_IRQ);
  243. call_handler(ML5238_Event_Load_Disconnect);
  244. }
  245. }
  246. void ml5238_irq_handler(void){
  247. shark_timer_post(&irq_task, 0);
  248. }
  249. static void ml5238_set_bits(uint8_t regaddr, uint8_t bit) {
  250. uint8_t value;
  251. ml5238_read(regaddr, &value);
  252. ml5238_write(regaddr, value|bit);
  253. }
  254. static void ml5238_clear_bits(uint8_t regaddr, uint8_t bit) {
  255. uint8_t value;
  256. ml5238_read(regaddr, &value);
  257. ml5238_write(regaddr, value&(~bit));
  258. }
  259. int ml5238_write(uint8_t regaddr, uint8_t data){
  260. uint16_t send_data=(((uint16_t)regaddr)<<(0x09))|((uint16_t)data);
  261. ml5238_cs(0);
  262. int ret = spi0_send_uint16(send_data, NULL);
  263. ml5238_cs(1);
  264. return ret;
  265. }
  266. static int ml5238_read(uint8_t regaddr, uint8_t *data){
  267. uint16_t send_data=((((uint16_t)regaddr)<<(0x09))|0x0100u)|((uint16_t)0x00u);
  268. ml5238_cs(0);
  269. int ret = spi0_send_uint16(send_data, data);
  270. ml5238_cs(1);
  271. return ret;
  272. }