Skip to content

HeltecV4: Fix battery ADC reading accuracy#2689

Open
TPRoberts wants to merge 2 commits into
meshcore-dev:devfrom
TPRoberts:fix_heltec_v4_battery_adc
Open

HeltecV4: Fix battery ADC reading accuracy#2689
TPRoberts wants to merge 2 commits into
meshcore-dev:devfrom
TPRoberts:fix_heltec_v4_battery_adc

Conversation

@TPRoberts
Copy link
Copy Markdown

Correct ADC_MULTIPLIER from 5.42 to 4.9 to match the R27/R28 resistor divider on the schematic (390kΩ + 100kΩ) / 100kΩ = 4.9.

Also switch from analogRead() with manual 3.3V/1024 conversion to analogReadMilliVolts() at 12-bit resolution, which uses the ESP32's built-in ADC calibration for improved accuracy.

Schematic reference: https://resource.heltec.cn/download/WiFi_LoRa_32_V4

Correct ADC_MULTIPLIER from 5.42 to 4.9 to match the R27/R28 resistor
divider on the schematic (390kΩ + 100kΩ) / 100kΩ = 4.9.

Also switch from analogRead() with manual 3.3V/1024 conversion to
analogReadMilliVolts() at 12-bit resolution, which uses the ESP32's
built-in ADC calibration for improved accuracy.

Schematic reference: https://resource.heltec.cn/download/WiFi_LoRa_32_V4
@fizzyfuzzle
Copy link
Copy Markdown

fizzyfuzzle commented Jun 5, 2026

Thanks for this PR, I also coincidental changed this in my local branch, so I can confirm it works and is more accurate then the current code 👍

One question: do we also need to change the Attenuation to a smaller range to have an even more accurate reading? Because I think the default is: ADC_ATTEN_DB_11 [0 mV ~ 3100 mV], but because of the voltage divider we will never measure above the 1000mv.
https://docs.espressif.com/projects/esp-idf/en/v4.4/esp32s3/api-reference/peripherals/adc.html

e.g.:
analogSetAttenuation(ADC_2_5db);

@TPRoberts
Copy link
Copy Markdown
Author

Hi @fizzyfuzzle

Thanks for testing it. I'm actually still testing mine, was going to wait for full drain and see how it performs before I move it from draft.

You raise a good point though. I think the default attenuator is 11dB but it could go as low as 0dB as the standard Lithium Polymer should only go from 615mV to 857mV at the ADC pin with that divider, so well within the 0dB range. Leaving it at the 11dB default would waste ADC counts and introduce more nonlinearity. I think 0dB gives the best linearity and resolution the ESP32-S3 ADC can offer, what do you think?

The resistor divider (390kΩ/100kΩ) keeps the ADC pin voltage in the
0.61-0.86V range across the full LiPoly range (3.0–4.2V). ADC_2_5db
(~1250mV full-scale) uses ~70% of the ADC range at full charge, giving
better resolution than the default ADC_11db (~20%) while maintaining
headroom over ADC_0db (~950mV) to handle chip-to-chip ADC variation.
@TPRoberts
Copy link
Copy Markdown
Author

TPRoberts commented Jun 5, 2026

Actually, you're suggestion if probably better @fizzyfuzzle , 0 dB might not give enough room on the top range for chip to chip variations, 2.5 dB would probably give better compatibility between users.

Change is made, I moved it from draft for now but I am still going through a full drain.

@TPRoberts TPRoberts marked this pull request as ready for review June 5, 2026 16:37
@TPRoberts
Copy link
Copy Markdown
Author

Mine reports 93%/ 4.12V when fully charged. I didn't take into account the charging IC cuts off charging to 4.2V. if anyone else has feedback on running this branch and can report their full charge and low charge that would be helpful. Or any other input but I will probably revise this PR.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants