diff --git a/openrtx/include/battery.h b/openrtx/include/battery.h index aed28038..b062c0cd 100644 --- a/openrtx/include/battery.h +++ b/openrtx/include/battery.h @@ -20,12 +20,13 @@ #ifndef BATTERY_H #define BATTERY_H +#include + /** - * This function uses battery charge tables to convert a battery voltage into a - * charge percentage. - * @param vbat: the voltage read from the battery in volt. - * @return the charge percentage. + * This function computes the battery's state of charge given its current voltage. + * @param vbat: battery voltage in millivolt. + * @return state of charge percentage, from 0% to 100%. */ -float battery_getCharge(float vbat); +uint8_t battery_getCharge(uint16_t vbat); #endif /* BATTERY_H */ diff --git a/openrtx/src/battery.c b/openrtx/src/battery.c index 62026f8e..f350c760 100644 --- a/openrtx/src/battery.c +++ b/openrtx/src/battery.c @@ -21,35 +21,59 @@ #include #include -/* This array acts as a lookup table for converting Li-Po voltage into - * charge percentage, elements range from 5% to 95% (included) with 5% steps. - * Data is taken from (https://blog.ampow.com/lipo-voltage-chart/). +/* + * Minimum and maximum battery voltages expressed in fixed point Q8.8 format. + * Obtained by multiplying the values in volt by 256. */ -#define V_LUT_STEPS 21 + #if defined BAT_LIPO_1S -float bat_v_min = 3.61f; -float bat_v_max = 4.15f; +static const uint16_t bat_v_min = 0x039C; // 3.61V +static const uint16_t bat_v_max = 0x0426; // 4.15V #elif defined BAT_LIPO_2S -float bat_v_min = 7.10f; -float bat_v_max = 8.10f; +static const uint16_t bat_v_min = 0x071A; // 7.10V +static const uint16_t bat_v_max = 0x0819; // 8.10V #elif defined BAT_LIPO_3S -float bat_v_min = 10.83; -float bat_v_max = 12.45; +static const uint16_t bat_v_min = 0x0AD4; // 10.83V +static const uint16_t bat_v_max = 0x0C73; // 12.45V #elif defined BAT_NONE -float bat_v_min = 0.0; -float bat_v_max = 0.0; +static const uint16_t bat_v_min = 0; +static const uint16_t bat_v_max = 0; #else #error Please define a battery type into platform/targets/.../hwconfig.h #endif -float battery_getCharge(float vbat) +uint8_t battery_getCharge(uint16_t vbat) { - #ifndef BAT_NONE - // Perform a linear interpolation between minimum and maximum charge values. - return (vbat - bat_v_min) / (bat_v_max - bat_v_min); - #else - // Return full charge if no battery is present. + #ifdef BAT_NONE + /* Return full charge if no battery is present. */ (void) vbat; - return 1.0f; + return 100; + #else + + /* + * Compute battery percentage by linear interpolation between zero and full + * charge voltage values using Q8.8 fixed-point math to avoid using both + * floating point and 64 bit variables, for maximum portability. + * + * Given that battery voltage parameter is an unsigned 16 bit value expressing + * the voltage in mV, we first have to convert it to Q8.8 before computing + * the charge percentage. + * + * Comparison between battery percentage computed using fixed point and + * floating point routines on a voltage range from 10.83V to 12.45V with + * increments of 1mV resulted in an average error of -0.015%, maximum error + * of 0.79% and minimum error of -0.78% + */ + + uint32_t vb = vbat << 16; + vb = vb / 1000; + vb = (vb + 256) >> 8; + + uint32_t diff = vb - bat_v_min; + uint32_t range = bat_v_max - bat_v_min; + uint32_t result = ((diff << 8) / range) * 100; + result += 128; + return result >> 8; + #endif }