feat(power): add battery monitoring and status overlays
This commit is contained in:
@@ -0,0 +1,43 @@
|
||||
# ADR 0005: Battery Management Ownership
|
||||
|
||||
## Status
|
||||
|
||||
Accepted
|
||||
|
||||
## Context
|
||||
|
||||
The current board uses GPIO9 to measure a protected 600 mAh single-cell Li-ion
|
||||
battery through a 100 kOhm / 100 kOhm divider. GPIO10 receives the active-low
|
||||
TP4057 charge indication. Battery state is affected by ADC calibration, audio
|
||||
and stepper load transients, SOC estimation, threshold hysteresis, and runtime
|
||||
policy, so it cannot have duplicate state in several layers.
|
||||
|
||||
## Decision
|
||||
|
||||
- `platform` owns ADC1 setup, calibration, trimmed-mean sampling, divider
|
||||
conversion, TP4057 GPIO sampling, and internal audio/stepper load-quality
|
||||
tracking.
|
||||
- `domain` owns the single battery status snapshot, voltage filtering, SOC
|
||||
curve interpolation, implausible-jump confirmation, charge/discharge
|
||||
direction constraints, and low/critical hysteresis.
|
||||
- `control_plane` owns the periodic monitoring worker and reactions to semantic
|
||||
state transitions.
|
||||
- `domain` maps its battery snapshot to semantic LCD visibility, while
|
||||
`platform` owns transparent PNG composition and panel serialization.
|
||||
- The first release logs low and critical transitions but intentionally does
|
||||
not stop actuators, enter sleep, or cut power. Typed shutdown preparation
|
||||
remains a reserved, unsupported hook until hardware wake and shutdown policy
|
||||
are decided.
|
||||
- `app_composition` keeps using the aggregate control-plane runtime lifecycle;
|
||||
it does not acquire battery samples directly.
|
||||
|
||||
## Consequences
|
||||
|
||||
- GPIO9 must never be configured as the legacy power-hold output on this board.
|
||||
- High-load samples remain available for diagnostics but cannot update SOC or
|
||||
low-battery state. Normal processing resumes after the configured cooldown.
|
||||
- GPIO10 cannot distinguish a full battery from an unplugged charger because
|
||||
both produce a high level; the public state therefore reports only charging
|
||||
versus not charging.
|
||||
- The voltage-to-SOC curve is an initial approximation and requires bench
|
||||
calibration against measured battery voltage and a controlled discharge run.
|
||||
@@ -0,0 +1,67 @@
|
||||
# Battery Management
|
||||
|
||||
## Hardware Profile
|
||||
|
||||
- Cell: protected single-cell Li-ion, 600 mAh, 3.7 V nominal, 4.2 V full.
|
||||
- Supported measurement range: 3.3 V to 4.2 V for SOC estimation.
|
||||
- GPIO9: ADC1 battery sense through R17=100 kOhm (VBAT to ADC) and R18=100
|
||||
kOhm (ADC to ground). `VBAT = VADC * 2`.
|
||||
- GPIO10: TP4057 active-low charge output with an input pull-up. A high level
|
||||
means either charge complete or charger absent.
|
||||
- Legacy power hold: disabled (`CONFIG_TQ_POWER_HOLD_GPIO=-1`).
|
||||
|
||||
## Processing Pipeline
|
||||
|
||||
Each hardware sample consists of 16 calibrated ADC readings. The platform
|
||||
driver sorts them, discards the lowest four and highest four, averages the
|
||||
remaining eight, and applies the divider ratio. Domain processing then applies:
|
||||
|
||||
1. A 2.5 V to 4.5 V plausibility check.
|
||||
2. Three-sample confirmation for voltage jumps greater than 300 mV.
|
||||
3. An exponential filter with 80% previous and 20% new voltage.
|
||||
4. Piecewise-linear interpolation over the Li-ion discharge curve.
|
||||
5. A two-percent maximum SOC change per accepted sample.
|
||||
6. Charge/discharge direction constraints.
|
||||
7. Three-sample confirmation and hysteresis for low and critical states.
|
||||
|
||||
The initial state thresholds are 20%/25% for low entry/recovery and 5%/10% for
|
||||
critical entry/recovery.
|
||||
|
||||
Board calibration can be adjusted without source changes using
|
||||
`CONFIG_TQ_BATTERY_CALIBRATION_GAIN_PPM` and
|
||||
`CONFIG_TQ_BATTERY_CALIBRATION_OFFSET_MV` after comparing the log against a
|
||||
multimeter.
|
||||
|
||||
## High-Load Handling
|
||||
|
||||
Audio playback events and synchronous stepper rotations update one
|
||||
platform-owned load tracker. While a load is active and for five seconds after
|
||||
its terminal event, samples are marked suppressed. The monitor continues to
|
||||
poll once per second for diagnostics and charge state, but suppressed voltage
|
||||
does not update filtered voltage, SOC, or low-battery state.
|
||||
|
||||
Playback generations prevent a stale terminal event from ending suppression
|
||||
for a newer playback. Stepper cleanup executes after every synchronous return,
|
||||
including errors and timeouts.
|
||||
|
||||
## LCD Status Overlays
|
||||
|
||||
The direct LCD renderer composites the transparent `charging.png` asset in the
|
||||
top-right corner whenever GPIO10 reports active-low charging. It composites
|
||||
`lowbat.png` at the bottom center after the domain level enters low or critical
|
||||
state. Both overlays may be visible together, and QR-code presentations omit
|
||||
them to preserve scan reliability. Overlay state changes do not trigger any
|
||||
shutdown, sleep, prompt, or actuator policy.
|
||||
|
||||
## Deferred Policy
|
||||
|
||||
Critical status currently produces a state-transition log only. The reserved
|
||||
shutdown hook returns `ESP_ERR_NOT_SUPPORTED`; it does not stop audio or the
|
||||
stepper, enter deep sleep, or release board power. Implement wake sources and
|
||||
the product shutdown sequence before enabling any automatic critical action.
|
||||
|
||||
## Bench Calibration
|
||||
|
||||
After flashing, compare the `cp_battery` voltage log with a multimeter at no
|
||||
load near 4.2 V, 3.9 V, 3.6 V, and 3.3 V. Record audio and stepper voltage sag,
|
||||
then run a controlled discharge to tune the SOC curve and threshold timing.
|
||||
@@ -23,7 +23,7 @@ dark. This is accepted for this plan.
|
||||
## Startup Order
|
||||
|
||||
```text
|
||||
power hold
|
||||
power-hold configuration (disabled on the current battery-sensing board)
|
||||
-> audio init
|
||||
-> play boot sound with timeout
|
||||
-> audio deinit or idle release
|
||||
@@ -42,7 +42,7 @@ power hold
|
||||
|
||||
| Order | Stage | Wait policy | Failure policy | Notes |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| 1 | Power hold GPIO | Wait | Continue only if board power remains stable | Configure the hold GPIO and assert the active level before any heavier work. |
|
||||
| 1 | Power-hold configuration | Wait | Continue only if board power remains stable | The current board sets the hold GPIO to `-1`; legacy boards may configure and assert a dedicated hold output. GPIO9 is reserved for battery ADC. |
|
||||
| 2 | Audio init | Wait with bounded timeout | Log and skip boot sound | Initializes the codec path needed for playback: I2C, I2S, codec, PA control, codec buffers, and decoder resources. |
|
||||
| 3 | Boot sound playback | Wait for completion or timeout | Stop playback and continue boot | The sound must not block startup indefinitely. Use a short product-defined timeout. |
|
||||
| 4 | Audio release | Wait for synchronous release | Continue if release reports a recoverable error | If Wi-Fi/TLS starts soon after, deinit or release idle audio resources to reduce DMA/internal heap pressure. |
|
||||
@@ -53,7 +53,7 @@ power hold
|
||||
| 9 | Turntable calibration | Product decision; default wait with timeout | Continue with degraded direction accuracy on timeout/failure | This is the mechanical SW1 homing/calibration process, not the stepper electrical init. |
|
||||
| 10 | Storage prepare | Wait | Stop features that need persistent state | Initializes NVS before Wi-Fi credentials, identity, auth, and fortune state are read or written. |
|
||||
| 11 | Wi-Fi bootstrap | Wait until STA connected or AP config mode starts | Enter config AP or keep retry policy active | Must not overlap with boot sound playback or heavy audio initialization. |
|
||||
| 12 | Runtime workers | Start and continue | Stop only failed dependent feature | Starts PTT, slot switch, Wi-Fi state monitor, model command worker, LCD runtime worker, and WebSocket wait worker as configured. |
|
||||
| 12 | Runtime workers | Start and continue | Stop only failed dependent feature | Starts battery monitoring, PTT, slot switch, Wi-Fi state monitor, model command worker, LCD runtime worker, and WebSocket wait worker as configured. |
|
||||
| 13 | Network services | Async after network readiness | Retry using existing policy | Includes multimodal WebSocket, LAN HTTP config server, SNTP, HTTPS fortune refresh, and auth flows. |
|
||||
|
||||
## Clarifications
|
||||
|
||||
@@ -15,7 +15,8 @@ the ESP32-S3 MCU perspective.
|
||||
| 6 | `CONFIG_TQ_SLOT_SWITCH_GPIO` | Input | Slot / key input | Rocker microswitch / original SW2 function | Uses the unconnected `TP_SCL` contact; active-low with internal pull-up |
|
||||
| 7 | `CONFIG_TQ_SCREEN_BACKLIGHT_GPIO` | Output | LCD | LCD adapter backlight control | Active-high by default |
|
||||
| 8 | `CONFIG_TQ_SCREEN_SPI_CLK_GPIO` | Output | LCD | ST7789P3 SPI clock / SCK | SPI2 host, 20 MHz default |
|
||||
| 9 | `CONFIG_TQ_POWER_HOLD_GPIO` | Output | Power | Board power hold | Active-high by default |
|
||||
| 9 | `CONFIG_TQ_BATTERY_ADC_GPIO` | Analog input | Battery | Battery voltage through 100 kOhm / 100 kOhm divider | ADC1 input; do not configure as a power-hold output |
|
||||
| 10 | `CONFIG_TQ_BATTERY_CHARGE_GPIO` | Input | Battery charger | TP4057 charge status | Active-low, internal pull-up enabled |
|
||||
| 11 | `CONFIG_MULTIMODAL_AUDIO_PA_GPIO` | Output | Audio amplifier | PA enable | Managed by codec GPIO interface |
|
||||
| 12 | `CONFIG_TQ_CALIBRATION_SWITCH_GPIO` | Input | Turntable calibration | Button 1 / SW1 direction calibration | Active-low, external and internal pull-up |
|
||||
| 13 | `CONFIG_MULTIMODAL_PTT_BUTTON_GPIO` | Input | Keys / multimodal | Button 2 / K2 push-to-talk | Active-low, external and internal pull-up |
|
||||
@@ -46,6 +47,7 @@ is installed.
|
||||
| `CONFIG_TQ_SLOT_SWITCH_PULLDOWN` | unset | SW2 uses pull-up only. |
|
||||
| `CONFIG_TQ_CALIBRATION_SWITCH_PULLDOWN` | unset | Calibration switch uses pull-up only. |
|
||||
| `CONFIG_MULTIMODAL_PTT_BUTTON_PULLDOWN` | unset | Button 2 uses pull-up only. |
|
||||
| `CONFIG_TQ_POWER_HOLD_GPIO` | `-1` | Legacy board power-hold output is disabled because GPIO9 is the battery ADC input. |
|
||||
|
||||
## Boot Hardware Test Profile
|
||||
|
||||
@@ -90,7 +92,6 @@ them to an active project feature.
|
||||
| --- | --- | --- |
|
||||
| GPIO0 / K1 | Switch to GND, commonly boot/download related | Not consumed by application code |
|
||||
| GPIO3 / `touch` | TTP223 touch output | Present on the board but not consumed by the current input policy |
|
||||
| GPIO10 / `Charge` | Charger status | No current firmware consumer found |
|
||||
| GPIO14 | Unassigned | Not used |
|
||||
| GPIO35 | Unassigned | Not used |
|
||||
| GPIO36 | Unassigned | Not used |
|
||||
@@ -107,6 +108,7 @@ them to an active project feature.
|
||||
- `docs/gpio-map.md`
|
||||
- `components/platform/src/lcd_direct.c`
|
||||
- `components/platform/src/platform_stepper_driver.c`
|
||||
- `components/platform/src/platform_battery_driver.c`
|
||||
- `components/platform/src/multimodal/audio_pipeline/audio_pipeline_codec_impl.c`
|
||||
- `components/control_plane/src/runtime/control_plane_key_input.c`
|
||||
- `components/platform/src/platform_console_driver.c`
|
||||
|
||||
+6
-5
@@ -1,8 +1,9 @@
|
||||
# ESP32-S3 GPIO Map
|
||||
|
||||
This document defines the reference GPIO assignments for the ESP32-S3 board
|
||||
from `SCH_招财猫0.3&商界0.2_2026-07-24.pdf`. Signal direction is described from
|
||||
the MCU's perspective.
|
||||
This document defines the active firmware GPIO assignments for the current
|
||||
battery-sensing ESP32-S3 board revision. Signal direction is described from the
|
||||
MCU's perspective. Older 2026-07-24 drawings assigned GPIO9 to a legacy power
|
||||
hold net; that assignment is not valid for the current board.
|
||||
|
||||
## GPIO Table
|
||||
|
||||
@@ -24,8 +25,8 @@ the MCU's perspective.
|
||||
| 14 | GPIO20 | ESP_D_P | Bidirectional | USB D+ | Type-C |
|
||||
| 15 | GPIO3 | touch | Input | TTP223 touch-button output | Present on the board but not consumed by the current input policy |
|
||||
| 16 | GPIO46 | UNASSIGNED | N/A | No connection assigned | Reserved; no signal assigned |
|
||||
| 17 | GPIO9 | Power | Output | Board power hold | Active high |
|
||||
| 18 | GPIO10 | Charge | Input | Charger status | Not consumed by current firmware |
|
||||
| 17 | GPIO9 | Power_t | Analog input | Battery voltage sense | R17=100 kOhm from VBAT and R18=100 kOhm to GND; ADC voltage is one half of VBAT |
|
||||
| 18 | GPIO10 | Charge | Input | TP4057 charger status | Active-low while charging; high means full or external power absent |
|
||||
| 19 | GPIO11 | PA_CTRL | Output | Audio power-amplifier enable | Amplifier control |
|
||||
| 20 | GPIO12 | SW1 | Input | Button 1 / turntable calibration switch | External 10 kOhm pull-up; active low |
|
||||
| 21 | GPIO13 | SW2 | Input | Button 2 / K2 push-to-talk input | External 10 kOhm pull-up; active low |
|
||||
|
||||
Reference in New Issue
Block a user