Skip to content

feat(stm32): Add STM32 ADC support to AnalogBatteryLevel#9369

Merged
Stary2001 merged 1 commit intomeshtastic:developfrom
mesh-malaysia:stm32wl-avbat
Apr 16, 2026
Merged

feat(stm32): Add STM32 ADC support to AnalogBatteryLevel#9369
Stary2001 merged 1 commit intomeshtastic:developfrom
mesh-malaysia:stm32wl-avbat

Conversation

@ndoo
Copy link
Copy Markdown
Contributor

@ndoo ndoo commented Jan 20, 2026

Integrate STM32 battery monitoring into AnalogBatteryLevel, supporting external GPIO ADC pins as well as internal VBAT channel.

Features:

  • ADC reading using STM32 LL (Lower Layer) macros supporting external ADC channels and internal VBAT channel (AVBAT)
  • ADC compensation using STM32 LL macros with factory-calibrated VREFINT (AVREF) for accurate voltage measurement
  • LFP battery OCV curve for STM32WL using AVBAT (STM32 VDD absolute maximum supply voltage 3.9V, direct connection of Li-Po batteries is not supported)

Internal VBAT channel implemented in:

  • Russell
  • RAK3172

In these variants, ADC_MULTIPLIER = (1.01f * 3) = 3.30; This is due to the 3:1 internal divider with a 10% tolerance (DS13105 Rev 12 §5.3.21).

🤝 Attestations

  • I have tested that my proposed changes behave as described.
  • I have tested that my proposed changes do not cause any obvious regressions on the following devices:
    • Heltec (Lora32) V3
    • LilyGo T-Deck
    • LilyGo T-Beam
    • RAK WisBlock 4631
    • Seeed Studio T-1000E tracker card
    • Other (please specify below)
      • RAK3172

@ndoo
Copy link
Copy Markdown
Contributor Author

ndoo commented Jan 27, 2026

Relocate to a more appropriate separate child class since this code really should not be mucking with the usual voltage divider code.

@ndoo ndoo force-pushed the stm32wl-avbat branch 4 times, most recently from 44ffbad to d7d7ad8 Compare January 27, 2026 14:01
@ndoo ndoo marked this pull request as ready for review January 27, 2026 14:01
@ndoo
Copy link
Copy Markdown
Contributor Author

ndoo commented Jan 27, 2026

Screenshot 2026-01-27 at 22 15 07

It works! Marking as ready for review.

@Stary2001
Copy link
Copy Markdown
Member

Tested on RAK3172 in a RAK19007, seems to work and returns 3.3V.

@ndoo
Copy link
Copy Markdown
Contributor Author

ndoo commented Jan 27, 2026

Whoops, going to reduce that terribly long commit message and force-push

Comment thread src/Power.cpp Outdated
Comment thread src/power.h
@ndoo ndoo requested a review from Stary2001 January 27, 2026 15:27
@github-actions github-actions Bot added the Stale Issues that will be closed if not triaged. label Mar 16, 2026
@github-actions github-actions Bot closed this Mar 27, 2026
@ndoo
Copy link
Copy Markdown
Contributor Author

ndoo commented Mar 27, 2026

Don't close :(

@thebentern thebentern reopened this Mar 27, 2026
@thebentern thebentern removed the Stale Issues that will be closed if not triaged. label Mar 27, 2026
@thebentern thebentern requested a review from Copilot March 27, 2026 11:40
@ndoo
Copy link
Copy Markdown
Contributor Author

ndoo commented Mar 27, 2026 via email

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds STM32WL-specific battery voltage sensing by reading the MCU’s internal VBAT ADC channel, and prefers this sensor over the generic analog divider approach when available.

Changes:

  • Add a new STM32WL HasBatteryLevel implementation that reads VBAT via internal ADC channels and integrates it into Power::setup().
  • Select an LFP-oriented default OCV curve when using STM32WL internal VBAT sensing.
  • Enable BATTERY_PIN = AVBAT for the Russell and RAK3172 STM32WL variants; reduce STM32WL flash usage by disabling nanolib float printf unless debug logs are enabled.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
variants/stm32/stm32.ini Disables PIO_FRAMEWORK_ARDUINO_NANOLIB_FLOAT_PRINTF by default for STM32WL to save flash (kept available for non-muted debug).
variants/stm32/russell/variant.h Enables internal VBAT sensing via BATTERY_PIN AVBAT and adds a sample (commented) primary-cell OCV curve.
variants/stm32/rak3172/variant.h Enables internal VBAT sensing via BATTERY_PIN AVBAT.
src/power.h Chooses an LFP default OCV curve when using STM32WL internal VBAT sensing; adds stm32wlInit() declaration.
src/Power.cpp Implements Stm32wlBatteryLevel and wires stm32wlInit() into the sensor selection order ahead of analogInit().

Comment thread src/Power.cpp Outdated
Comment thread src/Power.cpp Outdated
Comment thread src/Power.cpp Outdated
Comment thread src/Power.cpp Outdated
Comment thread src/Power.cpp Outdated
@ndoo
Copy link
Copy Markdown
Contributor Author

ndoo commented Mar 27, 2026 via email

@ndoo ndoo force-pushed the stm32wl-avbat branch 2 times, most recently from 78b2da6 to 5b7d59a Compare April 7, 2026 09:07
@ndoo
Copy link
Copy Markdown
Contributor Author

ndoo commented Apr 7, 2026

  1. Rebased on develop/head
  2. Implemented review feedback:
    • Throttling + LPF same as AnalogBatteryLevel but without averaging
    • Use instantaneous Vref when sampling AVBAT instead of the value from init
    • 12-bit ADC / ADC_RANGE fixes

@ndoo
Copy link
Copy Markdown
Contributor Author

ndoo commented Apr 7, 2026

CI errors look like HTTP errors?

@ndoo ndoo force-pushed the stm32wl-avbat branch 2 times, most recently from 2b162e6 to 978ff4b Compare April 13, 2026 07:56
@ndoo
Copy link
Copy Markdown
Contributor Author

ndoo commented Apr 13, 2026

A new class seems to be the wrong way to go, along the way I had to re-implement EXT_PWR_DETECT, EXT_CHG_DETECT etc.

In the end, just implementing the correct STM32 patterns within AnalogBatteryLevel looks like the way to go.

Reworked from scratch and force-pushed. Updating the PR text shortly.

@ndoo ndoo changed the title feat(stm32wl): Support reading Vbat from internal ADC channel feat(stm32): Add STM32 ADC support to AnalogBatteryLevel Apr 13, 2026
@ndoo
Copy link
Copy Markdown
Contributor Author

ndoo commented Apr 14, 2026

Ignore the bad timestamps from the ongoing RTC work, but so far so good, after using AnalogBatteryLevel implementation and the CHRG/DONE pins on CN3158 (with #10140 to directly connect these to STM32WLE GPIO)

Screenshot 2026-04-14 at 12 42 23

Integrate STM32 battery monitoring into AnalogBatteryLevel, supporting
external GPIO ADC pins as well as internal VBAT channel.

Features:
- ADC reading using STM32 LL (Lower Layer) macros supporting external
  ADC channels and internal VBAT channel (AVBAT)
- ADC compensation using STM32 LL macros with factory-calibrated VREFINT
  (AVREF) for accurate voltage measurement
- LFP battery OCV curve for STM32WL using AVBAT (STM32 VDD absolute
  maximum supply voltage 3.9V, direct connection of Li-Po batteries is
  not supported)

Internal VBAT channel implemented in:
- Russell
- RAK3172

In these variants, ADC_MULTIPLIER = (1.01f * 3) = 3.30 as there is a
3:1 internal divider (DS13105 Rev 12 §5.3.21), and a bit of tolerance
as the actual 10% spec leads to readings much too high.

Signed-off-by: Andrew Yong <me@ndoo.sg>
Assisted-by: Claude:sonnet-4-5
@ndoo
Copy link
Copy Markdown
Contributor Author

ndoo commented Apr 14, 2026

Reducing the extra ADC_MULTIPLIER tolerance to 1% as the readings come in way too high now with the full 10% tolerance.

@Stary2001
Copy link
Copy Markdown
Member

Tested on wio-e5 custom board, seems OK with analog reference and VBAT paths.
I noticed you must set ADC_MULTIPLIER to 3 yourself if using AVBAT, should the code do this?

Copy link
Copy Markdown
Member

@Stary2001 Stary2001 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm

@ndoo
Copy link
Copy Markdown
Contributor Author

ndoo commented Apr 16, 2026

Tested on wio-e5 custom board, seems OK with analog reference and VBAT paths. I noticed you must set ADC_MULTIPLIER to 3 yourself if using AVBAT, should the code do this?

Per reply in Discord, set it to 1.01f *3 in variants where it's implemented.

Future variant makers must remember to do this when using AVBAT channel. It’s intentionally not done in code just in case there is any use case for a custom multiplier even on AVBAT.

@ndoo
Copy link
Copy Markdown
Contributor Author

ndoo commented Apr 16, 2026

Tested on wio-e5 custom board, seems OK with analog reference and VBAT paths. I noticed you must set ADC_MULTIPLIER to 3 yourself if using AVBAT, should the code do this?

Per reply in Discord, set it to 1.01f *3 in variants where it's implemented.

Future variant makers must remember to do this when using AVBAT channel. It’s intentionally not done in code just in case there is any use case for a custom multiplier even on AVBAT.

  • Or in case the hardware designer wishes to build in a higher % tolerance in case for some reason a full battery doesn't read the highest OCV point e.g. a long wire or long trace.

@Stary2001 Stary2001 added hardware-support Hardware related: new devices or modules, problems specific to hardware enhancement New feature or request labels Apr 16, 2026
@Stary2001 Stary2001 merged commit 026213a into meshtastic:develop Apr 16, 2026
76 of 81 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request hardware-support Hardware related: new devices or modules, problems specific to hardware

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants