]> www.fi.muni.cz Git - bike-lights.git/blobdiff - firmware/battery.c
Error flags, error reporting
[bike-lights.git] / firmware / battery.c
index 472c1c47f099093c59bfe6454983276687e9dad8..4763f0563334f99423d99a6e2f9893cabe034a27 100644 (file)
@@ -2,12 +2,36 @@
 
 #include "lights.h"
 
+#define BATTERY_ADC_SHIFT      6
 #define RESISTOR_HI    1500    // kOhm
-#define RESISTOR_LO     150    // kOhm
+#define RESISTOR_LO     100    // kOhm
+/*
+ * The internal 1.1V reference has tolerance from 1.0 to 1.2V
+ * (datasheet, section 19.6). We have to measure the actual value
+ * of our part.
+ */
+#define AREF_1100MV    1060    // mV
 
-volatile unsigned char battery_100mv;
+static volatile uint16_t battery_adcval;
+volatile unsigned char battery_critical;
+
+void init_battery()
+{
+       battery_adcval = 0;
+       battery_critical = 0;
+}
 
 void battery_adc(uint16_t adcval)
+{
+       if (battery_adcval == 0) {
+               battery_adcval = adcval << BATTERY_ADC_SHIFT;
+       } else { // running average
+               battery_adcval += (adcval
+                       - (battery_adcval >> BATTERY_ADC_SHIFT));
+       }
+}
+
+unsigned char battery_100mv()
 {
        /*
         * This is tricky: we need to maintain precision, so we first
@@ -17,9 +41,89 @@ void battery_adc(uint16_t adcval)
         * We don't do running average, as the required precision
         * is coarse (0.1 V).
         */
-       battery_100mv = (unsigned char)
-               ((adcval * 11                              // 1.1V
+       return (unsigned char)
+               ((uint16_t)(
+               (battery_adcval >> BATTERY_ADC_SHIFT)
+               * (11                                      // 1.1V
                * (RESISTOR_HI+RESISTOR_LO)/RESISTOR_LO    // resistor ratio
-               / 4) >> 8);                                // divide by 1024
+               / 4)) >> 8);                               // divide by 1024
 }
 
+/* convert value in mV to value of ADC shifted by BATTERY_ADC_SHIFT */
+#define MV_TO_ADC(x) \
+       ((uint16_t)(((uint32_t)(x) * 1024 * (1 << BATTERY_ADC_SHIFT)) \
+               / ((uint32_t) AREF_1100MV \
+                       * ((RESISTOR_HI+RESISTOR_LO)/RESISTOR_LO))))
+
+/* convert value in mV to upper 8 bits of ADC value << BATTERY_ADC_SHIFT */
+#define MV_TO_ADC8(x)  ((unsigned char)(MV_TO_ADC(x) >> 8))
+
+/*
+ * Returns number from 1 to 10 (1 = battery almost empty, 10 = full)
+ * Lithium cells have voltage from about 2.9V to 4.1V. We consider battery
+ * above 4V full, and under 3.2V critically low. We guess whether
+ * the battery has two or three cells - voltages above 8.6V are considered
+ * from three-cell battery.
+ */
+unsigned char battery_gauge()
+{
+       unsigned char b8 = battery_adcval >> 8;
+       unsigned char rv;
+
+       if        (b8 < MV_TO_ADC8(2 * 3200)) {
+               rv = 1;
+       } else if (b8 < MV_TO_ADC8(2 * 3475)) {
+               rv = 2;
+       } else if (b8 < MV_TO_ADC8(2 * 3577)) {
+               rv = 3;
+       } else if (b8 < MV_TO_ADC8(2 * 3620)) {
+               rv = 4;
+       } else if (b8 < MV_TO_ADC8(2 * 3741)) {
+               rv = 5;
+       } else if (b8 < MV_TO_ADC8(2 * 3775)) {
+               rv = 6;
+       } else if (b8 < MV_TO_ADC8(2 * 3844)) {
+               rv = 7;
+       } else if (b8 < MV_TO_ADC8(2 * 3930)) {
+               rv = 8;
+       } else if (b8 < MV_TO_ADC8(2 * 4000)) {
+               rv = 9;
+       } else if (b8 < MV_TO_ADC8(2 * 4300)) {
+               rv = 10;
+       } else if (b8 < MV_TO_ADC8(3 * 3200)) { // three-cell battery
+               rv = 1;
+       } else if (b8 < MV_TO_ADC8(3 * 3475)) {
+               rv = 2;
+       } else if (b8 < MV_TO_ADC8(3 * 3577)) {
+               rv = 3;
+       } else if (b8 < MV_TO_ADC8(3 * 3620)) {
+               rv = 4;
+       } else if (b8 < MV_TO_ADC8(3 * 3741)) {
+               rv = 5;
+       } else if (b8 < MV_TO_ADC8(3 * 3775)) {
+               rv = 6;
+       } else if (b8 < MV_TO_ADC8(3 * 3844)) {
+               rv = 7;
+       } else if (b8 < MV_TO_ADC8(3 * 3930)) {
+               rv = 8;
+       } else if (b8 < MV_TO_ADC8(3 * 4000)) {
+               rv = 9;
+       } else {
+               rv = 10;
+       }
+
+#if 0
+       if (battery_adcval && rv == 1)
+               err_flags.err_battery = 1;
+       else
+               err_flags.err_battery = 0;
+#endif
+
+#if 0
+       log_byte(0xbb);
+       log_byte(rv);
+       log_flush();
+#endif
+
+       return rv;
+}