Skip to content

Commit

Permalink
battery voltage is now calculated using eFuse calibration #79
Browse files Browse the repository at this point in the history
  • Loading branch information
lmarzen committed Feb 17, 2024
1 parent 22f886a commit 607a0ba
Show file tree
Hide file tree
Showing 7 changed files with 87 additions and 43 deletions.
9 changes: 5 additions & 4 deletions platformio/include/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -278,10 +278,11 @@ extern const long SLEEP_DURATION;
extern const int BED_TIME;
extern const int WAKE_TIME;
extern const int HOURLY_GRAPH_MAX;
extern const float BATTERY_WARN_VOLTAGE;
extern const float LOW_BATTERY_VOLTAGE;
extern const float VERY_LOW_BATTERY_VOLTAGE;
extern const float CRIT_LOW_BATTERY_VOLTAGE;
extern const uint32_t MAX_BATTERY_VOLTAGE;
extern const uint32_t WARN_BATTERY_VOLTAGE;
extern const uint32_t LOW_BATTERY_VOLTAGE;
extern const uint32_t VERY_LOW_BATTERY_VOLTAGE;
extern const uint32_t CRIT_LOW_BATTERY_VOLTAGE;
extern const unsigned long LOW_BATTERY_SLEEP_INTERVAL;
extern const unsigned long VERY_LOW_BATTERY_SLEEP_INTERVAL;

Expand Down
5 changes: 3 additions & 2 deletions platformio/include/display_utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,9 @@ enum alert_category {
STRONG_WIND
};

int calcBatPercent(double v);
const uint8_t *getBatBitmap24(int batPercent);
uint32_t readBatteryVoltage();
uint32_t calcBatPercent(uint32_t v, uint32_t minv, uint32_t maxv);
const uint8_t *getBatBitmap24(uint32_t batPercent);
void getDateStr(String &s, tm *timeInfo);
void getRefreshTimeStr(String &s, bool timeSuccess, tm *timeInfo);
void toTitleCase(String &text);
Expand Down
2 changes: 1 addition & 1 deletion platformio/include/renderer.h
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ void drawAlerts(std::vector<owm_alerts_t> &alerts,
void drawLocationDate(const String &city, const String &date);
void drawOutlookGraph(owm_hourly_t *const hourly, tm timeInfo);
void drawStatusBar(const String &statusStr, const String &refreshTimeStr,
int rssi, double batVoltage);
int rssi, uint32_t batVoltage);
void drawError(const uint8_t *bitmap_196x196,
const String &errMsgLn1, const String &errMsgLn2="");

Expand Down
9 changes: 5 additions & 4 deletions platformio/src/config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -127,10 +127,11 @@ const int HOURLY_GRAPH_MAX = 24;
// minutes). Once the battery voltage has fallen to CRIT_LOW_BATTERY_VOLTAGE,
// the esp32 will hibernate and a manual press of the reset (RST) button to
// begin operating again.
const float BATTERY_WARN_VOLTAGE = 3.40; // (volts)
const float LOW_BATTERY_VOLTAGE = 3.20; // (volts)
const float VERY_LOW_BATTERY_VOLTAGE = 3.10; // (volts)
const float CRIT_LOW_BATTERY_VOLTAGE = 3.00; // (volts)
const uint32_t MAX_BATTERY_VOLTAGE = 4200; // (millivolts)
const uint32_t WARN_BATTERY_VOLTAGE = 3400; // (millivolts)
const uint32_t LOW_BATTERY_VOLTAGE = 3200; // (millivolts)
const uint32_t VERY_LOW_BATTERY_VOLTAGE = 3100; // (millivolts)
const uint32_t CRIT_LOW_BATTERY_VOLTAGE = 3000; // (millivolts)
const unsigned long LOW_BATTERY_SLEEP_INTERVAL = 30; // (minutes)
const unsigned long VERY_LOW_BATTERY_SLEEP_INTERVAL = 120; // (minutes)

Expand Down
78 changes: 62 additions & 16 deletions platformio/src/display_utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
#include <cmath>
#include <vector>
#include <Arduino.h>
#include <driver/adc.h>
#include <esp_adc_cal.h>

#include <aqi.h>

Expand All @@ -35,29 +37,73 @@
#include "icons/icons_64x64.h"
#include "icons/icons_196x196.h"

/* Returns battery voltage in millivolts (mv).
*/
uint32_t readBatteryVoltage()
{
esp_adc_cal_characteristics_t adc_chars;
esp_adc_cal_value_t val_type;
adc_power_acquire();
uint16_t adc_val = analogRead(PIN_BAT_ADC);
adc_power_release();

// We will use the eFuse ADC calibration bits, to get accurate voltage
// readings. The DFRobot FireBeetle Esp32-E V1.0's ADC is 12 bit, and uses
// 11db attenuation, which gives it a measurable input voltage range of 150mV
// to 2450mV.
val_type = esp_adc_cal_characterize(ADC_UNIT_1, ADC_ATTEN_11db,
ADC_WIDTH_BIT_12, 1100, &adc_chars);

#if DEBUG_LEVEL >= 1
if (val_type == ESP_ADC_CAL_VAL_EFUSE_VREF)
{
Serial.println("[debug] ADC Cal eFuse Vref");
}
else if (val_type == ESP_ADC_CAL_VAL_EFUSE_TP)
{
Serial.println("[debug] ADC Cal Two Point");
}
else
{
Serial.println("[debug] ADC Cal Default");
}
#endif

uint32_t batteryVoltage = esp_adc_cal_raw_to_voltage(adc_val, &adc_chars);
// DFRobot FireBeetle Esp32-E V1.0 voltage divider (1M+1M), so readings are
// multiplied by 2.
batteryVoltage *= 2;
return batteryVoltage;
} // end readBatteryVoltage

/* Returns battery percentage, rounded to the nearest integer.
* Takes a voltage and uses a pre-calculated polynomial to find an approximation
* of the battery life percentage remaining.
* Takes a voltage in millivolts and uses a sigmoidal approximation to find an
* approximation of the battery life percentage remaining.
*
* This function contains LGPLv3 code from
* <https://github.com/rlogiacco/BatterySense>.
*
* Symmetric sigmoidal approximation
* <https://www.desmos.com/calculator/7m9lu26vpy>
*
* c - c / (1 + k*x/v)^3
*/
int calcBatPercent(double v)
uint32_t calcBatPercent(uint32_t v, uint32_t minv, uint32_t maxv)
{
// this formula was calculated using samples collected from a lipo battery
double y = - 144.9390 * v * v * v
+ 1655.8629 * v * v
- 6158.8520 * v
+ 7501.3202;

// enforce bounds, 0-100
y = max(y, 0.0);
y = min(y, 100.0);

y = round(y);
return static_cast<int>(y);
// slow
//uint32_t p = 110 - (110 / (1 + pow(1.468 * (v - minv)/(maxv - minv), 6)));

// steep
//uint32_t p = 102 - (102 / (1 + pow(1.621 * (v - minv)/(maxv - minv), 8.1)));

// normal
uint32_t p = 105 - (105 / (1 + pow(1.724 * (v - minv)/(maxv - minv), 5.5)));
return p >= 100 ? 100 : p;
} // end calcBatPercent

/* Returns 24x24 bitmap incidcating battery status.
*/
const uint8_t *getBatBitmap24(int batPercent)
const uint8_t *getBatBitmap24(uint32_t batPercent)
{
if (batPercent >= 93)
{
Expand Down
15 changes: 3 additions & 12 deletions platformio/src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
#include <Arduino.h>
#include <Adafruit_BME280.h>
#include <Adafruit_Sensor.h>
#include <driver/adc.h>
#include <Preferences.h>
#include <time.h>
#include <WiFi.h>
Expand Down Expand Up @@ -135,17 +134,9 @@ void setup()
prefs.begin(NVS_NAMESPACE, false);

#if BATTERY_MONITORING
// GET BATTERY VOLTAGE
// DFRobot FireBeetle Esp32-E V1.0 has voltage divider (1M+1M), so readings
// are multiplied by 2. Readings are divided by 1000 to convert mV to V.
adc_power_acquire();
uint16_t batADC = analogRead(PIN_BAT_ADC);
adc_power_release();
double batteryVoltage = static_cast<double>(batADC) / 1000.0 * (3.5 / 2.0);
// use / 1000.0 * (3.3 / 2.0) multiplier above for firebeetle esp32
// use / 1000.0 * (3.5 / 2.0) for firebeetle esp32-E
uint32_t batteryVoltage = readBatteryVoltage();
Serial.print(TXT_BATTERY_VOLTAGE);
Serial.println(": " + String(batteryVoltage, 2));
Serial.println(": " + String(batteryVoltage) + "mv");

// When the battery is low, the display should be updated to reflect that, but
// only the first time we detect low voltage. The next time the display will
Expand Down Expand Up @@ -199,7 +190,7 @@ void setup()
prefs.putBool("lowBat", false);
}
#else
double batteryVoltage = NAN;
uint32_t batteryVoltage = UINT32_MAX;
#endif

// All data should have been loaded from NVS. Close filesystem.
Expand Down
12 changes: 8 additions & 4 deletions platformio/src/renderer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1114,7 +1114,7 @@ void drawOutlookGraph(owm_hourly_t *const hourly, tm timeInfo)
* the display.
*/
void drawStatusBar(const String &statusStr, const String &refreshTimeStr,
int rssi, double batVoltage)
int rssi, uint32_t batVoltage)
{
String dataStr;
uint16_t dataColor = GxEPD_BLACK;
Expand All @@ -1124,13 +1124,17 @@ void drawStatusBar(const String &statusStr, const String &refreshTimeStr,

#if BATTERY_MONITORING
// battery
int batPercent = calcBatPercent(batVoltage);
if (batVoltage < BATTERY_WARN_VOLTAGE) {
uint32_t batPercent = calcBatPercent(batVoltage,
LOW_BATTERY_VOLTAGE,
MAX_BATTERY_VOLTAGE);
#if defined(DISP_3C_B) || defined(DISP_7C_F)
if (batVoltage < WARN_BATTERY_VOLTAGE) {
dataColor = ACCENT_COLOR;
}
#endif
dataStr = String(batPercent) + "%";
#if STATUS_BAR_EXTRAS_BAT_VOLTAGE
dataStr += " (" + String( round(100.0 * batVoltage) / 100.0, 2 ) + "v)";
dataStr += " (" + String( round(batVoltage / 10.f) / 100.f, 2 ) + "v)";
#endif
drawString(pos, DISP_HEIGHT - 1 - 2, dataStr, RIGHT, dataColor);
pos -= getStringWidth(dataStr) + 25;
Expand Down

0 comments on commit 607a0ba

Please sign in to comment.