m5stack_core/driver/
axp2101.rs1use thiserror_no_std::Error;
16
17use crate::io::shared_i2c::SharedI2cBus;
18
19const REG_PWR_STATUS: u8 = 0x00;
20const REG_ADC_EN: u8 = 0x30; const REG_LDO_EN: u8 = 0x90;
22const REG_DLDO1_VOL: u8 = 0x99;
23const REG_VBAT_H: u8 = 0x34;
24
25const DLDO1_VOL_MIN_MV: u16 = 500;
26const DLDO1_VOL_STEP_MV: u16 = 100;
27const DLDO1_EN_BIT: u8 = 0x80; const VBUS_PRESENT_BIT: u8 = 0x08; const VBAT_ADC_EN_BIT: u8 = 0x01; #[derive(Debug, Error)]
32pub enum Axp2101Error {
33 #[error("I2C error: {0:?}")]
34 I2cError(#[from] esp_hal::i2c::master::Error),
35
36 #[error("Voltage out of range")]
37 VoltageOutOfRange,
38}
39
40pub struct Axp2101Driver {
41 i2c: &'static SharedI2cBus,
42 address: u8,
43}
44
45impl Axp2101Driver {
46 pub fn new(i2c: &'static SharedI2cBus, address: u8) -> Self {
47 Self { i2c, address }
48 }
49
50 async fn read_reg(&mut self, reg: u8) -> Result<u8, Axp2101Error> {
51 let mut buf = [0u8; 1];
52 self.i2c
53 .lock()
54 .await
55 .write_read_async(self.address, &[reg], &mut buf)
56 .await?;
57 debug!("AXP2101 rd 0x{:02x} = 0x{:02x}", reg, buf[0]);
58 Ok(buf[0])
59 }
60
61 async fn write_reg(&mut self, reg: u8, value: u8) -> Result<(), Axp2101Error> {
62 debug!("AXP2101 wr 0x{:02x} = 0x{:02x}", reg, value);
63 self.i2c
64 .lock()
65 .await
66 .write_async(self.address, &[reg, value])
67 .await?;
68 Ok(())
69 }
70
71 pub async fn set_dldo1(&mut self, enabled: bool, mv: u16) -> Result<(), Axp2101Error> {
73 if mv < DLDO1_VOL_MIN_MV || mv > 3400 || (mv - DLDO1_VOL_MIN_MV) % DLDO1_VOL_STEP_MV != 0 {
74 return Err(Axp2101Error::VoltageOutOfRange);
75 }
76 let vol_val = ((mv - DLDO1_VOL_MIN_MV) / DLDO1_VOL_STEP_MV) as u8;
77 debug!(
78 "AXP2101 DLDO1 enabled={} {}mV (reg_val={})",
79 enabled, mv, vol_val
80 );
81 self.write_reg(REG_DLDO1_VOL, vol_val).await?;
82
83 let en_reg = self.read_reg(REG_LDO_EN).await?;
84 let en_val = if enabled {
85 en_reg | DLDO1_EN_BIT
86 } else {
87 en_reg & !DLDO1_EN_BIT
88 };
89 self.write_reg(REG_LDO_EN, en_val).await?;
90 Ok(())
91 }
92
93 pub async fn enable_battery_adc(&mut self) -> Result<(), Axp2101Error> {
97 let en = self.read_reg(REG_ADC_EN).await?;
98 self.write_reg(REG_ADC_EN, en | VBAT_ADC_EN_BIT).await?;
99 Ok(())
100 }
101
102 pub async fn battery_voltage_mv(&mut self) -> Result<u16, Axp2101Error> {
104 let hi = self.read_reg(REG_VBAT_H).await?;
105 let mut lo_buf = [0u8; 1];
106 self.i2c
107 .lock()
108 .await
109 .write_read_async(self.address, &[REG_VBAT_H + 1], &mut lo_buf)
110 .await?;
111 debug!("AXP2101 rd 0x{:02x} = 0x{:02x}", REG_VBAT_H + 1, lo_buf[0]);
112 let raw = ((hi as u16 & 0x3F) << 8) | lo_buf[0] as u16;
113 Ok(raw)
114 }
115
116 pub async fn vbus_present(&mut self) -> Result<bool, Axp2101Error> {
118 let status = self.read_reg(REG_PWR_STATUS).await?;
119 Ok(status & VBUS_PRESENT_BIT != 0)
120 }
121}