axp192_dd/lib.rs
1#![cfg_attr(not(any(test, feature = "std")), no_std)]
2//! # AXP192 Power Management Chip Interface
3//!
4//! This crate provides a bisync-based driver for the AXP192 power management IC,
5//! built upon the `device-driver` crate for robust, declarative register
6//! definitions via a YAML manifest. It supports both asynchronous (`async`)
7//! and blocking operation through a unified API, using the [`bisync`](https://docs.rs/bisync) crate
8//! for seamless compatibility with both `embedded-hal` and `embedded-hal-async` traits.
9//!
10//! ## Features
11//!
12//! * **Declarative Register Map:** Full device configuration defined in `device.yaml`.
13//! * **Unified Async/Blocking Support:** Write your code once and use it in both async and blocking contexts via bisync.
14//! * **Type-Safe API:** High-level functions for common operations (e.g., setting voltages)
15//! and a generated low-level API (`ll`) for direct register access.
16//! * **Comprehensive Register Coverage:** Aims to support the full feature set of the AXP192.
17//! * **`defmt` and `log` Integration:** Optional support for logging and debugging.
18//!
19//! ## Getting Started
20//!
21//! To use the driver, instantiate `Axp192` (blocking) or `Axp192Async` (async) with your I2C bus implementation:
22//!
23//! ```rust,no_run
24//! # use embedded_hal::i2c::I2c;
25//! # use axp192_dd::{Axp192, DcId};
26//! let i2c_bus = todo!();
27//! let mut axp = Axp192::new(i2c_bus);
28//!
29//! axp.set_dcdc_voltage(DcId::Dcdc1, 3300)?;
30//! # Ok(())
31//! ```
32//!
33//! For async environments, use `Axp192Async` (re-exported from the `asynchronous` module):
34//!
35//! ```rust,no_run
36//! # use embedded_hal_async::i2c::I2c;
37//! # use axp192_dd::{Axp192Async, DcId};
38//! let i2c_bus = todo!();
39//! let mut axp = Axp192Async::new(i2c_bus);
40//!
41//! axp.set_dcdc_voltage(DcId::Dcdc1, 3300).await?;
42//! # Ok(())
43//! ```
44//!
45//! For a detailed register map, please refer to the `device.yaml` file in the
46//! [repository](https://github.com/okhsunrog/axp192-dd).
47//!
48//! ## Supported Devices
49//!
50//! The AXP192 is found in various embedded devices, including but not limited to:
51//!
52//! * [M5Stack Core 2](https://docs.m5stack.com/en/core/core2) (including the [Core 2 for
53//! AWS](https://docs.m5stack.com/en/core/core2_for_aws) variant)
54//! * [M5Stack Tough](https://docs.m5stack.com/en/core/tough)
55//! * [M5StickC](https://docs.m5stack.com/en/core/m5stickc)
56//! * [M5StickC PLUS](https://docs.m5stack.com/en/core/m5stickc_plus)
57//!
58//! ## Warning!
59//!
60//! ***Caution!*** This chip controls power to the microcontroller and other critical
61//! components. Incorrect configuration can potentially damage or brick your device.
62//! Proceed with care and always consult the AXP192 datasheet.
63//!
64//! ## Datasheet
65//!
66//! [AXP192 Datasheet v1.1 (English Draft)](https://github.com/m5stack/M5-Schematic/blob/master/Core/AXP192%20Datasheet_v1.1_en_draft_2211.pdf)
67//!
68
69#[macro_use]
70pub(crate) mod fmt;
71mod adc_helpers;
72
73use thiserror::Error;
74
75device_driver::create_device!(device_name: AxpLowLevel, manifest: "device.yaml");
76pub const AXP192_I2C_ADDRESS: u8 = 0x34;
77
78#[derive(Debug, Error)]
79#[cfg_attr(feature = "defmt", derive(defmt::Format))]
80pub enum AxpError<I2cErr> {
81 #[error("I2C error")]
82 I2c(I2cErr),
83 #[error("Invalid voltage: {0}mV for setting")]
84 InvalidVoltage(u16),
85 #[error("Invalid current: {0}mA for setting")]
86 InvalidCurrent(u16),
87 #[error("Feature or specific mode not supported/implemented: {0}")]
88 NotSupported(&'static str),
89}
90
91#[derive(Debug, Clone, Copy, PartialEq, Eq)]
92#[cfg_attr(feature = "defmt", derive(defmt::Format))]
93pub enum DcId {
94 Dcdc1,
95 Dcdc2,
96 Dcdc3,
97}
98
99#[derive(Debug, Clone, Copy, PartialEq, Eq)]
100#[cfg_attr(feature = "defmt", derive(defmt::Format))]
101pub enum LdoId {
102 // Ldo1 is not configurable, set to 1.3V in hardware.
103 Ldo2,
104 Ldo3,
105}
106
107pub struct AxpInterface<I2CBus> {
108 i2c_bus: I2CBus,
109}
110
111impl<I2CBus> AxpInterface<I2CBus> {
112 pub fn new(i2c_bus: I2CBus) -> Self {
113 Self { i2c_bus }
114 }
115}
116
117#[path = "."]
118mod asynchronous {
119 use bisync::asynchronous::*;
120 use device_driver::AsyncRegisterInterface as RegisterInterface;
121 use embedded_hal_async::i2c::I2c;
122 mod driver;
123 pub use driver::*;
124}
125pub use asynchronous::Axp192 as Axp192Async;
126
127#[path = "."]
128mod blocking {
129 use bisync::synchronous::*;
130 use device_driver::RegisterInterface;
131 use embedded_hal::i2c::I2c;
132 #[allow(clippy::duplicate_mod)]
133 mod driver;
134 pub use driver::*;
135}
136pub use blocking::Axp192;