axp2101-dd 0.2.0

A driver for the AXP2101 power management IC (uses device-driver crate)
Documentation

AXP2101 Power Management IC Driver (axp2101-dd)

Crates.io Docs.rs License: MIT OR Apache-2.0 Build Status

This crate provides a no_std driver for the AXP2101 power management IC, a highly integrated PMIC for single-cell Li-battery applications. The project aims to support the full functionality of the AXP2101 PMIC, leveraging the device-driver crate with a declarative YAML manifest (device.yaml) for a robust, type-safe register map definition. The low-level API covers 100% of the AXP2101's registers, with device.yaml providing a comprehensive and accurate description of all registers and their fields. While the low-level API is complete, some high-level convenience methods for easier access may still be added in the future.

Overview

The axp2101-dd driver offers:

  • Declarative Configuration: The AXP2101 register map is defined in device.yaml, enabling device-driver to generate a type-safe, low-level register access API. This approach enhances maintainability and extensibility.
  • Unified Async/Blocking API: Uses the bisync crate to provide both asynchronous (Axp2101Async) and blocking (Axp2101) drivers from the same codebase, with no feature flags required.
  • High-Level and Low-Level APIs:
    • High-level methods simplify tasks like setting DC-DC/LDO voltages, reading ADC values, managing battery charging.
    • Low-level API (via the ll field of the Axp2101/Axp2101Async struct) offers direct, type-safe access to all registers defined in device.yaml via raw values or enums.
  • Peripheral Control: Manages 5 DC-DCs, 11 LDOs, ADC conversions, interrupts, battery charging, fuel gauge, and power settings.
  • no_std and no-alloc: Optimized for bare-metal and RTOS environments.
  • Optional Logging: Supports defmt and the log facade for debugging.

⚠️ Warning! ⚠️

Caution! The AXP2101 controls power to the microcontroller and critical components. Incorrect configuration may cause malfunctions, data loss, or hardware damage.

  • Always consult the official AXP2101 datasheet before modifying power settings.
  • Verify voltage and current limits for your device and components.
  • Exercise caution when adjusting output voltages or charging parameters.
  • The authors are not liable for damage caused by misuse.

Features

  • Declarative Register Map: Defined in device.yaml.
  • Unified Async/Blocking API: Both async and blocking drivers are always available; no feature flags required.
  • Type-Safe Register Access: Generated by device-driver.
  • Comprehensive Control: (See device.yaml for details)
    • 5 DC-DC converters (DCDC1-5) with voltage control.
    • 11 LDO outputs (ALDO1-4, BLDO1-2, DLDO1-2, CPUSLDO, RTCLDO1-2).
    • Battery charging configuration and status.
    • 14-bit ADC readings (battery voltage, VBUS, VSYS, die temperature, TS pin, GPADC).
    • Fuel gauge for battery percentage.
    • Interrupt management.
    • Power key (PWRON) parameters.
  • no_std and no-alloc.
  • Optional Logging: Supports defmt and log facade.

Getting Started

  1. Add axp2101-dd to Cargo.toml:

    [dependencies]
    axp2101-dd = "0.1.0"
    # For blocking usage (Axp2101):
    embedded-hal = "1.0.0"
    # For async usage (Axp2101Async):
    embedded-hal-async = "1.0.0"
    

    Note: Add the relevant embedded-hal crate for your use case, no need for both

    • Use embedded-hal for blocking drivers (Axp2101)
    • Use embedded-hal-async for async drivers (Axp2101Async)
  2. Instantiate the driver with your I2C bus:

    • Blocking:

      use axp2101_dd::{Axp2101, DcId, LdoId, AdcChannel};
      use embedded_hal::i2c::I2c;
      
      let i2c_bus_impl = /* your I2C bus */;
      let mut axp = Axp2101::new(i2c_bus_impl);
      
      // Configure power outputs
      axp.set_dcdc_voltage(DcId::Dcdc1, 3300)?;
      axp.set_dcdc_enable(DcId::Dcdc1, true)?;
      axp.set_ldo_voltage_mv(LdoId::Aldo1, 3300)?;
      axp.set_ldo_enable(LdoId::Aldo1, true)?;
      
      // Enable and read ADC
      axp.set_adc_channel_enable(AdcChannel::BatteryVoltage, true)?;
      let battery_mv = axp.get_battery_voltage_mv()?;
      
    • Async:

      use axp2101_dd::{Axp2101Async, DcId, LdoId, AdcChannel};
      use embedded_hal_async::i2c::I2c;
      
      let i2c_bus_impl = /* your I2C bus */;
      let mut axp = Axp2101Async::new(i2c_bus_impl);
      
      // Configure power outputs
      axp.set_dcdc_voltage(DcId::Dcdc1, 3300).await?;
      axp.set_dcdc_enable(DcId::Dcdc1, true).await?;
      axp.set_ldo_voltage_mv(LdoId::Aldo1, 3300).await?;
      axp.set_ldo_enable(LdoId::Aldo1, true).await?;
      
      // Enable and read ADC
      axp.set_adc_channel_enable(AdcChannel::BatteryVoltage, true).await?;
      let battery_mv = axp.get_battery_voltage_mv().await?;
      

Examples

Examples for ESP32-C3 using esp-hal are included. Setup is required (see esp-hal docs).

Register Map

The AXP2101 register map is defined in device.yaml, which device-driver uses to generate Rust code. This file specifies:

  • Register names, addresses, and sizes.
  • Field names, bit positions, and access modes (Read-Only, Read-Write, Write-1-Clear).
  • Enumerations for field values (e.g., charging currents, voltage settings).
  • Reset values and descriptions based on the datasheet.

Access the low-level API via axp.ll (e.g., axp.ll.power_status().read()). High-level methods provide convenient access to common features.

Supported Devices

The AXP2101 is used in various embedded devices and development boards that require single-cell Li-battery power management with multiple voltage rails.

Known devices using the AXP2101:

  • M5Stack Core2 v1.1 - ESP32-based IoT development kit with touch screen

Feature Flags

  • default = []: No default features; async and blocking drivers are always available.
  • std: Enables std features for thiserror.
  • log: Enables log facade logging. Requires log = { version = "0.4", optional = true }.
  • defmt: Enables defmt logging. Requires defmt = { version = "1.0", optional = true }.

Contributions are welcome! While the register map in device.yaml is complete, you can contribute by:

  • Adding high-level convenience methods to simplify common operations (e.g., battery management, interrupt handling).
  • Enhancing documentation with additional examples or clarifications.
  • Reporting issues or suggesting improvements.
  • Suggest code refactoring.

Please submit issues, fork the repository, and create pull requests.

License

This project is dual-licensed under the MIT License or Apache License 2.0, at your option.