sl-mechanical
c96ed54af2
feat: Implement Issue #325 - Battery coulomb counter (STM32 firmware)
ADC-based coulomb integration for SaltyBot battery state-of-charge (SOC) tracking:
**Core Features**:
- INA219 I2C current sensor integration (10mΩ shunt, ±3.2A range)
- Coulomb integration at 1kHz tick rate (Q = ∫I dt)
- SOC calculation: 100% × (1 - Discharged_Q / Capacity_Q)
- Runtime state tracking: current, coulombs, SOC, tick count, charging flag
- Cycle tracking with depth-of-discharge (DOD) calculation
- Flash-persistent calibration (offset/scale) with magic checksum (0xCAFEBABE)
**API Functions**:
- coulomb_init() - Initialize INA219, load calibration
- coulomb_tick() - 1kHz integration (current → coulombs → SOC)
- coulomb_set_soc() / coulomb_mark_full_charge() - Manual calibration points
- coulomb_mark_fully_discharged() - Cycle tracking
- coulomb_save/load_calibration() - Flash persistence
- coulomb_factory_reset() - Clear all state and calibration
**Test Coverage** (19 test suites, 49 assertions):
- Initialization and state reset
- coulomb_tick() integration accuracy (zero current, constant discharge)
- SOC calculation accuracy and clamping (0–100%)
- Charging vs. discharging detection
- Flash read/write with magic validation
- Calibration offset/scale application
- Cycle counting and DOD tracking
- Long-duration integration (10s at 0.5A = 5 coulombs)
- Boundary conditions and rollover handling
- Capacity variants (2200–3000 mAh)
**Data Structures**:
- coulomb_state_t: Runtime state (volatile)
- coulomb_calibration_t: Flash storage (persistent)
- coulomb_cycle_t: Cycle history with DOD tracking
**Integration Details**:
- Battery capacity: 2200 mAh (611 coulombs) — configurable per variant
- Flash address: 0x0800D000 (1 sector, STM32F4)
- Sampling: 1kHz systick, 1ms per integration window
- Discharge threshold: 50mA (filtering noise)
All tests pass (49/49 assertions); ready for hardware integration.
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-03-03 00:49:52 -05:00
..
2026-03-02 10:34:35 -05:00
2026-02-28 13:09:18 -05:00
2026-03-03 00:49:52 -05:00
2026-03-02 08:35:48 -05:00
2026-02-28 19:43:48 -05:00
2026-03-02 09:40:18 -05:00
2026-03-02 12:51:42 -05:00
2026-03-02 11:44:56 -05:00
2026-03-02 08:35:48 -05:00
2026-03-02 13:29:18 -05:00
2026-02-28 11:58:23 -05:00
2026-02-28 17:48:53 -05:00
2026-02-28 11:58:23 -05:00
2026-03-02 11:51:26 -05:00
2026-02-28 21:07:15 -05:00
2026-03-02 10:53:02 -05:00
2026-03-02 11:06:13 -05:00
2026-02-28 17:48:53 -05:00
2026-02-28 21:06:26 -05:00
2026-02-28 17:15:40 -05:00
2026-02-28 17:42:24 -05:00
2026-03-02 09:56:18 -05:00
2026-03-02 10:53:02 -05:00
2026-03-02 20:49:26 -05:00
2026-03-01 04:55:54 -05:00
2026-03-02 11:44:56 -05:00
2026-03-01 04:55:54 -05:00
2026-03-02 12:22:09 -05:00
2026-03-02 21:09:17 -05:00