1. initial construction

This commit is contained in:
onexs-xsi
2026-01-14 10:33:24 +08:00
parent b83ce12dde
commit 1b11fa1212
10 changed files with 6439 additions and 23 deletions
+9
View File
@@ -0,0 +1,9 @@
idf_component_register(
SRCS
"src/M5PM1.cpp"
INCLUDE_DIRS
"src"
REQUIRES
"driver"
"espressif__i2c_bus"
)
+182 -23
View File
@@ -1,48 +1,207 @@
# Product Name
# M5PM1
## Overview
### SKU:xxx
**SKU: N/A**
Description of the product
M5PM1 is a dual-platform (ESP-IDF & Arduino) driver library for M5Stack PM1 Power Management IC. It provides comprehensive power management features including:
## Related Link
- Battery charging and monitoring
- Multiple power rails (DCDC 5V, LDO 3.3V)
- 5 GPIO pins with various functions (GPIO/IRQ/WAKE/PWM/ADC)
- PWM output (2 channels)
- ADC input (2 channels + temperature)
- NeoPixel LED control (up to 32 LEDs)
- Watchdog timer
- RTC RAM (32 bytes, retained in sleep)
- I2C auto-sleep/wake feature
- [Document & Datasheet](https://docs.m5stack.com/en/unit/product_Link)
## Features
## Required Libraries:
- **Dual-Platform Support**: Works with both Arduino and ESP-IDF frameworks
- **Arduino-Style API**: Familiar `pinMode()`, `digitalWrite()`, `digitalRead()` functions
- **I2C Auto-Wake**: Automatically handles PM1 sleep mode wake-up
- **Comprehensive Power Management**: Battery charging, voltage monitoring, power hold
- [Adafruit_BMP280_Library](https://github.com/adafruit/Required_Libraries_Link)
## Hardware
## License
- **I2C Address**: 0x6E (default)
- **I2C Speed**: 100KHz (default), 400KHz (configurable)
- **GPIO Pins**: 5 (GPIO0-GPIO4)
- **PWM Channels**: 2 (GPIO3, GPIO4)
- **ADC Channels**: 2 (GPIO1, GPIO2) + Internal Temperature
- [Product Name- MIT](LICENSE)
## Pin Functions
## Remaining steps(Editorial Staff Look,After following the steps, remember to delete all the content below)
| GPIO | Special Function | Description |
|------|-----------------|-------------|
| GPIO0 | LED_EN | NeoPixel LED enable |
| GPIO1 | ADC1 | Analog input channel 1 |
| GPIO2 | ADC2 | Analog input channel 2 |
| GPIO3 | PWM0 | PWM output channel 0 |
| GPIO4 | PWM1 | PWM output channel 1 |
1. Change [clang format check path](./.github/workflows/clang-format-check.yml#L42-L47).
2. Add License content to [LICENSE](/LICENSE).
3. Change link on line 78 of [bug-report.yml](./.github/ISSUE_TEMPLATE/bug-report.yml#L79).
## Usage
### Arduino
```cpp
Example
# M5Unit-ENV
#include <M5PM1.h>
## Overview
M5PM1 pm1;
### SKU:U001 & U001-B & U001-C
void setup() {
Serial.begin(115200);
Wire.begin(38, 39); // SDA, SCL
Contains M5Stack-**UNIT ENV** series related case programs.ENV is an environmental sensor with integrated SHT30 and QMP6988 internally to detect temperature, humidity, and atmospheric pressure data.
if (pm1.begin(&Wire) != M5PM1_OK) {
Serial.println("PM1 init failed!");
while (1) delay(100);
}
// Use Arduino-style API
pm1.pinMode(0, OUTPUT);
pm1.digitalWrite(0, HIGH);
// Read battery voltage
uint16_t vbat;
if (pm1.readVbat(&vbat) == M5PM1_OK) {
Serial.printf("Battery: %d mV\n", vbat);
}
}
void loop() {
// Toggle GPIO0
pm1.digitalWrite(0, HIGH);
delay(500);
pm1.digitalWrite(0, LOW);
delay(500);
}
```
### ESP-IDF
```cpp
#include "M5PM1.h"
M5PM1 pm1;
void app_main() {
// Initialize with self-created I2C bus
if (pm1.begin(I2C_NUM_0, M5PM1_DEFAULT_ADDR, 21, 22, 100000) != M5PM1_OK) {
ESP_LOGE("PM1", "Init failed!");
return;
}
// Or use existing i2c_master_bus_handle_t
// pm1.begin(existing_bus_handle, M5PM1_DEFAULT_ADDR, 100000);
// Configure GPIO
pm1.gpioSetFunc(M5PM1_GPIO_NUM_0, M5PM1_GPIO_FUNC_GPIO);
pm1.gpioSetMode(M5PM1_GPIO_NUM_0, M5PM1_GPIO_MODE_OUTPUT);
pm1.gpioSetOutput(M5PM1_GPIO_NUM_0, 1);
}
```
## API Reference
### Initialization
| Method | Description |
|--------|-------------|
| `begin()` | Initialize the PM1 device |
| `setAutoWakeEnable()` | Enable/disable auto-wake feature |
| `sendWakeSignal()` | Manually send wake signal |
### GPIO Functions
| Method | Description |
|--------|-------------|
| `pinMode()` | Set GPIO mode (Arduino-style) |
| `digitalWrite()` | Set GPIO output (Arduino-style) |
| `digitalRead()` | Read GPIO input (Arduino-style) |
| `gpioSetFunc()` | Set GPIO function (GPIO/IRQ/WAKE/OTHER) |
| `gpioSetMode()` | Set GPIO direction |
| `gpioSetOutput()` | Set GPIO output level |
| `gpioGetInput()` | Get GPIO input level |
| `gpioSetPull()` | Set GPIO pull-up/pull-down |
| `gpioSetDrive()` | Set GPIO drive mode |
### Power Management
| Method | Description |
|--------|-------------|
| `getPowerSource()` | Get current power source |
| `getWakeSource()` | Get wake source flags |
| `setPowerConfig()` | Set power configuration |
| `setChargeEnable()` | Enable/disable battery charging |
| `setDcdcEnable()` | Enable/disable 5V DCDC |
| `setLdoEnable()` | Enable/disable 3.3V LDO |
| `shutdown()` | Shutdown the system |
| `reboot()` | Reboot the system |
### Voltage Reading
| Method | Description |
|--------|-------------|
| `readVref()` | Read reference voltage |
| `readVbat()` | Read battery voltage |
| `readVin()` | Read VIN voltage |
| `read5VInOut()` | Read 5VINOUT voltage |
### PWM Functions
| Method | Description |
|--------|-------------|
| `setPwmFrequency()` | Set PWM frequency |
| `getPwmFrequency()` | Get PWM frequency |
| `setPwmDuty()` | Set PWM duty (percentage) |
| `getPwmDuty()` | Get PWM duty (percentage) |
| `setPwmDuty12bit()` | Set PWM duty (12-bit) |
| `getPwmDuty12bit()` | Get PWM duty (12-bit) |
| `analogWrite()` | Arduino-compatible PWM output |
### ADC Functions
| Method | Description |
|--------|-------------|
| `analogRead()` | Read ADC value |
| `isAdcBusy()` | Check ADC busy status |
| `disableAdc()` | Disable ADC conversion |
### NeoPixel Functions
| Method | Description |
|--------|-------------|
| `setLeds()` | Configure and set all LEDs |
| `setLedCount()` | Set LED count |
| `setLedColor()` | Set LED color |
| `refreshLeds()` | Refresh LED display |
| `disableLeds()` | Disable LED output |
### Watchdog Functions
| Method | Description |
|--------|-------------|
| `wdtSet()` | Set watchdog timeout |
| `wdtFeed()` | Feed the watchdog |
| `wdtGetCount()` | Get watchdog countdown |
### RTC RAM Functions
| Method | Description |
|--------|-------------|
| `writeRtcRAM()` | Write to RTC RAM |
| `readRtcRAM()` | Read from RTC RAM |
## Related Link
- [Document & Datasheet](https://docs.m5stack.com/en/unit/envIII)
- [Document & Datasheet](https://docs.m5stack.com/en/unit/pm1)
## Required Libraries:
## Required Libraries
- [Adafruit_BMP280_Library](https://github.com/adafruit/Adafruit_BMP280_Library)
- None (standalone library)
## License
- [M5Unit-ENV - MIT](LICENSE)
```
- [M5PM1 - MIT](LICENSE)
+273
View File
@@ -0,0 +1,273 @@
PY32 PMIC 说明手册
================================================================================
基本信息
================================================================================
I2C 地址: 0x6E
硬件/固件版本: HW:5 / SW:6 (硬件修订: 5, 固件主版本: 6)
文档版本: 1.7 (2025-12-13)
代码仓库: stamp_timerpower2_code
后续软件工程师: @任张涛
================================================================================
一、 芯片概述
================================================================================
[功能]
1. 电源管理: 支持 3.3V LDO/DCDC、5V IN/OUT、充电控制
2. GPIO 控制: 5路可复用 GPIO (输入/输出、NeoPixel、ADC、PWM、Wake In、IRQ Out)
3. 定时唤醒: 32-bit 定时器 (最大 214748364 秒), 支持多种唤醒动作
4. 安全监控: 看门狗, 低压保护
5. 存储备份: 32 字节 RTC RAM
[接口]
I2C 协议 (支持 100kHz/400kHz 模式, 默认支持 100kHz, 400kHz 需要配置)
--------------------------------------------------------------------------------
GPIO 功能分布表
--------------------------------------------------------------------------------
| 序号 | PIN | GPIO | WAKE支持情况 | IRQ | 复用功能 |
|-------|-----|------|---------------------|------|-----------|
| GPIO0 | 3 | 支持 | 支持 (与GPIO2互斥) | 支持 | Neopixel |
| GPIO1 | 17 | 支持 | 不支持 | 支持 | ADC |
| GPIO2 | 20 | 支持 | 支持 (与GPIO0互斥) | 支持 | ADC |
| GPIO3 | 13 | 支持 | 支持 (与GPIO4互斥) | 支持 | PWM |
| GPIO4 | 12 | 支持 | 支持 (与GPIO3互斥) | 支持 | PWM |
--------------------------------------------------------------------------------
内部 Pin 功能分布表
--------------------------------------------------------------------------------
| PIN | IO类型 | 上下拉 | 功能描述 |
|-----|----------|--------|----------|
| 1 | 模拟输出 | 无 | 开关电流采样: 高电平开启采样, 低电平关闭采样。默认为高电平 |
| 2 | 模拟输出 | 无 | 使能电池充电: 低电平停止充电, 高电平开启充电。默认为高电平 |
| 3 | GPIO | 无 | GPIO0, 默认为输入 |
| 4 | 电源VSS | 无 | 无 |
| 5 | 模拟输出 | 无 | LED灯控制, 输出低电平或高电平, 默认为高电平 |
| 6 | 电源VCC | 无 | 无 |
| 7 | 输入 | 上拉 | 按键检测 |
| 8 | I2C | 无 | I2C SDA |
| 9 | I2C | 无 | I2C SCL |
| 10 | 模拟输出 | 无 | 5V DC/DC控制, 输出低电平或高电平, 默认为低电平 |
| 11 | ADC | 无 | 电池ADC输入 (分压系数为1:1) |
| 12 | GPIO | 无 | GPIO4, 默认为输入 |
| 13 | GPIO | 无 | GPIO3, 默认为输入 |
| 14 | 模拟输出 | 无 | 3V3 DC/DC控制, 输出低电平或高电平, 默认为高电平 |
| 15 | 开漏输出 | 无 | 控制ESP32 BOOT, 默认为高电平 |
| 16 | ADC | 无 | 5VIN ADC输入 (分压系数为1:1) |
| 17 | GPIO | 无 | GPIO1, 默认为输入 |
| 18 | 模拟输出 | 无 | 3V3 LDO控制, 输出低电平或高电平, 默认为高电平 |
| 19 | ADC | 无 | 5VOUT ADC值输入 (分压系数为1:1) |
| 20 | GPIO | 无 | GPIO2, 默认为输入 |
================================================================================
二、 注意事项
================================================================================
1. 内部通道 ADC 的使用
- 3个通道都有特定功能, 必须严格对应接入。
- ADC 5VOUT:
* 5VOUT 有输入和输出功能, 5VOUT 升压打开前, 需要先检测 5VOUT 的电压, 确保上面没有电源输入才能打开升压, 否则保持输入。
* 低电压阈值检测。
* 5VOUT 电源插入唤醒。
* 5VOUT 电源移除与插入检测。
- ADC BAT:
* 低电压阈值检测。
* 电池插入移除检测。
- ADC 5VIN:
* 低电压阈值检测。
* 5VIN 插入移除检测。
2. 低电压自动关机
- 低电压阈值由寄存器 BATT_LVP(0x08) 决定。
- 在 5VIN 或 5VINOUT 没有插入的前提下, 电池电压低于阈值, 会自动关机。
================================================================================
逻辑流程描述
================================================================================
[流程1: 低电压保护 (LVP) 与自动关机]
步骤:
1. 检测是否触发 LVP (低电压保护)。
2. 判断: 5VIN 或 5VINOUT 是否有电?
- 是: 进入 [正常运行]。
- 否: 判断 VBAT 是否大于最低电压?
- 是: 进入 [正常运行]。
- 否: 进入 [DeepSleep待机]。
注: 在没有插入 Vin 的情况下, 需要 BAT 电压大于 BATT_LVP 电压 + 100mV, 才能退出低电压待机循环。
[流程2: 关机逻辑]
步骤:
1. 接收到关机指令。
2. 检查寄存器 gpio_power_hold_cfg 的 bit5/6 是否为 1?
- 否: bit5=0 (3.3V LDO关闭); bit6=0 (5V VOUT关闭)。
- 是: bit5=1 (3.3V LDO保持); bit6=1 (5V VOUT保持)。
3. 执行操作:
(1) 3.3V DCDC 关闭。
(2) LED_EN 关闭。
(3) 充电使能不受影响。
[流程3: 下载模式]
步骤:
1. 进入下载模式。
2. 复位电源与gpio寄存器; 置位 power_gpio_hold 寄存器。
3. 下电。
4. BOOT_OUT 输出低电平。
5. 延时 300ms。
6. 上电。
7. 延时 500ms。
8. BOOT_OUT 输出高电平。
[流程4: 复位模式]
步骤:
1. 进入复位模式。
2. 复位电源与gpio寄存器; 置位 power_gpio_hold 寄存器。
3. 下电。
4. 延时 500ms。
5. 上电。
================================================================================
特殊功能细节与寄存器访问限制
================================================================================
[寄存器访问]
I2C Burst 读写支持连续读写特定区块:
0x00~0x0C, 0x10~0x19, 0x20~0x2A, 0x30~0x35, 0x38~0x3D, 0x40~0x45, 0x48~0x4A, 0x50、0x53, 0x60~0x9F, 0xA0~0xBF。
超出范围需分次操作。
[GPIO 限制]
1. GPIO1 与 SDA 共用中断线, 不可用干唤醒。
2. GPIO0/2 共用中断线; GPIO3/4 共用中断线 (均为互斥使用)。
3. GPIO_WAKE_EN (0x18) 和 GPIO_WAKE_CFG (0x19) 的配置不会因为进入下载模式、复位和关机而失效。
4. WAKE 是否启用上下拉由 GPIO_PU/PD_0 (0x14) 和 GPIO_PU/PD_1 (0x15) 控制。
5. GPIO_DRV (0x13) 输出类型拥有最高优先级, 不会随复用功能失效。默认为开漏, 即使复用为 PWM 或 Neopixel, 若配置为开漏则仍为开漏。
[电源事件]
IRQ Status 2 中的电池插入/移除事件仅在充电未使能 (CHG_EN=0) 时有效; 5VINOUT 事件仅在 INPUT 模式 (5VIN/OUT=0) 有效。
[NeoPixel 数据]
数据存储在 PIX0_L=0x60 ... PIX31_H=0x9F (共64字节)。刷新时 (REFRESH=1) 禁止 I2C 中断约 7ms。
[PWM 配置]
PWM0/1 的高低位配置分为两个字节, 需一次写入两个字节, 否则可能在极短时间内出现参数不一致。
[按键逻辑]
单击复位; 双击关机; 长按进入下载模式; 具体时间由 BTN_CFG_1 决定。
================================================================================
三、 寄存器映射表 (Register Map)
================================================================================
说明: 以下表格中 "Def" 代表默认值 (Default)。
Reset行为包括: 按键复位, 命令复位, I2C看门狗复位, 用户定时器复位。
关机行为包括: 按键关机, 命令关机, 用户定时器关机。
| Register | Type | Addr | Bits | R/W | Def | 描述 | Reset后状态 | Download后状态 | 关机后状态 |
|---|---|---|---|---|---|---|---|---|---|
| Device_ID | Sys | 0x00 | [7:0] | R | 0x50 | 设备类型 | - | - | - |
| Device_Model | Sys | 0x01 | [7:0] | R | 0x20 | 设备型号 | - | - | - |
| HW_REV | Sys | 0x02 | [7:0] | R | 0x05 | 硬件版本号 | - | - | - |
| SW_REV | Sys | 0x03 | [7:0] | R | 0x06 | 固件版本号 | - | - | - |
| PWR_SRC | Sys | 0x04 | [7:3] Rsv; [2:0] VALID | R | - | 电源来源位图 | - | - | - |
| WAKE_SRC | Sys | 0x05 | [7] Rsv; [6:0] FLAGS | R/W | - | 唤醒源标志 | - | - | - |
| PWR_CFG | Sys | 0x06 | [7:5] Rsv; [4] LED CTRL; [3] 5V IO; [2] 3V3 LDO; [1] 3V3 DCDC; [0] CHG EN | R/W | 0x17 | 电源管理位 | 0b00010011x (充电状态不受复位影响) | 0b00010011x (充电状态不受复位影响) | 0b00010011x (充电状态不受关机影响) |
| HOLD_CFG | Sys | 0x07 | [7] Rsv; [6] 5V IO; [5] 3V3 LDO; [4:0] GPIO4~0 | R/W | 0x00 | 置1则对应状态在关机后保留; 复位或下载模式时此寄存器复位为0 | 0x00 | 0x00 | - |
| BATT_LVP | Sys | 0x08 | [7:0] | R/W | 0x40 | 低压阈值: 2000mV + n*7.81mV | - | - | - |
| I2C_CFG | Sys | 0x09 | [7:4] Rsv; [4] SPD; [3:0] SLP_TO | R/W | 0x00 | SPD: 0=100k, 1=400k; SLP_TO: I2C超时休眠(秒)。PWM使能或下载模式时禁止休眠 | - | - | - |
| WDT_CNT | Sys | 0x0A | [7:0] | R/W | 0x00 | 看门狗倒计时(秒), 0=关闭 | - | - | - |
| WDT_KEY | Sys | 0x0B | [7:0] | W | - | 写 0xA5 清零/复位 | - | - | - |
| SYS_CMD | Sys | 0x0C | [7:4] KEY(0xA); [1:0] CMD | W | - | CMD: 01=关机, 10=重启, 11=下载 | - | - | - |
| GPIO_MODE | GPIO | 0x10 | [7:5] Rsv; [4:0] GPIO4~0 | R/W | 0x00 | 1=输出, 0=输入 (需GPIO_FUNC=00) | 由Hold寄存器决定 (1=保持, 0=复位) | 0x00 | 由Hold寄存器决定 |
| GPIO_OUT | GPIO | 0x11 | [7:5] Rsv; [4:0] GPIO4~0 | R/W | 0x00 | 写1=高电平 | 由Hold寄存器决定 | 0x00 | 由Hold寄存器决定 |
| GPIO_IN | GPIO | 0x12 | 同上 | R | - | 实时输入值 | - | - | - |
| GPIO_DRV | GPIO | 0x13 | [7:6] Rsv; [5] LED; [4:0] GPIO | R/W | 0x1F | 1=开漏, 0=推挽 | 由Hold寄存器决定 (LED不受影响) | 0x1F | 由Hold寄存器决定 |
| GPIO_PU/PD_0 | GPIO | 0x14 | [7:6] G3; [5:4] G2; [3:2] G1; [1:0] G0 | R/W | 0x00 | 00=无, 01=上拉, 10=下拉 | 由Hold寄存器决定 | 0x00 | 由Hold寄存器决定 |
| GPIO_PU/PD_1 | GPIO | 0x15 | [7:2] Rsv; [1:0] GPIO4 | R/W | 0x00 | 同上 | 由Hold寄存器决定 | 0x00 | 由Hold寄存器决定 |
| GPIO_FUNC0 | GPIO | 0x16 | [7:6] G3; [5:4] G2; [3:2] G1; [1:0] G0 | R/W | 0x00 | 00=GPIO, 01=IRQ, 11=特殊, 10=保留 | 由Hold寄存器决定 | 0x00 | 由Hold寄存器决定 |
| GPIO_FUNC1 | GPIO | 0x17 | [7:2] Rsv; [1:0] GPIO4 | R/W | 0x00 | 同上 | 由Hold寄存器决定 | 0x00 | 由Hold寄存器决定 |
| GPIO_WAKE_EN | GPIO | 0x18 | [7:5] Rsv; [4:0] GPIO4~0 | R/W | 0x00 | 1=使能WAKE; 注意中断线互斥规则 | - | - | - |
| GPIO_WAKE_CFG | GPIO | 0x19 | [7:5] Rsv; [4:0] GPIO4~0 | R/W | 0x00 | 1=上升沿, 0=下降沿 | - | - | - |
| VREF_L/H | ADC | 0x20 | [7:0] | R | - | MCU ADC 参考电压 (L:0x20, H:0x21) | - | - | - |
| VBAT_L/H | ADC | 0x22 | [7:0] | R | - | 电池电压 (L:0x22, H:0x23) | - | - | - |
| VIN_L/H | ADC | 0x24 | [7:0] | R | - | 5VIN 电压 (L:0x24, H:0x25) | - | - | - |
| 5VOUT_L/H | ADC | 0x26 | [7:0] | R | - | 5VOUT 电压 (L:0x26, H:0x27) | - | - | - |
| ADC_RES_L/H | ADC | 0x28 | [7:0] / [3:0] Data | R | - | ADC 转换结果 | - | - | - |
| ADC_CTRL | ADC | 0x2A | [3:1] CH_SEL; [0] START | R/W | 0x00 | START=1开始; CH_SEL: 1/2=GPIO, 6=Temp | - | - | - |
| PWM0_L/HC | PWM | 0x30 | [7:0] / [5] POL [4] EN | R/W | 0x00 | PWM0 控制 | - | - | - |
| PWM1_L/HC | PWM | 0x32 | [7:0] / [5] POL [4] EN | R/W | 0x00 | PWM1 控制 | - | - | - |
| PWM_FREQ_L/H | PWM | 0x34 | [7:0] | R/W | F4/01 | PWM 频率 (16bit) | - | - | - |
| TIM_CNT_BYTE | Tim | 0x38 | [7:0] (0x38-0x3B) | R/W | 0x00 | 定时唤醒计数器 (32bit, 秒) | - | - | - |
| TIM_CFG | Tim | 0x3C | [3] ARM; [2:0] ACTION | R/W | 0x00 | ACTION: 000=停, 001=标志, 010=重启, 011=上电, 100=关机 | - | - | - |
| TIM_KEY | Tim | 0x3D | [7:0] | W | - | 写 0xA5 清零重载 | - | - | - |
| IRQ Status 1 | IRQ | 0x40 | [4:0] GPIO4~0 | R/W | 0x00 | GPIO 电平变化 | - | - | - |
| IRQ Status 2 | IRQ | 0x41 | [5/4] Bat Rm/Add; [3/2] 5Vout Rm/Add; [1/0] 5Vin Rm/Add | R/W | 0x00 | 电源事件 (写1清零) | - | - | - |
| IRQ Status 3 | IRQ | 0x42 | [2] Dbl Click; [1] Wake; [0] Click | R/W | 0x00 | 按键/唤醒事件 (bit0=RST中断, bit1=Wakeup中断, bit2=双击中断) | - | - | - |
| IRQ Mask 1/2/3| IRQ | 0x43 | 对应 Status 位 | R/W | 0x00 | 写1屏蔽对应中断 (0x43~0x45) | - | - | - |
| BTN_Status | BTN | 0x48 | [7] Event; [0] Status | R | 0x00 | 按键状态 | - | - | - |
| BTN_CFG_1 | BTN | 0x49 | [7] Lock; [6:5] Dbl; [4:3] Long; [2:1] Single; [0] Sngl_Rst_Dis | R/W | 0x2A | 按键时间配置; bit0=1禁止单击复位 | - | - | - |
| BTN_CFG_2 | BTN | 0x4A | [0] Dbl_Off_Dis | R/W | 0x00 | bit0=1禁止双击关机 | - | - | - |
| NEO_CFG | RGB | 0x50 | [6] Refresh; [5:0] Count | R/W | 0x00 | NeoPixel控制 | - | - | - |
| PULSE_CTRL | Pulse| 0x53 | [7] Refresh; [6:5] Num; [4:0] GPIO | R/W | 0x00 | AW8737A 脉冲触发 | - | - | - |
| NEO_PIXn | RGB | 0x60 | [7:0] | R/W | 0x00 | 0x60-0x9F RGB数据缓存 | - | - | - |
| RTC_MEM | RTC | 0xA0 | [7:0] | R/W | 0x00 | 0xA0-0xBF RTC数据缓存 | - | - | - |
================================================================================
四、 关键寄存器功能详解
================================================================================
1. PWR_SRC (0x04) - 电源来源状态
- [2] BAT: 电池有效
- [1] 5VINOUT: 5VINOUT 有效 (仅当 5V 升压关闭时有效)
- [0] 5VIN: 5VIN 有效
- 注: 系统通过 ADC 检测电压判断电源来源。建议无电池时关闭电池充电。
2. WAKE_SRC (0x05) - 唤醒来源
- [6] 5V INOUT 插入唤醒 (仅当 5V 升压关闭时)
- [5] EXT_WAKE: GPIO 唤醒
- [4] CMD_RST: 复位命令
- [3] RSTBTN: 按键复位
- [2] PWRBTN: 电源按钮
- [1] VIN: 5VIN 插入
- [0] TIM: 定时器
3. HOLD_CFG (0x07) - 状态保持
- 将对应位设为 1, 则关机后对应的 GPIO、LDO 或 5VINOUT 状态会保持原样。
- 注意: 进入下载模式或触发任何 Reset (包括看门狗), 该寄存器会清零。
4. BATT_LVP (0x08) - 低压保护
- 低压阈值计算: 2.0 V + (reg_value * 7.81 mV)。
- 重新开机条件: 电池电压 > 阈值+100mV; 或插入 5VIN; 或插入 5VINOUT。
5. I2C_CFG (0x09) - I2C配置
- SPD: 0=100k, 1=400k。
- SLP_TO: 若设置非0, 代表 I2C 总线空闲多少秒后芯片休眠。
- 限制: PWM 使能或下载模式下, I2C 空闲休眠强制关闭。
6. GPIO_MODE / OUT / DRV
- GPIO_MODE: 1=输出, 0=输入。需 GPIO_FUNC 设置为 00 才生效。
- GPIO_OUT: 1=高, 0=低。
- GPIO_DRV: 1=开漏, 0=推挽。DRV 优先级最高, 若复用功能开启但 DRV=1, 仍为开漏。
7. ADC_CTRL (0x2A) - ADC控制
- CH_SEL: 通道选择。1=GPIO1, 2=GPIO2, 6=内部温度。
- 使用 GPIO 作 ADC 输入时, 必须将对应的 GPIO_FUNC 设为 11。
8. IRQ Status 注意事项
- 若没有 GPIO 被配置为 IRQ 引脚, Status 寄存器会自动清零。
- 若要使用 Wakeup IRQ (Status 3 bit1), 请勿清除 WAKE_SRC 寄存器, 直到重新配置 GPIO 为 IRQ 引脚。
================================================================================
五、 附加功能说明与变更记录 (Change Log)
================================================================================
[附加功能说明]
(1) 32-bit 定时器最大秒数限制为 214749364 秒。
(2) 关机时, GPIO 恢复为默认输入无上下拉; 电源恢复默认状态 (除非 HOLD_CFG 对应位为 1)。
(3) 进入下载模式, HOLD_CFG 清零, I2C 看门狗/休眠/用户定时器停止, GPIO 恢复默认。
(4) LED 提示逻辑: 复位闪烁1次; 下载模式 500ms 间隔闪烁; 屏蔽按键复位且有 IRQ 时 200ms 间隔闪烁; 屏蔽关机且有 IRQ 时 100ms 间隔闪烁。
(5) 充电功能默认打开。
[文档变更记录]
| 版本 | 日期 | 变更描述 |
|------|------------|----------|
| 1.0 | 2025-06-30 | 初始版本 |
| 1.1 | 2025-07-23 | 硬件修订: 3, 固件主版本: 2 |
| 1.2 | 2025-08-04 | 修订部分描述错误 |
| 1.3 | 2025-09-01 | 硬件修订: 4, 固件主版本: 3 |
| 1.4 | 2025-09-10 | 对关键寄存器详解进行了补充 |
| 1.5 | 2025-09-17 | 硬件修订: 5, 固件主版本: 4; (1) LED 指示灯在单击或双击中断触发指示; (2) 升级失败时 GPIO 和 bootout 设置为开漏; (3) 改用 ADC 采样判断 5VINOUT; (4) PIN1 逻辑修改。 |
| 1.6 | 2025-11-04 | 硬件修订: 5, 固件主版本: 5; (1) 添加 AW8737A 调频脉冲输出; (2) 添加 DCDC_5V 保持功能; (3) 看门狗默认关闭。 |
| 1.7 | 2025-12-13 | 硬件修订: 5, 固件主版本: 6; (1) 更新寄存器映射; (2) 新增 BTN_Status (0x48); (3) 移除 UID 寄存器, 新增 Device_ID/Model。 |
+14
View File
@@ -0,0 +1,14 @@
description: "M5Stack M5PM1 Power Management IC Library"
maintainers:
- "M5Stack"
license: MIT
tags:
- "m5stack"
- "power-management"
dependencies:
idf:
version: ">=4.4"
espressif/i2c_bus:
version: "^1.0.0"
public: true
version: "1.0.1"
+49
View File
@@ -0,0 +1,49 @@
{
"name": "M5PM1",
"version": "1.0.1",
"description": "M5Stack PM1 Power Management IC Driver Library",
"keywords": [
"m5stack",
"pm1",
"power-management",
"i2c",
"esp32",
"arduino"
],
"repository": {
"type": "git",
"url": "https://github.com/m5stack/M5PM1.git"
},
"authors": [
{
"name": "M5Stack",
"email": "m5stack@m5stack.com",
"url": "https://m5stack.com",
"maintainer": true
}
],
"license": "MIT",
"homepage": "https://github.com/m5stack/M5PM1",
"frameworks": [
"arduino",
"espidf"
],
"platforms": [
"espressif32"
],
"export": {
"include": [
"src/*",
"library.json",
"library.properties",
"CMakeLists.txt",
"idf_component.yml",
"LICENSE",
"README.md"
]
},
"build": {
"srcDir": "src",
"includeDir": "src"
}
}
+10
View File
@@ -0,0 +1,10 @@
name=M5PM1
version=1.0.1
author=M5Stack
maintainer=M5Stack
sentence=M5Stack PM1 Power Management IC Driver Library
paragraph=Dual-platform (ESP-IDF & Arduino) driver for PM1 power management IC with battery charging, GPIO, PWM, ADC, NeoPixel, and watchdog support.
category=Device Control
url=https://github.com/m5stack/M5PM1
architectures=esp32
includes=M5PM1.h
View File
+4140
View File
File diff suppressed because it is too large Load Diff
+1484
View File
File diff suppressed because it is too large Load Diff
+278
View File
@@ -0,0 +1,278 @@
/*
* SPDX-FileCopyrightText: 2025 M5Stack Technology CO LTD
*
* SPDX-License-Identifier: MIT
*/
#ifndef __M5PM1_I2C_COMPAT_H__
#define __M5PM1_I2C_COMPAT_H__
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#ifdef ARDUINO
#include "Wire.h"
// ============================
// Arduino I2C Functions
// Arduino I2C 功能
// ============================
#ifndef M5PM1_I2C_READ_BYTE
static inline bool M5PM1_I2C_READ_BYTE(TwoWire *wire, uint8_t addr, uint8_t reg, uint8_t *data) {
wire->beginTransmission(addr);
wire->write(reg);
if (wire->endTransmission(false) != 0) {
return false;
}
if (wire->requestFrom(addr, (uint8_t)1) != 1) {
return false;
}
*data = wire->read();
return true;
}
#endif
#ifndef M5PM1_I2C_READ_BYTES
static inline bool M5PM1_I2C_READ_BYTES(TwoWire *wire, uint8_t addr, uint8_t start_reg, size_t len, uint8_t *data) {
wire->beginTransmission(addr);
wire->write(start_reg);
if (wire->endTransmission(false) != 0) {
return false;
}
if (wire->requestFrom(addr, (uint8_t)len) != len) {
return false;
}
for (size_t i = 0; i < len; i++) {
data[i] = wire->read();
}
return true;
}
#endif
#ifndef M5PM1_I2C_READ_REG16
static inline bool M5PM1_I2C_READ_REG16(TwoWire *wire, uint8_t addr, uint8_t reg, uint16_t *data) {
uint8_t buf[2];
if (!M5PM1_I2C_READ_BYTES(wire, addr, reg, 2, buf)) {
return false;
}
// Little-endian: low byte first
// 小端模式:低字节在前
*data = (uint16_t)buf[0] | ((uint16_t)buf[1] << 8);
return true;
}
#endif
#ifndef M5PM1_I2C_WRITE_BYTE
static inline bool M5PM1_I2C_WRITE_BYTE(TwoWire *wire, uint8_t addr, uint8_t reg, uint8_t data) {
wire->beginTransmission(addr);
wire->write(reg);
wire->write(data);
if (wire->endTransmission() != 0) {
return false;
}
return true;
}
#endif
#ifndef M5PM1_I2C_WRITE_BYTES
static inline bool M5PM1_I2C_WRITE_BYTES(TwoWire *wire, uint8_t addr, uint8_t start_reg, size_t len, const uint8_t *data) {
wire->beginTransmission(addr);
wire->write(start_reg);
for (size_t i = 0; i < len; i++) {
wire->write(data[i]);
}
if (wire->endTransmission() != 0) {
return false;
}
return true;
}
#endif
#ifndef M5PM1_I2C_WRITE_REG16
static inline bool M5PM1_I2C_WRITE_REG16(TwoWire *wire, uint8_t addr, uint8_t reg, uint16_t data) {
uint8_t buf[2];
// Little-endian: low byte first
// 小端模式:低字节在前
buf[0] = (uint8_t)(data & 0xFF);
buf[1] = (uint8_t)((data >> 8) & 0xFF);
return M5PM1_I2C_WRITE_BYTES(wire, addr, reg, 2, buf);
}
#endif
// Wake signal for PM1 sleep mode
// PM1睡眠模式唤醒信号
#ifndef M5PM1_I2C_SEND_WAKE
static inline void M5PM1_I2C_SEND_WAKE(TwoWire *wire, uint8_t addr) {
// Send START signal to generate SDA falling edge for PM1 wake
// PM1 uses SDA pin (PB4) falling edge to trigger EXTI4 interrupt for wakeup
wire->beginTransmission(addr);
wire->endTransmission(false); // Send START without STOP
}
#endif
#else // ESP-IDF
#include <esp_err.h>
#include <driver/i2c_master.h> // ESP-IDF native i2c_master driver
#include <i2c_bus.h> // esp-idf-lib i2c_bus component
#ifdef __cplusplus
extern "C" {
#endif
// ============================
// I2C Driver Type Selection
// I2C 驱动类型选择
// ============================
typedef enum {
M5PM1_I2C_DRIVER_NONE = 0, // Not initialized / 未初始化
M5PM1_I2C_DRIVER_SELF_CREATED, // Self-created using i2c_port_t / 使用 i2c_port_t 自创建
M5PM1_I2C_DRIVER_MASTER, // ESP-IDF native i2c_master driver / ESP-IDF 原生 i2c_master 驱动
M5PM1_I2C_DRIVER_BUS // esp-idf-lib i2c_bus component / esp-idf-lib i2c_bus 组件
} m5pm1_i2c_driver_t;
// ============================
// ESP-IDF I2C Functions (i2c_bus)
// ESP-IDF I2C 函数 (i2c_bus)
// ============================
#ifndef M5PM1_I2C_READ_BYTE
static inline esp_err_t M5PM1_I2C_READ_BYTE(i2c_bus_device_handle_t dev, uint8_t reg, uint8_t *data) {
return i2c_bus_read_byte(dev, reg, data);
}
#endif
#ifndef M5PM1_I2C_READ_BYTES
static inline esp_err_t M5PM1_I2C_READ_BYTES(i2c_bus_device_handle_t dev, uint8_t start_reg, size_t len, uint8_t *data) {
return i2c_bus_read_bytes(dev, start_reg, len, data);
}
#endif
#ifndef M5PM1_I2C_READ_REG16
static inline esp_err_t M5PM1_I2C_READ_REG16(i2c_bus_device_handle_t dev, uint8_t reg, uint16_t *data) {
uint8_t buf[2];
esp_err_t ret = i2c_bus_read_bytes(dev, reg, 2, buf);
if (ret == ESP_OK) {
// Little-endian: low byte first
// 小端模式:低字节在前
*data = (uint16_t)buf[0] | ((uint16_t)buf[1] << 8);
}
return ret;
}
#endif
#ifndef M5PM1_I2C_WRITE_BYTE
static inline esp_err_t M5PM1_I2C_WRITE_BYTE(i2c_bus_device_handle_t dev, uint8_t reg, uint8_t data) {
return i2c_bus_write_byte(dev, reg, data);
}
#endif
#ifndef M5PM1_I2C_WRITE_BYTES
static inline esp_err_t M5PM1_I2C_WRITE_BYTES(i2c_bus_device_handle_t dev, uint8_t start_reg, size_t len, const uint8_t *data) {
return i2c_bus_write_bytes(dev, start_reg, len, (uint8_t*)data);
}
#endif
#ifndef M5PM1_I2C_WRITE_REG16
static inline esp_err_t M5PM1_I2C_WRITE_REG16(i2c_bus_device_handle_t dev, uint8_t reg, uint16_t data) {
uint8_t buf[2];
// Little-endian: low byte first
// 小端模式:低字节在前
buf[0] = (uint8_t)(data & 0xFF);
buf[1] = (uint8_t)((data >> 8) & 0xFF);
return i2c_bus_write_bytes(dev, reg, 2, buf);
}
#endif
// ============================
// ESP-IDF I2C Functions (i2c_master - native driver)
// ESP-IDF I2C 函数 (i2c_master - 原生驱动)
// ============================
#ifndef M5PM1_I2C_MASTER_READ_BYTE
static inline esp_err_t M5PM1_I2C_MASTER_READ_BYTE(i2c_master_dev_handle_t dev, uint8_t reg, uint8_t *data) {
return i2c_master_transmit_receive(dev, &reg, 1, data, 1, -1);
}
#endif
#ifndef M5PM1_I2C_MASTER_READ_BYTES
static inline esp_err_t M5PM1_I2C_MASTER_READ_BYTES(i2c_master_dev_handle_t dev, uint8_t start_reg, size_t len, uint8_t *data) {
return i2c_master_transmit_receive(dev, &start_reg, 1, data, len, -1);
}
#endif
#ifndef M5PM1_I2C_MASTER_READ_REG16
static inline esp_err_t M5PM1_I2C_MASTER_READ_REG16(i2c_master_dev_handle_t dev, uint8_t reg, uint16_t *data) {
uint8_t buf[2];
esp_err_t ret = i2c_master_transmit_receive(dev, &reg, 1, buf, 2, -1);
if (ret == ESP_OK) {
// Little-endian: low byte first
// 小端模式:低字节在前
*data = (uint16_t)buf[0] | ((uint16_t)buf[1] << 8);
}
return ret;
}
#endif
#ifndef M5PM1_I2C_MASTER_WRITE_BYTE
static inline esp_err_t M5PM1_I2C_MASTER_WRITE_BYTE(i2c_master_dev_handle_t dev, uint8_t reg, uint8_t data) {
uint8_t buf[2] = {reg, data};
return i2c_master_transmit(dev, buf, 2, -1);
}
#endif
#ifndef M5PM1_I2C_MASTER_WRITE_BYTES
static inline esp_err_t M5PM1_I2C_MASTER_WRITE_BYTES(i2c_master_dev_handle_t dev, uint8_t start_reg, size_t len, const uint8_t *data) {
// Need to prepend register address
// 需要在数据前添加寄存器地址
uint8_t *buf = (uint8_t*)malloc(len + 1);
if (buf == NULL) return ESP_ERR_NO_MEM;
buf[0] = start_reg;
memcpy(buf + 1, data, len);
esp_err_t ret = i2c_master_transmit(dev, buf, len + 1, -1);
free(buf);
return ret;
}
#endif
#ifndef M5PM1_I2C_MASTER_WRITE_REG16
static inline esp_err_t M5PM1_I2C_MASTER_WRITE_REG16(i2c_master_dev_handle_t dev, uint8_t reg, uint16_t data) {
uint8_t buf[3];
buf[0] = reg;
// Little-endian: low byte first
// 小端模式:低字节在前
buf[1] = (uint8_t)(data & 0xFF);
buf[2] = (uint8_t)((data >> 8) & 0xFF);
return i2c_master_transmit(dev, buf, 3, -1);
}
#endif
// Wake signal for PM1 sleep mode using i2c_bus
// 使用i2c_bus的PM1睡眠模式唤醒信号
#ifndef M5PM1_I2C_SEND_WAKE
static inline esp_err_t M5PM1_I2C_SEND_WAKE(i2c_bus_device_handle_t dev, uint8_t reg) {
// Read any register to generate I2C start signal for wake
uint8_t dummy;
return i2c_bus_read_byte(dev, reg, &dummy);
}
#endif
// Wake signal for PM1 sleep mode using i2c_master
// 使用i2c_master的PM1睡眠模式唤醒信号
#ifndef M5PM1_I2C_MASTER_SEND_WAKE
static inline esp_err_t M5PM1_I2C_MASTER_SEND_WAKE(i2c_master_bus_handle_t bus, uint8_t addr) {
// Use i2c_master_probe to generate START signal for wake
return i2c_master_probe(bus, addr, 10);
}
#endif
#ifdef __cplusplus
}
#endif
#endif // ARDUINO
#endif // __M5PM1_I2C_COMPAT_H__