Reform 2 MCU (LPC11U24) experiments based on microbuilder
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
This repo is archived. You can view files and clone it, but cannot push or open issues/pull-requests.
 
 
 
 
 
 

654 lines
17 KiB

  1. #include "projectconfig.h"
  2. #ifdef CFG_BRD_REFORM2
  3. #include <string.h> /* strlen */
  4. #include "boards/board.h"
  5. #include "core/gpio/gpio.h"
  6. #include "core/delay/delay.h"
  7. #include "core/eeprom/eeprom.h"
  8. #include "core/pmu/pmu.h"
  9. #include "core/i2c/i2c.h"
  10. #include "core/ssp1/ssp1.h"
  11. #include "core/uart/uart.h"
  12. #ifdef CFG_USB
  13. #include "core/usb/usbd.h"
  14. #ifdef CFG_USB_CDC
  15. #include "core/usb/usb_cdc.h"
  16. #endif
  17. #endif
  18. #ifdef CFG_INTERFACE
  19. #include "cli/cli.h"
  20. #endif
  21. #ifdef CFG_PROTOCOL
  22. #include "protocol/protocol.h"
  23. #endif
  24. #define REF2_DEBUG 0
  25. #define INA260_ADDRESS 0x4e
  26. #define LTC4162F_ADDRESS 0x68
  27. #define I2C_READ 1
  28. #define ST_EXPECT_DIGIT_0 0
  29. #define ST_EXPECT_DIGIT_1 1
  30. #define ST_EXPECT_DIGIT_2 2
  31. #define ST_EXPECT_DIGIT_3 3
  32. #define ST_EXPECT_CMD 4
  33. #define ST_SYNTAX_ERROR 5
  34. #define ST_EXPECT_RETURN 6
  35. extern volatile uint8_t I2CMasterBuffer[I2C_BUFSIZE];
  36. extern volatile uint8_t I2CSlaveBuffer[I2C_BUFSIZE];
  37. extern volatile uint32_t I2CReadLength, I2CWriteLength;
  38. err_t i2c_write8(uint8_t i2c_addr, uint8_t reg, uint8_t value)
  39. {
  40. I2CWriteLength = 3;
  41. I2CReadLength = 0;
  42. I2CMasterBuffer[0] = i2c_addr << 1;
  43. I2CMasterBuffer[1] = reg;
  44. I2CMasterBuffer[2] = value;
  45. i2cEngine();
  46. return ERROR_NONE;
  47. }
  48. int16_t i2c_read16_le(uint8_t i2c_addr, uint8_t reg)
  49. {
  50. I2CWriteLength = 2;
  51. I2CReadLength = 2;
  52. I2CMasterBuffer[0] = i2c_addr << 1;
  53. I2CMasterBuffer[1] = reg;
  54. I2CMasterBuffer[2] = (i2c_addr << 1) | I2C_READ;
  55. i2cEngine();
  56. int16_t value = (I2CSlaveBuffer[0] << 8) | I2CSlaveBuffer[1];
  57. return value;
  58. }
  59. int16_t i2c_read16_be(uint8_t i2c_addr, uint8_t reg)
  60. {
  61. I2CWriteLength = 2;
  62. I2CReadLength = 2;
  63. I2CMasterBuffer[0] = i2c_addr << 1;
  64. I2CMasterBuffer[1] = reg;
  65. I2CMasterBuffer[2] = (i2c_addr << 1) | I2C_READ;
  66. i2cEngine();
  67. int16_t value = (I2CSlaveBuffer[1] << 8) | I2CSlaveBuffer[0];
  68. return value;
  69. }
  70. err_t i2c_write16_be(uint8_t i2c_addr, uint8_t reg, uint16_t value)
  71. {
  72. I2CWriteLength = 4;
  73. I2CReadLength = 0;
  74. I2CMasterBuffer[0] = i2c_addr << 1;
  75. I2CMasterBuffer[1] = reg;
  76. I2CMasterBuffer[2] = value&0xff;
  77. I2CMasterBuffer[3] = value>>8;
  78. i2cEngine();
  79. return ERROR_NONE;
  80. }
  81. // see https://www.analog.com/media/en/technical-documentation/data-sheets/680324fa.pdf
  82. // default = 0x41
  83. uint8_t calc_pec(uint8_t d, uint8_t pec) {
  84. //uint8_t pec = 0x41; // 0100 0001
  85. for (int i=0; i<8; i++) {
  86. uint8_t bit = (d>>7)&1; // pop off upper bit
  87. d = d<<1;
  88. uint8_t in0 = bit ^ (pec>>7);
  89. uint8_t in1 = (pec & 1) ^ in0;
  90. uint8_t in2 = ((pec & 2)>>1) ^ in0;
  91. pec = (pec<<1)&0xf8;
  92. pec |= in2<<2;
  93. pec |= in1<<1;
  94. pec |= in0;
  95. }
  96. return pec;
  97. }
  98. enum state_t {
  99. ST_CHARGE,
  100. ST_OVERVOLTED,
  101. ST_UNDERVOLTED,
  102. ST_MISSING
  103. };
  104. // charging state machine
  105. int state = ST_CHARGE;
  106. int cycles_in_state = 0;
  107. int charge_current = 1;
  108. uint32_t cur_second = 0;
  109. uint32_t last_second = 0;
  110. float ampSecs = 10*3600.0;
  111. float volts = 0;
  112. float current = 0;
  113. unsigned long lastTime = 0;
  114. char uartBuffer[255] = {0};
  115. float cells_v[8] = {0,0,0,0,0,0,0,0};
  116. int num_undervolted_cells = 0;
  117. int num_overvolted_cells = 0;
  118. int num_missing_cells = 0;
  119. uint16_t discharge_bits = 0;
  120. uint16_t overvoltage_bits = 0;
  121. uint16_t undervoltage_bits = 0;
  122. uint16_t missing_bits = 0;
  123. uint8_t spir[64];
  124. #define OVERVOLTAGE_VALUE 3.6
  125. #define UNDERVOLTAGE_VALUE 2.5
  126. #define MISSING_VALUE 5
  127. void measure_cell_voltages_and_control_discharge() {
  128. // delay is measured in "ticks", which are basically ms?
  129. // 0x10: WRCFG, write config
  130. spir[0] = 0x01;
  131. spir[1] = 0xc7;
  132. spir[2] = 0xe1; // set cdc to 2 = continuous measurement
  133. //spir[3] = discharge_bits&0xff; // first 8 bits of discharge switches
  134. //spir[4] = (discharge_bits&0x700)>>8; // last 4 bits of discharge switches
  135. spir[3] = 0x0;
  136. spir[4] = 0x0;
  137. spir[5] = 0x0;
  138. spir[6] = 0x0;
  139. spir[7] = 0x0;
  140. uint8_t pec = 0x41;
  141. for (int i=2; i<=7; i++) {
  142. pec = calc_pec(spir[i], pec);
  143. }
  144. spir[8] = pec;
  145. LPC_GPIO->CLR[1] = (1 << 23);
  146. ssp1Send(spir, 9);
  147. LPC_GPIO->SET[1] = (1 << 23);
  148. // 0x10: STCVDC, start adc
  149. spir[0] = 0x60;
  150. spir[1] = 0xe7;
  151. LPC_GPIO->CLR[1] = (1 << 23);
  152. ssp1Send(spir, 2);
  153. LPC_GPIO->SET[1] = (1 << 23);
  154. delay(50); // FIXME tunable
  155. // 0x4: RDCV, read all cell voltages
  156. spir[0] = 0x4;
  157. spir[1] = 0xdc;
  158. LPC_GPIO->CLR[1] = (1 << 23);
  159. ssp1Send(spir, 2);
  160. memset(spir, 0, 32);
  161. ssp1Receive(spir, 19);
  162. LPC_GPIO->SET[1] = (1 << 23);
  163. int j=0;
  164. for (int i=0; i<8; i+=2) {
  165. cells_v[i] = ((float)((spir[j]|((spir[j+1]&0xf)<<8))-512)) * 1.5 / 1000.0;
  166. cells_v[i+1] = ((float)((spir[j+1]&0xf0)>>4|(spir[j+2]<<4))-512) * 1.5 / 1000.0;
  167. j+=3;
  168. #ifdef REF2_DEBUG
  169. sprintf(uartBuffer,"cell %d: %fV cell %d: %fV\r\n",
  170. i, cells_v[i], i+1, cells_v[i+1]);
  171. uartSend((uint8_t *)uartBuffer, strlen(uartBuffer));
  172. #endif
  173. }
  174. num_missing_cells = 0;
  175. num_undervolted_cells = 0;
  176. num_overvolted_cells = 0;
  177. missing_bits = 0;
  178. undervoltage_bits = 0;
  179. overvoltage_bits = 0;
  180. for (int i=0; i<8; i++) {
  181. if (cells_v[i] >= MISSING_VALUE || cells_v[i]<0.5) {
  182. missing_bits |= (1<<i);
  183. num_missing_cells++;
  184. }
  185. else if (cells_v[i] >= OVERVOLTAGE_VALUE) {
  186. overvoltage_bits |= (1<<i);
  187. num_overvolted_cells++;
  188. }
  189. else if (cells_v[i] <= UNDERVOLTAGE_VALUE) {
  190. undervoltage_bits |= (1<<i);
  191. num_undervolted_cells++;
  192. }
  193. }
  194. // 0x2: RDCFG, read config registers
  195. /*spir[0] = 0x2;
  196. spir[1] = 0xce;
  197. LPC_GPIO->CLR[1] = (1 << 23);
  198. delay(2);
  199. ssp1Send(spir, 2);
  200. memset(spir, 0, 32);
  201. ssp1Receive(spir, 7);
  202. delay(2);
  203. LPC_GPIO->SET[1] = (1 << 23);
  204. sprintf(uartBuffer,"CFG00 %02x %02x %02x %02x %02x %02x %02x %02x\r\n",
  205. spir[0], spir[1], spir[2], spir[3], spir[4], spir[5], spir[6], spir[7]);
  206. uartSend((uint8_t *)uartBuffer, strlen(uartBuffer));*/
  207. }
  208. void discharge_overvolted_cells() {
  209. discharge_bits = overvoltage_bits;
  210. }
  211. void reset_discharge_bits() {
  212. discharge_bits = 0;
  213. }
  214. // using INA260 current monitor, count amp-secs going in and out of battery
  215. // (battery gauge)
  216. void measure_and_accumulate_current() {
  217. float raw_volts = (float)i2c_read16_le(INA260_ADDRESS, 0x2);
  218. float raw_current = (float)i2c_read16_le(INA260_ADDRESS, 0x1);
  219. volts = raw_volts * 0.00125;
  220. current = raw_current * 0.001;
  221. if (current>-0.02 && current<0.02) current = 0; // clamp to zero
  222. unsigned long thisTime = delayGetSecondsActive();
  223. if (lastTime>0 && thisTime>lastTime) {
  224. unsigned long secondsPassed = thisTime - lastTime;
  225. if (secondsPassed >= 1) {
  226. lastTime = thisTime;
  227. // decrease estimated battery capacity
  228. ampSecs -= current*(secondsPassed);
  229. }
  230. } else {
  231. // timer uninitialized or timer wrap
  232. lastTime = thisTime;
  233. }
  234. #ifdef REF2_DEBUG
  235. sprintf(uartBuffer,"\033[H\033[2JINA Ah: %f V: %f A: %f\r\n",ampSecs/3600,volts,current);
  236. uartSend((uint8_t *)uartBuffer, strlen(uartBuffer));
  237. #endif
  238. }
  239. uint16_t charger_state;
  240. uint16_t charge_status;
  241. uint16_t system_status;
  242. uint16_t limit_alerts;
  243. uint16_t charger_alerts;
  244. uint16_t status_alerts;
  245. float chg_vin;
  246. float chg_vbat;
  247. void configure_charger(int charge_current) {
  248. }
  249. void turn_som_power_on(void) {
  250. LPC_GPIO->SET[1] = (1 << 16); // 3v3, high = on
  251. // FIXME this turns 1v5 off :/
  252. LPC_GPIO->SET[0] = (1 << 20); // PCIe, low = on
  253. LPC_GPIO->SET[1] = (1 << 15); // 5v, high = on
  254. LPC_GPIO->SET[1] = (1 << 19); // 1v2, high = on
  255. }
  256. void turn_som_power_off(void) {
  257. LPC_GPIO->CLR[1] = (1 << 19); // 1v2, high = on
  258. LPC_GPIO->CLR[1] = (1 << 15); // 5v, high = on
  259. LPC_GPIO->CLR[0] = (1 << 20); // PCIe, low = on
  260. LPC_GPIO->CLR[1] = (1 << 16); // 3v3, high = on
  261. // FIXME experiment: temp. disable charger to reset its timers
  262. configure_charger(0);
  263. }
  264. void brownout_setup(void) {
  265. // Set brownout threshold to 2.63-2.71V (highest level)
  266. // and enable brownout reset
  267. LPC_SYSCON->BODCTRL = 0x3 | (1<<4);
  268. }
  269. void watchdog_feed(void) {
  270. LPC_WWDT->FEED = 0xAA;
  271. LPC_WWDT->FEED = 0x55;
  272. }
  273. #define WWDT_WDMOD_WDEN ((uint32_t) (1 << 0))
  274. #define WWDT_WDMOD_WDRESET ((uint32_t) (1 << 1))
  275. void watchdog_setup(void) {
  276. LPC_SYSCON->SYSAHBCLKCTRL |= (1<<15); // WWDT enable
  277. LPC_SYSCON->WDTOSCCTRL =
  278. (1<<5) | // FREQSEL 0.6MHz
  279. 31; // DIVSEL 64 (31+1)*2
  280. LPC_SYSCON->PDRUNCFG &= ~(1<<6); // WDTOSC_PD disable
  281. LPC_WWDT->CLKSEL = 1; // WDOSC
  282. LPC_WWDT->TC = 0xffff/5; // timeout counter, ~5 seconds
  283. LPC_WWDT->MOD = 0;
  284. LPC_WWDT->MOD |= WWDT_WDMOD_WDRESET; // enable WDRESET (watchdog resets system)
  285. LPC_WWDT->MOD |= WWDT_WDMOD_WDEN; // watchdog enable
  286. watchdog_feed();
  287. }
  288. void boardInit(void)
  289. {
  290. SystemCoreClockUpdate();
  291. GPIOInit();
  292. delayInit();
  293. // 5V regulator on/off
  294. LPC_GPIO->DIR[1] |= (1 << 15);
  295. // 3V3 rail transistor on/off
  296. LPC_GPIO->DIR[1] |= (1 << 16);
  297. // 1V2 regulator on/off
  298. LPC_GPIO->DIR[1] |= (1 << 19);
  299. // PCIe 1 power supply transistor
  300. LPC_GPIO->DIR[0] |= (1 << 20);
  301. turn_som_power_on();
  302. uartInit(CFG_UART_BAUDRATE);
  303. i2cInit(I2CMASTER);
  304. ssp1Init();
  305. ssp1ClockSlow();
  306. LPC_GPIO->DIR[1] |= (1 << 31);
  307. LPC_GPIO->DIR[1] |= (1 << 25);
  308. // SPI chip select
  309. LPC_GPIO->DIR[1] |= (1 << 23);
  310. LPC_GPIO->SET[1] = (1 << 23); // active low
  311. #ifdef REF2_DEBUG
  312. sprintf(uartBuffer, "\r\nMNT Reform 2.0 MCU initialized.\r\n");
  313. uartSend((uint8_t*)uartBuffer, strlen(uartBuffer));
  314. #endif
  315. }
  316. char remote_cmd = 0;
  317. uint8_t remote_arg = 0;
  318. unsigned char cmd_state = ST_EXPECT_DIGIT_0;
  319. unsigned int cmd_number = 0;
  320. int cmd_echo = 1;
  321. void handle_commands() {
  322. if (!uartRxBufferDataPending()) return;
  323. char chr = uartRxBufferRead();
  324. if (cmd_echo) {
  325. sprintf(uartBuffer, "%c", chr);
  326. uartSend((uint8_t*)uartBuffer, strlen(uartBuffer));
  327. }
  328. // states:
  329. // 0-3 digits of optional command argument
  330. // 4 command letter expected
  331. // 5 syntax error (unexpected character)
  332. // 6 command letter entered
  333. // TODO get cell voltage
  334. // TODO get charger state
  335. // TODO get charger status / mode
  336. if (cmd_state>=ST_EXPECT_DIGIT_0 && cmd_state<=ST_EXPECT_DIGIT_3) {
  337. // read number or command
  338. if (chr >= '0' && chr <= '9') {
  339. cmd_number*=10;
  340. cmd_number+=(chr-'0');
  341. cmd_state++;
  342. } else if ((chr >= 'a' && chr <= 'z') || (chr >= 'A' && chr <= 'Z')) {
  343. // command entered instead of digit
  344. remote_cmd = chr;
  345. cmd_state = ST_EXPECT_RETURN;
  346. } else if (chr == '\n' || chr == ' ') {
  347. // ignore newlines or spaces
  348. } else if (chr == '\r') {
  349. sprintf(uartBuffer, "error:syntax\r\n");
  350. uartSend((uint8_t*)uartBuffer, strlen(uartBuffer));
  351. cmd_state = ST_EXPECT_DIGIT_0;
  352. cmd_number = 0;
  353. } else {
  354. // syntax error
  355. cmd_state = ST_SYNTAX_ERROR;
  356. }
  357. }
  358. else if (cmd_state == ST_EXPECT_CMD) {
  359. // read command
  360. if ((chr >= 'a' && chr <= 'z') || (chr >= 'A' && chr <= 'Z')) {
  361. remote_cmd = chr;
  362. cmd_state = ST_EXPECT_RETURN;
  363. } else {
  364. cmd_state = ST_SYNTAX_ERROR;
  365. }
  366. }
  367. else if (cmd_state == ST_SYNTAX_ERROR) {
  368. // syntax error
  369. if (chr == '\r') {
  370. sprintf(uartBuffer, "error:syntax\r\n");
  371. uartSend((uint8_t*)uartBuffer, strlen(uartBuffer));
  372. cmd_state = ST_EXPECT_DIGIT_0;
  373. cmd_number = 0;
  374. }
  375. }
  376. else if (cmd_state == ST_EXPECT_RETURN) {
  377. if (chr == '\n' || chr == ' ') {
  378. // ignore newlines or spaces
  379. }
  380. else if (chr == '\r') {
  381. if (cmd_echo) {
  382. // FIXME
  383. sprintf(uartBuffer,"\n");
  384. uartSend((uint8_t*)uartBuffer, strlen(uartBuffer));
  385. }
  386. // execute
  387. if (remote_cmd == 'p') {
  388. // toggle system 5V power
  389. if (cmd_number == 0) {
  390. turn_som_power_off();
  391. sprintf(uartBuffer,"system: off\r\n");
  392. uartSend((uint8_t*)uartBuffer, strlen(uartBuffer));
  393. } else {
  394. turn_som_power_on();
  395. sprintf(uartBuffer,"system: on\r\n");
  396. uartSend((uint8_t*)uartBuffer, strlen(uartBuffer));
  397. }
  398. }
  399. else if (remote_cmd == 'a') {
  400. // get system current (mA)
  401. sprintf(uartBuffer,"%d\r\n",(int)(current*1000.0));
  402. uartSend((uint8_t*)uartBuffer, strlen(uartBuffer));
  403. }
  404. else if (remote_cmd == 'v' && cmd_number>=0 && cmd_number<=7) {
  405. // get cell voltage
  406. sprintf(uartBuffer,"%d\r\n",(int)(cells_v[cmd_number]*1000.0));
  407. uartSend((uint8_t*)uartBuffer, strlen(uartBuffer));
  408. }
  409. else if (remote_cmd == 'V') {
  410. // get system voltage
  411. sprintf(uartBuffer,"%d\r\n",(int)(volts*1000.0));
  412. uartSend((uint8_t*)uartBuffer, strlen(uartBuffer));
  413. }
  414. else if (remote_cmd == 's') {
  415. // get charger system state
  416. if (state == ST_CHARGE) {
  417. sprintf(uartBuffer,"idle:%x st:%x sy:%x i:%d b:%d l!%x c!%x s!%x [%d]\r",charger_state,charge_status,system_status,(int)chg_vin,(int)chg_vbat,limit_alerts,charger_alerts,status_alerts,cycles_in_state);
  418. } else if (state == ST_OVERVOLTED) {
  419. sprintf(uartBuffer,"overvolt [%d]\r",cycles_in_state);
  420. } else if (state == ST_UNDERVOLTED) {
  421. sprintf(uartBuffer,"undervolt [%d]\r",cycles_in_state);
  422. } else if (state == ST_MISSING) {
  423. sprintf(uartBuffer,"cell missing [%d]\r",cycles_in_state);
  424. } else if (state == ST_MISSING) {
  425. sprintf(uartBuffer,"unknown [%d]\r",cycles_in_state);
  426. }
  427. uartSend((uint8_t*)uartBuffer, strlen(uartBuffer));
  428. }
  429. else if (remote_cmd == 'c' && cmd_number>=0 && cmd_number<=7) {
  430. // get cell status
  431. int n = cmd_number;
  432. sprintf(uartBuffer,"%c%c%c%c\r\n",
  433. missing_bits &(1<<n)?'m':'.',
  434. undervoltage_bits &(1<<n)?'u':'.',
  435. overvoltage_bits &(1<<n)?'o':'.',
  436. discharge_bits &(1<<n)?'d':'.');
  437. uartSend((uint8_t*)uartBuffer, strlen(uartBuffer));
  438. }
  439. else if (remote_cmd == 'S') {
  440. // get charger system cycles in current state
  441. sprintf(uartBuffer, "%d\r\n", cycles_in_state);
  442. uartSend((uint8_t*)uartBuffer, strlen(uartBuffer));
  443. }
  444. else if (remote_cmd == 'C') {
  445. // set/get battery capacity (mAh)
  446. if (cmd_number>0) {
  447. ampSecs = ((float)cmd_number)*3.6;
  448. }
  449. sprintf(uartBuffer,"%d\r\n",(int)(ampSecs/3.6));
  450. uartSend((uint8_t*)uartBuffer, strlen(uartBuffer));
  451. }
  452. else if (remote_cmd == 'e') {
  453. // toggle serial echo
  454. cmd_echo = cmd_number?1:0;
  455. }
  456. else {
  457. sprintf(uartBuffer, "error:command\r\n");
  458. uartSend((uint8_t*)uartBuffer, strlen(uartBuffer));
  459. }
  460. cmd_state = ST_EXPECT_DIGIT_0;
  461. cmd_number = 0;
  462. } else {
  463. cmd_state = ST_SYNTAX_ERROR;
  464. }
  465. }
  466. }
  467. int main(void)
  468. {
  469. boardInit();
  470. //reset_discharge_bits();
  471. state = ST_CHARGE;
  472. cycles_in_state = 0;
  473. last_second = delayGetSecondsActive();
  474. // WIP, not yet tested
  475. //watchdog_setup();
  476. //sprintf(uartBuffer, "\r\nwatchdog_setup() completed.\r\n");
  477. //uartSend((uint8_t*)uartBuffer, strlen(uartBuffer));
  478. while (1)
  479. {
  480. // algorithm idea:
  481. // - check all cell voltages
  482. // - charging state: if a cell voltage is higher than nominal, do not charge, enter balancing state
  483. // - option 1: suspend_charger (CONFIG_BITS_REG, 0x14, bit [5])
  484. // - option 2: charge_current_setting (0x1A) to a low level
  485. // - charging state: if cell voltages are on average lower than nominal, enter charging state
  486. // - balancing state: discharge the cell with highest voltage (enable discharge switch)
  487. // - idle state: if one cell voltages is below undervoltage threshold, enter alert state
  488. // - alert state: constantly signal undervoltage alert to host. after timeout, switch off 5v rail and 3v3 rail
  489. // charge current 2: ~0.2A
  490. //watchdog_feed();
  491. measure_and_accumulate_current();
  492. measure_cell_voltages_and_control_discharge();
  493. /*if (state == ST_CHARGE) {
  494. configure_charger(charge_current);
  495. if (cycles_in_state > 5) {
  496. // some cool-off time
  497. if (num_missing_cells > 0) {
  498. //state = ST_MISSING;
  499. //cycles_in_state = 0;
  500. }
  501. else if (num_undervolted_cells > 0) {
  502. state = ST_UNDERVOLTED;
  503. cycles_in_state = 0;
  504. }
  505. else if (num_overvolted_cells > 0) {
  506. state = ST_OVERVOLTED;
  507. cycles_in_state = 0;
  508. }
  509. }
  510. }
  511. else if (state == ST_UNDERVOLTED) {
  512. // TODO: issue alert -- switch off system if critical
  513. // TODO: how to get out of this state?
  514. configure_charger(charge_current);
  515. if (cycles_in_state > 5) {
  516. state = ST_CHARGE;
  517. cycles_in_state = 0;
  518. }
  519. }
  520. else if (state == ST_OVERVOLTED) {
  521. // suspend charger
  522. configure_charger(0);
  523. discharge_overvolted_cells();
  524. // FIXME optimize cycles
  525. if (cycles_in_state > 5 && (num_undervolted_cells==0 || num_undervolted_cells>0)) {
  526. reset_discharge_bits();
  527. state = ST_CHARGE;
  528. cycles_in_state = 0;
  529. }
  530. }
  531. else if (state == ST_MISSING) {
  532. configure_charger(0);
  533. reset_discharge_bits();
  534. if (cycles_in_state > 5) {
  535. if (num_missing_cells < 1) {
  536. state = ST_CHARGE;
  537. cycles_in_state = 0;
  538. }
  539. }
  540. }*/
  541. handle_commands();
  542. cur_second = delayGetSecondsActive();
  543. if (last_second != cur_second) {
  544. if (cur_second-last_second<10) {
  545. // prevent rollovers
  546. cycles_in_state += cur_second-last_second;
  547. }
  548. last_second = cur_second;
  549. }
  550. }
  551. }
  552. #endif