mirror of
https://github.com/m5stack/M5PM1.git
synced 2026-05-20 11:49:32 -07:00
1. Format the project text and fix some issues
This commit is contained in:
@@ -1,207 +1,27 @@
|
||||
# M5PM1
|
||||
# M5PM1
|
||||
|
||||
## Overview
|
||||
|
||||
**SKU: N/A**
|
||||
**SKU:N/A**
|
||||
|
||||
M5PM1 is a dual-platform (ESP-IDF & Arduino) driver library for M5Stack PM1 Power Management IC. It provides comprehensive power management features including:
|
||||
|
||||
- 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
|
||||
|
||||
## Features
|
||||
|
||||
- **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
|
||||
|
||||
## Hardware
|
||||
|
||||
- **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
|
||||
|
||||
## Pin Functions
|
||||
|
||||
| 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 |
|
||||
|
||||
## Usage
|
||||
|
||||
### Arduino
|
||||
|
||||
```cpp
|
||||
#include <M5PM1.h>
|
||||
|
||||
M5PM1 pm1;
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
Wire.begin(38, 39); // SDA, SCL
|
||||
|
||||
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 |
|
||||
M5PM1 is a dual-platform (ESP-IDF & Arduino) driver library for M5Stack PM1 Power Management IC. It provides comprehensive power management features including battery charging and monitoring, multiple power rails (DCDC 5V, LDO 3.3V), 5 GPIO pins with various functions (GPIO/IRQ/WAKE/PWM/ADC), built-in NeoPixel LED driver, Watchdog timer, RTC RAM, and I2C auto-sleep/wake feature.
|
||||
|
||||
## Related Link
|
||||
|
||||
- [Document & Datasheet](https://docs.m5stack.com/en/unit/pm1)
|
||||
- N/A
|
||||
|
||||
## Required Libraries
|
||||
## Required Libraries:
|
||||
|
||||
- None (standalone library)
|
||||
- N/A
|
||||
|
||||
## Examples
|
||||
|
||||
- examples/basic_power_adc/basic_power_adc.ino
|
||||
- examples/gpio_pwm/gpio_pwm.ino
|
||||
- examples/interrupt_button_sleep/interrupt_button_sleep.ino
|
||||
- examples/neopixel/neopixel.ino
|
||||
|
||||
## License
|
||||
|
||||
- [M5PM1 - MIT](LICENSE)
|
||||
|
||||
|
||||
@@ -0,0 +1,154 @@
|
||||
# M5PM1 功能总览(中文)
|
||||
|
||||
面向 Arduino/ESP-IDF 双平台的 PM1 电源管理驱动库功能分类说明。
|
||||
|
||||
- **版本**: 1.0.1
|
||||
- **默认 I2C 地址**: `0x6E`
|
||||
- **I2C 速度**: 默认 100 kHz,可切换 400 kHz(切换后需重新初始化 I2C)
|
||||
|
||||
## 项目结构与角色
|
||||
|
||||
- `src/M5PM1.h`: 公共 API、寄存器/枚举、缓存结构定义。
|
||||
- `src/M5PM1.cpp`: 驱动实现、冲突校验、快照与缓存逻辑。
|
||||
- `src/M5PM1_i2c_compat.h`: Arduino/ESP-IDF I2C 读写兼容封装。
|
||||
|
||||
## 示例
|
||||
|
||||
- `examples/basic_power_adc/basic_power_adc.ino`: 初始化、设备信息、VBAT/VIN/5V 读数、ADC/温度采样、电源轨控制示例。
|
||||
- `examples/gpio_pwm/gpio_pwm.ino`: GPIO 输出/输入读取与 PWM 呼吸灯示例。
|
||||
- `examples/interrupt_button_sleep/interrupt_button_sleep.ino`: GPIO 中断、按钮 API、定时器/唤醒与关机示例。
|
||||
- `examples/neopixel/neopixel.ino`: NeoPixel 彩虹渐变示例。
|
||||
|
||||
## 功能分类
|
||||
|
||||
### 1) 初始化与日志
|
||||
|
||||
- **初始化**
|
||||
- Arduino: `begin(TwoWire*, addr, sda, scl, speed)`
|
||||
- ESP-IDF: `begin(i2c_port_t, addr, sda, scl, speed)`
|
||||
- ESP-IDF: `begin(i2c_master_bus_handle_t, addr, speed)`
|
||||
- ESP-IDF: `begin(i2c_bus_handle_t, addr, speed)`
|
||||
- **日志**
|
||||
- `setLogLevel`/`getLogLevel`
|
||||
|
||||
### 2) 设备信息
|
||||
|
||||
- `getDeviceId`/`getDeviceModel`/`getHwVersion`/`getSwVersion`
|
||||
|
||||
### 3) GPIO 基础与高级控制
|
||||
|
||||
- **Arduino 风格**
|
||||
- `pinMode`/`digitalWrite`/`digitalRead`
|
||||
- **带返回值版本**
|
||||
- `pinModeWithRes`/`digitalWriteWithRes`/`digitalReadWithRes`
|
||||
- **高级配置**
|
||||
- `gpioSet`/`gpioSetFunc`/`gpioSetMode`/`gpioSetOutput`/`gpioGetInput`
|
||||
- `gpioSetPull`/`gpioSetDrive`/`ledEnSetDrive`
|
||||
- `gpioSetWakeEnable`/`gpioSetWakeEdge`
|
||||
- **引脚状态与校验**
|
||||
- `dumpPinStatus`/`verifyPinConfig`/`getPinStatus`/`getPinStatusArray`
|
||||
|
||||
### 4) 电源保持
|
||||
|
||||
- `gpioSetPowerHold`/`gpioGetPowerHold`
|
||||
- `ldoSetPowerHold`/`ldoGetPowerHold`
|
||||
- `dcdcSetPowerHold`/`dcdcGetPowerHold`
|
||||
|
||||
### 5) ADC 与温度
|
||||
|
||||
- `analogRead`/`isAdcBusy`/`disableAdc`/`readTemperature`
|
||||
|
||||
### 6) PWM
|
||||
|
||||
- `setPwmFrequency`/`getPwmFrequency`
|
||||
- `setPwmDuty`/`getPwmDuty` (0-100%)
|
||||
- `setPwmDuty12bit`/`getPwmDuty12bit` (0-4095)
|
||||
- `setPwmConfig`
|
||||
- `analogWrite` (0-255)
|
||||
|
||||
### 7) 电压读取
|
||||
|
||||
- `readVref`/`getRefVoltage`/`readVbat`/`readVin`/`read5VInOut`
|
||||
|
||||
### 8) 电源管理与电池
|
||||
|
||||
- `getPowerSource`
|
||||
- `getWakeSource`/`clearWakeSource`
|
||||
- `setPowerConfig`/`getPowerConfig`/`clearPowerConfig`
|
||||
- `setChargeEnable`/`setDcdcEnable`/`setLdoEnable`/`set5VInOutEnable`/`setLedEnLevel`
|
||||
- `setBatteryLvp`
|
||||
|
||||
### 9) 看门狗与定时器
|
||||
|
||||
- `wdtSet`/`wdtFeed`/`wdtGetCount`
|
||||
- `timerSet`/`timerClear`
|
||||
|
||||
### 10) 按钮
|
||||
|
||||
- `btnSetConfig`/`btnGetState`/`btnGetFlag`
|
||||
- `setSingleResetDisable`/`getSingleResetDisable`
|
||||
- `setDoubleOffDisable`/`getDoubleOffDisable`
|
||||
|
||||
### 11) 中断
|
||||
|
||||
- **状态读取与清除**
|
||||
- `irqGetGpioStatus`/`irqClearGpio`
|
||||
- `irqGetSysStatus`/`irqClearSys`
|
||||
- `irqGetBtnStatus`/`irqClearBtn`
|
||||
- **枚举式读取**
|
||||
- `irqGetGpioStatusEnum`/`irqGetSysStatusEnum`/`irqGetBtnStatusEnum`
|
||||
- **中断屏蔽**
|
||||
- `irqSetGpioMask`/`irqGetGpioMask`/`irqSetGpioMaskAll`/`irqGetGpioMaskAll`
|
||||
- `irqSetSysMask`/`irqGetSysMask`/`irqSetSysMaskAll`/`irqGetSysMaskAll`
|
||||
- `irqSetBtnMask`/`irqGetBtnMask`/`irqSetBtnMaskAll`/`irqGetBtnMaskAll`
|
||||
|
||||
### 12) 系统命令
|
||||
|
||||
- `sysCmd`/`shutdown`/`reboot`/`enterDownloadMode`
|
||||
- `setDownloadLock`/`getDownloadLock`
|
||||
|
||||
### 13) NeoPixel
|
||||
|
||||
- `setLeds`/`setLedCount`/`setLedColor`/`refreshLeds`/`disableLeds`
|
||||
|
||||
### 14) AW8737A 脉冲控制
|
||||
|
||||
- `setAw8737aPulse`/`refreshAw8737aPulse`
|
||||
|
||||
### 15) RTC RAM
|
||||
|
||||
- `writeRtcRAM`/`readRtcRAM`
|
||||
|
||||
### 16) I2C 配置与自动唤醒
|
||||
|
||||
- `setI2cConfig`/`switchI2cSpeed`/`getI2cSpeed`
|
||||
- `setI2cSleepTime`/`getI2cSleepTime`
|
||||
- `setAutoWakeEnable`/`isAutoWakeEnabled`/`sendWakeSignal`
|
||||
- 兼容层: `M5PM1_i2c_compat.h`
|
||||
|
||||
### 17) 状态快照/缓存/校验
|
||||
|
||||
- `setAutoSnapshot`/`isAutoSnapshotEnabled`/`updateSnapshot`/`verifySnapshot`
|
||||
- `validateConfig`
|
||||
- `getCachedPwmFrequency`/`getCachedPwmState`/`getCachedAdcState`
|
||||
- `getCachedPowerConfig`/`getCachedButtonConfig`
|
||||
- `getCachedIrqMasks`/`getCachedIrqStatus`
|
||||
|
||||
## 引脚与功能限制
|
||||
|
||||
| 功能区域 | 说明 | 备注 |
|
||||
| :--- | :--- | :--- |
|
||||
| **GPIO 互斥** | GPIO0/2 共享 WAKE/IRQ 线;GPIO3/4 互斥 | GPIO0/2 互斥 |
|
||||
| **唤醒 (WAKE)** | GPIO0, GPIO2 支持唤醒 | GPIO1 不支持 WAKE |
|
||||
| **ADC 通道** | GPIO1=ADC1, GPIO2=ADC2 | 温度为内部通道 |
|
||||
| **PWM 通道** | GPIO3=PWM0, GPIO4=PWM1 | 频率全通道共享 |
|
||||
| **NeoPixel** | 数据区 0x60 - 0x9F | 刷新时 I2C 短暂不可中断 |
|
||||
| **I2C 休眠** | 空闲超时可进入低功耗 | PWM 使能或下载模式下禁止休眠 |
|
||||
| **寄存器区块** | 0x00 - 0x0C, 0x10 - 0x19, 0x20 - 0x2A, 0x30 - 0x35 0x38 - 0x3D, 0x40 - 0x45, 0x48 - 0x4A, 0x50 0x53, 0x60 - 0x9F, 0xA0 - 0xBF | 支持连续读写 |
|
||||
|
||||
## 版本与依赖
|
||||
|
||||
- **版本**: 1.0.1
|
||||
- **平台**: Arduino / ESP-IDF (>=4.4)
|
||||
- **依赖**: espressif/i2c_bus
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
-273
@@ -1,273 +0,0 @@
|
||||
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。 |
|
||||
@@ -0,0 +1,188 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2026 M5Stack Technology CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <M5PM1.h>
|
||||
|
||||
/*
|
||||
* 基础电源/ADC示例:读取设备信息、电压、ADC/温度,并演示电源轨开关。
|
||||
* Basic power/ADC demo: read device info, voltages, ADC/temp, and toggle rails.
|
||||
*
|
||||
* 接线:PM1通过I2C连接;若PM1_I2C_SDA/SCL为-1则使用默认Wire引脚。
|
||||
* Wiring: PM1 via I2C; if PM1_I2C_SDA/SCL = -1, default Wire pins are used.
|
||||
*
|
||||
* ADC1=GPIO1、ADC2=GPIO2,使用前需将GPIO功能设为OTHER。
|
||||
* ADC1=GPIO1, ADC2=GPIO2; set GPIO func to OTHER before ADC reads.
|
||||
*
|
||||
* 注意:切换DCDC/LDO/5VINOUT可能影响外接负载供电,请确认不会误断电。一般DCDC为芯片提供供电,若关闭DCDC则芯片有可能直接下电。
|
||||
* Note: toggling DCDC/LDO/5VINOUT may affect external loads; typically DCDC powers the chip, disabling it may cause immediate power loss.
|
||||
*/
|
||||
|
||||
M5PM1 pm1;
|
||||
|
||||
#define LOGI(fmt, ...) Serial.printf("[PM1][I] " fmt "\r\n", ##__VA_ARGS__)
|
||||
#define LOGW(fmt, ...) Serial.printf("[PM1][W] " fmt "\r\n", ##__VA_ARGS__)
|
||||
#define LOGE(fmt, ...) Serial.printf("[PM1][E] " fmt "\r\n", ##__VA_ARGS__)
|
||||
|
||||
#ifndef PM1_I2C_SDA
|
||||
#define PM1_I2C_SDA 47
|
||||
#endif
|
||||
#ifndef PM1_I2C_SCL
|
||||
#define PM1_I2C_SCL 48
|
||||
#endif
|
||||
#ifndef PM1_I2C_FREQ
|
||||
#define PM1_I2C_FREQ M5PM1_I2C_FREQ_100K
|
||||
#endif
|
||||
|
||||
static const uint8_t PWR_CFG_CHG = 0x01;
|
||||
static const uint8_t PWR_CFG_DCDC = 0x02;
|
||||
static const uint8_t PWR_CFG_LDO = 0x04;
|
||||
static const uint8_t PWR_CFG_5V = 0x08;
|
||||
|
||||
static void printDivider() {
|
||||
Serial.println("--------------------------------------------------");
|
||||
}
|
||||
|
||||
static void printDeviceInfo() {
|
||||
uint8_t id = 0;
|
||||
uint8_t model = 0;
|
||||
uint8_t hw = 0;
|
||||
uint8_t sw = 0;
|
||||
|
||||
if (pm1.getDeviceId(&id) == M5PM1_OK) {
|
||||
LOGI("Device ID: 0x%02X", id);
|
||||
}
|
||||
if (pm1.getDeviceModel(&model) == M5PM1_OK) {
|
||||
LOGI("Device Model: 0x%02X", model);
|
||||
}
|
||||
if (pm1.getHwVersion(&hw) == M5PM1_OK) {
|
||||
LOGI("HW Version: 0x%02X", hw);
|
||||
}
|
||||
if (pm1.getSwVersion(&sw) == M5PM1_OK) {
|
||||
LOGI("SW Version: 0x%02X", sw);
|
||||
}
|
||||
}
|
||||
|
||||
static void printPowerConfig(uint8_t cfg) {
|
||||
LOGI("Power CFG: CHG=%s DCDC=%s LDO=%s 5V=%s",
|
||||
(cfg & PWR_CFG_CHG) ? "ON" : "OFF",
|
||||
(cfg & PWR_CFG_DCDC) ? "ON" : "OFF",
|
||||
(cfg & PWR_CFG_LDO) ? "ON" : "OFF",
|
||||
(cfg & PWR_CFG_5V) ? "ON" : "OFF");
|
||||
}
|
||||
|
||||
static void demoPowerRails() {
|
||||
uint8_t cfg = 0;
|
||||
if (pm1.getPowerConfig(&cfg) != M5PM1_OK) {
|
||||
LOGW("Get power config failed");
|
||||
return;
|
||||
}
|
||||
|
||||
LOGI("Power rail demo start (only enable)");
|
||||
printPowerConfig(cfg);
|
||||
|
||||
// 只开启不关闭。
|
||||
// Only enable, do not disable.
|
||||
|
||||
pm1.setChargeEnable(true);
|
||||
LOGI("Charge -> ON");
|
||||
delay(300);
|
||||
|
||||
pm1.setDcdcEnable(true);
|
||||
LOGI("DCDC -> ON");
|
||||
delay(300);
|
||||
|
||||
pm1.setLdoEnable(true);
|
||||
LOGI("LDO -> ON");
|
||||
delay(300);
|
||||
|
||||
pm1.set5VInOutEnable(true);
|
||||
LOGI("5V IN/OUT -> ON");
|
||||
delay(300);
|
||||
|
||||
if (pm1.getPowerConfig(&cfg) == M5PM1_OK) {
|
||||
printPowerConfig(cfg);
|
||||
}
|
||||
LOGI("Power rail demo done");
|
||||
}
|
||||
|
||||
static void printVoltages() {
|
||||
uint16_t mv = 0;
|
||||
|
||||
// 电压读数单位为 mV。
|
||||
// Voltage readings are in mV.
|
||||
|
||||
if (pm1.readVref(&mv) == M5PM1_OK) {
|
||||
LOGI("Vref: %u mV (%.3f V)", mv, mv / 1000.0f);
|
||||
}
|
||||
if (pm1.readVbat(&mv) == M5PM1_OK) {
|
||||
LOGI("VBAT: %u mV (%.3f V)", mv, mv / 1000.0f);
|
||||
}
|
||||
if (pm1.readVin(&mv) == M5PM1_OK) {
|
||||
LOGI("VIN: %u mV (%.3f V)", mv, mv / 1000.0f);
|
||||
}
|
||||
if (pm1.read5VInOut(&mv) == M5PM1_OK) {
|
||||
LOGI("5V IN/OUT: %u mV (%.3f V)", mv, mv / 1000.0f);
|
||||
}
|
||||
}
|
||||
|
||||
static void printAdcAndTemp() {
|
||||
uint16_t adc = 0;
|
||||
uint16_t temp = 0;
|
||||
|
||||
// ADC1=GPIO1,ADC2=GPIO2
|
||||
// ADC1=GPIO1, ADC2=GPIO2
|
||||
|
||||
if (pm1.analogRead(M5PM1_ADC_CH_1, &adc) == M5PM1_OK) {
|
||||
LOGI("ADC1 (GPIO1): %u", adc);
|
||||
}
|
||||
if (pm1.analogRead(M5PM1_ADC_CH_2, &adc) == M5PM1_OK) {
|
||||
LOGI("ADC2 (GPIO2): %u", adc);
|
||||
}
|
||||
if (pm1.readTemperature(&temp) == M5PM1_OK) {
|
||||
LOGI("Temp: %u", temp);
|
||||
}
|
||||
}
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
delay(200);
|
||||
printDivider();
|
||||
LOGI("Basic + ADC + Power demo start");
|
||||
|
||||
m5pm1_err_t err = pm1.begin(&Wire, M5PM1_DEFAULT_ADDR, PM1_I2C_SDA, PM1_I2C_SCL, PM1_I2C_FREQ);
|
||||
if (err != M5PM1_OK) {
|
||||
LOGE("PM1 begin failed: %d", err);
|
||||
while (true) {
|
||||
delay(1000);
|
||||
}
|
||||
}
|
||||
|
||||
printDeviceInfo();
|
||||
printDivider();
|
||||
|
||||
demoPowerRails();
|
||||
printDivider();
|
||||
|
||||
// ADC通道需要将GPIO1/2切到OTHER功能。
|
||||
// ADC channels require GPIO1/2 to be set as OTHER function.
|
||||
pm1.gpioSetFunc(M5PM1_GPIO_NUM_1, M5PM1_GPIO_FUNC_OTHER);
|
||||
pm1.gpioSetFunc(M5PM1_GPIO_NUM_2, M5PM1_GPIO_FUNC_OTHER);
|
||||
}
|
||||
|
||||
void loop() {
|
||||
static uint32_t lastMs = 0;
|
||||
const uint32_t intervalMs = 2000;
|
||||
|
||||
if (millis() - lastMs >= intervalMs) {
|
||||
lastMs = millis();
|
||||
// 每2秒输出一次电压、ADC、温度信息。
|
||||
// Print voltages, ADC, and temperature every 2 seconds.
|
||||
printVoltages();
|
||||
printAdcAndTemp();
|
||||
printDivider();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2026 M5Stack Technology CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <M5PM1.h>
|
||||
|
||||
/*
|
||||
* GPIO 输入/输出 + PWM 呼吸灯示例。
|
||||
* GPIO input/output + PWM breathing LED demo.
|
||||
*
|
||||
* 接线建议:
|
||||
* - GPIO0:接LED(串电阻)到GND,演示普通GPIO翻转。
|
||||
* - GPIO1:接按键到GND(内部上拉),用于输入读取。
|
||||
* - PWM_CH_0 对应 GPIO3:接LED(串电阻)到GND,演示PWM呼吸灯。
|
||||
* Wiring suggestion:
|
||||
* - GPIO0: LED (with resistor) to GND for GPIO toggling.
|
||||
* - GPIO1: Button to GND (internal pull-up) for input reading.
|
||||
* - PWM_CH_0 maps to GPIO3: LED (with resistor) to GND for PWM breathing.
|
||||
*
|
||||
* 注意:PWM 使用 GPIO3/4,且需要将引脚功能设为 OTHER。
|
||||
* Note: PWM uses GPIO3/4 and requires GPIO func set to OTHER.
|
||||
*
|
||||
* 若使用 NeoPixel,请勿将 GPIO0 用作普通 GPIO。
|
||||
* If using NeoPixel, do not use GPIO0 as a normal GPIO.
|
||||
*/
|
||||
|
||||
M5PM1 pm1;
|
||||
|
||||
#define LOGI(fmt, ...) Serial.printf("[PM1][I] " fmt "\r\n", ##__VA_ARGS__)
|
||||
#define LOGW(fmt, ...) Serial.printf("[PM1][W] " fmt "\r\n", ##__VA_ARGS__)
|
||||
#define LOGE(fmt, ...) Serial.printf("[PM1][E] " fmt "\r\n", ##__VA_ARGS__)
|
||||
|
||||
#ifndef PM1_I2C_SDA
|
||||
#define PM1_I2C_SDA 47
|
||||
#endif
|
||||
#ifndef PM1_I2C_SCL
|
||||
#define PM1_I2C_SCL 48
|
||||
#endif
|
||||
#ifndef PM1_I2C_FREQ
|
||||
#define PM1_I2C_FREQ M5PM1_I2C_FREQ_100K
|
||||
#endif
|
||||
|
||||
static const m5pm1_gpio_num_t GPIO_OUT = M5PM1_GPIO_NUM_0;
|
||||
static const m5pm1_gpio_num_t GPIO_IN = M5PM1_GPIO_NUM_1;
|
||||
static const m5pm1_pwm_channel_t PWM_CH = M5PM1_PWM_CH_0;
|
||||
|
||||
static void printDivider() {
|
||||
Serial.println("--------------------------------------------------");
|
||||
}
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
delay(200);
|
||||
printDivider();
|
||||
LOGI("GPIO + PWM demo start");
|
||||
|
||||
m5pm1_err_t err = pm1.begin(&Wire, M5PM1_DEFAULT_ADDR, PM1_I2C_SDA, PM1_I2C_SCL, PM1_I2C_FREQ);
|
||||
if (err != M5PM1_OK) {
|
||||
LOGE("PM1 begin failed: %d", err);
|
||||
while (true) {
|
||||
delay(1000);
|
||||
}
|
||||
}
|
||||
|
||||
// GPIO0 作为普通输出脚。
|
||||
// GPIO0 works as a normal output pin.
|
||||
pm1.pinMode(GPIO_OUT, OUTPUT);
|
||||
pm1.digitalWrite(GPIO_OUT, LOW);
|
||||
|
||||
// GPIO1 作为输入脚,内部上拉,按键接GND即可触发低电平。
|
||||
// GPIO1 as input with pull-up; button to GND pulls it low.
|
||||
pm1.pinMode(GPIO_IN, INPUT_PULLUP);
|
||||
|
||||
// PWM_CH_0 对应 GPIO3,需要设为 OTHER 才能输出PWM。
|
||||
// PWM_CH_0 maps to GPIO3; set func to OTHER for PWM output.
|
||||
// 使用 ANALOG 模式将引脚功能设为 OTHER (适用于 PWM/ADC)
|
||||
// Use ANALOG mode to set pin function to OTHER (for PWM/ADC)
|
||||
pm1.pinMode(M5PM1_GPIO_NUM_3, ANALOG);
|
||||
// PWM 频率全通道共享。
|
||||
// PWM frequency is shared across channels.
|
||||
pm1.setPwmFrequency(1000);
|
||||
pm1.setPwmDuty(PWM_CH, 0, false, true);
|
||||
|
||||
LOGI("GPIO OUT=%u, GPIO IN=%u, PWM CH=%u", GPIO_OUT, GPIO_IN, PWM_CH);
|
||||
printDivider();
|
||||
}
|
||||
|
||||
void loop() {
|
||||
static uint32_t lastBlinkMs = 0;
|
||||
static uint32_t lastLogMs = 0;
|
||||
static uint32_t lastPwmMs = 0;
|
||||
static bool ledOn = false;
|
||||
static int duty = 0;
|
||||
static int step = 2;
|
||||
|
||||
uint32_t now = millis();
|
||||
|
||||
if (now - lastBlinkMs >= 500) {
|
||||
lastBlinkMs = now;
|
||||
ledOn = !ledOn;
|
||||
pm1.digitalWrite(GPIO_OUT, ledOn ? HIGH : LOW);
|
||||
}
|
||||
|
||||
if (now - lastPwmMs >= 20) {
|
||||
lastPwmMs = now;
|
||||
duty += step;
|
||||
if (duty >= 100) {
|
||||
duty = 100;
|
||||
step = -step;
|
||||
} else if (duty <= 0) {
|
||||
duty = 0;
|
||||
step = -step;
|
||||
}
|
||||
pm1.setPwmDuty(PWM_CH, static_cast<uint8_t>(duty), false, true);
|
||||
}
|
||||
|
||||
if (now - lastLogMs >= 1000) {
|
||||
lastLogMs = now;
|
||||
int inLevel = pm1.digitalRead(GPIO_IN);
|
||||
LOGI("GPIO_IN=%d PWM_DUTY=%d%%", inLevel, duty);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,178 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2026 M5Stack Technology CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <M5PM1.h>
|
||||
|
||||
/*
|
||||
* 中断/按键/关机与唤醒示例。
|
||||
* Interrupt/button/sleep & wake demo.
|
||||
*
|
||||
* IRQ_GPIO=GPIO2 用于外部中断/唤醒输入;GPIO0/2 共用线,勿同时启用唤醒。
|
||||
* IRQ_GPIO=GPIO2 for external IRQ/wake; GPIO0/2 share a line, don't enable both.
|
||||
*
|
||||
* 双击电源键触发 PM1 关机(延迟5秒),10 秒后定时唤醒。
|
||||
* Double-click power button triggers PM1 shutdown (5s delay); timer wakes after 10s.
|
||||
*/
|
||||
|
||||
M5PM1 pm1;
|
||||
|
||||
#define LOGI(fmt, ...) Serial.printf("[PM1][I] " fmt "\r\n", ##__VA_ARGS__)
|
||||
#define LOGW(fmt, ...) Serial.printf("[PM1][W] " fmt "\r\n", ##__VA_ARGS__)
|
||||
#define LOGE(fmt, ...) Serial.printf("[PM1][E] " fmt "\r\n", ##__VA_ARGS__)
|
||||
|
||||
#ifndef PM1_I2C_SDA
|
||||
#define PM1_I2C_SDA 47
|
||||
#endif
|
||||
#ifndef PM1_I2C_SCL
|
||||
#define PM1_I2C_SCL 48
|
||||
#endif
|
||||
#ifndef PM1_I2C_FREQ
|
||||
#define PM1_I2C_FREQ M5PM1_I2C_FREQ_100K
|
||||
#endif
|
||||
#ifndef PM1_ESP_IRQ_GPIO
|
||||
#define PM1_ESP_IRQ_GPIO 13
|
||||
#endif
|
||||
|
||||
volatile bool irqFlag = false;
|
||||
void IRAM_ATTR pm1_irq_handler() {
|
||||
irqFlag = true;
|
||||
}
|
||||
|
||||
static const m5pm1_gpio_num_t IRQ_GPIO = M5PM1_GPIO_NUM_1;
|
||||
static const uint32_t WAKE_TIMER_SEC = 10;
|
||||
|
||||
static void printDivider() {
|
||||
Serial.println("--------------------------------------------------");
|
||||
}
|
||||
|
||||
static void printWakeSource(uint8_t src) {
|
||||
LOGI("Wake source mask: 0x%02X", src);
|
||||
if (src & M5PM1_WAKE_SRC_TIM) LOGI("- TIMER");
|
||||
if (src & M5PM1_WAKE_SRC_VIN) LOGI("- VIN");
|
||||
if (src & M5PM1_WAKE_SRC_PWRBTN) LOGI("- PWR_BTN");
|
||||
if (src & M5PM1_WAKE_SRC_RSTBTN) LOGI("- RST_BTN");
|
||||
if (src & M5PM1_WAKE_SRC_CMD_RST) LOGI("- CMD_RESET");
|
||||
if (src & M5PM1_WAKE_SRC_EXT_WAKE) LOGI("- EXT_WAKE");
|
||||
if (src & M5PM1_WAKE_SRC_5VINOUT) LOGI("- 5VINOUT");
|
||||
}
|
||||
|
||||
static void enterSleep() {
|
||||
LOGW("Prepare for shutdown with wake sources");
|
||||
|
||||
// 先配置10s的定时开机
|
||||
// Configure 10s timer wake up first
|
||||
pm1.timerSet(WAKE_TIMER_SEC, M5PM1_TIM_ACTION_POWERON);
|
||||
|
||||
// 触发双击后等待5s关机
|
||||
// Wait 5s before shutdown after double click
|
||||
LOGW("Wait 5s before shutdown...");
|
||||
delay(5000);
|
||||
|
||||
// 关闭LED_EN灯显(将默认电平配置为低电平)
|
||||
// Turn off LED_EN indicator (by setting default level to LOW)
|
||||
pm1.setLedEnLevel(false);
|
||||
vTaskDelay(100 / portTICK_PERIOD_MS);
|
||||
|
||||
LOGW("Shutdown now. Wake by GPIO%u or %us timer", IRQ_GPIO, WAKE_TIMER_SEC);
|
||||
pm1.shutdown();
|
||||
}
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
delay(200);
|
||||
printDivider();
|
||||
LOGI("Interrupt + Button + Sleep demo start");
|
||||
|
||||
m5pm1_err_t err = pm1.begin(&Wire, M5PM1_DEFAULT_ADDR, PM1_I2C_SDA, PM1_I2C_SCL, PM1_I2C_FREQ);
|
||||
if (err != M5PM1_OK) {
|
||||
LOGE("PM1 begin failed: %d", err);
|
||||
while (true) {
|
||||
delay(1000);
|
||||
}
|
||||
}
|
||||
|
||||
// 读取并清除一次唤醒来源,便于调试本次启动原因。
|
||||
// Read and clear wake source once for debugging this boot reason.
|
||||
uint8_t wakeSrc = 0;
|
||||
if (pm1.getWakeSource(&wakeSrc, M5PM1_CLEAN_ONCE) == M5PM1_OK) {
|
||||
printWakeSource(wakeSrc);
|
||||
}
|
||||
|
||||
// 清空timer设置,避免误触发。
|
||||
// Clear timer settings to avoid mis-trigger.
|
||||
pm1.timerClear();
|
||||
|
||||
// 禁用单击复位/双击关机,避免与示例流程冲突。
|
||||
// Disable single-reset/double-off to avoid conflicts with demo flow.
|
||||
pm1.setSingleResetDisable(true);
|
||||
pm1.setDoubleOffDisable(true);
|
||||
|
||||
pm1.btnSetConfig(M5PM1_BTN_TYPE_CLICK, M5PM1_BTN_DELAY_250MS);
|
||||
pm1.btnSetConfig(M5PM1_BTN_TYPE_DOUBLE, M5PM1_BTN_DELAY_250MS);
|
||||
pm1.btnSetConfig(M5PM1_BTN_TYPE_LONG, M5PM1_BTN_DELAY_500MS);
|
||||
|
||||
pm1.gpioSetFunc(IRQ_GPIO, M5PM1_GPIO_FUNC_IRQ);
|
||||
pm1.gpioSetMode(IRQ_GPIO, M5PM1_GPIO_MODE_INPUT);
|
||||
pm1.gpioSetPull(IRQ_GPIO, M5PM1_GPIO_PULL_UP);
|
||||
|
||||
// 设置ESP32的中断引脚,用于接收PM1的IRQ信号。
|
||||
// Setup ESP32 interrupt pin to receive IRQ signal from PM1.
|
||||
pinMode(PM1_ESP_IRQ_GPIO, INPUT_PULLUP);
|
||||
attachInterrupt(PM1_ESP_IRQ_GPIO, pm1_irq_handler, FALLING);
|
||||
|
||||
// 启用 PM1 GPIO1 的中断输出(这里的Mask Disable代表允许产生中断)。
|
||||
// Enable PM1 GPIO1 IRQ output (Mask Disable means interrupt enabled).
|
||||
pm1.irqSetGpioMask(IRQ_GPIO, M5PM1_IRQ_MASK_DISABLE);
|
||||
|
||||
// 启用按钮中断输出。
|
||||
// Enable button IRQ output.
|
||||
pm1.irqSetBtnMaskAll(M5PM1_IRQ_MASK_DISABLE);
|
||||
pm1.irqSetGpioMaskAll(M5PM1_IRQ_MASK_ENABLE);
|
||||
pm1.irqSetSysMaskAll(M5PM1_IRQ_MASK_ENABLE);
|
||||
|
||||
printDivider();
|
||||
}
|
||||
|
||||
void loop() {
|
||||
if (irqFlag) {
|
||||
irqFlag = false;
|
||||
|
||||
uint8_t gpioIrq = 0;
|
||||
if (pm1.irqGetGpioStatus(&gpioIrq, M5PM1_CLEAN_ONCE) == M5PM1_OK) {
|
||||
if (gpioIrq != M5PM1_IRQ_GPIO_NONE) {
|
||||
LOGI("GPIO IRQ status: 0x%02X", gpioIrq);
|
||||
if (gpioIrq & M5PM1_IRQ_GPIO0) LOGI("- GPIO0 IRQ triggered");
|
||||
if (gpioIrq & M5PM1_IRQ_GPIO1) LOGI("- GPIO1 IRQ triggered");
|
||||
if (gpioIrq & M5PM1_IRQ_GPIO2) LOGI("- GPIO2 IRQ triggered");
|
||||
if (gpioIrq & M5PM1_IRQ_GPIO3) LOGI("- GPIO3 IRQ triggered");
|
||||
if (gpioIrq & M5PM1_IRQ_GPIO4) LOGI("- GPIO4 IRQ triggered");
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t btnIrq = 0;
|
||||
if (pm1.irqGetBtnStatus(&btnIrq, M5PM1_CLEAN_ONCE) == M5PM1_OK) {
|
||||
if (btnIrq != M5PM1_IRQ_BTN_NONE) {
|
||||
LOGI("Button IRQ status: 0x%02X", btnIrq);
|
||||
if (btnIrq & M5PM1_IRQ_BTN_CLICK) LOGI("- Single Click triggered");
|
||||
if (btnIrq & M5PM1_IRQ_BTN_DOUBLE) {
|
||||
LOGI("- Double Click triggered");
|
||||
enterSleep();
|
||||
}
|
||||
if (btnIrq & M5PM1_IRQ_BTN_WAKE) LOGI("- Wake Button triggered");
|
||||
}
|
||||
}
|
||||
} else if (digitalRead(PM1_ESP_IRQ_GPIO) == LOW) {
|
||||
// 存在未处理的中断信号,读取以清除(但忽略内容)
|
||||
// Unhandled IRQ signal exists, read to clear (but ignore content)
|
||||
uint8_t dummy;
|
||||
pm1.irqGetGpioStatus(&dummy, M5PM1_CLEAN_ALL);
|
||||
pm1.irqGetBtnStatus(&dummy, M5PM1_CLEAN_ALL);
|
||||
pm1.irqGetSysStatus(&dummy, M5PM1_CLEAN_ALL);
|
||||
}
|
||||
|
||||
delay(10);
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2026 M5Stack Technology CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <M5PM1.h>
|
||||
|
||||
/*
|
||||
* NeoPixel 彩虹渐变示例(使用 GPIO0 作为 LED_EN/数据相关功能)。
|
||||
* NeoPixel rainbow demo (uses GPIO0 for LED_EN/data-related function).
|
||||
*
|
||||
* 注意:NeoPixel 仅支持 GPIO0,且 LED 数量最大 31(寄存器 5-bit 限制)。
|
||||
* Note: NeoPixel is only supported on GPIO0, and LED count max is 31 (5-bit limit).
|
||||
*/
|
||||
|
||||
M5PM1 pm1;
|
||||
|
||||
#define LOGI(fmt, ...) Serial.printf("[PM1][I] " fmt "\r\n", ##__VA_ARGS__)
|
||||
#define LOGW(fmt, ...) Serial.printf("[PM1][W] " fmt "\r\n", ##__VA_ARGS__)
|
||||
#define LOGE(fmt, ...) Serial.printf("[PM1][E] " fmt "\r\n", ##__VA_ARGS__)
|
||||
|
||||
#ifndef PM1_I2C_SDA
|
||||
#define PM1_I2C_SDA 47
|
||||
#endif
|
||||
#ifndef PM1_I2C_SCL
|
||||
#define PM1_I2C_SCL 48
|
||||
#endif
|
||||
#ifndef PM1_I2C_FREQ
|
||||
#define PM1_I2C_FREQ M5PM1_I2C_FREQ_100K
|
||||
#endif
|
||||
|
||||
static const uint8_t LED_COUNT = 8;
|
||||
static const uint8_t BRIGHTNESS = 64;
|
||||
|
||||
static void printDivider() {
|
||||
Serial.println("--------------------------------------------------");
|
||||
}
|
||||
|
||||
static uint8_t scale(uint8_t v, uint8_t scale) {
|
||||
// 通过亮度系数缩放颜色,避免过亮。
|
||||
// Scale color by brightness to avoid excessive intensity.
|
||||
return static_cast<uint8_t>((static_cast<uint16_t>(v) * scale) / 255);
|
||||
}
|
||||
|
||||
static m5pm1_rgb_t wheel(uint8_t pos) {
|
||||
pos = 255 - pos;
|
||||
m5pm1_rgb_t c = {0, 0, 0};
|
||||
if (pos < 85) {
|
||||
c.r = 255 - pos * 3;
|
||||
c.g = 0;
|
||||
c.b = pos * 3;
|
||||
} else if (pos < 170) {
|
||||
pos -= 85;
|
||||
c.r = 0;
|
||||
c.g = pos * 3;
|
||||
c.b = 255 - pos * 3;
|
||||
} else {
|
||||
pos -= 170;
|
||||
c.r = pos * 3;
|
||||
c.g = 255 - pos * 3;
|
||||
c.b = 0;
|
||||
}
|
||||
c.r = scale(c.r, BRIGHTNESS);
|
||||
c.g = scale(c.g, BRIGHTNESS);
|
||||
c.b = scale(c.b, BRIGHTNESS);
|
||||
return c;
|
||||
}
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
delay(200);
|
||||
printDivider();
|
||||
LOGI("NeoPixel demo start");
|
||||
|
||||
m5pm1_err_t err = pm1.begin(&Wire, M5PM1_DEFAULT_ADDR, PM1_I2C_SDA, PM1_I2C_SCL, PM1_I2C_FREQ);
|
||||
if (err != M5PM1_OK) {
|
||||
LOGE("PM1 begin failed: %d", err);
|
||||
while (true) {
|
||||
delay(1000);
|
||||
}
|
||||
}
|
||||
|
||||
// GPIO0 设置为 OTHER 以启用 NeoPixel;避免与 GPIO/IRQ/WAKE 冲突。
|
||||
// Set GPIO0 to OTHER for NeoPixel; avoid GPIO/IRQ/WAKE conflicts.
|
||||
pm1.gpioSetFunc(M5PM1_GPIO_NUM_0, M5PM1_GPIO_FUNC_OTHER);
|
||||
// LED_EN 默认高电平使能灯带。
|
||||
// LED_EN default high level enables LEDs.
|
||||
pm1.setLedEnLevel(true);
|
||||
// 设置灯带数量(1-31)。
|
||||
// Set LED count (1-31).
|
||||
pm1.setLedCount(LED_COUNT);
|
||||
|
||||
LOGI("LED count: %u", LED_COUNT);
|
||||
printDivider();
|
||||
}
|
||||
|
||||
void loop() {
|
||||
static uint8_t offset = 0;
|
||||
|
||||
for (uint8_t i = 0; i < LED_COUNT; ++i) {
|
||||
// 计算彩虹色,并写入缓存。
|
||||
// Compute rainbow color and write to buffer.
|
||||
m5pm1_rgb_t c = wheel(static_cast<uint8_t>(i * 256 / LED_COUNT + offset));
|
||||
pm1.setLedColor(i, c);
|
||||
}
|
||||
// 刷新后才会显示到灯带。
|
||||
// Refresh is required to apply colors to LEDs.
|
||||
pm1.refreshLeds();
|
||||
|
||||
offset++;
|
||||
delay(40);
|
||||
}
|
||||
+737
-626
File diff suppressed because it is too large
Load Diff
+575
-526
File diff suppressed because it is too large
Load Diff
+57
-32
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025 M5Stack Technology CO LTD
|
||||
* SPDX-FileCopyrightText: 2026 M5Stack Technology CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
@@ -21,7 +21,8 @@
|
||||
// ============================
|
||||
|
||||
#ifndef M5PM1_I2C_READ_BYTE
|
||||
static inline bool M5PM1_I2C_READ_BYTE(TwoWire *wire, uint8_t addr, uint8_t reg, uint8_t *data) {
|
||||
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) {
|
||||
@@ -36,7 +37,8 @@ static inline bool M5PM1_I2C_READ_BYTE(TwoWire *wire, uint8_t addr, uint8_t reg,
|
||||
#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) {
|
||||
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) {
|
||||
@@ -53,7 +55,8 @@ static inline bool M5PM1_I2C_READ_BYTES(TwoWire *wire, uint8_t addr, uint8_t sta
|
||||
#endif
|
||||
|
||||
#ifndef M5PM1_I2C_READ_REG16
|
||||
static inline bool M5PM1_I2C_READ_REG16(TwoWire *wire, uint8_t addr, uint8_t reg, uint16_t *data) {
|
||||
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;
|
||||
@@ -66,7 +69,8 @@ static inline bool M5PM1_I2C_READ_REG16(TwoWire *wire, uint8_t addr, uint8_t reg
|
||||
#endif
|
||||
|
||||
#ifndef M5PM1_I2C_WRITE_BYTE
|
||||
static inline bool M5PM1_I2C_WRITE_BYTE(TwoWire *wire, uint8_t addr, uint8_t reg, uint8_t data) {
|
||||
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);
|
||||
@@ -78,7 +82,9 @@ static inline bool M5PM1_I2C_WRITE_BYTE(TwoWire *wire, uint8_t addr, uint8_t reg
|
||||
#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) {
|
||||
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++) {
|
||||
@@ -92,7 +98,8 @@ static inline bool M5PM1_I2C_WRITE_BYTES(TwoWire *wire, uint8_t addr, uint8_t st
|
||||
#endif
|
||||
|
||||
#ifndef M5PM1_I2C_WRITE_REG16
|
||||
static inline bool M5PM1_I2C_WRITE_REG16(TwoWire *wire, uint8_t addr, uint8_t reg, uint16_t data) {
|
||||
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
|
||||
@@ -105,7 +112,8 @@ static inline bool M5PM1_I2C_WRITE_REG16(TwoWire *wire, uint8_t addr, uint8_t re
|
||||
// PM1睡眠模式唤醒信号
|
||||
// Wake signal for PM1 sleep mode
|
||||
#ifndef M5PM1_I2C_SEND_WAKE
|
||||
static inline void M5PM1_I2C_SEND_WAKE(TwoWire *wire, uint8_t addr) {
|
||||
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);
|
||||
@@ -113,11 +121,11 @@ static inline void M5PM1_I2C_SEND_WAKE(TwoWire *wire, uint8_t addr) {
|
||||
}
|
||||
#endif
|
||||
|
||||
#else // ESP-IDF
|
||||
#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
|
||||
#include <i2c_bus.h> // esp-idf-lib i2c_bus component
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@@ -128,10 +136,10 @@ extern "C" {
|
||||
// I2C Driver Type Selection
|
||||
// ============================
|
||||
typedef enum {
|
||||
M5PM1_I2C_DRIVER_NONE = 0, // 未初始化 / Not initialized
|
||||
M5PM1_I2C_DRIVER_SELF_CREATED, // 使用 i2c_port_t 自创建 / Self-created using i2c_port_t
|
||||
M5PM1_I2C_DRIVER_MASTER, // ESP-IDF 原生 i2c_master 驱动 / ESP-IDF native i2c_master driver
|
||||
M5PM1_I2C_DRIVER_BUS // esp-idf-lib i2c_bus 组件 / esp-idf-lib i2c_bus component
|
||||
M5PM1_I2C_DRIVER_NONE = 0, // 未初始化 / Not initialized
|
||||
M5PM1_I2C_DRIVER_SELF_CREATED, // 使用 i2c_port_t 自创建 / Self-created using i2c_port_t
|
||||
M5PM1_I2C_DRIVER_MASTER, // ESP-IDF 原生 i2c_master 驱动 / ESP-IDF native i2c_master driver
|
||||
M5PM1_I2C_DRIVER_BUS // esp-idf-lib i2c_bus 组件 / esp-idf-lib i2c_bus component
|
||||
} m5pm1_i2c_driver_t;
|
||||
|
||||
// ============================
|
||||
@@ -140,19 +148,22 @@ typedef enum {
|
||||
// ============================
|
||||
|
||||
#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) {
|
||||
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) {
|
||||
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) {
|
||||
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) {
|
||||
@@ -165,19 +176,23 @@ static inline esp_err_t M5PM1_I2C_READ_REG16(i2c_bus_device_handle_t dev, uint8_
|
||||
#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) {
|
||||
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);
|
||||
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) {
|
||||
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
|
||||
@@ -193,19 +208,23 @@ static inline esp_err_t M5PM1_I2C_WRITE_REG16(i2c_bus_device_handle_t dev, uint8
|
||||
// ============================
|
||||
|
||||
#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) {
|
||||
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, ®, 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) {
|
||||
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) {
|
||||
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, ®, 1, buf, 2, -1);
|
||||
if (ret == ESP_OK) {
|
||||
@@ -218,17 +237,20 @@ static inline esp_err_t M5PM1_I2C_MASTER_READ_REG16(i2c_master_dev_handle_t dev,
|
||||
#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) {
|
||||
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) {
|
||||
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);
|
||||
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);
|
||||
@@ -239,7 +261,8 @@ static inline esp_err_t M5PM1_I2C_MASTER_WRITE_BYTES(i2c_master_dev_handle_t dev
|
||||
#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) {
|
||||
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;
|
||||
// 小端模式:低字节在前
|
||||
@@ -253,7 +276,8 @@ static inline esp_err_t M5PM1_I2C_MASTER_WRITE_REG16(i2c_master_dev_handle_t dev
|
||||
// 使用i2c_bus的PM1睡眠模式唤醒信号
|
||||
// Wake signal for PM1 sleep mode using i2c_bus
|
||||
#ifndef M5PM1_I2C_SEND_WAKE
|
||||
static inline esp_err_t M5PM1_I2C_SEND_WAKE(i2c_bus_device_handle_t dev, uint8_t reg) {
|
||||
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);
|
||||
@@ -263,7 +287,8 @@ static inline esp_err_t M5PM1_I2C_SEND_WAKE(i2c_bus_device_handle_t dev, uint8_t
|
||||
// 使用i2c_master的PM1睡眠模式唤醒信号
|
||||
// Wake signal for PM1 sleep mode using i2c_master
|
||||
#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) {
|
||||
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);
|
||||
}
|
||||
@@ -273,6 +298,6 @@ static inline esp_err_t M5PM1_I2C_MASTER_SEND_WAKE(i2c_master_bus_handle_t bus,
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // ARDUINO
|
||||
#endif // ARDUINO
|
||||
|
||||
#endif // __M5PM1_I2C_COMPAT_H__
|
||||
#endif // __M5PM1_I2C_COMPAT_H__
|
||||
|
||||
Reference in New Issue
Block a user