BQ27441 Rust Driver
A no_std Rust driver for the Texas Instruments BQ27441-G1 battery fuel gauge IC.
Features
- I²C Communication: Full support for blocking and async I²C operations
- Comprehensive Battery Monitoring:
- State of Charge (SOC) - 0-100% (filtered/unfiltered)
- Voltage measurements (mV)
- Current measurements (mA)
- Temperature readings (°C or 0.1K)
- Remaining capacity and full charge capacity (mAh, filtered/unfiltered)
- State of Health (SOH) percentage
- Average power (mW)
- Power Management: Support for NORMAL, SLEEP, HIBERNATE, and SHUTDOWN modes
- Battery Configuration Workflow: Typed
BatteryConfig(design capacity, OpConfig, current thresholds, safety/discharge/charge-termination alarms, Ra table) applied in one call viaconfigure_battery(), which drives the full unseal → CONFIG UPDATE → apply → exit → reseal sequence for you - Golden-File Snapshots: Read/write the calibrated Data Memory block set (
GoldenSnapshot) used to back up or clone a tuned device - Learning-Cycle Monitoring:
learning_progress()and related helpers to track Impedance Track™ Qmax/Ra learning status - Raw Data Memory Access: Block- and subclass-level read/write escape hatches for anything not covered by the typed config API
- Security: SEALED/UNSEALED modes
- YAML-Based Register Definitions: Uses the
device-drivercrate for type-safe register access - Async Support: Optional async/await support via
embedded-hal-async - Smart Battery HAL:
Bq27441Asyncimplementsembedded-batteries-async'sSmartBatterytrait - Embassy Compatible: Works seamlessly with the Embassy framework
- defmt Support: Optional defmt logging for debugging
Hardware
The BQ27441-G1 is a System-Side Impedance Track™ Fuel Gauge for single-cell Li-Ion batteries.
- I²C Address: 0x55 (default)
- Supply Voltage: 1.8V - 3.6V
- Sense Resistor: Typically 10mΩ between SRN and SRP pins
- Variants:
- BQ27441-G1A: For 4.2V maximum charge voltage batteries
- BQ27441-G1B: For 4.3V or 4.35V maximum charge voltage batteries
Usage
Blocking I²C
use Bq27441;
use I2c;
// Create driver with default I2C address (0x55)
let mut gauge = new?;
// Read battery status
let voltage = gauge.voltage?; // mV
let soc = gauge.state_of_charge?; // %
let capacity = gauge.remaining_capacity?; // mAh
let current = gauge.average_current?; // mA (signed)
let temp = gauge.temperature_celsius?; // °C
// Check charging status
if gauge.is_charging?
if gauge.is_full_charged?
Async I²C (with Embassy)
use Bq27441Async;
use I2c;
// Create async driver
let mut gauge = new.await?;
// Read battery status asynchronously
let voltage = gauge.voltage.await?;
let soc = gauge.state_of_charge.await?;
let capacity = gauge.remaining_capacity.await?;
embedded-batteries-async SmartBattery trait
With the async feature, Bq27441Async implements
embedded_batteries_async::smart_battery::SmartBattery.
Core measurements (voltage, SOC, capacity, temperature, status flags, design capacity) are
mapped to the gauge registers. SBS commands the BQ27441 does not implement return
Error::Unsupported.
use Bq27441Async;
use SmartBattery;
async
Configuring a New Battery
configure_battery() runs the whole CONFIG UPDATE workflow (unseal, enter config mode, write
Data Memory, commit checksums, exit, reseal) in one call:
use ;
let config = for_chemistry;
gauge.configure_battery?;
Start from BatteryConfig::G1A_DEFAULT / BatteryConfig::G1B_DEFAULT (or for_chemistry) and
override fields such as design_capacity_mah, current_thresholds, safety, discharge,
charge_termination, or ra_table as needed. Use configure_battery_default() if you don't
have your own DelayMs implementation. For manual control over the sequence, combine unseal(),
enter_config_mode(), apply_battery_config(), and exit_config() yourself.
Golden-File Snapshots
// Back up a calibrated device
let snapshot = gauge.read_golden_snapshot?;
// ...later, restore it onto another unit (device must be in CONFIG UPDATE mode)
gauge.write_golden_snapshot?;
Learning-Cycle Monitoring
let progress = gauge.learning_progress?;
if let Some = progress.phase
Manual Seal/Config-Mode Control
// Unseal device for configuration
gauge.unseal?;
// Enter config update mode
gauge.enter_config_mode?;
// Modify configuration via Data Memory
// (see `configure_battery`/`BatteryConfig` above, or use the raw
// `read_data_memory_block`/`write_data_memory_block` escape hatches)
// Exit config mode
gauge.exit_config_mode?;
// Seal device to protect configuration
gauge.seal?;
Examples
See the examples/ directory for complete working examples:
stm32wba65ri_embassy.rs- Embassy async example for STM32WBA65RI
To run an example:
API Overview
Core Methods
voltage()- Read battery voltage in mVstate_of_charge()/state_of_charge_unfiltered()- Read SOC percentage (0-100%)remaining_capacity()/remaining_capacity_unfiltered()/remaining_capacity_filtered()- Remaining capacity in mAhfull_charge_capacity()/full_charge_capacity_unfiltered()/full_charge_capacity_filtered()- Full charge capacity in mAhnominal_available_capacity()/full_available_capacity()- Unfiltered capacity readings in mAhaverage_current()- Read average current in mA (signed)average_power()- Read average power in mW (signed)standby_current()/max_load_current()- Additional current readings in mAtemperature_celsius()/internal_temperature_celsius()- Temperature in °Cstate_of_health()/state_of_health_status()- SOH percentage / decoded status
Status Methods
is_battery_detected()- Check if battery is connectedis_charging()/is_discharging()- Check charge directionis_full_charged()- Check if battery is fully chargedis_over_temp()/is_under_temp()- Check temperature alarmsneeds_config_reload()- Check whether Data Memory needs to be re-appliedflags()- Read all status flags
Control & Lifecycle Methods
control_read(cmd)/control_write(cmd)- Send raw control subcommandscontrol_status()/is_sealed()- Read decodedCONTROL_STATUSfirmware_version()- Read firmware versionchemistry_id()- Read chemistry ID (ChemId::G1A/G1B)seal()/unseal()- Enter/exit SEALED modeenter_config_mode()/exit_config_mode()/exit_config(ConfigExit)- CONFIG UPDATE mode controlbat_insert()/bat_remove()- Battery presence signalingset_hibernate()/clear_hibernate()- Hibernate mode controlshutdown_enable()/shutdown()- Shutdown mode controlreset()/soft_reset()/pulse_gpout()- Device reset and GPOUT control
Configuration Methods
read_battery_config()- Read the currentBatteryConfigfrom Data Memory (unsealed)apply_battery_config(config)- Write aBatteryConfigwhile already in CONFIG UPDATE modeconfigure_battery(config, options, &mut delay)/configure_battery_default(config, options)- Full unseal/apply/reseal workflowread_golden_snapshot()/write_golden_snapshot(snapshot, &mut delay)- Back up/restore calibrated Data Memoryread_data_memory_block()/write_data_memory_block()/read_data_memory_subclass()/write_data_memory_subclass()- Raw block/subclass accesslearning_progress()/update_status()/qmax_cell_0()/delta_voltage_mv()- Learning-cycle monitoring
Features
Enable optional features in your Cargo.toml:
[]
= { = "0.3", = ["async", "defmt-03"] }
Available features:
async- Enable async/await support (Bq27441Async), async config/golden/learning helpers, andembedded-batteries-asyncSmartBatterysupportdefmt-03- Enable defmt loggingembassy- Enable both async and defmt (convenience feature)
Register Access
For low-level register access, use the .device() method:
// Access generated device API directly
let flags = gauge.device.flags.read?;
if flags.bat_det
Development
Building
# Build for embedded target
# Build with async support
# Build with Embassy + defmt
Register Definitions
Register definitions are maintained in src/bq27441.yaml using the device-driver crate's YAML format. The build script (build.rs) generates type-safe register access code at compile time.
Changelog
See CHANGELOG.md for release notes, including breaking changes.
License
The contents of this repository are dual-licensed under the MIT OR Apache 2.0
License. That means you can choose either the MIT license or the Apache 2.0
license when you re-use this code. See LICENSE-MIT or
LICENSE-APACHE for more information on each specific
license.