Acett SAM : board v02 support
authorNathael Pajani <nathael.pajani@ed3l.fr>
Sat, 1 May 2021 19:37:47 +0000 (21:37 +0200)
committerNathael Pajani <nathael.pajani@ed3l.fr>
Sat, 1 May 2021 19:37:47 +0000 (21:37 +0200)
apps/acett/v02/Makefile [new file with mode: 0644]
apps/acett/v02/main.c [new file with mode: 0644]

diff --git a/apps/acett/v02/Makefile b/apps/acett/v02/Makefile
new file mode 100644 (file)
index 0000000..da44d1f
--- /dev/null
@@ -0,0 +1,12 @@
+# Makefile for "base" apps
+
+MODULE = $(shell basename $(shell cd .. && pwd && cd -))
+NAME = $(shell basename $(CURDIR))
+
+.PHONY: $(NAME).bin
+$(NAME).bin:
+       @make -C ../../.. --no-print-directory NAME=$(NAME) MODULE=$(MODULE) apps/$(MODULE)/$(NAME)/$@
+
+clean mrproper:
+       @make -C ../../.. --no-print-directory $@
+
diff --git a/apps/acett/v02/main.c b/apps/acett/v02/main.c
new file mode 100644 (file)
index 0000000..386f3bd
--- /dev/null
@@ -0,0 +1,668 @@
+/****************************************************************************
+ *   apps/ledstrip/main.c
+ *
+ * WS2812 Chainable leds example using Adafruit les strip
+ *
+ * Copyright 2013-2015 Nathael Pajani <nathael.pajani@ed3l.fr>
+ *
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ *************************************************************************** */
+
+
+#include "lib/stdint.h"
+#include "core/system.h"
+#include "core/systick.h"
+#include "core/pio.h"
+#include "core/iap.h"
+#include "lib/stdio.h"
+#include "lib/errno.h"
+#include "lib/utils.h"
+#include "drivers/serial.h"
+#include "drivers/gpio.h"
+#include "drivers/i2c.h"
+
+#include "extdrv/bq769x0_bms.h"
+
+#define MODULE_VERSION    0x01
+#define MODULE_NAME "Bulle BMS"
+
+#define SELECTED_FREQ  FREQ_SEL_36MHz
+
+
+/***************************************************************************** */
+#define DEBUG 1
+
+#if defined DEBUG && DEBUG == 1
+#define debug_uprintf(...) \
+  if (verbose >= 2) { uprintf(UART0, __VA_ARGS__ ); }
+#else
+#define debug_uprintf(...) do {} while (0)
+#endif
+
+static uint8_t verbose = 2; /* Start with full verbosity for possible debug */
+
+
+/***************************************************************************** */
+/* Initial Pins configuration */
+const struct pio_config common_pins[] = {
+       /* UART 0 */
+       { LPC_GPIO_0_0, LPC_UART0_RX, 0 },
+       { LPC_GPIO_0_4, LPC_UART0_TX, 0 },
+       /* UART 1 */
+       { LPC_GPIO_0_17, LPC_UART1_RX, 0 },
+       { LPC_GPIO_0_23, LPC_UART1_TX, 0 },
+       /* I2C 0 */
+       { LPC_I2C0_SCL_PIO_0_10, LPC_FIXED, 0 },
+       { LPC_I2C0_SDA_PIO_0_11, LPC_FIXED, 0 },
+       /* GPIO */
+       { LPC_GPIO_0_2, LPC_GPIO, 0 },  /* Led */
+       { LPC_GPIO_0_15, LPC_GPIO, 0 }, /* Battery Alert */
+       ARRAY_LAST_PIO,
+};
+
+
+const struct pio alert = LPC_GPIO_0_15; /* Alert to/from BMS */
+const struct pio led = LPC_GPIO_0_2; /* Led status */
+
+/***************************************************************************** */
+void system_init()
+{
+       /* FIXME : Add watchdog */
+       system_set_default_power_state();
+       clock_config(SELECTED_FREQ);
+       set_pins(common_pins);
+       gpio_on();
+       /* System tick timer MUST be configured and running in order to use the sleeping
+        * functions */
+       systick_timer_on(1); /* 1ms */
+       systick_start();
+}
+
+/* Define our fault handler. This one is not mandatory, the dummy fault handler
+ * will be used when it's not overridden here.
+ * Note : The default one does a simple infinite loop. If the watchdog is deactivated
+ * the system will hang.
+ */
+void fault_info(const char* name, uint32_t len)
+{
+       debug_uprintf(name);
+       while (1);
+}
+
+
+/***************************************************************************** */
+/* PMU unit */
+int save_gp_retain(uint32_t* values, uint8_t nb, uint8_t offset)
+{
+       struct lpc_pm_unit* pmu = LPC_PMU;
+       int i = 0;
+
+       if ((offset + nb) > 4) {
+               return -EINVAL;
+       }
+       for (i = 0; i < nb; i++) {
+               pmu->gp_data[offset + i] = values[i];
+       }
+       return 0;
+}
+
+int read_gp_retain(uint32_t* values, uint8_t nb, uint8_t offset)
+{
+       struct lpc_pm_unit* pmu = LPC_PMU;
+       int i = 0;
+
+       if ((offset + nb) > 4) {
+               return -EINVAL;
+       }
+       for (i = 0; i < nb; i++) {
+               values[i] = pmu->gp_data[offset + i];
+       }
+       return 0;
+}
+
+/***************************************************************************** */
+/* BMS */
+
+#define BMS_BQ769X006_I2C_ADDR  0x30
+#define BMS_NB_CELLS 5
+#define BMS_NB_TH 1
+struct bq769x0_bms_conf bms = {
+       .addr = BMS_BQ769X006_I2C_ADDR,
+       .bus_num = I2C0,
+       .crc_check = 0, /* BQ769X006 does not have CRC */
+       .nb_cells = BMS_NB_CELLS,
+       .nb_thermistors = BMS_NB_TH,
+};
+
+void bms_config(void)
+{
+       int ret = 0;
+       uint16_t uvlo16 = 0, ovp16 = 0;
+       uint8_t uvlo = 0, ovp = 0;
+       uint8_t old_status = 0;
+       uint16_t vth = 0;
+       uint16_t vcells[BMS_NB_CELLS] = {0};
+
+       ret = bq769x0_bms_config(&bms, &old_status);
+       if (ret != 0) {
+               debug_uprintf("Battery Management System config error: %d, %d\n", bms.probe_ok, ret);
+               return;
+       } else {
+               debug_uprintf("Battery Management System UP !\n");
+               debug_uprintf(" old status: 0x%02x\n", old_status);
+               debug_uprintf(" ADC gain: %d (%d µV), off: %d\n",
+                                                       bms.adc_gain, bms.adc_gain_uV, bms.adc_offset);
+       }
+       msleep(100);
+       ret = bq769x0_bms_get_and_erase_status(&bms, &old_status);
+       if (ret != 0) {
+               debug_uprintf("Battery Management System get status error: %d\n", ret);
+               return;
+       } else {
+               debug_uprintf(" new status: 0x%02x\n", old_status);
+       }
+
+       /* Configure battery limits :
+        * - Cell uvlo : 2600mV
+        * - Cell ovp : 3650mV
+        * - scd is 22mV (0x00) : 22mV / 5mOhms = 4.4 Amps
+        * - ocd is 14mV (0x02) : 14mV / 5mOhms = 2.8 Amps
+        */
+       uvlo16 = ((2600 - bms.adc_offset) * 1000) / bms.adc_gain_uV;
+       uvlo = ((uvlo16 >> 4) & 0xFF);
+       ovp16 = ((3650 - bms.adc_offset) * 1000) / bms.adc_gain_uV;
+       ovp = ((ovp16 >> 4) & 0xFF);
+       ret = bq769x0_bms_set_ranges(&bms, uvlo, ovp, 0x02, 0);
+       if (ret != 0) {
+               debug_uprintf("BMS limit configuration error: %d (%d)!\n", ret, bms.probe_ok);
+       } else {
+               debug_uprintf("Limits set. \n UVLO: 2.6V (0x%02x), OVP: 3.65V (0x%02x)\n",      uvlo, ovp);
+               debug_uprintf(" SCD: 4.4A (22mV), OCD: 2.8A (14mV)\n");
+       }
+
+       /* Display cells voltage */
+       ret = bq769x0_bms_read_adc(&bms, vcells, ALL_CELLS, BMS_NB_CELLS);
+       if (ret != 0) {
+               debug_uprintf("BMS ADC read error for VCELLS: %d (%d)!\n", ret, bms.probe_ok);
+       } else {
+               int i = 0;
+               int32_t vbatt = 0, v = 0;
+               for (i = 0; i < BMS_NB_CELLS; i++) {
+                       v = ((vcells[i] * bms.adc_gain_uV) / 1000) + bms.adc_offset;
+                       vbatt += v;
+                       debug_uprintf(" Cell %d voltage : %d (mV)\n", i, v);
+               }
+               debug_uprintf("Battery voltage : %d (mV)\n", vbatt);
+       }
+
+       /* Display thermistor voltage */
+       ret = bq769x0_bms_read_adc(&bms, &vth, THERMISTORS, BMS_NB_TH);
+       if (ret != 0) {
+               debug_uprintf("BMS ADC read error for Vth: %d (%d)!\n", ret, bms.probe_ok);
+       } else {
+               uint32_t v = ((vth * 382) / 1000); /* in mV */
+               uint32_t r = (v * 10000) / (3300 - v);
+               debug_uprintf("Thermistor voltage : %d (mV), Rth: %d (Ohms)\n", v, r);
+       }
+}
+
+
+/* Battery allert is set whenever there"s a new CC count to read, or on any battery error */
+volatile uint8_t batt_event_detected = 0;
+void batt_alert(uint32_t gpio)
+{
+       batt_event_detected = 1;
+}
+
+static uint8_t charge_state = 0;
+static uint8_t discharge_state = 0;
+
+/* Count the number of CC cycles since system start.
+ * Wraps after 34 years with CC events every 250ms.
+ */
+static uint32_t cycles = 0;
+
+#define PKT_START  '#'
+struct bms_data {
+       /* Header */
+       uint8_t start;
+       uint8_t status; /* Actual status */
+       uint8_t charge;
+       uint8_t checksum; /* Checksum */
+
+       /* Battery power stored in "mW * s" (milli-Watt second) */
+       uint32_t batt_power;
+       uint32_t batt_power_max;
+       int32_t cycle_power;
+
+       /* Number of cycles since system startup */
+       uint32_t cycles;
+
+       /* Current in mA */
+       int32_t milli_amps;
+
+       /* Vcells in mV */
+       uint16_t vcells[4];
+} __attribute__ ((__packed__));
+
+/* Battery power stored in "mW * s" (milli-Watt second) */
+static uint32_t batt_power = 0;
+static uint32_t batt_power_max = 0;
+
+int thermistor_discharge_hysteresis = 0;
+int thermistor_charge_hysteresis = 0;
+#define THERMISTOR_HYSTERESIS  (4 * 60) /* 60 seconds */
+
+int vbat_charge_hysteresis = 0;
+int vbat_discharge_hysteresis = 0;
+#define VBAT_HYSTERESIS  (4 * 60) /* 60 seconds */
+
+int icharge_hysteresis = 0;
+int idischarge_hysteresis = 0;
+#define ICHARGE_HYSTERESIS  (4 * 60) /* 60 seconds */
+
+/*
+ * Power computation is the following :
+ * E = P * t = U * I * t = Ut * Um / R * t
+ *   E is in Ws (Watt second)
+ *   t = 250ms = 1/4s  (CC integration time)
+ *   R = 5 * 10^-3 Ohms
+ *   Um is measured through CC in uV (10^-6), N is the value when Ut = N * 10^-6 Volts
+ *   Ut is the battery voltage
+ * E = Ut * N * 10^-6 / ( 5 * 10^-3 * 4)
+ * E = Ut * N * 10^-3 / 20
+ *   CC readings have a 8.44uV LSB, so N / 20 = CC * 8.44 / 20 = CC * 0.422
+ *   max CC reading is +/- 32000 which is 270.08 mV and represents approx 54 Amps (through 5 mOms)
+ * E = (Ut * CC * 422 / 1000) * 10^-3
+ *  or
+ * E = (Ut * (CC * 844 / 500) / 4 * 10^-3  (Watt second)
+ *
+ * Current computation is :
+ * CC LSB is 8.44uV --> CC in uV
+ * I = U/R = (cc * 844 / 100) * 10^-6 / (5 * 10^-3)
+ * I = (cc * 844 / 500 ) * 10^-3 A = (cc * 844 / 500) mA
+ */
+int periodic_check(void)
+{
+       struct bms_data bdata = {0};
+       int32_t vbatt = 0;
+       uint16_t vcells[BMS_NB_CELLS] = {0};
+       uint16_t vcells_max = 0;
+       int16_t cc = 0;
+       int32_t milli_amps = 0;
+       uint16_t vth = 0;
+       uint8_t charge = 1, discharge = 1;
+       uint8_t status = 0;
+       int ret = 0;
+
+       /* Read global status */
+       ret = bq769x0_bms_get_and_erase_status(&bms, &status);
+       if (ret != 0) {
+               debug_uprintf("Battery Management System get status error: %d\n", ret);
+               return -1;
+       }
+       bdata.status = status;
+
+       if (status & 0x3F) {
+               /* Perform necessary actions ! */
+               if (SHORT_CIRCUIT_DISCHARGE(status)) {
+                       charge = 0, discharge = 0;
+                       /* FIXME : Disable for a longer time */
+               } else if (OVER_CURRENT_DISCHARGE(status)) {
+                       charge = 0, discharge = 0;
+               } else if (OVER_VOLTAGE(status)) {
+                       charge = 0;
+               } else if (UNDER_VOLTAGE(status)) {
+                       discharge = 0;
+               }
+               debug_uprintf(" BMS status: 0x%02x\n", status);
+       }
+
+       /* Update battery state based on errors immediately */
+       if ((charge + discharge) != 2) {
+               msleep(2);
+               ret = bq769x0_bms_change_state(&bms, charge, discharge);
+               if (ret != 0) {
+                       debug_uprintf(" BMS Change state error ch:%d, dis:%d\n", charge, discharge);
+               } else {
+                       debug_uprintf(" BMS state changed on error condition : charge: %d, discharge: %d\n", charge, discharge);
+                       charge_state = charge;
+                       discharge_state = discharge;
+               }
+       }
+
+
+       /* Read thermistor voltage */
+       msleep(2);
+       ret = bq769x0_bms_read_adc(&bms, &vth, THERMISTORS, BMS_NB_TH);
+       if (ret != 0) {
+               debug_uprintf("BMS ADC read error for Vth: %d (%d)!\n", ret, bms.probe_ok);
+       } else {
+               uint32_t v = ((vth * 382) / 1000);  /* in mV */
+               uint32_t r = (v * 10000) / (3300 - v);
+               debug_uprintf("Thermistor voltage : %d (mV), Rth: %d (Ohms)\n", v, r);
+               /* Stop charge if temp too high or too low
+                * Rth is 55k at -10°C, 32k at 0°C, 10k at 25°C, 5k at 45°C and 2.5k at 60°C.
+                * Stop charge above 32k or below 5k, and stop use above 55k and below 2.5k
+                */
+               if ((r > 55000) || (r < 2500)) {
+                       discharge = 0;
+                       debug_uprintf("Discharge disabled for 60s due to battery temperature\n");
+                       thermistor_discharge_hysteresis = THERMISTOR_HYSTERESIS;
+               }
+               if ((r > 32000) || (r < 5000)) {
+                       debug_uprintf("Charge disabled for 60s due to battery temperature\n");
+                       charge = 0;
+                       thermistor_charge_hysteresis = THERMISTOR_HYSTERESIS;
+               }
+       }
+       if (thermistor_discharge_hysteresis > 0) {
+               thermistor_discharge_hysteresis--;
+               discharge = 0;
+       } else if (thermistor_charge_hysteresis  > 0) {
+               thermistor_charge_hysteresis--;
+               charge = 0;
+       }
+
+       /* Display cells voltage */
+       msleep(2);
+       ret = bq769x0_bms_read_adc(&bms, vcells, ALL_CELLS, BMS_NB_CELLS);
+       if (ret != 0) {
+               debug_uprintf("BMS ADC read error for VCELLS: %d (%d)!\n", ret, bms.probe_ok);
+       } else {
+               int i = 0;
+               uint32_t v = 0;
+               uint8_t cnt = 0;
+               for (i = 0; i < BMS_NB_CELLS; i++) {
+                       /* Real number of cells is 4, so skip cell number 3 */
+                       if (i == 3) { continue; }
+                       v = ((vcells[i] * bms.adc_gain_uV) / 1000) + bms.adc_offset;
+                       vbatt += v;
+                       debug_uprintf(" Cell %d : %d (mV)\n", i, v);
+                       if (v > 3650) {
+                               /* Do not charge over 3.65 Volt */
+                               charge = 0;
+                               vbat_charge_hysteresis = VBAT_HYSTERESIS;
+                               debug_uprintf("BMS detected over charge for cell %d, charge turned OFF\n", cnt);
+                       }
+                       if (v < 2650) {
+                               /* Do not discharge below 2.65 Volt */
+                               discharge = 0;
+                               vbat_discharge_hysteresis = VBAT_HYSTERESIS;
+                               debug_uprintf("BMS detected over discharge for cell %d, discharge turned OFF\n", cnt);
+                       }
+                       bdata.vcells[cnt++] = v;
+                       /* Keep track of highest vcell */
+                       if (v > vcells_max) {
+                               vcells_max = v;
+                       }
+               }
+               debug_uprintf("Battery voltage : %d (mV)\n", vbatt);
+       }
+       if (vbat_charge_hysteresis > 0) {
+               vbat_charge_hysteresis--;
+               charge = 0;
+       }
+       if (vbat_discharge_hysteresis > 0) {
+               vbat_discharge_hysteresis--;
+               discharge = 0;
+       }
+
+       /* Display Coulomb counter */
+       if (CC_READY(status)) {
+               msleep(2);
+               ret = bq769x0_bms_read_adc(&bms, (uint16_t*)&cc, CC_COUNT, 1);
+               if (ret != 0) {
+                       debug_uprintf("BMS ADC read error for CC_COUNT: %d (%d)!\n", ret, bms.probe_ok);
+               } else {
+                       int32_t cycle_power = 0;
+                       int32_t tmp = ((cc * 844) / 100);
+                       milli_amps = tmp / 5; /* See on top of function for explanation */
+
+                       if (milli_amps > 2000) {
+                               /* Do not charge at over 2 Amp */
+                               charge = 0;
+                               icharge_hysteresis = ICHARGE_HYSTERESIS;
+                               debug_uprintf("BMS detected fast charge over 2Amp, charge turned OFF\n");
+                       }
+                       if (milli_amps < (-4500)) {
+                               /* Do not discharge at over 4.5 Amp */
+                               discharge = 0;
+                               idischarge_hysteresis = ICHARGE_HYSTERESIS;
+                               debug_uprintf("BMS detected fast discharge over 4.5Amp, discharge turned OFF\n");
+                       }
+                       debug_uprintf("CC reading: %d : %d uV\n", cc, tmp);
+                       debug_uprintf("Current: %d mA\n", milli_amps);
+
+                       /* Compute power */
+                       cycle_power = ((vbatt * tmp) / (20 * 1000)); /* vbatt is in mV */
+                       debug_uprintf("Power: %d (mWs)\n", cycle_power);
+                       if ((cycle_power > 0) || (batt_power > abs(cycle_power))) {
+                               batt_power += cycle_power;
+                       } else {
+                               /* batt_power reflect remaining battery juce, so getting lower means we are
+                                * getting more out of the battery, but there cannot be less than 0 */
+                               batt_power = 0;
+                               debug_uprintf("Battery has more than that !\n");
+                       }
+
+                       if (batt_power > batt_power_max) {
+                               /* Update max battery power */
+                               batt_power_max = batt_power;
+                               /* Save max battery charge to the third retain registers */
+                               ret = save_gp_retain(&batt_power_max, 1, 2);
+                               debug_uprintf("Battery max power updated: %d (ret: %d)\n", batt_power_max, ret);
+                       }
+                       /* Shift by 10 is equivalent to divide by approx 10^3 (1024) */
+                       debug_uprintf("Battery remaining power : %d/%d (Ws)\n", (batt_power >> 10), (batt_power_max >> 10)); /* divide by 1024 */
+
+                       /* Count 1 cycle for each battery event */
+                       cycles++;
+                       bdata.cycles = cycles;
+                       bdata.milli_amps = milli_amps;
+                       bdata.cycle_power = cycle_power;
+                       bdata.batt_power = batt_power;
+                       bdata.batt_power_max = batt_power_max;
+               }
+               /* Save current battery charge status to the first retain registers */
+               save_gp_retain(&batt_power, 1, 0);
+       }
+       if (icharge_hysteresis > 0) {
+               icharge_hysteresis--;
+               charge = 0;
+       }
+       if (idischarge_hysteresis > 0) {
+               idischarge_hysteresis--;
+               discharge = 0;
+       }
+
+       /* Update battery state based on errors and old state immediately */
+       if ((charge != charge_state) || (discharge != discharge_state)) {
+               msleep(2);
+               ret = bq769x0_bms_change_state(&bms, charge, discharge);
+               if (ret != 0) {
+                       debug_uprintf(" BMS Change state error ch:%d, dis:%d\n", charge, discharge);
+               } else {
+                       debug_uprintf(" BMS state changed : charge: %d, discharge: %d\n", charge, discharge);
+                       charge_state = charge;
+                       discharge_state = discharge;
+               }
+       }
+
+       /* Update led only in critical cases */
+       if ((charge_state + discharge_state) == 2) {
+               /* Everything OK, clear led */
+               gpio_set(led);
+       } else if ((vcells_max < 3660) && (OVER_VOLTAGE(status) || (vbat_charge_hysteresis > 0))) {
+               /* Over voltage when charging but not critical, only end of charge */
+               gpio_set(led);
+       } else {
+               /* Error : set led */
+               gpio_clear(led);
+       }
+       
+       if (verbose >= 1) {
+               int i = 0;
+               uint8_t* data = (uint8_t*)(&bdata);
+               uint8_t cksum = 0;
+
+               bdata.start = PKT_START;
+               bdata.charge = (charge_state | (discharge_state << 4));
+               for (i = 0; i < sizeof(struct bms_data); i++) {
+                       cksum += data[i];
+               }
+
+               debug_uprintf("Tick : %d - State C: %d, D: %d\n", systick_get_tick_count(), charge_state, discharge_state);
+
+               bdata.checksum = (uint8_t)(256 - cksum);
+               serial_write(UART1, (char*)(&bdata), sizeof(struct bms_data));
+       }
+
+       return 0;
+}
+
+volatile uint8_t cmd = 0;
+void cmd_rx(uint8_t c)
+{
+       cmd = c;
+}
+
+int handle_cmd(void)
+{
+       int ret = 0;
+
+       switch (cmd) {
+               /* Charge control */
+               case 'C': /* Charge Enable */
+                       ret = bq769x0_bms_change_state(&bms, 1, discharge_state); /* charge on, discharge on */
+                       if (ret != 0) {
+                               debug_uprintf(" BMS CMD Enable charge error ch:%d, dis:%d\n", charge_state, discharge_state);
+                       } else {
+                               debug_uprintf("BMS charge Enabled\n");
+                               charge_state = 1;
+                       }
+                       break;
+               case 'S': /* Charge Disable (Stop) */
+                       ret = bq769x0_bms_change_state(&bms, 0, discharge_state); /* charge off, discharge on*/
+                       if (ret != 0) {
+                               debug_uprintf(" BMS CMD Stop charge error ch:%d, dis:%d\n", charge_state, discharge_state);
+                       } else {
+                               debug_uprintf("BMS charge Disabled\n");
+                               charge_state = 0;
+                       }
+                       break;
+
+               /* Verbosity control : turn verbosity on or off to save power */
+               case 'L': /* Low power */
+                       debug_uprintf("Setting verbosity to 0\n");
+                       verbose = 0;
+                       break;
+               case 'v':
+                       debug_uprintf("Setting verbosity to 1\n");
+                       verbose = 1;
+                       break;
+               case 'V':
+                       verbose = 2;
+                       debug_uprintf("Verbosity set to 2\n");
+                       break;
+       }
+       return 0;
+}
+
+/***************************************************************************** */
+/* Use a countdown value to track activity and go to sleep state */
+#define PING_RESET_VAL  128
+static uint8_t ping = PING_RESET_VAL;
+
+int enter_sleep_mode(void)
+{
+       /* FIXME */
+       msleep(500);
+       return 0;
+}
+
+/***************************************************************************** */
+int main(void)
+{
+       system_init();
+       uart_on(UART0, 115200, cmd_rx);
+       uart_on(UART1, 115200, cmd_rx);
+
+       debug_uprintf("Sarting\n");
+       /* I2C config */
+       i2c_on(I2C0, I2C_CLK_100KHz, I2C_MASTER);
+       msleep(10);
+       bms_config();
+
+       debug_uprintf("I2C config done\n");
+
+       /* GPIO configuration */
+       config_gpio(&led, 0, GPIO_DIR_OUT, 0); /* FIXME : Starting with led ON for debug, set to 1 (OFF) for normal case */
+       config_gpio(&alert, 0, GPIO_DIR_IN, 0);
+
+       debug_uprintf("GPIO config done\n");
+
+       /* Activate on both edges */
+       set_gpio_callback(batt_alert, &alert, EDGES_BOTH);
+       debug_uprintf("Button config done\n");
+
+       /* Read old battery state values */
+       read_gp_retain(&batt_power_max, 1, 2);
+       read_gp_retain(&batt_power, 1, 0);
+       /* Shift by 10 is equivalent to divide by approx 10^3 (1024) */
+       debug_uprintf("Batt power from retain registers: max: %d, actual: %d\n",
+                                               (batt_power_max >> 10), (batt_power >> 10));
+
+       /* Perform a first periodic check to make sure we did not miss an alert,
+        * but wait for the 250ms delay requested for BMS stability as requested in section
+        * 10.3 "Feature description" (10.3.1.1.2) of BQ76920 datasheet (SLUSBK2H)
+        */
+       msleep(400);
+       periodic_check();
+
+       /* Lower the verbosity */
+       verbose = 0;
+
+       while (1) {
+
+               if (batt_event_detected == 1) {
+                       periodic_check();
+                       batt_event_detected = 0;
+                       /* Decrease the ping counter */
+                       if (ping > 0) {
+                               ping--;
+                       }
+               }
+
+               if (cmd != 0) {
+                       handle_cmd();
+                       ping = PING_RESET_VAL;
+                       cmd = 0;
+               }
+
+               /* Ping counter reached 0, go to sleep mode */
+               if (ping == 0) {
+                       verbose = 2;
+                       periodic_check();
+                       //enter_sleep_mode();
+               }
+       }
+       return 0;
+}
+
+
+
+