Heltec ESP32 only charging to 40% at 3.65V

My Heltec ESP32 module is only charging to 40% at 3.65V.

I am using a 100mA 3.7V Battery.

Tried 1.2.45 Beta and 1.2.49 Alpha FW

Anyone else having this issue?

Perhaps the battery is too small?

Thanks

Hi,

Had the same issue, I fixed this by changing the ADC_MULTIPLIER to 3.75 (in configuration.h) instead the 3.2 by default.

To calculate the exact multiplier you can test that:
-measure the voltage on the battery pluged in the Heltec with the usb power source unplugged ( Voltage1 ).
-write down the voltage shown on the screen of Heltec ( Voltage2 ).
-Now divide the voltage shown on the screen by 3.2 ( value of the Heltecs infernal voltage divider bridge ), then divide the measured voltage of the battery by the prévious result.

Ex:
Admit your battery is full charged, ( Voltage 1 = approx 4.2 V ), and HELTEC showing 3.65 V (V2)

Voltage2 / 3,2 = 3.65 / 3.2 = 1,140625
then
Voltage1 / 1.140625 = 4.2 / 1.140625 = 3,68…

I have compile 3 firmwares with differents ADC MULTIPLIER for HELTEC V2.1 [1.2.49.5354c49 alpha]
3.75 / 3.70 or 3.68.

https://drive.google.com/drive/folders/11ZDinEPILCysmWVHV3-4HvuXDFoh6reV?usp=sharing

You can download them and try.

Bisx

Cool - I will try them out.

Thanks very much!

Are those numbers reported by the firmware, or manual readings directly at the battery?

I ve checked with multimeter ( pin 37 ) compared with the real battery voltage and the divider bridge of 3,2 is correct. I think there is a problem with the translation of ADC reading ( factor correction or/and ADC resolution ), so i compensate it by changing the value of ADC MULTIPLIER to match the best value corresponding to the real battery voltage (measured by multimeter ). It’s not 100 % accurate by better than default values cause to the non linearity of the adc reading. I ll do some more tests to correct the readings. When the device show “low voltage” 3,25v (0%) and go to sleep, i have a difference of approx +0,25 v on battery voltage (3,5 v). I ll do a two points measurement (full charged 4,2v and dischargerd battery 3,25 v) and map the values in between. Check the file power.cpp in the src/ file of meshtastic device github, you ll see the formule employed to calculate the voltage.

Here’s mine for TLora32 2.1:

Firmware. Actual
75%. 5v USB
70%. 4.2V
32%. 3.95V
8%. 3.7V

Looks like if the firmware reads it 25% higher, should be much more accurate.

Dunno how the 70% of 4.2v came up. Here’s the formula for the battery voltage measurement:

#define MIN_BAT_MILLIVOLTS 3250 // millivolts. 10% per Lipo Voltage Chart: Show the Relationship of Voltage and Capacity - Ampow Blog
#define BAT_MILLIVOLTS_FULL 4100
#define BAT_MILLIVOLTS_EMPTY 3500

batteryChargePercent =
clamp((int)(((batteryVoltageMv - BAT_MILLIVOLTS_EMPTY) * 1e2) / (BAT_MILLIVOLTS_FULL - BAT_MILLIVOLTS_EMPTY)),
0, 100);

I doubt it’s because of the non-linearity of the ESP32 ADC (I have not checked the adc raw values to see if they’re affected ) but it’s possible.

I think the gist of what we’re suggesting is that the mV value read by firmware is different from the actual battery mV read by a multimeter, by about 0.25V. The result of which is that a full charge is read as 70% and 3.7V is read as 8%.

Is the battery mV being read directly by a 5V ADC via GPIO? Is there anything that might affect this reading?

It’s a 0V to 3.3V measurement, so the measurement of the device under test is scaled down with the voltage divider.

It s not this formule the problem, it s this one :

scaled = 1000.0 * ADC_MULTIPLIER * (AREF_VOLTAGE / 1024.0) * raw;

Scaled doesnt correspond to real voltage, raw with adc_10 bits and without ADC_ATTEN_DB_6 shows a raw value to low, its needs some mapping.

Tested with another sketch and using the eblock efuse values gives me an accuracy of max 0,02mv difference.

1 Like

You may be onto something.

I updated the battery voltage reading for the RAK4631 board a few months ago. You may want to take a look at how that is done and design something similar for the Heltec board.

In the varaiant.h I defined VBAT_RAW_TO_SCALED(x)

Meshtastic-device/variants/WisCore_RAK4631_Board/variant.h

#define VBAT_MV_PER_LSB (0.73242188F)
// Voltage divider value => 1.5M + 1M voltage divider on VBAT = (1.5M / (1M + 1.5M))
#define VBAT_DIVIDER (0.4F)
// Compensation factor for the VBAT divider
#define VBAT_DIVIDER_COMP (1.73)
// Fixed calculation of milliVolt from compensation value
#define REAL_VBAT_MV_PER_LSB (VBAT_DIVIDER_COMP * VBAT_MV_PER_LSB)
#undef AREF_VOLTAGE
#define AREF_VOLTAGE 3.0
#define VBAT_AR_INTERNAL AR_INTERNAL_3_0
#define ADC_MULTIPLIER VBAT_DIVIDER_COMP //REAL_VBAT_MV_PER_LSB
#define VBAT_RAW_TO_SCALED(x) (REAL_VBAT_MV_PER_LSB * x)

It is used in Meshtastic-device/src/Power.cpp

if (millis() - last_read_time_ms > min_read_interval) {
    last_read_time_ms = millis();
    uint32_t raw = analogRead(BATTERY_PIN);
    float scaled;
    #ifndef VBAT_RAW_TO_SCALED
    scaled = 1000.0 * ADC_MULTIPLIER * (AREF_VOLTAGE / 1024.0) * raw;
    #else
    scaled = VBAT_RAW_TO_SCALED(raw); //defined in variant.h
    #endif
    // DEBUG_MSG("battery gpio %d raw val=%u scaled=%u\n", BATTERY_PIN, raw, (uint32_t)(scaled));
    last_read_value = scaled;
    return scaled;
} else {
    return last_read_value;
}

The Heltec board is an old one and it is not using the variant way of defining things. First step would be to figure out how a variant is defined and used for this board.

The most important is to get the best accurate readings between 3600mv and 3000mv, cause these two value (showed below) triggers events to deepsleep the module or to shutdown it. If the reading is not accurate in this range this may set your device unresponsive too early despite your battery is in real already charged.

Power.h :

MIN_BAT_MILLIVOLTS 3250

BAT_MILLIVOLTS_EMPTY 3500

Another question : May the fact that the pin 37 is equaly designed for GPS in the the configuration.h influence the reading of the adc by changing the pinmode, adc width ???

I can confirm that the ADC_MULTIPLIER value for the heltec_v2.1 needs to be about 3.65 or so.

It should not be 3.2 as defined for the heltec_v2
For my 2 devices, one needed 3.69 and a second needed 3.54 as adc_multiplier to get a display reading within +/- 1% of the battery reading.

1 Like

The heltec is using a variant now so you should be able to do something similar to the rak 4631

True, there is a place , for every different piece of hardware, where a compensation value can be defined.
Sadly this value cannot be modified by a user, only by ppl who compile for themself.
For the heltec2.1 we found already three different values in this topic: 3.75 , 3.69 and 3.54
These differences of upto 6 % means a lot .