From e2ccec30c33f37ce99f5361c491506c1999cfe5c Mon Sep 17 00:00:00 2001 From: onexs-xsi <850559025@qq.com> Date: Wed, 21 Jan 2026 15:34:26 +0800 Subject: [PATCH] 1. Format the project text and fix some issues --- README.md | 208 +-- README_FUNCTION_CN.md | 154 ++ docs/deprecated_api_reference.md | 843 ---------- docs/review.txt | 273 ---- examples/basic_power_adc/basic_power_adc.ino | 188 +++ examples/gpio_pwm/gpio_pwm.ino | 125 ++ .../interrupt_button_sleep.ino | 178 +++ examples/neopixel/neopixel.ino | 114 ++ migration_script.md | 0 src/M5PM1.cpp | 1363 +++++++++-------- src/M5PM1.h | 1101 ++++++------- src/M5PM1_i2c_compat.h | 89 +- 12 files changed, 2142 insertions(+), 2494 deletions(-) create mode 100644 README_FUNCTION_CN.md delete mode 100644 docs/deprecated_api_reference.md delete mode 100644 docs/review.txt create mode 100644 examples/basic_power_adc/basic_power_adc.ino create mode 100644 examples/gpio_pwm/gpio_pwm.ino create mode 100644 examples/interrupt_button_sleep/interrupt_button_sleep.ino create mode 100644 examples/neopixel/neopixel.ino delete mode 100644 migration_script.md diff --git a/README.md b/README.md index 23470bc..045781d 100644 --- a/README.md +++ b/README.md @@ -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 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) + diff --git a/README_FUNCTION_CN.md b/README_FUNCTION_CN.md new file mode 100644 index 0000000..55a1d50 --- /dev/null +++ b/README_FUNCTION_CN.md @@ -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 + diff --git a/docs/deprecated_api_reference.md b/docs/deprecated_api_reference.md deleted file mode 100644 index b187f23..0000000 --- a/docs/deprecated_api_reference.md +++ /dev/null @@ -1,843 +0,0 @@ -# m5_stamp_pm1 到 M5PM1 API 迁移参考手册 - -本文档帮助用户从旧版 `m5_stamp_pm1` 库迁移到新版 `M5PM1` 库。 - -## 目录 - -- [概述](#概述) -- [主要变化](#主要变化) -- [初始化](#初始化) -- [错误处理](#错误处理) -- [GPIO 功能](#gpio-功能) -- [ADC 功能](#adc-功能) -- [PWM 功能](#pwm-功能) -- [电压读取](#电压读取) -- [电源管理](#电源管理) -- [看门狗](#看门狗) -- [定时器](#定时器) -- [按钮功能](#按钮功能) -- [中断功能](#中断功能) -- [NeoPixel LED](#neopixel-led) -- [RTC RAM](#rtc-ram) -- [系统命令](#系统命令) -- [I2C 配置](#i2c-配置) -- [枚举类型对照表](#枚举类型对照表) -- [完整迁移示例](#完整迁移示例) - ---- - -## 概述 - -### 库名变化 - -| 旧库 | 新库 | -|------|------| -| `m5_stamp_pm1` | `M5PM1` | -| `#include "m5_stamp_pm1.h"` | `#include "M5PM1.h"` | - -### 编程风格变化 - -- **旧库**: C 风格函数 `pm1_*()` 或通过单例类调用 -- **新库**: 面向对象的 C++ 类实例方法 - -```cpp -// 旧库 (C 风格) -pm1_vbat_read(&voltage); - -// 旧库 (单例类) -m5_stamp_pm1::getInstance().pm1_vbat_read(&voltage); - -// 新库 -M5PM1 pm1; -pm1.readVbat(&voltage); -``` - ---- - -## 主要变化 - -| 特性 | 旧库 (`m5_stamp_pm1`) | 新库 (`M5PM1`) | -|------|------------------------|----------------| -| 头文件 | `m5_stamp_pm1.h` | `M5PM1.h` | -| 错误类型 | `esp_err_t` | `m5pm1_err_t` | -| 初始化 | `pm1_init()` | `pm1.begin()` | -| GPIO 风格 | 原生函数 | Arduino 兼容 | -| 状态缓存 | 无 | 内置快照机制 | -| 日志系统 | ESP-IDF 原生 | 可配置级别 | - ---- - -## 初始化 - -### 旧库 - -```cpp -#include "m5_stamp_pm1.h" - -// Arduino -Wire.begin(SDA_PIN, SCL_PIN, 400000); -pm1_init(&Wire, SDA_PIN, SCL_PIN, 400000); - -// 或使用单例 -m5_stamp_pm1::getInstance().pm1_init(&Wire, SDA_PIN, SCL_PIN, 400000); -``` - -### 新库 - -```cpp -#include "M5PM1.h" - -M5PM1 pm1; - -// Arduino - 方式1: 使用已初始化的 Wire -Wire.begin(SDA_PIN, SCL_PIN, 400000); -pm1.begin(&Wire); - -// Arduino - 方式2: 让库初始化 Wire -pm1.begin(&Wire, 0x6E, SDA_PIN, SCL_PIN, 400000); - -// ESP-IDF - 自动创建 I2C 总线 -pm1.begin(I2C_NUM_0, 0x6E, SDA_PIN, SCL_PIN, 400000); - -// ESP-IDF - 使用已存在的 I2C 总线 -pm1.begin(existing_bus_handle, 0x6E, 400000); -``` - -### API 对照 - -| 旧 API | 新 API | -|--------|--------| -| `pm1_init(wire, sda, scl, freq)` | `pm1.begin(wire, addr, sda, scl, speed)` | -| `pm1_deinit()` | *(析构函数自动处理)* | - ---- - -## 错误处理 - -### 错误类型变化 - -| 旧类型 | 新类型 | -|--------|--------| -| `esp_err_t` | `m5pm1_err_t` | -| `ESP_OK` | `M5PM1_OK` | -| `ESP_FAIL` | `M5PM1_FAIL` | -| `ESP_ERR_INVALID_ARG` | `M5PM1_ERR_INVALID_ARG` | - -### 新增错误码 - -```cpp -typedef enum { - M5PM1_OK = 0, // 成功 - M5PM1_FAIL = -1, // 一般失败 - M5PM1_ERR_I2C_CONFIG = -2, // I2C 配置错误 - M5PM1_ERR_RULE_VIOLATION = -3, // 条件规则错误 (引脚冲突) - M5PM1_ERR_INVALID_ARG = -4, // 无效参数 - M5PM1_ERR_TIMEOUT = -5, // 超时 - M5PM1_ERR_NOT_SUPPORTED = -6, // 不支持的功能 - M5PM1_ERR_I2C_COMM = -7, // I2C 通信错误 - M5PM1_ERR_NOT_INIT = -8, // 设备未初始化 - M5PM1_ERR_INTERNAL = -9, // 内部错误 -} m5pm1_err_t; -``` - ---- - -## GPIO 功能 - -### 基础 GPIO 操作 - -新库提供 Arduino 兼容的 `pinMode()`, `digitalWrite()`, `digitalRead()` 函数。 - -| 旧 API | 新 API | -|--------|--------| -| `pm1_gpio_set_mode(pin, PM1_GPIO_MODE_OUTPUT)` | `pm1.pinMode(pin, OUTPUT)` | -| `pm1_gpio_set_mode(pin, PM1_GPIO_MODE_INPUT)` | `pm1.pinMode(pin, INPUT)` | -| `pm1_gpio_set_state(pin, PM1_GPIO_OUTPUT_HIGH)` | `pm1.digitalWrite(pin, HIGH)` | -| `pm1_gpio_set_state(pin, PM1_GPIO_OUTPUT_LOW)` | `pm1.digitalWrite(pin, LOW)` | -| `pm1_gpio_get_in_state(pin, &state)` | `value = pm1.digitalRead(pin)` | - -### 高级 GPIO 配置 - -| 旧 API | 新 API | -|--------|--------| -| `pm1_gpio_set_func(pin, func)` | `pm1.gpioSetFunc(pin, func)` | -| `pm1_gpio_set(pin, mode, state, pupd, drv)` | `pm1.gpioSet(pin, mode, value, pull, drive)` | -| `pm1_gpio_set_pupd(pin, pupd)` | `pm1.gpioSetPull(pin, pull)` | -| `pm1_gpio_set_drv(pin, drv)` | `pm1.gpioSetDrive(pin, drive)` | -| `pm1_led_en_set_drv(drv)` | `pm1.ledEnSetDrive(drive)` | -| `pm1_gpio_set_wake_en(pin, enable)` | `pm1.gpioSetWakeEnable(pin, enable)` | -| `pm1_gpio_set_wake_cfg(pin, edge)` | `pm1.gpioSetWakeEdge(pin, edge)` | - -### GPIO 电源保持 - -| 旧 API | 新 API | -|--------|--------| -| `pm1_gpio_set_power_hold(pin, enable)` | `pm1.gpioSetPowerHold(pin, enable)` | -| `pm1_gpio_get_power_hold(pin, &enable)` | `pm1.gpioGetPowerHold(pin, &enable)` | -| `pm1_ldo_set_power_hold(enable)` | `pm1.ldoSetPowerHold(enable)` | -| `pm1_ldo_get_power_hold(&enable)` | `pm1.ldoGetPowerHold(&enable)` | -| `pm1_dcdc_set_power_hold(enable)` | `pm1.dcdcSetPowerHold(enable)` | -| `pm1_dcdc_get_power_hold(&enable)` | `pm1.dcdcGetPowerHold(&enable)` | - -### 示例对照 - -```cpp -// ===== 旧库 ===== -pm1_gpio_set_func(PM1_GPIO_NUM_0, PM1_GPIO_FUNC_GPIO); -pm1_gpio_set_mode(PM1_GPIO_NUM_0, PM1_GPIO_MODE_OUTPUT); -pm1_gpio_set_state(PM1_GPIO_NUM_0, PM1_GPIO_OUTPUT_HIGH); -pm1_gpio_set_pupd(PM1_GPIO_NUM_0, PM1_GPIO_PUPD_NC); - -// ===== 新库 ===== -pm1.pinMode(M5PM1_GPIO_NUM_0, OUTPUT); -pm1.digitalWrite(M5PM1_GPIO_NUM_0, HIGH); - -// 或使用高级配置 -pm1.gpioSet(M5PM1_GPIO_NUM_0, M5PM1_GPIO_MODE_OUTPUT, - HIGH, M5PM1_GPIO_PULL_NONE, M5PM1_GPIO_DRIVE_PUSHPULL); -``` - ---- - -## ADC 功能 - -| 旧 API | 新 API | -|--------|--------| -| `pm1_adc_read(channel, &value)` | `pm1.analogRead(channel, &value)` | -| *(无)* | `pm1.isAdcBusy(&busy)` | -| *(无)* | `pm1.disableAdc()` | -| *(无)* | `pm1.readTemperature(&temp)` | - -### ADC 通道枚举 - -| 旧枚举 | 新枚举 | -|--------|--------| -| `PM1_ADC_CHANNEL_1` | `M5PM1_ADC_CH_1` | -| `PM1_ADC_CHANNEL_2` | `M5PM1_ADC_CH_2` | -| `PM1_ADC_CHANNEL_TEMP` | `M5PM1_ADC_CH_TEMP` | - -### 示例对照 - -```cpp -// ===== 旧库 ===== -uint16_t adc_value; -pm1_adc_read(PM1_ADC_CHANNEL_1, &adc_value); - -// ===== 新库 ===== -uint16_t adc_value; -pm1.analogRead(M5PM1_ADC_CH_1, &adc_value); - -// 新功能: 读取温度 -uint16_t temperature; -pm1.readTemperature(&temperature); -``` - ---- - -## PWM 功能 - -| 旧 API | 新 API | -|--------|--------| -| `pm1_pwm_set(ch, ctrl, pol, freq, duty)` | `pm1.setPwmConfig(ch, enable, pol, freq, duty12)` | -| *(无)* | `pm1.setPwmFrequency(freq)` | -| *(无)* | `pm1.getPwmFrequency(&freq)` | -| *(无)* | `pm1.setPwmDuty(ch, duty8, pol, enable)` | -| *(无)* | `pm1.setPwmDuty12bit(ch, duty12, pol, enable)` | -| *(无)* | `pm1.analogWrite(ch, value)` | - -### PWM 通道枚举 - -| 旧枚举 | 新枚举 | -|--------|--------| -| `PM1_PWM_CHANNEL_0` | `M5PM1_PWM_CH_0` | -| `PM1_PWM_CHANNEL_1` | `M5PM1_PWM_CH_1` | - -### 示例对照 - -```cpp -// ===== 旧库 ===== -pm1_pwm_set(PM1_PWM_CHANNEL_0, PM1_PWM_CTRL_ENABLE, - PM1_PWM_POLARITY_NORMAL, 1000, 2048); - -// ===== 新库 ===== -// 方式1: 一次性配置 -pm1.setPwmConfig(M5PM1_PWM_CH_0, true, false, 1000, 2048); - -// 方式2: 分步配置 -pm1.setPwmFrequency(1000); -pm1.setPwmDuty12bit(M5PM1_PWM_CH_0, 2048, false, true); - -// 方式3: Arduino 风格 (8位精度) -pm1.analogWrite(M5PM1_PWM_CH_0, 128); // 50% 占空比 -``` - ---- - -## 电压读取 - -| 旧 API | 新 API | -|--------|--------| -| `pm1_vref_read(&mv)` | `pm1.readVref(&mv)` 或 `pm1.getRefVoltage(&mv)` | -| `pm1_vbat_read(&mv)` | `pm1.readVbat(&mv)` | -| `pm1_vin_read(&mv)` | `pm1.readVin(&mv)` | -| `pm1_5vinout_read(&mv)` | `pm1.read5VInOut(&mv)` | - -### 示例对照 - -```cpp -// ===== 旧库 ===== -uint16_t vbat, vin, vinout; -pm1_vbat_read(&vbat); -pm1_vin_read(&vin); -pm1_5vinout_read(&vinout); - -// ===== 新库 ===== -uint16_t vbat, vin, vinout; -pm1.readVbat(&vbat); -pm1.readVin(&vin); -pm1.read5VInOut(&vinout); -``` - ---- - -## 电源管理 - -### 电源源读取 - -| 旧 API | 新 API | -|--------|--------| -| `pm1_pwr_src_read(&src)` | `pm1.getPowerSource(&src)` | - -### 电源源枚举 - -| 旧枚举 | 新枚举 | -|--------|--------| -| `PM1_PWR_SRC_5VIN` | `M5PM1_PWR_SRC_5VIN` | -| `PM1_PWR_SRC_5VINOUT` | `M5PM1_PWR_SRC_5VINOUT` | -| `PM1_PWR_SRC_BAT` | `M5PM1_PWR_SRC_BAT` | -| `PM1_PWR_SRC_UNKNOWN` | `M5PM1_PWR_SRC_UNKNOWN` | - -### 唤醒源 - -| 旧 API | 新 API | -|--------|--------| -| `pm1_wake_src_read(&src, clean_type)` | `pm1.getWakeSource(&src, clearAfterRead)` | -| *(无)* | `pm1.clearWakeSource(mask)` | - -### 电源配置 - -| 旧 API | 新 API | -|--------|--------| -| `pm1_pwr_set_cfg(mask, value, &final)` | `pm1.setPowerConfig(mask, value)` | -| `pm1_pwr_clear_cfg(cfg, &final)` | `pm1.clearPowerConfig(mask)` | -| `pm1_pwr_get_cfg(&cfg)` | `pm1.getPowerConfig(&cfg)` | -| `pm1_pwr_set_chg_en(enable)` | `pm1.setChargeEnable(enable)` | -| `pm1_pwr_set_dcdc_en(enable)` | `pm1.setDcdcEnable(enable)` | -| `pm1_pwr_set_ldo_en(enable)` | `pm1.setLdoEnable(enable)` | -| `pm1_pwr_set_5v_inout(enable)` | `pm1.set5VInOutEnable(enable)` | -| `pm1_pwr_set_led_control(enable)` | `pm1.setLedControlEnable(enable)` | - -### 电池低压保护 - -| 旧 API | 新 API | -|--------|--------| -| `pm1_batt_set_lvp(mv)` | `pm1.setBatteryLvp(mv)` | - -### 示例对照 - -```cpp -// ===== 旧库 ===== -pm1_pwr_src_t pwr_src; -pm1_pwr_src_read(&pwr_src); -pm1_pwr_set_chg_en(1); -pm1_pwr_set_dcdc_en(1); - -// ===== 新库 ===== -m5pm1_pwr_src_t pwr_src; -pm1.getPowerSource(&pwr_src); -pm1.setChargeEnable(true); -pm1.setDcdcEnable(true); -``` - ---- - -## 看门狗 - -| 旧 API | 新 API | -|--------|--------| -| `pm1_wdt_set(ctrl, timeout)` | `pm1.wdtSet(timeout)` | -| `pm1_wdt_feed(key)` | `pm1.wdtFeed()` | -| `pm1_wdt_get_wdt_cnt(&cnt)` | `pm1.wdtGetCount(&cnt)` | - -### 示例对照 - -```cpp -// ===== 旧库 ===== -pm1_wdt_set(PM1_WDT_CTRL_ENABLE, 30); // 30秒超时 -pm1_wdt_feed(0xA5); // 喂狗 - -// ===== 新库 ===== -pm1.wdtSet(30); // 30秒超时, 0 禁用 -pm1.wdtFeed(); // 喂狗 (密钥自动处理) -``` - ---- - -## 定时器 - -| 旧 API | 新 API | -|--------|--------| -| `pm1_tim_set(ctrl, action, count)` | `pm1.timerSet(seconds, action, autoRearm)` | -| `pm1_tim_clear(key)` | `pm1.timerClear()` | - -### 定时器动作枚举 - -| 旧枚举 | 新枚举 | -|--------|--------| -| `PM1_TIM_ACTION_000` | `M5PM1_TIM_ACTION_STOP` | -| `PM1_TIM_ACTION_001` | `M5PM1_TIM_ACTION_FLAG` | -| `PM1_TIM_ACTION_010` | `M5PM1_TIM_ACTION_REBOOT` | -| `PM1_TIM_ACTION_011` | `M5PM1_TIM_ACTION_POWERON` | -| `PM1_TIM_ACTION_100` | `M5PM1_TIM_ACTION_POWEROFF` | - -### 示例对照 - -```cpp -// ===== 旧库 ===== -pm1_tim_set(PM1_ADDR_TIM_ENABLE, PM1_TIM_ACTION_010, 3600); // 1小时后重启 -pm1_tim_clear(0xA5); - -// ===== 新库 ===== -pm1.timerSet(3600, M5PM1_TIM_ACTION_REBOOT, false); // 1小时后重启 -pm1.timerClear(); // 密钥自动处理 -``` - ---- - -## 按钮功能 - -| 旧 API | 新 API | -|--------|--------| -| `pm1_btn_set_cfg(type, delay)` | `pm1.btnSetConfig(type, delay)` | -| `pm1_btn_get_status(&status, PM1_BTN_READ_STATUS)` | `pm1.btnGetState(&pressed)` | -| `pm1_btn_get_status(&status, PM1_BTN_READ_FLAG)` | `pm1.btnGetFlag(&wasPressed)` | -| `pm1_single_reset_dis_set(enable)` | `pm1.setSingleResetDisable(disable)` | -| `pm1_single_reset_dis_get(&enable)` | `pm1.getSingleResetDisable(&disabled)` | -| `pm1_double_poweroff_dis_set(enable)` | `pm1.setDoubleOffDisable(disable)` | -| `pm1_double_poweroff_dis_get(&enable)` | `pm1.getDoubleOffDisable(&disabled)` | - -### 按钮类型枚举 - -| 旧枚举 | 新枚举 | -|--------|--------| -| `PM1_ADDR_BTN_TYPE_CLICK` | `M5PM1_BTN_TYPE_CLICK` | -| `PM1_ADDR_BTN_TYPE_DOUBLE_CLICK` | `M5PM1_BTN_TYPE_DOUBLE` | -| `PM1_ADDR_BTN_TYPE_LONG_PRESS` | `M5PM1_BTN_TYPE_LONG` | - -### 按钮延时枚举 - -| 旧枚举 | 新枚举 | -|--------|--------| -| `PM1_ADDR_BTN_CLICK_DELAY_125MS` | `M5PM1_BTN_DELAY_125MS` | -| `PM1_ADDR_BTN_CLICK_DELAY_250MS` | `M5PM1_BTN_DELAY_250MS` | -| `PM1_ADDR_BTN_CLICK_DELAY_500MS` | `M5PM1_BTN_DELAY_500MS` | -| `PM1_ADDR_BTN_CLICK_DELAY_1000MS` | `M5PM1_BTN_DELAY_1000MS` | - -### 示例对照 - -```cpp -// ===== 旧库 ===== -pm1_btn_set_cfg(PM1_ADDR_BTN_TYPE_CLICK, PM1_ADDR_BTN_CLICK_DELAY_250MS); -pm1_btn_status_t status; -pm1_btn_get_status(&status, PM1_BTN_READ_STATUS); - -// ===== 新库 ===== -pm1.btnSetConfig(M5PM1_BTN_TYPE_CLICK, M5PM1_BTN_DELAY_250MS); -bool pressed; -pm1.btnGetState(&pressed); -``` - ---- - -## 中断功能 - -### GPIO 中断 - -| 旧 API | 新 API | -|--------|--------| -| `pm1_irq_get_status(&gpio, clean_type)` | `pm1.irqGetGpioStatus(&status, clearAfterRead)` | -| `pm1_irq_clear_gpio_flag(gpio)` | `pm1.irqClearGpio(mask)` | -| `pm1_irq_set_gpio_mask(pin, ctrl)` | `pm1.irqSetGpioMask(pin, mask)` | -| `pm1_irq_get_gpio_mask(pin, &ctrl)` | `pm1.irqGetGpioMask(pin, &mask)` | -| `pm1_irq_set_gpio_mask_all(value)` | `pm1.irqSetGpioMaskAll(mask)` | -| `pm1_irq_get_gpio_mask_all(&value)` | `pm1.irqGetGpioMaskAll(&mask)` | - -### 系统中断 - -| 旧 API | 新 API | -|--------|--------| -| `pm1_irq_get_sys_status(&sys, clean_type)` | `pm1.irqGetSysStatus(&status, clearAfterRead)` | -| `pm1_irq_clear_sys_status(sys)` | `pm1.irqClearSys(mask)` | -| `pm1_irq_set_sys_mask(sys, ctrl)` | `pm1.irqSetSysMask(event, mask)` | -| `pm1_irq_get_sys_mask(sys, &ctrl)` | `pm1.irqGetSysMask(event, &mask)` | -| `pm1_irq_set_sys_mask_all(value)` | `pm1.irqSetSysMaskAll(mask)` | -| `pm1_irq_get_sys_mask_all(&value)` | `pm1.irqGetSysMaskAll(&mask)` | - -### 按钮中断 - -| 旧 API | 新 API | -|--------|--------| -| `pm1_irq_get_btn_status(&btn, clean_type)` | `pm1.irqGetBtnStatus(&status, clearAfterRead)` | -| `pm1_irq_clear_btn_status(btn)` | `pm1.irqClearBtn(mask)` | -| `pm1_irq_set_btn_mask(btn, ctrl)` | `pm1.irqSetBtnMask(type, mask)` | -| `pm1_irq_get_btn_mask(btn, &ctrl)` | `pm1.irqGetBtnMask(type, &mask)` | -| `pm1_irq_set_btn_mask_all(value)` | `pm1.irqSetBtnMaskAll(mask)` | -| `pm1_irq_get_btn_mask_all(&value)` | `pm1.irqGetBtnMaskAll(&mask)` | - -### clearAfterRead 参数说明 - -| 值 | 说明 | -|----|------| -| `0` | 不清除状态 | -| `1` | 仅清除已触发的位 | -| `2` | 清除所有状态位 | - ---- - -## NeoPixel LED - -| 旧 API | 新 API | -|--------|--------| -| `pm1_neo_set_cfg(num, data, refresh)` | `pm1.setLeds(colors, arraySize, count, autoRefresh)` | -| `pm1_neo_refresh()` | `pm1.refreshLeds()` | -| *(无)* | `pm1.setLedCount(count)` | -| *(无)* | `pm1.setLedColor(index, r, g, b)` | -| *(无)* | `pm1.disableLeds()` | - -### 示例对照 - -```cpp -// ===== 旧库 ===== -uint16_t neo_data[3] = {0xF800, 0x07E0, 0x001F}; // RGB565 格式 -pm1_neo_set_cfg(3, neo_data, 1); - -// ===== 新库 ===== -// 方式1: 使用 RGB 结构 -m5pm1_rgb_t colors[3] = {{255,0,0}, {0,255,0}, {0,0,255}}; -pm1.setLeds(colors, 3, 3, true); - -// 方式2: 逐个设置 -pm1.setLedCount(3); -pm1.setLedColor(0, 255, 0, 0); // 红色 -pm1.setLedColor(1, 0, 255, 0); // 绿色 -pm1.setLedColor(2, 0, 0, 255); // 蓝色 -pm1.refreshLeds(); -``` - ---- - -## RTC RAM - -| 旧 API | 新 API | -|--------|--------| -| `pm1_rtc_ram_write(addr, len, data)` | `pm1.writeRtcRAM(offset, data, len)` | -| `pm1_rtc_ram_read(addr, len, data)` | `pm1.readRtcRAM(offset, data, len)` | - -### 示例对照 - -```cpp -// ===== 旧库 ===== -uint8_t write_data[4] = {0x12, 0x34, 0x56, 0x78}; -pm1_rtc_ram_write(0, 4, write_data); - -uint8_t read_data[4]; -pm1_rtc_ram_read(0, 4, read_data); - -// ===== 新库 ===== -uint8_t write_data[4] = {0x12, 0x34, 0x56, 0x78}; -pm1.writeRtcRAM(0, write_data, 4); - -uint8_t read_data[4]; -pm1.readRtcRAM(0, read_data, 4); -``` - ---- - -## 系统命令 - -| 旧 API | 新 API | -|--------|--------| -| `pm1_sys_cmd(PM1_SYS_CMD_SHUTDOWN)` | `pm1.shutdown()` 或 `pm1.sysCmd(M5PM1_SYS_CMD_OFF)` | -| `pm1_sys_cmd(PM1_SYS_CMD_REBOOT)` | `pm1.reboot()` 或 `pm1.sysCmd(M5PM1_SYS_CMD_RESET)` | -| `pm1_sys_cmd(PM1_SYS_CMD_JTAG)` | `pm1.enterDownloadMode()` 或 `pm1.sysCmd(M5PM1_SYS_CMD_DL)` | -| `pm1_download_enable_set(enable)` | `pm1.setDownloadLock(!enable)` | -| `pm1_download_enable_get(&enable)` | `pm1.getDownloadLock(&lock)` | - -### 系统命令枚举 - -| 旧枚举 | 新枚举 | -|--------|--------| -| `PM1_SYS_CMD_NULL` | `M5PM1_SYS_CMD_NONE` | -| `PM1_SYS_CMD_SHUTDOWN` | `M5PM1_SYS_CMD_OFF` | -| `PM1_SYS_CMD_REBOOT` | `M5PM1_SYS_CMD_RESET` | -| `PM1_SYS_CMD_JTAG` | `M5PM1_SYS_CMD_DL` | - ---- - -## I2C 配置 - -| 旧 API | 新 API | -|--------|--------| -| `pm1_set_clk_speed(speed)` | `pm1.switchI2cSpeed(speed)` | -| `pm1_set_i2c_sleep_time(time)` | `pm1.setI2cSleepTime(seconds)` | -| `pm1_i2c_try_wake(type, param)` | `pm1.sendWakeSignal()` | -| `pm1_i2c_set_auto_wake_enable(enable)` | `pm1.setAutoWakeEnable(enable)` | -| *(无)* | `pm1.setI2cConfig(sleepTime, speed)` | -| *(无)* | `pm1.getI2cSpeed(&speed)` | -| *(无)* | `pm1.getI2cSleepTime(&seconds)` | - -### I2C 速度枚举 - -| 旧枚举 | 新枚举 | -|--------|--------| -| `PM1_CLK_SPEED_100KHZ` | `M5PM1_I2C_SPEED_100K` | -| `PM1_CLK_SPEED_400KHZ` | `M5PM1_I2C_SPEED_400K` | - ---- - -## 枚举类型对照表 - -### GPIO 相关 - -| 旧枚举类型 | 新枚举类型 | -|------------|------------| -| `pm1_gpio_num_t` | `m5pm1_gpio_num_t` | -| `pm1_gpio_mode_t` | `m5pm1_gpio_mode_t` | -| `pm1_gpio_func_t` | `m5pm1_gpio_func_t` | -| `pm1_gpio_pupd_t` / `pm1_gpio_pull_t` | `m5pm1_gpio_pull_t` | -| `pm1_gpio_drv_t` | `m5pm1_gpio_drive_t` | -| `pm1_gpio_wake_edge_t` | `m5pm1_gpio_wake_edge_t` | - -### ADC/PWM 相关 - -| 旧枚举类型 | 新枚举类型 | -|------------|------------| -| `pm1_adc_channel_t` | `m5pm1_adc_channel_t` | -| `pm1_pwm_channel_t` | `m5pm1_pwm_channel_t` | - -### 电源相关 - -| 旧枚举类型 | 新枚举类型 | -|------------|------------| -| `pm1_pwr_src_t` | `m5pm1_pwr_src_t` | -| `pm1_wake_src_t` | `m5pm1_wake_src_t` | -| `pm1_sys_cmd_t` | `m5pm1_sys_cmd_t` | -| `pm1_tim_action_t` | `m5pm1_tim_action_t` | - -### 按钮相关 - -| 旧枚举类型 | 新枚举类型 | -|------------|------------| -| `pm1_btn_type_t` | `m5pm1_btn_type_t` | -| `pm1_btn_delay_t` | `m5pm1_btn_delay_t` | -| `pm1_irq_btn_t` | `m5pm1_btn_irq_t` | - -### I2C 相关 - -| 旧枚举类型 | 新枚举类型 | -|------------|------------| -| `pm1_clk_speed_t` | `m5pm1_i2c_speed_t` | - ---- - -## 新库独有功能 - -新库 `M5PM1` 提供了一些旧库没有的功能: - -### 1. 状态快照 - -```cpp -pm1.setAutoSnapshot(true); // 启用自动快照 -pm1.updateSnapshot(); // 手动更新快照 -m5pm1_snapshot_verify_t result = pm1.verifySnapshot(); // 验证快照一致性 -``` - -### 2. 配置验证 - -```cpp -m5pm1_validation_t v = pm1.validateConfig(pin, M5PM1_CONFIG_PWM, true); -if (!v.valid) { - Serial.printf("Config error: %s\r\n", v.error_msg); -} -``` - -### 3. 日志级别控制 - -```cpp -M5PM1::setLogLevel(M5PM1_LOG_LEVEL_DEBUG); -m5pm1_log_level_t level = M5PM1::getLogLevel(); -``` - -### 4. 缓存状态查询 - -```cpp -uint16_t freq; -pm1.getCachedPwmFrequency(&freq); - -uint16_t duty; -bool enable, polarity; -pm1.getCachedPwmState(M5PM1_PWM_CH_0, &duty, &enable, &polarity); -``` - -### 5. 引脚状态获取 - -```cpp -m5pm1_pin_status_t status; -pm1.getPinStatus(M5PM1_GPIO_NUM_0, &status); -pm1.dumpPinStatus(); // 调试用,打印所有引脚状态 -``` - ---- - -## 完整迁移示例 - -### 旧库代码 - -```cpp -#include "m5_stamp_pm1.h" - -void setup() { - Serial.begin(115200); - Wire.begin(47, 48, 400000); - - // 初始化 - if (pm1_init(&Wire, 47, 48, 400000) != ESP_OK) { - Serial.println("PM1 init failed"); - return; - } - - // 读取设备信息 - uint8_t device_id, sw_ver; - pm1_get_device_id(&device_id); - pm1_get_sw_version(&sw_ver); - Serial.printf("Device ID: 0x%02X, FW: %d\n", device_id, sw_ver); - - // 配置 GPIO - pm1_gpio_set_func(PM1_GPIO_NUM_0, PM1_GPIO_FUNC_GPIO); - pm1_gpio_set_mode(PM1_GPIO_NUM_0, PM1_GPIO_MODE_OUTPUT); - pm1_gpio_set_state(PM1_GPIO_NUM_0, PM1_GPIO_OUTPUT_HIGH); - - // 配置 PWM - pm1_gpio_set_func(PM1_GPIO_NUM_3, PM1_GPIO_FUNC_OTHER); - pm1_pwm_set(PM1_PWM_CHANNEL_0, PM1_PWM_CTRL_ENABLE, - PM1_PWM_POLARITY_NORMAL, 1000, 2048); - - // 读取电压 - uint16_t vbat, vin; - pm1_vbat_read(&vbat); - pm1_vin_read(&vin); - Serial.printf("VBAT: %dmV, VIN: %dmV\n", vbat, vin); - - // 配置看门狗 - pm1_wdt_set(PM1_WDT_CTRL_ENABLE, 30); -} - -void loop() { - pm1_wdt_feed(0xA5); - delay(10000); -} -``` - -### 新库代码 - -```cpp -#include "M5PM1.h" - -M5PM1 pm1; - -void setup() { - Serial.begin(115200); - - // 初始化 (方式1: 让库处理 Wire) - if (pm1.begin(&Wire, 0x6E, 47, 48, 400000) != M5PM1_OK) { - Serial.println("PM1 init failed"); - return; - } - - // 读取设备信息 - uint8_t device_id, sw_ver; - pm1.getDeviceId(&device_id); - pm1.getSwVersion(&sw_ver); - Serial.printf("Device ID: 0x%02X, FW: %d\r\n", device_id, sw_ver); - - // 配置 GPIO (Arduino 风格) - pm1.pinMode(M5PM1_GPIO_NUM_0, OUTPUT); - pm1.digitalWrite(M5PM1_GPIO_NUM_0, HIGH); - - // 配置 PWM - pm1.gpioSetFunc(M5PM1_GPIO_NUM_3, M5PM1_GPIO_FUNC_OTHER); - pm1.setPwmConfig(M5PM1_PWM_CH_0, true, false, 1000, 2048); - - // 读取电压 - uint16_t vbat, vin; - pm1.readVbat(&vbat); - pm1.readVin(&vin); - Serial.printf("VBAT: %dmV, VIN: %dmV\r\n", vbat, vin); - - // 配置看门狗 - pm1.wdtSet(30); -} - -void loop() { - pm1.wdtFeed(); - delay(10000); -} -``` - ---- - -## 常见问题 - -### Q1: 新库是否兼容旧库的 I2C 地址? - -是的,默认 I2C 地址都是 `0x6E`。 - -### Q2: 如何处理 `esp_err_t` 和 `m5pm1_err_t` 的差异? - -两者都是整数类型,`M5PM1_OK (0)` 等同于 `ESP_OK (0)`。可以直接用布尔判断: - -```cpp -if (pm1.readVbat(&vbat) != M5PM1_OK) { - // 处理错误 -} -``` - -### Q3: 新库的 Arduino 风格 GPIO 函数没有返回值怎么办? - -使用带 `WithRes` 后缀的版本: - -```cpp -m5pm1_err_t err; -pm1.digitalWriteWithRes(0, HIGH, &err); -if (err != M5PM1_OK) { - // 处理错误 -} -``` - -### Q4: 旧库的 AW8737A 功能在新库中如何使用? - -```cpp -// 旧库 -pm1_aw8737a_pulse_set(PM1_GPIO_NUM_0, PM1_AW8737A_PULSE_NUM_2, PM1_AW8737A_REFRESH_NOW); - -// 新库 -pm1.setAw8737aPulse(M5PM1_GPIO_NUM_0, M5PM1_AW8737A_PULSE_2, M5PM1_AW8737A_REFRESH_NOW); -``` - ---- - -## 版本信息 - -- 旧库版本: `PM1_DEV_VERSION "0.0.3"` -- 新库版本: 请参考 `library.json` 或 `library.properties` -- 本文档最后更新: 2025-01-15 diff --git a/docs/review.txt b/docs/review.txt deleted file mode 100644 index 3443816..0000000 --- a/docs/review.txt +++ /dev/null @@ -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。 | \ No newline at end of file diff --git a/examples/basic_power_adc/basic_power_adc.ino b/examples/basic_power_adc/basic_power_adc.ino new file mode 100644 index 0000000..77ed790 --- /dev/null +++ b/examples/basic_power_adc/basic_power_adc.ino @@ -0,0 +1,188 @@ +/* + * SPDX-FileCopyrightText: 2026 M5Stack Technology CO LTD + * + * SPDX-License-Identifier: MIT + */ + +#include +#include + +/* + * 基础电源/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(); + } +} diff --git a/examples/gpio_pwm/gpio_pwm.ino b/examples/gpio_pwm/gpio_pwm.ino new file mode 100644 index 0000000..7d9fca5 --- /dev/null +++ b/examples/gpio_pwm/gpio_pwm.ino @@ -0,0 +1,125 @@ +/* + * SPDX-FileCopyrightText: 2026 M5Stack Technology CO LTD + * + * SPDX-License-Identifier: MIT + */ + +#include +#include + +/* + * 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(duty), false, true); + } + + if (now - lastLogMs >= 1000) { + lastLogMs = now; + int inLevel = pm1.digitalRead(GPIO_IN); + LOGI("GPIO_IN=%d PWM_DUTY=%d%%", inLevel, duty); + } +} diff --git a/examples/interrupt_button_sleep/interrupt_button_sleep.ino b/examples/interrupt_button_sleep/interrupt_button_sleep.ino new file mode 100644 index 0000000..9be308c --- /dev/null +++ b/examples/interrupt_button_sleep/interrupt_button_sleep.ino @@ -0,0 +1,178 @@ +/* + * SPDX-FileCopyrightText: 2026 M5Stack Technology CO LTD + * + * SPDX-License-Identifier: MIT + */ + +#include +#include + +/* + * 中断/按键/关机与唤醒示例。 + * 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); +} diff --git a/examples/neopixel/neopixel.ino b/examples/neopixel/neopixel.ino new file mode 100644 index 0000000..98e651c --- /dev/null +++ b/examples/neopixel/neopixel.ino @@ -0,0 +1,114 @@ +/* + * SPDX-FileCopyrightText: 2026 M5Stack Technology CO LTD + * + * SPDX-License-Identifier: MIT + */ + +#include +#include + +/* + * 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((static_cast(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(i * 256 / LED_COUNT + offset)); + pm1.setLedColor(i, c); + } + // 刷新后才会显示到灯带。 + // Refresh is required to apply colors to LEDs. + pm1.refreshLeds(); + + offset++; + delay(40); +} diff --git a/migration_script.md b/migration_script.md deleted file mode 100644 index e69de29..0000000 diff --git a/src/M5PM1.cpp b/src/M5PM1.cpp index d53ec42..286000f 100644 --- a/src/M5PM1.cpp +++ b/src/M5PM1.cpp @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2025 M5Stack Technology CO LTD + * SPDX-FileCopyrightText: 2026 M5Stack Technology CO LTD * * SPDX-License-Identifier: MIT */ @@ -11,47 +11,47 @@ static const char* TAG = "M5PM1"; #ifdef ARDUINO - #include - #define M5PM1_DELAY_MS(ms) delay(ms) - #define M5PM1_GET_TIME_MS() millis() +#include +#define M5PM1_DELAY_MS(ms) delay(ms) +#define M5PM1_GET_TIME_MS() millis() - // Arduino 日志级别控制 - // Arduino log level control - static m5pm1_log_level_t _m5pm1_log_level = M5PM1_LOG_LEVEL_INFO; +// Arduino 日志级别控制 +// Arduino log level control +static m5pm1_log_level_t _m5pm1_log_level = M5PM1_LOG_LEVEL_INFO; - #define M5PM1_LOG_I(tag, fmt, ...) \ - do { \ - if (_m5pm1_log_level >= M5PM1_LOG_LEVEL_INFO) { \ - Serial.printf("[%s] " fmt "\r\n", tag, ##__VA_ARGS__); \ - } \ - } while (0) +#define M5PM1_LOG_I(tag, fmt, ...) \ + do { \ + if (_m5pm1_log_level >= M5PM1_LOG_LEVEL_INFO) { \ + Serial.printf("[%s] " fmt "\r\n", tag, ##__VA_ARGS__); \ + } \ + } while (0) - #define M5PM1_LOG_W(tag, fmt, ...) \ - do { \ - if (_m5pm1_log_level >= M5PM1_LOG_LEVEL_WARN) { \ - Serial.printf("[%s] WARN: " fmt "\r\n", tag, ##__VA_ARGS__); \ - } \ - } while (0) +#define M5PM1_LOG_W(tag, fmt, ...) \ + do { \ + if (_m5pm1_log_level >= M5PM1_LOG_LEVEL_WARN) { \ + Serial.printf("[%s] WARN: " fmt "\r\n", tag, ##__VA_ARGS__); \ + } \ + } while (0) - #define M5PM1_LOG_E(tag, fmt, ...) \ - do { \ - if (_m5pm1_log_level >= M5PM1_LOG_LEVEL_ERROR) { \ - Serial.printf("[%s] ERROR: " fmt "\r\n", tag, ##__VA_ARGS__); \ - } \ - } while (0) +#define M5PM1_LOG_E(tag, fmt, ...) \ + do { \ + if (_m5pm1_log_level >= M5PM1_LOG_LEVEL_ERROR) { \ + Serial.printf("[%s] ERROR: " fmt "\r\n", tag, ##__VA_ARGS__); \ + } \ + } while (0) #else - #include "esp_log.h" - #include "freertos/FreeRTOS.h" - #include "freertos/task.h" - #define M5PM1_DELAY_MS(ms) vTaskDelay(pdMS_TO_TICKS(ms)) - #define M5PM1_GET_TIME_MS() (xTaskGetTickCount() * portTICK_PERIOD_MS) - #define M5PM1_LOG_I(tag, fmt, ...) ESP_LOGI(tag, fmt, ##__VA_ARGS__) - #define M5PM1_LOG_W(tag, fmt, ...) ESP_LOGW(tag, fmt, ##__VA_ARGS__) - #define M5PM1_LOG_E(tag, fmt, ...) ESP_LOGE(tag, fmt, ##__VA_ARGS__) +#include "esp_log.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#define M5PM1_DELAY_MS(ms) vTaskDelay(pdMS_TO_TICKS(ms)) +#define M5PM1_GET_TIME_MS() (xTaskGetTickCount() * portTICK_PERIOD_MS) +#define M5PM1_LOG_I(tag, fmt, ...) ESP_LOGI(tag, fmt, ##__VA_ARGS__) +#define M5PM1_LOG_W(tag, fmt, ...) ESP_LOGW(tag, fmt, ##__VA_ARGS__) +#define M5PM1_LOG_E(tag, fmt, ...) ESP_LOGE(tag, fmt, ##__VA_ARGS__) - // ESP-IDF 平台日志级别控制 - // ESP-IDF platform log level control - static m5pm1_log_level_t _m5pm1_current_log_level = M5PM1_LOG_LEVEL_INFO; +// ESP-IDF 平台日志级别控制 +// ESP-IDF platform log level control +static m5pm1_log_level_t _m5pm1_current_log_level = M5PM1_LOG_LEVEL_INFO; #endif // ============================ @@ -111,61 +111,63 @@ m5pm1_log_level_t M5PM1::getLogLevel() // Constructor / Destructor // ============================ -M5PM1::M5PM1() { - _addr = M5PM1_DEFAULT_ADDR; - _initialized = false; - _autoWakeEnabled = false; - _autoSnapshot = true; - _i2cSleepTime = 0; - _requestedSpeed = M5PM1_I2C_FREQ_100K; +M5PM1::M5PM1() +{ + _addr = M5PM1_DEFAULT_ADDR; + _initialized = false; + _autoWakeEnabled = false; + _autoSnapshot = true; + _i2cSleepTime = 0; + _requestedSpeed = M5PM1_I2C_FREQ_100K; _i2cConfig.sleepTime = 0; _i2cConfig.speed400k = false; - _i2cConfigValid = false; - _lastCommTime = 0; + _i2cConfigValid = false; + _lastCommTime = 0; memset(_pwmStates, 0, sizeof(_pwmStates)); - _pwmFrequency = 0; - _pwmStatesValid = false; - _adcState.channel = 0; - _adcState.busy = false; + _pwmFrequency = 0; + _pwmStatesValid = false; + _adcState.channel = 0; + _adcState.busy = false; _adcState.lastValue = 0; - _adcStateValid = false; - _powerCfg = 0; - _holdCfg = 0; - _powerConfigValid = false; - _btnCfg1 = 0; - _btnCfg2 = 0; - _btnConfigValid = false; - _btnFlagCache = false; - _irqMask1 = 0; - _irqMask2 = 0; - _irqMask3 = 0; - _irqMaskValid = false; - _irqStatus1 = 0; - _irqStatus2 = 0; - _irqStatus3 = 0; - _irqStatusValid = false; - _neoCfg = 0; - _neoConfigValid = false; - _cacheValid = false; + _adcStateValid = false; + _powerCfg = 0; + _holdCfg = 0; + _powerConfigValid = false; + _btnCfg1 = 0; + _btnCfg2 = 0; + _btnConfigValid = false; + _btnFlagCache = false; + _irqMask1 = 0; + _irqMask2 = 0; + _irqMask3 = 0; + _irqMaskValid = false; + _irqStatus1 = 0; + _irqStatus2 = 0; + _irqStatus3 = 0; + _irqStatusValid = false; + _neoCfg = 0; + _neoConfigValid = false; + _cacheValid = false; #ifdef ARDUINO _wire = nullptr; - _sda = -1; - _scl = -1; + _sda = -1; + _scl = -1; #else - _i2cDriverType = M5PM1_I2C_DRIVER_NONE; + _i2cDriverType = M5PM1_I2C_DRIVER_NONE; _i2c_master_bus = nullptr; _i2c_master_dev = nullptr; - _i2c_bus = nullptr; - _i2c_device = nullptr; - _busExternal = false; - _sda = -1; - _scl = -1; - _port = I2C_NUM_0; + _i2c_bus = nullptr; + _i2c_device = nullptr; + _busExternal = false; + _sda = -1; + _scl = -1; + _port = I2C_NUM_0; #endif } -M5PM1::~M5PM1() { +M5PM1::~M5PM1() +{ #ifndef ARDUINO // Cleanup based on driver type switch (_i2cDriverType) { @@ -207,18 +209,17 @@ M5PM1::~M5PM1() { #ifdef ARDUINO -m5pm1_err_t M5PM1::begin(TwoWire *wire, uint8_t addr, int8_t sda, int8_t scl, uint32_t speed) { +m5pm1_err_t M5PM1::begin(TwoWire* wire, uint8_t addr, int8_t sda, int8_t scl, uint32_t speed) +{ _wire = wire; _addr = addr; - _sda = sda; - _scl = scl; - + _sda = sda; + _scl = scl; // 步骤1:校验用户频率并记录 // Step 1: Validate requested speed and store it if (!_isValidI2cFrequency(speed)) { - M5PM1_LOG_W(TAG, - "Invalid I2C frequency: %lu Hz. PM1 only supports 100KHz or 400KHz. Falling back to 100KHz.", + M5PM1_LOG_W(TAG, "Invalid I2C frequency: %lu Hz. PM1 only supports 100KHz or 400KHz. Falling back to 100KHz.", (unsigned long)speed); _requestedSpeed = M5PM1_I2C_FREQ_100K; } else { @@ -278,8 +279,8 @@ m5pm1_err_t M5PM1::begin(TwoWire *wire, uint8_t addr, int8_t sda, int8_t scl, ui // 步骤4:配置设备I2C参数(关闭睡眠 + 目标频率) // Step 4: Configure device I2C (sleep off + target speed) - m5pm1_i2c_speed_t targetSpeed = (_requestedSpeed == M5PM1_I2C_FREQ_400K) - ? M5PM1_I2C_SPEED_400K : M5PM1_I2C_SPEED_100K; + m5pm1_i2c_speed_t targetSpeed = + (_requestedSpeed == M5PM1_I2C_FREQ_400K) ? M5PM1_I2C_SPEED_400K : M5PM1_I2C_SPEED_100K; if (setI2cConfig(0, targetSpeed) != M5PM1_OK) { M5PM1_LOG_W(TAG, "Failed to set I2C config"); } @@ -302,26 +303,25 @@ m5pm1_err_t M5PM1::begin(TwoWire *wire, uint8_t addr, int8_t sda, int8_t scl, ui _clearAll(); } - M5PM1_LOG_I(TAG, "M5PM1 initialized at address 0x%02X (I2C: %lu Hz)", _addr, - (unsigned long)_requestedSpeed); + M5PM1_LOG_I(TAG, "M5PM1 initialized at address 0x%02X (I2C: %lu Hz)", _addr, (unsigned long)_requestedSpeed); return M5PM1_OK; } -#else // ESP-IDF +#else // ESP-IDF -m5pm1_err_t M5PM1::begin(i2c_port_t port, uint8_t addr, int sda, int scl, uint32_t speed) { - _addr = addr; - _busExternal = false; +m5pm1_err_t M5PM1::begin(i2c_port_t port, uint8_t addr, int sda, int scl, uint32_t speed) +{ + _addr = addr; + _busExternal = false; _i2cDriverType = M5PM1_I2C_DRIVER_SELF_CREATED; - _port = port; - _sda = sda; - _scl = scl; + _port = port; + _sda = sda; + _scl = scl; // 步骤1:校验用户频率并记录 // Step 1: Validate requested speed and store it if (!_isValidI2cFrequency(speed)) { - M5PM1_LOG_W(TAG, - "Invalid I2C frequency: %lu Hz. PM1 only supports 100KHz or 400KHz. Falling back to 100KHz.", + M5PM1_LOG_W(TAG, "Invalid I2C frequency: %lu Hz. PM1 only supports 100KHz or 400KHz. Falling back to 100KHz.", (unsigned long)speed); _requestedSpeed = M5PM1_I2C_FREQ_100K; } else { @@ -331,17 +331,18 @@ m5pm1_err_t M5PM1::begin(i2c_port_t port, uint8_t addr, int sda, int scl, uint32 // 步骤2:创建I2C主总线 // Step 2: Create I2C master bus i2c_master_bus_config_t bus_config = { - .i2c_port = port, - .sda_io_num = (gpio_num_t)sda, - .scl_io_num = (gpio_num_t)scl, - .clk_source = I2C_CLK_SRC_DEFAULT, + .i2c_port = port, + .sda_io_num = (gpio_num_t)sda, + .scl_io_num = (gpio_num_t)scl, + .clk_source = I2C_CLK_SRC_DEFAULT, .glitch_ignore_cnt = 7, - .intr_priority = 0, + .intr_priority = 0, .trans_queue_depth = 0, - .flags = { - .enable_internal_pullup = true, - .allow_pd = false, - }, + .flags = + { + .enable_internal_pullup = true, + .allow_pd = false, + }, }; esp_err_t ret = i2c_new_master_bus(&bus_config, &_i2c_master_bus); @@ -354,12 +355,13 @@ m5pm1_err_t M5PM1::begin(i2c_port_t port, uint8_t addr, int sda, int scl, uint32 // Step 2: Create device handle at 100KHz i2c_device_config_t dev_config = { .dev_addr_length = I2C_ADDR_BIT_LEN_7, - .device_address = _addr, - .scl_speed_hz = M5PM1_I2C_FREQ_100K, - .scl_wait_us = 0, - .flags = { - .disable_ack_check = false, - }, + .device_address = _addr, + .scl_speed_hz = M5PM1_I2C_FREQ_100K, + .scl_wait_us = 0, + .flags = + { + .disable_ack_check = false, + }, }; ret = i2c_master_bus_add_device(_i2c_master_bus, &dev_config, &_i2c_master_dev); @@ -367,7 +369,7 @@ m5pm1_err_t M5PM1::begin(i2c_port_t port, uint8_t addr, int sda, int scl, uint32 M5PM1_LOG_E(TAG, "Failed to add I2C device: %s", esp_err_to_name(ret)); i2c_del_master_bus(_i2c_master_bus); _i2c_master_bus = nullptr; - _initialized = false; + _initialized = false; return M5PM1_ERR_I2C_CONFIG; } @@ -398,7 +400,7 @@ m5pm1_err_t M5PM1::begin(i2c_port_t port, uint8_t addr, int sda, int scl, uint32 // 以400K重新创建设备句柄 // Recreate device handle at 400K dev_config.scl_speed_hz = M5PM1_I2C_FREQ_400K; - ret = i2c_master_bus_add_device(_i2c_master_bus, &dev_config, &_i2c_master_dev); + ret = i2c_master_bus_add_device(_i2c_master_bus, &dev_config, &_i2c_master_dev); if (ret != ESP_OK) { M5PM1_LOG_E(TAG, "Failed to add I2C device at 400KHz: %s", esp_err_to_name(ret)); i2c_del_master_bus(_i2c_master_bus); @@ -423,29 +425,26 @@ m5pm1_err_t M5PM1::begin(i2c_port_t port, uint8_t addr, int sda, int scl, uint32 } _initialized = true; - // 步骤5:配置设备I2C参数(关闭睡眠 + 目标频率) // Step 5: Configure device I2C (sleep off + target speed) - m5pm1_i2c_speed_t targetSpeed = (_requestedSpeed == M5PM1_I2C_FREQ_400K) - ? M5PM1_I2C_SPEED_400K : M5PM1_I2C_SPEED_100K; + m5pm1_i2c_speed_t targetSpeed = + (_requestedSpeed == M5PM1_I2C_FREQ_400K) ? M5PM1_I2C_SPEED_400K : M5PM1_I2C_SPEED_100K; if (setI2cConfig(0, targetSpeed) != M5PM1_OK) { M5PM1_LOG_W(TAG, "Failed to set I2C config"); } - // 步骤6:重建设备句柄到目标频率 // Step 6: Recreate device handle at target speed i2c_master_bus_rm_device(_i2c_master_dev); _i2c_master_dev = nullptr; dev_config.scl_speed_hz = _requestedSpeed; - ret = i2c_master_bus_add_device(_i2c_master_bus, &dev_config, &_i2c_master_dev); + ret = i2c_master_bus_add_device(_i2c_master_bus, &dev_config, &_i2c_master_dev); if (ret != ESP_OK) { - M5PM1_LOG_E(TAG, "Failed to switch device to %lu Hz: %s", - (unsigned long)_requestedSpeed, esp_err_to_name(ret)); + M5PM1_LOG_E(TAG, "Failed to switch device to %lu Hz: %s", (unsigned long)_requestedSpeed, esp_err_to_name(ret)); i2c_del_master_bus(_i2c_master_bus); _i2c_master_bus = nullptr; - _initialized = false; + _initialized = false; return M5PM1_ERR_I2C_CONFIG; } @@ -457,22 +456,21 @@ m5pm1_err_t M5PM1::begin(i2c_port_t port, uint8_t addr, int sda, int scl, uint32 } _initialized = true; - M5PM1_LOG_I(TAG, "M5PM1 initialized at address 0x%02X (I2C: %lu Hz)", _addr, - (unsigned long)_requestedSpeed); + M5PM1_LOG_I(TAG, "M5PM1 initialized at address 0x%02X (I2C: %lu Hz)", _addr, (unsigned long)_requestedSpeed); return M5PM1_OK; } -m5pm1_err_t M5PM1::begin(i2c_master_bus_handle_t bus, uint8_t addr, uint32_t speed) { - _addr = addr; - _busExternal = true; - _i2cDriverType = M5PM1_I2C_DRIVER_MASTER; +m5pm1_err_t M5PM1::begin(i2c_master_bus_handle_t bus, uint8_t addr, uint32_t speed) +{ + _addr = addr; + _busExternal = true; + _i2cDriverType = M5PM1_I2C_DRIVER_MASTER; _i2c_master_bus = bus; // 步骤1:校验用户频率并记录 // Step 1: Validate requested speed and store it if (!_isValidI2cFrequency(speed)) { - M5PM1_LOG_W(TAG, - "Invalid I2C frequency: %lu Hz. PM1 only supports 100KHz or 400KHz. Falling back to 100KHz.", + M5PM1_LOG_W(TAG, "Invalid I2C frequency: %lu Hz. PM1 only supports 100KHz or 400KHz. Falling back to 100KHz.", (unsigned long)speed); _requestedSpeed = M5PM1_I2C_FREQ_100K; } else { @@ -483,12 +481,13 @@ m5pm1_err_t M5PM1::begin(i2c_master_bus_handle_t bus, uint8_t addr, uint32_t spe // Step 3: Create device handle at 100KHz i2c_device_config_t dev_config = { .dev_addr_length = I2C_ADDR_BIT_LEN_7, - .device_address = _addr, - .scl_speed_hz = M5PM1_I2C_FREQ_100K, - .scl_wait_us = 0, - .flags = { - .disable_ack_check = false, - }, + .device_address = _addr, + .scl_speed_hz = M5PM1_I2C_FREQ_100K, + .scl_wait_us = 0, + .flags = + { + .disable_ack_check = false, + }, }; esp_err_t ret = i2c_master_bus_add_device(_i2c_master_bus, &dev_config, &_i2c_master_dev); @@ -524,7 +523,7 @@ m5pm1_err_t M5PM1::begin(i2c_master_bus_handle_t bus, uint8_t addr, uint32_t spe // 以400K重新创建设备句柄 // Recreate device handle at 400K dev_config.scl_speed_hz = M5PM1_I2C_FREQ_400K; - ret = i2c_master_bus_add_device(_i2c_master_bus, &dev_config, &_i2c_master_dev); + ret = i2c_master_bus_add_device(_i2c_master_bus, &dev_config, &_i2c_master_dev); if (ret != ESP_OK) { M5PM1_LOG_E(TAG, "Failed to add I2C device at 400KHz: %s", esp_err_to_name(ret)); return M5PM1_ERR_I2C_CONFIG; @@ -547,23 +546,21 @@ m5pm1_err_t M5PM1::begin(i2c_master_bus_handle_t bus, uint8_t addr, uint32_t spe // 步骤4:配置设备I2C参数(关闭睡眠 + 目标频率) // Step 4: Configure device I2C (sleep off + target speed) - m5pm1_i2c_speed_t targetSpeed = (_requestedSpeed == M5PM1_I2C_FREQ_400K) - ? M5PM1_I2C_SPEED_400K : M5PM1_I2C_SPEED_100K; + m5pm1_i2c_speed_t targetSpeed = + (_requestedSpeed == M5PM1_I2C_FREQ_400K) ? M5PM1_I2C_SPEED_400K : M5PM1_I2C_SPEED_100K; if (setI2cConfig(0, targetSpeed) != M5PM1_OK) { M5PM1_LOG_W(TAG, "Failed to set I2C config"); } - // 步骤5:重建设备句柄到目标频率 // Step 5: Recreate device handle at target speed i2c_master_bus_rm_device(_i2c_master_dev); _i2c_master_dev = nullptr; dev_config.scl_speed_hz = _requestedSpeed; - ret = i2c_master_bus_add_device(_i2c_master_bus, &dev_config, &_i2c_master_dev); + ret = i2c_master_bus_add_device(_i2c_master_bus, &dev_config, &_i2c_master_dev); if (ret != ESP_OK) { - M5PM1_LOG_E(TAG, "Failed to switch device to %lu Hz: %s", - (unsigned long)_requestedSpeed, esp_err_to_name(ret)); + M5PM1_LOG_E(TAG, "Failed to switch device to %lu Hz: %s", (unsigned long)_requestedSpeed, esp_err_to_name(ret)); _initialized = false; return M5PM1_ERR_I2C_CONFIG; } @@ -576,22 +573,21 @@ m5pm1_err_t M5PM1::begin(i2c_master_bus_handle_t bus, uint8_t addr, uint32_t spe } _initialized = true; - M5PM1_LOG_I(TAG, "M5PM1 initialized at address 0x%02X (I2C: %lu Hz)", _addr, - (unsigned long)_requestedSpeed); + M5PM1_LOG_I(TAG, "M5PM1 initialized at address 0x%02X (I2C: %lu Hz)", _addr, (unsigned long)_requestedSpeed); return M5PM1_OK; } -m5pm1_err_t M5PM1::begin(i2c_bus_handle_t bus, uint8_t addr, uint32_t speed) { - _addr = addr; - _busExternal = true; +m5pm1_err_t M5PM1::begin(i2c_bus_handle_t bus, uint8_t addr, uint32_t speed) +{ + _addr = addr; + _busExternal = true; _i2cDriverType = M5PM1_I2C_DRIVER_BUS; - _i2c_bus = bus; + _i2c_bus = bus; // 步骤1:校验用户频率并记录 // Step 1: Validate requested speed and store it if (!_isValidI2cFrequency(speed)) { - M5PM1_LOG_W(TAG, - "Invalid I2C frequency: %lu Hz. PM1 only supports 100KHz or 400KHz. Falling back to 100KHz.", + M5PM1_LOG_W(TAG, "Invalid I2C frequency: %lu Hz. PM1 only supports 100KHz or 400KHz. Falling back to 100KHz.", (unsigned long)speed); _requestedSpeed = M5PM1_I2C_FREQ_100K; } else { @@ -653,11 +649,10 @@ m5pm1_err_t M5PM1::begin(i2c_bus_handle_t bus, uint8_t addr, uint32_t speed) { } _initialized = true; - // 步骤4:配置设备I2C参数(关闭睡眠 + 目标频率) // Step 4: Configure device I2C (sleep off + target speed) - m5pm1_i2c_speed_t targetSpeed = (_requestedSpeed == M5PM1_I2C_FREQ_400K) - ? M5PM1_I2C_SPEED_400K : M5PM1_I2C_SPEED_100K; + m5pm1_i2c_speed_t targetSpeed = + (_requestedSpeed == M5PM1_I2C_FREQ_400K) ? M5PM1_I2C_SPEED_400K : M5PM1_I2C_SPEED_100K; if (setI2cConfig(0, targetSpeed) != M5PM1_OK) { M5PM1_LOG_W(TAG, "Failed to set I2C config"); } @@ -682,28 +677,26 @@ m5pm1_err_t M5PM1::begin(i2c_bus_handle_t bus, uint8_t addr, uint32_t speed) { } _initialized = true; - M5PM1_LOG_I(TAG, "M5PM1 initialized at address 0x%02X (I2C: %lu Hz)", _addr, - (unsigned long)_requestedSpeed); + M5PM1_LOG_I(TAG, "M5PM1 initialized at address 0x%02X (I2C: %lu Hz)", _addr, (unsigned long)_requestedSpeed); return M5PM1_OK; } -#endif // ARDUINO +#endif // ARDUINO // ============================ // 内部辅助函数 // Internal Helper Functions // ============================ -bool M5PM1::_initDevice() { +bool M5PM1::_initDevice() +{ // Verify device ID - uint8_t id = 0; + uint8_t id = 0; uint8_t model = 0; - uint8_t hw = 0; - uint8_t sw = 0; - if (!_readReg(M5PM1_REG_DEVICE_ID, &id) || - !_readReg(M5PM1_REG_DEVICE_MODEL, &model) || - !_readReg(M5PM1_REG_HW_REV, &hw) || - !_readReg(M5PM1_REG_SW_REV, &sw)) { + uint8_t hw = 0; + uint8_t sw = 0; + if (!_readReg(M5PM1_REG_DEVICE_ID, &id) || !_readReg(M5PM1_REG_DEVICE_MODEL, &model) || + !_readReg(M5PM1_REG_HW_REV, &hw) || !_readReg(M5PM1_REG_SW_REV, &sw)) { return false; } if (sw >= 'A' && sw <= 'Z') { @@ -721,23 +714,28 @@ bool M5PM1::_initDevice() { return true; } -bool M5PM1::_isValidPin(uint8_t pin) { +bool M5PM1::_isValidPin(uint8_t pin) +{ return pin < M5PM1_MAX_GPIO_PINS; } -bool M5PM1::_isAdcPin(uint8_t pin) { +bool M5PM1::_isAdcPin(uint8_t pin) +{ return (pin == M5PM1_GPIO_NUM_1 || pin == M5PM1_GPIO_NUM_2); } -bool M5PM1::_isPwmPin(uint8_t pin) { +bool M5PM1::_isPwmPin(uint8_t pin) +{ return (pin == M5PM1_GPIO_NUM_3 || pin == M5PM1_GPIO_NUM_4); } -bool M5PM1::_isNeoPin(uint8_t pin) { +bool M5PM1::_isNeoPin(uint8_t pin) +{ return (pin == M5PM1_GPIO_NUM_0); } -bool M5PM1::_hasActiveAdc(uint8_t pin) { +bool M5PM1::_hasActiveAdc(uint8_t pin) +{ if (!_adcStateValid) return false; if (pin == M5PM1_GPIO_NUM_1) { @@ -749,7 +747,8 @@ bool M5PM1::_hasActiveAdc(uint8_t pin) { return false; } -bool M5PM1::_hasActivePwm(uint8_t pin) { +bool M5PM1::_hasActivePwm(uint8_t pin) +{ if (!_pwmStatesValid) return false; if (pin == M5PM1_GPIO_NUM_3) { @@ -761,29 +760,34 @@ bool M5PM1::_hasActivePwm(uint8_t pin) { return false; } -bool M5PM1::_hasActiveIrq(uint8_t pin) { +bool M5PM1::_hasActiveIrq(uint8_t pin) +{ if (!_cacheValid) return false; return _pinStatus[pin].func == M5PM1_GPIO_FUNC_IRQ; } -bool M5PM1::_hasActiveWake(uint8_t pin) { +bool M5PM1::_hasActiveWake(uint8_t pin) +{ if (!_cacheValid) return false; return _pinStatus[pin].func == M5PM1_GPIO_FUNC_WAKE || _pinStatus[pin].wake_en; } -bool M5PM1::_hasActiveNeo(uint8_t pin) { +bool M5PM1::_hasActiveNeo(uint8_t pin) +{ if (!_cacheValid) return false; return _isNeoPin(pin) && _pinStatus[pin].func == M5PM1_GPIO_FUNC_OTHER; } -bool M5PM1::_isValidI2cFrequency(uint32_t speed) { +bool M5PM1::_isValidI2cFrequency(uint32_t speed) +{ return (speed == M5PM1_I2C_FREQ_100K || speed == M5PM1_I2C_FREQ_400K); } -void M5PM1::_checkAutoWake() { +void M5PM1::_checkAutoWake() +{ if (!_autoWakeEnabled || !_i2cConfigValid || _i2cConfig.sleepTime == 0) return; - uint32_t now = M5PM1_GET_TIME_MS(); + uint32_t now = M5PM1_GET_TIME_MS(); uint32_t elapsed = now - _lastCommTime; // If more than 1 second since last communication, send wake signal @@ -793,7 +797,8 @@ void M5PM1::_checkAutoWake() { } } -bool M5PM1::_snapshotI2cConfig() { +bool M5PM1::_snapshotI2cConfig() +{ uint8_t cfg = 0; if (!_readReg(M5PM1_REG_I2C_CFG, &cfg)) { return false; @@ -801,32 +806,35 @@ bool M5PM1::_snapshotI2cConfig() { _i2cConfig.sleepTime = cfg & M5PM1_I2C_CFG_SLEEP_MASK; _i2cConfig.speed400k = (cfg & M5PM1_I2C_CFG_SPEED_400K) != 0; - _i2cConfigValid = true; - _i2cSleepTime = _i2cConfig.sleepTime; + _i2cConfigValid = true; + _i2cSleepTime = _i2cConfig.sleepTime; return true; } -void M5PM1::_clearI2cConfig() { +void M5PM1::_clearI2cConfig() +{ _i2cConfig.sleepTime = 0; _i2cConfig.speed400k = false; - _i2cConfigValid = false; - _i2cSleepTime = 0; + _i2cConfigValid = false; + _i2cSleepTime = 0; } -bool M5PM1::_snapshotNeoConfig() { +bool M5PM1::_snapshotNeoConfig() +{ uint8_t cfg = 0; if (!_readReg(M5PM1_REG_NEO_CFG, &cfg)) { _neoConfigValid = false; return false; } - _neoCfg = cfg & M5PM1_NEO_CFG_COUNT_MASK; + _neoCfg = cfg & M5PM1_NEO_CFG_COUNT_MASK; _neoConfigValid = true; return true; } -void M5PM1::_clearNeoConfig() { - _neoCfg = 0; +void M5PM1::_clearNeoConfig() +{ + _neoCfg = 0; _neoConfigValid = false; } @@ -835,61 +843,69 @@ void M5PM1::_clearNeoConfig() { // Cache Management Functions // ============================ -void M5PM1::_clearPinStates() { +void M5PM1::_clearPinStates() +{ for (int i = 0; i < M5PM1_MAX_GPIO_PINS; i++) { - _pinStatus[i].func = M5PM1_GPIO_FUNC_GPIO; - _pinStatus[i].mode = M5PM1_GPIO_MODE_INPUT; - _pinStatus[i].output = 0; - _pinStatus[i].pull = M5PM1_GPIO_PULL_NONE; - _pinStatus[i].wake_en = false; - _pinStatus[i].wake_edge = M5PM1_GPIO_WAKE_FALLING; - _pinStatus[i].drive = M5PM1_GPIO_DRIVE_PUSHPULL; + _pinStatus[i].func = M5PM1_GPIO_FUNC_GPIO; + _pinStatus[i].mode = M5PM1_GPIO_MODE_INPUT; + _pinStatus[i].output = 0; + _pinStatus[i].pull = M5PM1_GPIO_PULL_NONE; + _pinStatus[i].wake_en = false; + _pinStatus[i].wake_edge = M5PM1_GPIO_WAKE_FALLING; + _pinStatus[i].drive = M5PM1_GPIO_DRIVE_PUSHPULL; _pinStatus[i].power_hold = false; } _cacheValid = false; } -void M5PM1::_clearPwmStates() { +void M5PM1::_clearPwmStates() +{ memset(_pwmStates, 0, sizeof(_pwmStates)); - _pwmFrequency = 0; + _pwmFrequency = 0; _pwmStatesValid = false; } -void M5PM1::_clearAdcState() { - _adcState.channel = 0; - _adcState.busy = false; +void M5PM1::_clearAdcState() +{ + _adcState.channel = 0; + _adcState.busy = false; _adcState.lastValue = 0; - _adcStateValid = false; + _adcStateValid = false; } -void M5PM1::_clearPowerConfig() { - _powerCfg = 0; - _holdCfg = 0; +void M5PM1::_clearPowerConfig() +{ + _powerCfg = 0; + _holdCfg = 0; _powerConfigValid = false; } -void M5PM1::_clearButtonConfig() { - _btnCfg1 = 0; - _btnCfg2 = 0; +void M5PM1::_clearButtonConfig() +{ + _btnCfg1 = 0; + _btnCfg2 = 0; _btnConfigValid = false; - _btnFlagCache = false; + _btnFlagCache = false; } -void M5PM1::_clearIrqMasks() { - _irqMask1 = 0; - _irqMask2 = 0; - _irqMask3 = 0; +void M5PM1::_clearIrqMasks() +{ + _irqMask1 = 0; + _irqMask2 = 0; + _irqMask3 = 0; _irqMaskValid = false; } -void M5PM1::_clearIrqStatus() { - _irqStatus1 = 0; - _irqStatus2 = 0; - _irqStatus3 = 0; +void M5PM1::_clearIrqStatus() +{ + _irqStatus1 = 0; + _irqStatus2 = 0; + _irqStatus3 = 0; _irqStatusValid = false; } -void M5PM1::_clearAll() { +void M5PM1::_clearAll() +{ _clearPinStates(); _clearPwmStates(); _clearAdcState(); @@ -901,15 +917,16 @@ void M5PM1::_clearAll() { _clearNeoConfig(); } -bool M5PM1::_snapshotPinStates() { - uint8_t mode = 0; - uint8_t out = 0; - uint8_t drv = 0; - uint8_t pupd0 = 0; - uint8_t pupd1 = 0; - uint8_t func0 = 0; - uint8_t func1 = 0; - uint8_t wakeEn = 0; +bool M5PM1::_snapshotPinStates() +{ + uint8_t mode = 0; + uint8_t out = 0; + uint8_t drv = 0; + uint8_t pupd0 = 0; + uint8_t pupd1 = 0; + uint8_t func0 = 0; + uint8_t func1 = 0; + uint8_t wakeEn = 0; uint8_t wakeCfg = 0; uint8_t holdCfg = 0; @@ -955,11 +972,11 @@ bool M5PM1::_snapshotPinStates() { } for (int pin = 0; pin < M5PM1_MAX_GPIO_PINS; pin++) { - _pinStatus[pin].mode = (mode & (1 << pin)) ? M5PM1_GPIO_MODE_OUTPUT : M5PM1_GPIO_MODE_INPUT; - _pinStatus[pin].output = (out >> pin) & 0x01; - _pinStatus[pin].drive = (drv & (1 << pin)) ? M5PM1_GPIO_DRIVE_OPENDRAIN : M5PM1_GPIO_DRIVE_PUSHPULL; - _pinStatus[pin].wake_en = (wakeEn & (1 << pin)) != 0; - _pinStatus[pin].wake_edge = (wakeCfg & (1 << pin)) ? M5PM1_GPIO_WAKE_RISING : M5PM1_GPIO_WAKE_FALLING; + _pinStatus[pin].mode = (mode & (1 << pin)) ? M5PM1_GPIO_MODE_OUTPUT : M5PM1_GPIO_MODE_INPUT; + _pinStatus[pin].output = (out >> pin) & 0x01; + _pinStatus[pin].drive = (drv & (1 << pin)) ? M5PM1_GPIO_DRIVE_OPENDRAIN : M5PM1_GPIO_DRIVE_PUSHPULL; + _pinStatus[pin].wake_en = (wakeEn & (1 << pin)) != 0; + _pinStatus[pin].wake_edge = (wakeCfg & (1 << pin)) ? M5PM1_GPIO_WAKE_RISING : M5PM1_GPIO_WAKE_FALLING; _pinStatus[pin].power_hold = (holdCfg & (1 << pin)) != 0; if (pin < 4) { @@ -975,7 +992,8 @@ bool M5PM1::_snapshotPinStates() { return true; } -bool M5PM1::_snapshotPwmStates() { +bool M5PM1::_snapshotPwmStates() +{ if (!_readReg16(M5PM1_REG_PWM_FREQ_L, &_pwmFrequency)) { _pwmStatesValid = false; return false; @@ -984,7 +1002,7 @@ bool M5PM1::_snapshotPwmStates() { for (uint8_t ch = 0; ch < M5PM1_MAX_PWM_CHANNELS; ch++) { uint8_t regL = (ch == 0) ? M5PM1_REG_PWM0_L : M5PM1_REG_PWM1_L; uint8_t regH = (ch == 0) ? M5PM1_REG_PWM0_HC : M5PM1_REG_PWM1_HC; - uint8_t low = 0; + uint8_t low = 0; uint8_t high = 0; if (!_readReg(regL, &low)) { @@ -996,8 +1014,8 @@ bool M5PM1::_snapshotPwmStates() { return false; } - _pwmStates[ch].duty12 = (uint16_t)(low | ((high & 0x0F) << 8)); - _pwmStates[ch].enabled = (high & 0x10) != 0; + _pwmStates[ch].duty12 = (uint16_t)(low | ((high & 0x0F) << 8)); + _pwmStates[ch].enabled = (high & 0x10) != 0; _pwmStates[ch].polarity = (high & 0x20) != 0; } @@ -1005,7 +1023,8 @@ bool M5PM1::_snapshotPwmStates() { return true; } -bool M5PM1::_snapshotAdcState() { +bool M5PM1::_snapshotAdcState() +{ uint8_t ctrl = 0; if (!_readReg(M5PM1_REG_ADC_CTRL, &ctrl)) { _adcStateValid = false; @@ -1013,7 +1032,7 @@ bool M5PM1::_snapshotAdcState() { } _adcState.channel = (ctrl >> 1) & 0x07; - _adcState.busy = (ctrl & 0x01) != 0; + _adcState.busy = (ctrl & 0x01) != 0; if (!_readReg16(M5PM1_REG_ADC_RES_L, &_adcState.lastValue)) { _adcStateValid = false; return false; @@ -1023,7 +1042,8 @@ bool M5PM1::_snapshotAdcState() { return true; } -bool M5PM1::_snapshotPowerConfig() { +bool M5PM1::_snapshotPowerConfig() +{ if (!_readReg(M5PM1_REG_PWR_CFG, &_powerCfg)) { _powerConfigValid = false; return false; @@ -1037,7 +1057,8 @@ bool M5PM1::_snapshotPowerConfig() { return true; } -bool M5PM1::_snapshotButtonConfig() { +bool M5PM1::_snapshotButtonConfig() +{ if (!_readReg(M5PM1_REG_BTN_CFG_1, &_btnCfg1)) { _btnConfigValid = false; return false; @@ -1051,7 +1072,8 @@ bool M5PM1::_snapshotButtonConfig() { return true; } -bool M5PM1::_snapshotIrqMasks() { +bool M5PM1::_snapshotIrqMasks() +{ if (!_readReg(M5PM1_REG_IRQ_MASK1, &_irqMask1)) { _irqMaskValid = false; return false; @@ -1069,7 +1091,8 @@ bool M5PM1::_snapshotIrqMasks() { return true; } -bool M5PM1::_snapshotIrqStatus() { +bool M5PM1::_snapshotIrqStatus() +{ if (!_readReg(M5PM1_REG_IRQ_STATUS1, &_irqStatus1)) { _irqStatusValid = false; return false; @@ -1087,16 +1110,17 @@ bool M5PM1::_snapshotIrqStatus() { return true; } -bool M5PM1::_snapshotAll() { - bool gpio = _snapshotPinStates(); - bool pwm = _snapshotPwmStates(); - bool adc = _snapshotAdcState(); - bool power = _snapshotPowerConfig(); - bool button = _snapshotButtonConfig(); - bool irqMask = _snapshotIrqMasks(); +bool M5PM1::_snapshotAll() +{ + bool gpio = _snapshotPinStates(); + bool pwm = _snapshotPwmStates(); + bool adc = _snapshotAdcState(); + bool power = _snapshotPowerConfig(); + bool button = _snapshotButtonConfig(); + bool irqMask = _snapshotIrqMasks(); bool irqStatus = _snapshotIrqStatus(); - bool i2c = _snapshotI2cConfig(); - bool neo = _snapshotNeoConfig(); + bool i2c = _snapshotI2cConfig(); + bool neo = _snapshotNeoConfig(); if (!i2c) { _clearI2cConfig(); @@ -1108,7 +1132,8 @@ bool M5PM1::_snapshotAll() { return gpio && pwm && adc && power && button && irqMask && irqStatus && i2c && neo; } -void M5PM1::_autoSnapshotUpdate(uint16_t domains) { +void M5PM1::_autoSnapshotUpdate(uint16_t domains) +{ if (!_autoSnapshot) return; if (domains & M5PM1_SNAPSHOT_DOMAIN_GPIO) { @@ -1144,11 +1169,13 @@ void M5PM1::_autoSnapshotUpdate(uint16_t domains) { } } -void M5PM1::_initPinCache() { +void M5PM1::_initPinCache() +{ _clearPinStates(); } -bool M5PM1::_readBtnStatus(uint8_t* rawValue) { +bool M5PM1::_readBtnStatus(uint8_t* rawValue) +{ // 读取 BTN_STATUS 寄存器并更新内部 BTN_FLAG 缓存 // Read BTN_STATUS register and update internal BTN_FLAG cache uint8_t val; @@ -1166,7 +1193,8 @@ bool M5PM1::_readBtnStatus(uint8_t* rawValue) { return true; } -bool M5PM1::_writeReg(uint8_t reg, uint8_t value) { +bool M5PM1::_writeReg(uint8_t reg, uint8_t value) +{ _checkAutoWake(); bool success = false; for (int attempt = 0; attempt < M5PM1_I2C_RETRY_COUNT; ++attempt) { @@ -1197,7 +1225,8 @@ bool M5PM1::_writeReg(uint8_t reg, uint8_t value) { return success; } -bool M5PM1::_writeReg16(uint8_t reg, uint16_t value) { +bool M5PM1::_writeReg16(uint8_t reg, uint16_t value) +{ _checkAutoWake(); bool success = false; for (int attempt = 0; attempt < M5PM1_I2C_RETRY_COUNT; ++attempt) { @@ -1228,7 +1257,8 @@ bool M5PM1::_writeReg16(uint8_t reg, uint16_t value) { return success; } -bool M5PM1::_readReg(uint8_t reg, uint8_t* value) { +bool M5PM1::_readReg(uint8_t reg, uint8_t* value) +{ _checkAutoWake(); bool success = false; for (int attempt = 0; attempt < M5PM1_I2C_RETRY_COUNT; ++attempt) { @@ -1259,7 +1289,8 @@ bool M5PM1::_readReg(uint8_t reg, uint8_t* value) { return success; } -bool M5PM1::_readReg16(uint8_t reg, uint16_t* value) { +bool M5PM1::_readReg16(uint8_t reg, uint16_t* value) +{ _checkAutoWake(); bool success = false; for (int attempt = 0; attempt < M5PM1_I2C_RETRY_COUNT; ++attempt) { @@ -1290,7 +1321,8 @@ bool M5PM1::_readReg16(uint8_t reg, uint16_t* value) { return success; } -bool M5PM1::_writeBytes(uint8_t reg, const uint8_t* data, uint8_t len) { +bool M5PM1::_writeBytes(uint8_t reg, const uint8_t* data, uint8_t len) +{ _checkAutoWake(); bool success = false; for (int attempt = 0; attempt < M5PM1_I2C_RETRY_COUNT; ++attempt) { @@ -1321,7 +1353,8 @@ bool M5PM1::_writeBytes(uint8_t reg, const uint8_t* data, uint8_t len) { return success; } -bool M5PM1::_readBytes(uint8_t reg, uint8_t* data, uint8_t len) { +bool M5PM1::_readBytes(uint8_t reg, uint8_t* data, uint8_t len) +{ _checkAutoWake(); bool success = false; for (int attempt = 0; attempt < M5PM1_I2C_RETRY_COUNT; ++attempt) { @@ -1357,7 +1390,8 @@ bool M5PM1::_readBytes(uint8_t reg, uint8_t* data, uint8_t len) { // Device Information // ============================ -m5pm1_err_t M5PM1::getDeviceId(uint8_t* id) { +m5pm1_err_t M5PM1::getDeviceId(uint8_t* id) +{ if (id == nullptr) { M5PM1_LOG_E(TAG, "getDeviceId id is null"); return M5PM1_ERR_INVALID_ARG; @@ -1373,7 +1407,8 @@ m5pm1_err_t M5PM1::getDeviceId(uint8_t* id) { return M5PM1_OK; } -m5pm1_err_t M5PM1::getDeviceModel(uint8_t* model) { +m5pm1_err_t M5PM1::getDeviceModel(uint8_t* model) +{ if (model == nullptr) { M5PM1_LOG_E(TAG, "getDeviceModel model is null"); return M5PM1_ERR_INVALID_ARG; @@ -1389,7 +1424,8 @@ m5pm1_err_t M5PM1::getDeviceModel(uint8_t* model) { return M5PM1_OK; } -m5pm1_err_t M5PM1::getHwVersion(uint8_t* version) { +m5pm1_err_t M5PM1::getHwVersion(uint8_t* version) +{ if (version == nullptr) { M5PM1_LOG_E(TAG, "getHwVersion version is null"); return M5PM1_ERR_INVALID_ARG; @@ -1405,7 +1441,8 @@ m5pm1_err_t M5PM1::getHwVersion(uint8_t* version) { return M5PM1_OK; } -m5pm1_err_t M5PM1::getSwVersion(uint8_t* version) { +m5pm1_err_t M5PM1::getSwVersion(uint8_t* version) +{ if (version == nullptr) { M5PM1_LOG_E(TAG, "getSwVersion version is null"); return M5PM1_ERR_INVALID_ARG; @@ -1426,7 +1463,8 @@ m5pm1_err_t M5PM1::getSwVersion(uint8_t* version) { // GPIO Functions (Arduino-style - WithRes) // ============================ -void M5PM1::pinModeWithRes(uint8_t pin, uint8_t mode, m5pm1_err_t* err) { +void M5PM1::pinModeWithRes(uint8_t pin, uint8_t mode, m5pm1_err_t* err) +{ m5pm1_err_t localErr = M5PM1_OK; if (!_isValidPin(pin)) { @@ -1441,44 +1479,44 @@ void M5PM1::pinModeWithRes(uint8_t pin, uint8_t mode, m5pm1_err_t* err) { return; } - m5pm1_gpio_func_t func = M5PM1_GPIO_FUNC_GPIO; + m5pm1_gpio_func_t func = M5PM1_GPIO_FUNC_GPIO; m5pm1_gpio_mode_t gpioMode = M5PM1_GPIO_MODE_INPUT; - m5pm1_gpio_pull_t pull = M5PM1_GPIO_PULL_NONE; - m5pm1_gpio_drive_t drive = M5PM1_GPIO_DRIVE_PUSHPULL; - bool setDrive = false; + m5pm1_gpio_pull_t pull = M5PM1_GPIO_PULL_NONE; + m5pm1_gpio_drive_t drive = M5PM1_GPIO_DRIVE_PUSHPULL; + bool setDrive = false; switch (mode) { case INPUT: gpioMode = M5PM1_GPIO_MODE_INPUT; - pull = M5PM1_GPIO_PULL_NONE; + pull = M5PM1_GPIO_PULL_NONE; break; case OUTPUT: gpioMode = M5PM1_GPIO_MODE_OUTPUT; - pull = M5PM1_GPIO_PULL_NONE; - drive = M5PM1_GPIO_DRIVE_PUSHPULL; + pull = M5PM1_GPIO_PULL_NONE; + drive = M5PM1_GPIO_DRIVE_PUSHPULL; setDrive = true; break; case PULLUP: case INPUT_PULLUP: gpioMode = M5PM1_GPIO_MODE_INPUT; - pull = M5PM1_GPIO_PULL_UP; + pull = M5PM1_GPIO_PULL_UP; break; case PULLDOWN: case INPUT_PULLDOWN: gpioMode = M5PM1_GPIO_MODE_INPUT; - pull = M5PM1_GPIO_PULL_DOWN; + pull = M5PM1_GPIO_PULL_DOWN; break; case OPEN_DRAIN: case OUTPUT_OPEN_DRAIN: gpioMode = M5PM1_GPIO_MODE_OUTPUT; - pull = M5PM1_GPIO_PULL_NONE; - drive = M5PM1_GPIO_DRIVE_OPENDRAIN; + pull = M5PM1_GPIO_PULL_NONE; + drive = M5PM1_GPIO_DRIVE_OPENDRAIN; setDrive = true; break; case ANALOG: - func = M5PM1_GPIO_FUNC_OTHER; + func = M5PM1_GPIO_FUNC_OTHER; gpioMode = M5PM1_GPIO_MODE_INPUT; - pull = M5PM1_GPIO_PULL_NONE; + pull = M5PM1_GPIO_PULL_NONE; break; default: M5PM1_LOG_E(TAG, "Invalid mode: 0x%02X", mode); @@ -1516,7 +1554,8 @@ void M5PM1::pinModeWithRes(uint8_t pin, uint8_t mode, m5pm1_err_t* err) { if (err) *err = localErr; } -void M5PM1::digitalWriteWithRes(uint8_t pin, uint8_t value, m5pm1_err_t* err) { +void M5PM1::digitalWriteWithRes(uint8_t pin, uint8_t value, m5pm1_err_t* err) +{ m5pm1_err_t localErr = M5PM1_OK; if (!_isValidPin(pin)) { @@ -1535,7 +1574,8 @@ void M5PM1::digitalWriteWithRes(uint8_t pin, uint8_t value, m5pm1_err_t* err) { if (err) *err = localErr; } -int M5PM1::digitalReadWithRes(uint8_t pin, m5pm1_err_t* err) { +int M5PM1::digitalReadWithRes(uint8_t pin, m5pm1_err_t* err) +{ m5pm1_err_t localErr = M5PM1_OK; if (!_isValidPin(pin)) { @@ -1550,7 +1590,7 @@ int M5PM1::digitalReadWithRes(uint8_t pin, m5pm1_err_t* err) { return -1; } uint8_t value = 0; - localErr = gpioGetInput((m5pm1_gpio_num_t)pin, &value); + localErr = gpioGetInput((m5pm1_gpio_num_t)pin, &value); if (localErr != M5PM1_OK) { if (err) *err = localErr; return -1; @@ -1564,16 +1604,26 @@ int M5PM1::digitalReadWithRes(uint8_t pin, m5pm1_err_t* err) { // GPIO Functions (Arduino-style) // ============================ -void M5PM1::pinMode(uint8_t pin, uint8_t mode) { pinModeWithRes(pin, mode, nullptr); } -void M5PM1::digitalWrite(uint8_t pin, uint8_t value) { digitalWriteWithRes(pin, value, nullptr); } -int M5PM1::digitalRead(uint8_t pin) { return digitalReadWithRes(pin, nullptr); } +void M5PM1::pinMode(uint8_t pin, uint8_t mode) +{ + pinModeWithRes(pin, mode, nullptr); +} +void M5PM1::digitalWrite(uint8_t pin, uint8_t value) +{ + digitalWriteWithRes(pin, value, nullptr); +} +int M5PM1::digitalRead(uint8_t pin) +{ + return digitalReadWithRes(pin, nullptr); +} // ============================ // 高级 GPIO 功能 // Advanced GPIO Functions // ============================ -m5pm1_err_t M5PM1::gpioSetFunc(m5pm1_gpio_num_t pin, m5pm1_gpio_func_t func) { +m5pm1_err_t M5PM1::gpioSetFunc(m5pm1_gpio_num_t pin, m5pm1_gpio_func_t func) +{ if (!_isValidPin(pin)) return M5PM1_ERR_INVALID_ARG; if (!_initialized) { M5PM1_LOG_E(TAG, "Not initialized"); @@ -1581,7 +1631,7 @@ m5pm1_err_t M5PM1::gpioSetFunc(m5pm1_gpio_num_t pin, m5pm1_gpio_func_t func) { } uint8_t regAddr = (pin < 4) ? M5PM1_REG_GPIO_FUNC0 : M5PM1_REG_GPIO_FUNC1; - uint8_t shift = (pin < 4) ? (pin * 2) : ((pin - 4) * 2); + uint8_t shift = (pin < 4) ? (pin * 2) : ((pin - 4) * 2); uint8_t regVal; if (!_readReg(regAddr, ®Val)) return M5PM1_ERR_I2C_COMM; @@ -1594,7 +1644,8 @@ m5pm1_err_t M5PM1::gpioSetFunc(m5pm1_gpio_num_t pin, m5pm1_gpio_func_t func) { return M5PM1_OK; } -m5pm1_err_t M5PM1::gpioSetMode(m5pm1_gpio_num_t pin, m5pm1_gpio_mode_t mode) { +m5pm1_err_t M5PM1::gpioSetMode(m5pm1_gpio_num_t pin, m5pm1_gpio_mode_t mode) +{ if (!_isValidPin(pin)) return M5PM1_ERR_INVALID_ARG; if (!_initialized) { M5PM1_LOG_E(TAG, "Not initialized"); @@ -1615,7 +1666,8 @@ m5pm1_err_t M5PM1::gpioSetMode(m5pm1_gpio_num_t pin, m5pm1_gpio_mode_t mode) { return M5PM1_OK; } -m5pm1_err_t M5PM1::gpioSetOutput(m5pm1_gpio_num_t pin, uint8_t value) { +m5pm1_err_t M5PM1::gpioSetOutput(m5pm1_gpio_num_t pin, uint8_t value) +{ if (!_isValidPin(pin)) return M5PM1_ERR_INVALID_ARG; if (!_initialized) { M5PM1_LOG_E(TAG, "Not initialized"); @@ -1636,7 +1688,8 @@ m5pm1_err_t M5PM1::gpioSetOutput(m5pm1_gpio_num_t pin, uint8_t value) { return M5PM1_OK; } -m5pm1_err_t M5PM1::gpioGetInput(m5pm1_gpio_num_t pin, uint8_t* value) { +m5pm1_err_t M5PM1::gpioGetInput(m5pm1_gpio_num_t pin, uint8_t* value) +{ if (!_isValidPin(pin)) return M5PM1_ERR_INVALID_ARG; if (value == nullptr) return M5PM1_ERR_INVALID_ARG; if (!_initialized) { @@ -1651,7 +1704,8 @@ m5pm1_err_t M5PM1::gpioGetInput(m5pm1_gpio_num_t pin, uint8_t* value) { return M5PM1_OK; } -m5pm1_err_t M5PM1::gpioSetPull(m5pm1_gpio_num_t pin, m5pm1_gpio_pull_t pull) { +m5pm1_err_t M5PM1::gpioSetPull(m5pm1_gpio_num_t pin, m5pm1_gpio_pull_t pull) +{ if (!_isValidPin(pin)) return M5PM1_ERR_INVALID_ARG; if (!_initialized) { M5PM1_LOG_E(TAG, "Not initialized"); @@ -1659,7 +1713,7 @@ m5pm1_err_t M5PM1::gpioSetPull(m5pm1_gpio_num_t pin, m5pm1_gpio_pull_t pull) { } uint8_t regAddr = (pin < 4) ? M5PM1_REG_GPIO_PUPD0 : M5PM1_REG_GPIO_PUPD1; - uint8_t shift = (pin < 4) ? (pin * 2) : ((pin - 4) * 2); + uint8_t shift = (pin < 4) ? (pin * 2) : ((pin - 4) * 2); uint8_t regVal; if (!_readReg(regAddr, ®Val)) return M5PM1_ERR_I2C_COMM; @@ -1672,7 +1726,8 @@ m5pm1_err_t M5PM1::gpioSetPull(m5pm1_gpio_num_t pin, m5pm1_gpio_pull_t pull) { return M5PM1_OK; } -m5pm1_err_t M5PM1::gpioSetDrive(m5pm1_gpio_num_t pin, m5pm1_gpio_drive_t drive) { +m5pm1_err_t M5PM1::gpioSetDrive(m5pm1_gpio_num_t pin, m5pm1_gpio_drive_t drive) +{ if (!_isValidPin(pin)) return M5PM1_ERR_INVALID_ARG; if (!_initialized) { M5PM1_LOG_E(TAG, "Not initialized"); @@ -1693,7 +1748,8 @@ m5pm1_err_t M5PM1::gpioSetDrive(m5pm1_gpio_num_t pin, m5pm1_gpio_drive_t drive) return M5PM1_OK; } -m5pm1_err_t M5PM1::gpioSetWakeEnable(m5pm1_gpio_num_t pin, bool enable) { +m5pm1_err_t M5PM1::gpioSetWakeEnable(m5pm1_gpio_num_t pin, bool enable) +{ if (!_isValidPin(pin)) return M5PM1_ERR_INVALID_ARG; if (!_initialized) { M5PM1_LOG_E(TAG, "Not initialized"); @@ -1745,7 +1801,8 @@ m5pm1_err_t M5PM1::gpioSetWakeEnable(m5pm1_gpio_num_t pin, bool enable) { return M5PM1_OK; } -m5pm1_err_t M5PM1::gpioSetWakeEdge(m5pm1_gpio_num_t pin, m5pm1_gpio_wake_edge_t edge) { +m5pm1_err_t M5PM1::gpioSetWakeEdge(m5pm1_gpio_num_t pin, m5pm1_gpio_wake_edge_t edge) +{ if (!_isValidPin(pin)) return M5PM1_ERR_INVALID_ARG; if (!_initialized) { M5PM1_LOG_E(TAG, "Not initialized"); @@ -1773,8 +1830,9 @@ m5pm1_err_t M5PM1::gpioSetWakeEdge(m5pm1_gpio_num_t pin, m5pm1_gpio_wake_edge_t return M5PM1_OK; } -m5pm1_err_t M5PM1::gpioSet(m5pm1_gpio_num_t pin, m5pm1_gpio_mode_t mode, - uint8_t value, m5pm1_gpio_pull_t pull, m5pm1_gpio_drive_t drive) { +m5pm1_err_t M5PM1::gpioSet(m5pm1_gpio_num_t pin, m5pm1_gpio_mode_t mode, uint8_t value, m5pm1_gpio_pull_t pull, + m5pm1_gpio_drive_t drive) +{ if (!_isValidPin(pin)) return M5PM1_ERR_INVALID_ARG; if (!_initialized) { M5PM1_LOG_E(TAG, "Not initialized"); @@ -1801,7 +1859,8 @@ m5pm1_err_t M5PM1::gpioSet(m5pm1_gpio_num_t pin, m5pm1_gpio_mode_t mode, return M5PM1_OK; } -m5pm1_err_t M5PM1::ledEnSetDrive(m5pm1_gpio_drive_t drive) { +m5pm1_err_t M5PM1::ledEnSetDrive(m5pm1_gpio_drive_t drive) +{ if (!_initialized) { M5PM1_LOG_E(TAG, "Not initialized"); return M5PM1_ERR_NOT_INIT; @@ -1820,7 +1879,8 @@ m5pm1_err_t M5PM1::ledEnSetDrive(m5pm1_gpio_drive_t drive) { return M5PM1_OK; } -m5pm1_err_t M5PM1::dumpPinStatus() { +m5pm1_err_t M5PM1::dumpPinStatus() +{ uint8_t mode, out, in, drv, pupd0, pupd1, func0, func1, wakeEn, wakeCfg; if (!_initialized) { @@ -1846,16 +1906,15 @@ m5pm1_err_t M5PM1::dumpPinStatus() { const char* funcNames[] = {"GPIO", "IRQ", "WAKE", "OTHER"}; const char* pullNames[] = {"NONE", "UP", "DOWN", "?"}; - const char* drvNames[] = {"PP", "OD"}; + const char* drvNames[] = {"PP", "OD"}; for (int i = 0; i < 5; i++) { uint8_t funcVal = (i < 4) ? ((func0 >> (i * 2)) & 0x03) : ((func1 >> 0) & 0x03); uint8_t pullVal = (i < 4) ? ((pupd0 >> (i * 2)) & 0x03) : ((pupd1 >> 0) & 0x03); uint8_t modeVal = (mode >> i) & 0x01; - uint8_t outVal = (out >> i) & 0x01; - uint8_t inVal = (in >> i) & 0x01; - M5PM1_LOG_I(TAG, "GPIO%d: %s %s %s OUT=%d IN=%d", - i, funcNames[funcVal], modeVal ? "OUT" : "IN", + uint8_t outVal = (out >> i) & 0x01; + uint8_t inVal = (in >> i) & 0x01; + M5PM1_LOG_I(TAG, "GPIO%d: %s %s %s OUT=%d IN=%d", i, funcNames[funcVal], modeVal ? "OUT" : "IN", pullNames[pullVal], outVal, inVal); } @@ -1865,7 +1924,8 @@ m5pm1_err_t M5PM1::dumpPinStatus() { return M5PM1_OK; } -m5pm1_err_t M5PM1::verifyPinConfig(bool enableLog) { +m5pm1_err_t M5PM1::verifyPinConfig(bool enableLog) +{ if (!_initialized) { M5PM1_LOG_E(TAG, "Not initialized"); return M5PM1_ERR_NOT_INIT; @@ -1967,11 +2027,13 @@ m5pm1_err_t M5PM1::verifyPinConfig(bool enableLog) { } // 检查 WAKE_EDGE - m5pm1_gpio_wake_edge_t actualWakeEdge = (wakeCfg & (1 << pin)) ? M5PM1_GPIO_WAKE_RISING : M5PM1_GPIO_WAKE_FALLING; + m5pm1_gpio_wake_edge_t actualWakeEdge = + (wakeCfg & (1 << pin)) ? M5PM1_GPIO_WAKE_RISING : M5PM1_GPIO_WAKE_FALLING; if (cached.wake_edge != actualWakeEdge) { hasError = true; if (enableLog) { - M5PM1_LOG_W(TAG, "GPIO%d WAKE_EDGE mismatch: cached=%d actual=%d", pin, cached.wake_edge, actualWakeEdge); + M5PM1_LOG_W(TAG, "GPIO%d WAKE_EDGE mismatch: cached=%d actual=%d", pin, cached.wake_edge, + actualWakeEdge); } } @@ -1980,7 +2042,8 @@ m5pm1_err_t M5PM1::verifyPinConfig(bool enableLog) { if (cached.power_hold != actualPowerHold) { hasError = true; if (enableLog) { - M5PM1_LOG_W(TAG, "GPIO%d POWER_HOLD mismatch: cached=%d actual=%d", pin, cached.power_hold, actualPowerHold); + M5PM1_LOG_W(TAG, "GPIO%d POWER_HOLD mismatch: cached=%d actual=%d", pin, cached.power_hold, + actualPowerHold); } } } @@ -1994,7 +2057,8 @@ m5pm1_err_t M5PM1::verifyPinConfig(bool enableLog) { return hasError ? M5PM1_ERR_VERIFY_FAILED : M5PM1_OK; } -m5pm1_err_t M5PM1::getPinStatus(m5pm1_gpio_num_t pin, m5pm1_pin_status_t* status) { +m5pm1_err_t M5PM1::getPinStatus(m5pm1_gpio_num_t pin, m5pm1_pin_status_t* status) +{ if (!_isValidPin(pin)) return M5PM1_ERR_INVALID_ARG; if (status == nullptr) return M5PM1_ERR_INVALID_ARG; @@ -2006,7 +2070,8 @@ m5pm1_err_t M5PM1::getPinStatus(m5pm1_gpio_num_t pin, m5pm1_pin_status_t* status return M5PM1_OK; } -const m5pm1_pin_status_t* M5PM1::getPinStatusArray() const { +const m5pm1_pin_status_t* M5PM1::getPinStatusArray() const +{ return _pinStatus; } @@ -2015,7 +2080,8 @@ const m5pm1_pin_status_t* M5PM1::getPinStatusArray() const { // Power Hold Functions // ============================ -m5pm1_err_t M5PM1::gpioSetPowerHold(m5pm1_gpio_num_t pin, bool enable) { +m5pm1_err_t M5PM1::gpioSetPowerHold(m5pm1_gpio_num_t pin, bool enable) +{ if (!_isValidPin(pin)) return M5PM1_ERR_INVALID_ARG; if (!_initialized) { M5PM1_LOG_E(TAG, "Not initialized"); @@ -2036,7 +2102,8 @@ m5pm1_err_t M5PM1::gpioSetPowerHold(m5pm1_gpio_num_t pin, bool enable) { return M5PM1_OK; } -m5pm1_err_t M5PM1::gpioGetPowerHold(m5pm1_gpio_num_t pin, bool* enable) { +m5pm1_err_t M5PM1::gpioGetPowerHold(m5pm1_gpio_num_t pin, bool* enable) +{ if (!_isValidPin(pin)) return M5PM1_ERR_INVALID_ARG; if (enable == nullptr) return M5PM1_ERR_INVALID_ARG; if (!_initialized) { @@ -2051,7 +2118,8 @@ m5pm1_err_t M5PM1::gpioGetPowerHold(m5pm1_gpio_num_t pin, bool* enable) { return M5PM1_OK; } -m5pm1_err_t M5PM1::ldoSetPowerHold(bool enable) { +m5pm1_err_t M5PM1::ldoSetPowerHold(bool enable) +{ if (!_initialized) { M5PM1_LOG_E(TAG, "Not initialized"); return M5PM1_ERR_NOT_INIT; @@ -2070,7 +2138,8 @@ m5pm1_err_t M5PM1::ldoSetPowerHold(bool enable) { return M5PM1_OK; } -m5pm1_err_t M5PM1::ldoGetPowerHold(bool* enable) { +m5pm1_err_t M5PM1::ldoGetPowerHold(bool* enable) +{ if (enable == nullptr) return M5PM1_ERR_INVALID_ARG; if (!_initialized) { M5PM1_LOG_E(TAG, "Not initialized"); @@ -2083,7 +2152,8 @@ m5pm1_err_t M5PM1::ldoGetPowerHold(bool* enable) { return M5PM1_OK; } -m5pm1_err_t M5PM1::dcdcSetPowerHold(bool enable) { +m5pm1_err_t M5PM1::dcdcSetPowerHold(bool enable) +{ if (!_initialized) { M5PM1_LOG_E(TAG, "Not initialized"); return M5PM1_ERR_NOT_INIT; @@ -2102,7 +2172,8 @@ m5pm1_err_t M5PM1::dcdcSetPowerHold(bool enable) { return M5PM1_OK; } -m5pm1_err_t M5PM1::dcdcGetPowerHold(bool* enable) { +m5pm1_err_t M5PM1::dcdcGetPowerHold(bool* enable) +{ if (enable == nullptr) return M5PM1_ERR_INVALID_ARG; if (!_initialized) { M5PM1_LOG_E(TAG, "Not initialized"); @@ -2120,7 +2191,8 @@ m5pm1_err_t M5PM1::dcdcGetPowerHold(bool* enable) { // ADC Functions // ============================ -m5pm1_err_t M5PM1::analogRead(m5pm1_adc_channel_t channel, uint16_t* value) { +m5pm1_err_t M5PM1::analogRead(m5pm1_adc_channel_t channel, uint16_t* value) +{ if (value == nullptr) { M5PM1_LOG_E(TAG, "analogRead value is null"); return M5PM1_ERR_INVALID_ARG; @@ -2145,15 +2217,15 @@ m5pm1_err_t M5PM1::analogRead(m5pm1_adc_channel_t channel, uint16_t* value) { // 等待转换完成 // Wait for conversion completion uint8_t reg = 0; - int tries = 0; + int tries = 0; do { - M5PM1_DELAY_MS(1); + M5PM1_DELAY_MS(10); // 增加间隔 Increase interval if (!_readReg(M5PM1_REG_ADC_CTRL, ®)) { M5PM1_LOG_E(TAG, "Failed to read ADC_CTRL register"); return M5PM1_ERR_I2C_COMM; } tries++; - } while ((reg & 0x01) && tries < 20); + } while ((reg & 0x01) && tries < 50); // 最多等待 500ms / Max wait 500ms if (reg & 0x01) { M5PM1_LOG_E(TAG, "ADC conversion timeout on channel %d", channel); @@ -2165,11 +2237,16 @@ m5pm1_err_t M5PM1::analogRead(m5pm1_adc_channel_t channel, uint16_t* value) { return M5PM1_ERR_I2C_COMM; } + // 屏蔽高4位,只保留12位ADC数据 + // Mask high 4 bits, keep only 12-bit ADC data + *value &= 0x0FFF; + _autoSnapshotUpdate(M5PM1_SNAPSHOT_DOMAIN_ADC); return M5PM1_OK; } -m5pm1_err_t M5PM1::isAdcBusy(bool* busy) { +m5pm1_err_t M5PM1::isAdcBusy(bool* busy) +{ if (busy == nullptr) { M5PM1_LOG_E(TAG, "isAdcBusy busy is null"); return M5PM1_ERR_INVALID_ARG; @@ -2189,7 +2266,8 @@ m5pm1_err_t M5PM1::isAdcBusy(bool* busy) { return M5PM1_OK; } -m5pm1_err_t M5PM1::disableAdc() { +m5pm1_err_t M5PM1::disableAdc() +{ if (!_initialized) { M5PM1_LOG_E(TAG, "Not initialized"); return M5PM1_ERR_NOT_INIT; @@ -2227,7 +2305,8 @@ m5pm1_err_t M5PM1::disableAdc() { // Temperature Sensor // ============================ -m5pm1_err_t M5PM1::readTemperature(uint16_t* temperature) { +m5pm1_err_t M5PM1::readTemperature(uint16_t* temperature) +{ return analogRead(M5PM1_ADC_CH_TEMP, temperature); } @@ -2236,7 +2315,8 @@ m5pm1_err_t M5PM1::readTemperature(uint16_t* temperature) { // PWM Functions // ============================ -m5pm1_err_t M5PM1::setPwmFrequency(uint16_t frequency) { +m5pm1_err_t M5PM1::setPwmFrequency(uint16_t frequency) +{ if (!_initialized) { M5PM1_LOG_E(TAG, "Not initialized"); return M5PM1_ERR_NOT_INIT; @@ -2260,8 +2340,7 @@ m5pm1_err_t M5PM1::setPwmFrequency(uint16_t frequency) { // 验证关键位是否匹配 // Verify critical bits match if (actualFreq != frequency) { - M5PM1_LOG_E(TAG, "PWM frequency verification failed: expected=%d, actual=%d", - frequency, actualFreq); + M5PM1_LOG_E(TAG, "PWM frequency verification failed: expected=%d, actual=%d", frequency, actualFreq); return M5PM1_FAIL; } @@ -2271,7 +2350,8 @@ m5pm1_err_t M5PM1::setPwmFrequency(uint16_t frequency) { return M5PM1_OK; } -m5pm1_err_t M5PM1::getPwmFrequency(uint16_t* frequency) { +m5pm1_err_t M5PM1::getPwmFrequency(uint16_t* frequency) +{ if (frequency == nullptr) { M5PM1_LOG_E(TAG, "getPwmFrequency frequency is null"); return M5PM1_ERR_INVALID_ARG; @@ -2290,8 +2370,8 @@ m5pm1_err_t M5PM1::getPwmFrequency(uint16_t* frequency) { return M5PM1_OK; } -m5pm1_err_t M5PM1::setPwmDuty(m5pm1_pwm_channel_t channel, uint8_t duty, - bool polarity, bool enable) { +m5pm1_err_t M5PM1::setPwmDuty(m5pm1_pwm_channel_t channel, uint8_t duty, bool polarity, bool enable) +{ if (channel > M5PM1_PWM_CH_1 || duty > 100) { M5PM1_LOG_E(TAG, "Invalid PWM channel or duty: ch=%d duty=%d", channel, duty); return M5PM1_ERR_INVALID_ARG; @@ -2307,8 +2387,8 @@ m5pm1_err_t M5PM1::setPwmDuty(m5pm1_pwm_channel_t channel, uint8_t duty, return setPwmDuty12bit(channel, duty12, polarity, enable); } -m5pm1_err_t M5PM1::getPwmDuty(m5pm1_pwm_channel_t channel, uint8_t* duty, - bool* polarity, bool* enable) { +m5pm1_err_t M5PM1::getPwmDuty(m5pm1_pwm_channel_t channel, uint8_t* duty, bool* polarity, bool* enable) +{ if (channel > M5PM1_PWM_CH_1) { M5PM1_LOG_E(TAG, "Invalid PWM channel: %d", channel); return M5PM1_ERR_INVALID_ARG; @@ -2322,7 +2402,7 @@ m5pm1_err_t M5PM1::getPwmDuty(m5pm1_pwm_channel_t channel, uint8_t* duty, return M5PM1_ERR_NOT_INIT; } - uint8_t regL = (channel == M5PM1_PWM_CH_0) ? M5PM1_REG_PWM0_L : M5PM1_REG_PWM1_L; + uint8_t regL = (channel == M5PM1_PWM_CH_0) ? M5PM1_REG_PWM0_L : M5PM1_REG_PWM1_L; uint16_t data = 0; if (!_readReg16(regL, &data)) { M5PM1_LOG_E(TAG, "Failed to read PWM channel %d duty register", channel); @@ -2330,20 +2410,20 @@ m5pm1_err_t M5PM1::getPwmDuty(m5pm1_pwm_channel_t channel, uint8_t* duty, } uint16_t duty12 = data & 0x0FFF; - *duty = (uint8_t)((duty12 * 100) / 0x0FFF); - *polarity = (data & ((uint16_t)0x20 << 8)) != 0; - *enable = (data & ((uint16_t)0x10 << 8)) != 0; + *duty = (uint8_t)((duty12 * 100) / 0x0FFF); + *polarity = (data & ((uint16_t)0x20 << 8)) != 0; + *enable = (data & ((uint16_t)0x10 << 8)) != 0; - _pwmStates[channel].duty12 = duty12; + _pwmStates[channel].duty12 = duty12; _pwmStates[channel].polarity = *polarity; - _pwmStates[channel].enabled = *enable; - _pwmStatesValid = true; + _pwmStates[channel].enabled = *enable; + _pwmStatesValid = true; return M5PM1_OK; } -m5pm1_err_t M5PM1::setPwmDuty12bit(m5pm1_pwm_channel_t channel, uint16_t duty12, - bool polarity, bool enable) { +m5pm1_err_t M5PM1::setPwmDuty12bit(m5pm1_pwm_channel_t channel, uint16_t duty12, bool polarity, bool enable) +{ if (channel > M5PM1_PWM_CH_1 || duty12 > 0x0FFF) { M5PM1_LOG_E(TAG, "Invalid PWM channel or duty12: ch=%d duty12=%d", channel, duty12); return M5PM1_ERR_INVALID_ARG; @@ -2353,7 +2433,7 @@ m5pm1_err_t M5PM1::setPwmDuty12bit(m5pm1_pwm_channel_t channel, uint16_t duty12, return M5PM1_ERR_NOT_INIT; } - uint8_t regL = (channel == M5PM1_PWM_CH_0) ? M5PM1_REG_PWM0_L : M5PM1_REG_PWM1_L; + uint8_t regL = (channel == M5PM1_PWM_CH_0) ? M5PM1_REG_PWM0_L : M5PM1_REG_PWM1_L; uint8_t dataL = (uint8_t)(duty12 & 0xFF); uint8_t dataH = (uint8_t)((duty12 >> 8) & 0x0F); if (polarity) dataH |= 0x20; @@ -2379,28 +2459,28 @@ m5pm1_err_t M5PM1::setPwmDuty12bit(m5pm1_pwm_channel_t channel, uint16_t duty12, // 验证关键位是否匹配 // Verify critical bits match uint16_t actualDuty12 = actualData & 0x0FFF; - bool actualPolarity = (actualData & ((uint16_t)0x20 << 8)) != 0; - bool actualEnable = (actualData & ((uint16_t)0x10 << 8)) != 0; + bool actualPolarity = (actualData & ((uint16_t)0x20 << 8)) != 0; + bool actualEnable = (actualData & ((uint16_t)0x10 << 8)) != 0; if (actualDuty12 != duty12 || actualPolarity != polarity || actualEnable != enable) { - M5PM1_LOG_E(TAG, "PWM channel %d verification failed: duty=%d/%d, pol=%d/%d, en=%d/%d", - channel, duty12, actualDuty12, polarity, actualPolarity, enable, actualEnable); + M5PM1_LOG_E(TAG, "PWM channel %d verification failed: duty=%d/%d, pol=%d/%d, en=%d/%d", channel, duty12, + actualDuty12, polarity, actualPolarity, enable, actualEnable); return M5PM1_FAIL; } - _pwmStates[channel].duty12 = duty12; + _pwmStates[channel].duty12 = duty12; _pwmStates[channel].polarity = polarity; - _pwmStates[channel].enabled = enable; - _pwmStatesValid = true; + _pwmStates[channel].enabled = enable; + _pwmStatesValid = true; _autoSnapshotUpdate(M5PM1_SNAPSHOT_DOMAIN_PWM); - M5PM1_LOG_I(TAG, "PWM channel %d set and verified: duty=%d, pol=%d, en=%d", - channel, duty12, polarity, enable); + M5PM1_LOG_I(TAG, "PWM channel %d set and verified: duty=%d, pol=%d, en=%d", channel, duty12, polarity, enable); return M5PM1_OK; } -m5pm1_err_t M5PM1::setPwmConfig(m5pm1_pwm_channel_t channel, bool enable, bool polarity, - uint16_t frequency, uint16_t duty12) { +m5pm1_err_t M5PM1::setPwmConfig(m5pm1_pwm_channel_t channel, bool enable, bool polarity, uint16_t frequency, + uint16_t duty12) +{ if (channel > M5PM1_PWM_CH_1 || duty12 > 0x0FFF) { M5PM1_LOG_E(TAG, "Invalid PWM config: ch=%d duty12=%d", channel, duty12); return M5PM1_ERR_INVALID_ARG; @@ -2422,11 +2502,9 @@ m5pm1_err_t M5PM1::setPwmConfig(m5pm1_pwm_channel_t channel, bool enable, bool p } if (_pwmStatesValid && _pwmFrequency != frequency) { - m5pm1_pwm_channel_t other = - (channel == M5PM1_PWM_CH_0) ? M5PM1_PWM_CH_1 : M5PM1_PWM_CH_0; + m5pm1_pwm_channel_t other = (channel == M5PM1_PWM_CH_0) ? M5PM1_PWM_CH_1 : M5PM1_PWM_CH_0; if (_pwmStates[other].enabled) { - M5PM1_LOG_W(TAG, "PWM frequency change affects other channel: %d -> %d", - _pwmFrequency, frequency); + M5PM1_LOG_W(TAG, "PWM frequency change affects other channel: %d -> %d", _pwmFrequency, frequency); } } @@ -2435,8 +2513,8 @@ m5pm1_err_t M5PM1::setPwmConfig(m5pm1_pwm_channel_t channel, bool enable, bool p return setPwmFrequency(frequency); } -m5pm1_err_t M5PM1::getPwmDuty12bit(m5pm1_pwm_channel_t channel, uint16_t* duty12, - bool* polarity, bool* enable) { +m5pm1_err_t M5PM1::getPwmDuty12bit(m5pm1_pwm_channel_t channel, uint16_t* duty12, bool* polarity, bool* enable) +{ if (channel > M5PM1_PWM_CH_1 || duty12 == nullptr || polarity == nullptr || enable == nullptr) { return M5PM1_ERR_INVALID_ARG; } @@ -2445,26 +2523,27 @@ m5pm1_err_t M5PM1::getPwmDuty12bit(m5pm1_pwm_channel_t channel, uint16_t* duty12 return M5PM1_ERR_NOT_INIT; } - uint8_t regL = (channel == M5PM1_PWM_CH_0) ? M5PM1_REG_PWM0_L : M5PM1_REG_PWM1_L; + uint8_t regL = (channel == M5PM1_PWM_CH_0) ? M5PM1_REG_PWM0_L : M5PM1_REG_PWM1_L; uint16_t data = 0; if (!_readReg16(regL, &data)) { M5PM1_LOG_E(TAG, "Failed to read PWM channel %d duty register", channel); return M5PM1_ERR_I2C_COMM; } - *duty12 = data & 0x0FFF; + *duty12 = data & 0x0FFF; *polarity = (data & ((uint16_t)0x20 << 8)) != 0; - *enable = (data & ((uint16_t)0x10 << 8)) != 0; + *enable = (data & ((uint16_t)0x10 << 8)) != 0; - _pwmStates[channel].duty12 = *duty12; + _pwmStates[channel].duty12 = *duty12; _pwmStates[channel].polarity = *polarity; - _pwmStates[channel].enabled = *enable; - _pwmStatesValid = true; + _pwmStates[channel].enabled = *enable; + _pwmStatesValid = true; return M5PM1_OK; } -m5pm1_err_t M5PM1::analogWrite(m5pm1_pwm_channel_t channel, uint8_t value) { +m5pm1_err_t M5PM1::analogWrite(m5pm1_pwm_channel_t channel, uint8_t value) +{ if (channel > M5PM1_PWM_CH_1) { M5PM1_LOG_E(TAG, "Invalid channel: ch=%d", channel); return M5PM1_ERR_INVALID_ARG; @@ -2491,7 +2570,8 @@ m5pm1_err_t M5PM1::analogWrite(m5pm1_pwm_channel_t channel, uint8_t value) { // Voltage Reading Functions // ============================ -m5pm1_err_t M5PM1::readVref(uint16_t* mv) { +m5pm1_err_t M5PM1::readVref(uint16_t* mv) +{ if (mv == nullptr) { M5PM1_LOG_E(TAG, "readVref mv is null"); return M5PM1_ERR_INVALID_ARG; @@ -2507,11 +2587,13 @@ m5pm1_err_t M5PM1::readVref(uint16_t* mv) { return M5PM1_OK; } -m5pm1_err_t M5PM1::getRefVoltage(uint16_t* mv) { +m5pm1_err_t M5PM1::getRefVoltage(uint16_t* mv) +{ return readVref(mv); } -m5pm1_err_t M5PM1::readVbat(uint16_t* mv) { +m5pm1_err_t M5PM1::readVbat(uint16_t* mv) +{ if (mv == nullptr) return M5PM1_ERR_INVALID_ARG; if (!_initialized) { M5PM1_LOG_E(TAG, "Not initialized"); @@ -2521,7 +2603,8 @@ m5pm1_err_t M5PM1::readVbat(uint16_t* mv) { return M5PM1_OK; } -m5pm1_err_t M5PM1::readVin(uint16_t* mv) { +m5pm1_err_t M5PM1::readVin(uint16_t* mv) +{ if (mv == nullptr) return M5PM1_ERR_INVALID_ARG; if (!_initialized) { M5PM1_LOG_E(TAG, "Not initialized"); @@ -2531,7 +2614,8 @@ m5pm1_err_t M5PM1::readVin(uint16_t* mv) { return M5PM1_OK; } -m5pm1_err_t M5PM1::read5VInOut(uint16_t* mv) { +m5pm1_err_t M5PM1::read5VInOut(uint16_t* mv) +{ if (mv == nullptr) return M5PM1_ERR_INVALID_ARG; if (!_initialized) { M5PM1_LOG_E(TAG, "Not initialized"); @@ -2546,7 +2630,8 @@ m5pm1_err_t M5PM1::read5VInOut(uint16_t* mv) { // Power Management // ============================ -m5pm1_err_t M5PM1::getPowerSource(m5pm1_pwr_src_t* src) { +m5pm1_err_t M5PM1::getPowerSource(m5pm1_pwr_src_t* src) +{ if (src == nullptr) return M5PM1_ERR_INVALID_ARG; if (!_initialized) { M5PM1_LOG_E(TAG, "Not initialized"); @@ -2562,7 +2647,8 @@ m5pm1_err_t M5PM1::getPowerSource(m5pm1_pwr_src_t* src) { // 唤醒源读取 // Wake Source Read // ============================ -m5pm1_err_t M5PM1::getWakeSource(uint8_t* src, m5pm1_clean_type_t cleanType) { +m5pm1_err_t M5PM1::getWakeSource(uint8_t* src, m5pm1_clean_type_t cleanType) +{ if (src == nullptr) return M5PM1_ERR_INVALID_ARG; if (!_initialized) { M5PM1_LOG_E(TAG, "Not initialized"); @@ -2585,7 +2671,8 @@ m5pm1_err_t M5PM1::getWakeSource(uint8_t* src, m5pm1_clean_type_t cleanType) { return M5PM1_OK; } -m5pm1_err_t M5PM1::clearWakeSource(uint8_t mask) { +m5pm1_err_t M5PM1::clearWakeSource(uint8_t mask) +{ if (!_initialized) { M5PM1_LOG_E(TAG, "Not initialized"); return M5PM1_ERR_NOT_INIT; @@ -2605,7 +2692,8 @@ m5pm1_err_t M5PM1::clearWakeSource(uint8_t mask) { return M5PM1_OK; } -m5pm1_err_t M5PM1::setPowerConfig(uint8_t mask, uint8_t value) { +m5pm1_err_t M5PM1::setPowerConfig(uint8_t mask, uint8_t value) +{ if (!_initialized) { M5PM1_LOG_E(TAG, "Not initialized"); return M5PM1_ERR_NOT_INIT; @@ -2618,7 +2706,8 @@ m5pm1_err_t M5PM1::setPowerConfig(uint8_t mask, uint8_t value) { return M5PM1_OK; } -m5pm1_err_t M5PM1::getPowerConfig(uint8_t* config) { +m5pm1_err_t M5PM1::getPowerConfig(uint8_t* config) +{ if (config == nullptr) return M5PM1_ERR_INVALID_ARG; if (!_initialized) { M5PM1_LOG_E(TAG, "Not initialized"); @@ -2628,7 +2717,8 @@ m5pm1_err_t M5PM1::getPowerConfig(uint8_t* config) { return M5PM1_OK; } -m5pm1_err_t M5PM1::clearPowerConfig(uint8_t mask) { +m5pm1_err_t M5PM1::clearPowerConfig(uint8_t mask) +{ if (!_initialized) { M5PM1_LOG_E(TAG, "Not initialized"); return M5PM1_ERR_NOT_INIT; @@ -2641,23 +2731,28 @@ m5pm1_err_t M5PM1::clearPowerConfig(uint8_t mask) { return M5PM1_OK; } -m5pm1_err_t M5PM1::setChargeEnable(bool enable) { +m5pm1_err_t M5PM1::setChargeEnable(bool enable) +{ return setPowerConfig(M5PM1_PWR_CFG_CHG_EN, enable ? M5PM1_PWR_CFG_CHG_EN : 0); } -m5pm1_err_t M5PM1::setDcdcEnable(bool enable) { +m5pm1_err_t M5PM1::setDcdcEnable(bool enable) +{ return setPowerConfig(M5PM1_PWR_CFG_DCDC_EN, enable ? M5PM1_PWR_CFG_DCDC_EN : 0); } -m5pm1_err_t M5PM1::setLdoEnable(bool enable) { +m5pm1_err_t M5PM1::setLdoEnable(bool enable) +{ return setPowerConfig(M5PM1_PWR_CFG_LDO_EN, enable ? M5PM1_PWR_CFG_LDO_EN : 0); } -m5pm1_err_t M5PM1::set5VInOutEnable(bool enable) { +m5pm1_err_t M5PM1::set5VInOutEnable(bool enable) +{ return setPowerConfig(M5PM1_PWR_CFG_5V_INOUT, enable ? M5PM1_PWR_CFG_5V_INOUT : 0); } -m5pm1_err_t M5PM1::setLedEnLevel(bool level) { +m5pm1_err_t M5PM1::setLedEnLevel(bool level) +{ return setPowerConfig(M5PM1_PWR_CFG_LED_CTRL, level ? M5PM1_PWR_CFG_LED_CTRL : 0); } @@ -2666,7 +2761,8 @@ m5pm1_err_t M5PM1::setLedEnLevel(bool level) { // Battery Functions // ============================ -m5pm1_err_t M5PM1::setBatteryLvp(uint16_t mv) { +m5pm1_err_t M5PM1::setBatteryLvp(uint16_t mv) +{ // 检查初始化状态 / Check if initialized if (!_initialized) { M5PM1_LOG_E(TAG, "Not initialized"); @@ -2693,7 +2789,8 @@ m5pm1_err_t M5PM1::setBatteryLvp(uint16_t mv) { // Watchdog Functions // ============================ -m5pm1_err_t M5PM1::wdtSet(uint8_t timeout_sec) { +m5pm1_err_t M5PM1::wdtSet(uint8_t timeout_sec) +{ if (!_initialized) { M5PM1_LOG_E(TAG, "Not initialized"); return M5PM1_ERR_NOT_INIT; @@ -2702,7 +2799,8 @@ m5pm1_err_t M5PM1::wdtSet(uint8_t timeout_sec) { return M5PM1_OK; } -m5pm1_err_t M5PM1::wdtFeed() { +m5pm1_err_t M5PM1::wdtFeed() +{ if (!_initialized) { M5PM1_LOG_E(TAG, "Not initialized"); return M5PM1_ERR_NOT_INIT; @@ -2711,7 +2809,8 @@ m5pm1_err_t M5PM1::wdtFeed() { return M5PM1_OK; } -m5pm1_err_t M5PM1::wdtGetCount(uint8_t* count) { +m5pm1_err_t M5PM1::wdtGetCount(uint8_t* count) +{ if (count == nullptr) return M5PM1_ERR_INVALID_ARG; if (!_initialized) { M5PM1_LOG_E(TAG, "Not initialized"); @@ -2726,7 +2825,8 @@ m5pm1_err_t M5PM1::wdtGetCount(uint8_t* count) { // Timer Functions // ============================ -m5pm1_err_t M5PM1::timerSet(uint32_t seconds, m5pm1_tim_action_t action) { +m5pm1_err_t M5PM1::timerSet(uint32_t seconds, m5pm1_tim_action_t action) +{ // 检查初始化状态 / Check if initialized if (!_initialized) { M5PM1_LOG_E(TAG, "Not initialized"); @@ -2760,7 +2860,8 @@ m5pm1_err_t M5PM1::timerSet(uint32_t seconds, m5pm1_tim_action_t action) { return M5PM1_OK; } -m5pm1_err_t M5PM1::timerClear() { +m5pm1_err_t M5PM1::timerClear() +{ if (!_initialized) { M5PM1_LOG_E(TAG, "Not initialized"); return M5PM1_ERR_NOT_INIT; @@ -2781,7 +2882,8 @@ m5pm1_err_t M5PM1::timerClear() { // Button Functions // ============================ -m5pm1_err_t M5PM1::btnSetConfig(m5pm1_btn_type_t type, m5pm1_btn_delay_t delay) { +m5pm1_err_t M5PM1::btnSetConfig(m5pm1_btn_type_t type, m5pm1_btn_delay_t delay) +{ // 检查初始化状态 / Check if initialized if (!_initialized) { M5PM1_LOG_E(TAG, "Not initialized"); @@ -2824,7 +2926,8 @@ m5pm1_err_t M5PM1::btnSetConfig(m5pm1_btn_type_t type, m5pm1_btn_delay_t delay) return M5PM1_OK; } -m5pm1_err_t M5PM1::btnGetState(bool* pressed) { +m5pm1_err_t M5PM1::btnGetState(bool* pressed) +{ if (pressed == nullptr) return M5PM1_ERR_INVALID_ARG; if (!_initialized) { M5PM1_LOG_E(TAG, "Not initialized"); @@ -2840,7 +2943,8 @@ m5pm1_err_t M5PM1::btnGetState(bool* pressed) { return M5PM1_OK; } -m5pm1_err_t M5PM1::btnGetFlag(bool* wasPressed) { +m5pm1_err_t M5PM1::btnGetFlag(bool* wasPressed) +{ if (wasPressed == nullptr) return M5PM1_ERR_INVALID_ARG; if (!_initialized) { M5PM1_LOG_E(TAG, "Not initialized"); @@ -2850,19 +2954,20 @@ m5pm1_err_t M5PM1::btnGetFlag(bool* wasPressed) { // 使用内部函数读取寄存器并更新 BTN_FLAG 缓存 // Use internal function to read register and update BTN_FLAG cache if (!_readBtnStatus(&val)) return M5PM1_ERR_I2C_COMM; - + // 检查 BTN_FLAG 是否被置位(无论是本次读取还是之前缓存的) // Check if BTN_FLAG was set (either from this read or cached from previous reads) *wasPressed = _btnFlagCache; - + // 报告后清除缓存(消耗该标志) // Clear cache after reporting (consume the flag) _btnFlagCache = false; - + return M5PM1_OK; } -m5pm1_err_t M5PM1::setSingleResetDisable(bool disable) { +m5pm1_err_t M5PM1::setSingleResetDisable(bool disable) +{ if (!_initialized) { M5PM1_LOG_E(TAG, "Not initialized"); return M5PM1_ERR_NOT_INIT; @@ -2884,7 +2989,8 @@ m5pm1_err_t M5PM1::setSingleResetDisable(bool disable) { return M5PM1_OK; } -m5pm1_err_t M5PM1::getSingleResetDisable(bool* disabled) { +m5pm1_err_t M5PM1::getSingleResetDisable(bool* disabled) +{ if (disabled == nullptr) { M5PM1_LOG_E(TAG, "getSingleResetDisable disabled is null"); return M5PM1_ERR_INVALID_ARG; @@ -2899,7 +3005,8 @@ m5pm1_err_t M5PM1::getSingleResetDisable(bool* disabled) { return M5PM1_OK; } -m5pm1_err_t M5PM1::setDoubleOffDisable(bool disable) { +m5pm1_err_t M5PM1::setDoubleOffDisable(bool disable) +{ if (!_initialized) { M5PM1_LOG_E(TAG, "Not initialized"); return M5PM1_ERR_NOT_INIT; @@ -2921,7 +3028,8 @@ m5pm1_err_t M5PM1::setDoubleOffDisable(bool disable) { return M5PM1_OK; } -m5pm1_err_t M5PM1::getDoubleOffDisable(bool* disabled) { +m5pm1_err_t M5PM1::getDoubleOffDisable(bool* disabled) +{ if (disabled == nullptr) { M5PM1_LOG_E(TAG, "getDoubleOffDisable disabled is null"); return M5PM1_ERR_INVALID_ARG; @@ -2941,7 +3049,8 @@ m5pm1_err_t M5PM1::getDoubleOffDisable(bool* disabled) { // IRQ Functions // ============================ -m5pm1_err_t M5PM1::irqGetGpioStatus(uint8_t* status, m5pm1_clean_type_t cleanType) { +m5pm1_err_t M5PM1::irqGetGpioStatus(uint8_t* status, m5pm1_clean_type_t cleanType) +{ if (status == nullptr) { M5PM1_LOG_E(TAG, "irqGetGpioStatus status is null"); return M5PM1_ERR_INVALID_ARG; @@ -2967,7 +3076,8 @@ m5pm1_err_t M5PM1::irqGetGpioStatus(uint8_t* status, m5pm1_clean_type_t cleanTyp return M5PM1_OK; } -m5pm1_err_t M5PM1::irqClearGpio(uint8_t mask) { +m5pm1_err_t M5PM1::irqClearGpio(uint8_t mask) +{ if (!_initialized) { M5PM1_LOG_E(TAG, "Not initialized"); return M5PM1_ERR_NOT_INIT; @@ -2988,7 +3098,8 @@ m5pm1_err_t M5PM1::irqClearGpio(uint8_t mask) { return M5PM1_OK; } -m5pm1_err_t M5PM1::irqGetSysStatus(uint8_t* status, m5pm1_clean_type_t cleanType) { +m5pm1_err_t M5PM1::irqGetSysStatus(uint8_t* status, m5pm1_clean_type_t cleanType) +{ if (status == nullptr) { M5PM1_LOG_E(TAG, "irqGetSysStatus status is null"); return M5PM1_ERR_INVALID_ARG; @@ -3014,7 +3125,8 @@ m5pm1_err_t M5PM1::irqGetSysStatus(uint8_t* status, m5pm1_clean_type_t cleanType return M5PM1_OK; } -m5pm1_err_t M5PM1::irqClearSys(uint8_t mask) { +m5pm1_err_t M5PM1::irqClearSys(uint8_t mask) +{ if (!_initialized) { M5PM1_LOG_E(TAG, "Not initialized"); return M5PM1_ERR_NOT_INIT; @@ -3035,7 +3147,8 @@ m5pm1_err_t M5PM1::irqClearSys(uint8_t mask) { return M5PM1_OK; } -m5pm1_err_t M5PM1::irqGetBtnStatus(uint8_t* status, m5pm1_clean_type_t cleanType) { +m5pm1_err_t M5PM1::irqGetBtnStatus(uint8_t* status, m5pm1_clean_type_t cleanType) +{ if (status == nullptr) { M5PM1_LOG_E(TAG, "irqGetBtnStatus status is null"); return M5PM1_ERR_INVALID_ARG; @@ -3061,7 +3174,8 @@ m5pm1_err_t M5PM1::irqGetBtnStatus(uint8_t* status, m5pm1_clean_type_t cleanType return M5PM1_OK; } -m5pm1_err_t M5PM1::irqClearBtn(uint8_t mask) { +m5pm1_err_t M5PM1::irqClearBtn(uint8_t mask) +{ if (!_initialized) { M5PM1_LOG_E(TAG, "Not initialized"); return M5PM1_ERR_NOT_INIT; @@ -3087,8 +3201,8 @@ m5pm1_err_t M5PM1::irqClearBtn(uint8_t mask) { // IRQ Status Read (Enum Return, User-Friendly) // ============================ -m5pm1_err_t M5PM1::irqGetGpioStatusEnum(m5pm1_irq_gpio_t* gpio_num, - m5pm1_clean_type_t cleanType) { +m5pm1_err_t M5PM1::irqGetGpioStatusEnum(m5pm1_irq_gpio_t* gpio_num, m5pm1_clean_type_t cleanType) +{ // 参数验证 // Parameter validation if (gpio_num == nullptr) { @@ -3138,8 +3252,8 @@ m5pm1_err_t M5PM1::irqGetGpioStatusEnum(m5pm1_irq_gpio_t* gpio_num, return M5PM1_OK; } -m5pm1_err_t M5PM1::irqGetSysStatusEnum(m5pm1_irq_sys_t* sys_irq, - m5pm1_clean_type_t cleanType) { +m5pm1_err_t M5PM1::irqGetSysStatusEnum(m5pm1_irq_sys_t* sys_irq, m5pm1_clean_type_t cleanType) +{ // 参数验证 // Parameter validation if (sys_irq == nullptr) { @@ -3189,8 +3303,8 @@ m5pm1_err_t M5PM1::irqGetSysStatusEnum(m5pm1_irq_sys_t* sys_irq, return M5PM1_OK; } -m5pm1_err_t M5PM1::irqGetBtnStatusEnum(m5pm1_btn_irq_t* btn_irq, - m5pm1_clean_type_t cleanType) { +m5pm1_err_t M5PM1::irqGetBtnStatusEnum(m5pm1_btn_irq_t* btn_irq, m5pm1_clean_type_t cleanType) +{ // 参数验证 // Parameter validation if (btn_irq == nullptr) { @@ -3240,8 +3354,8 @@ m5pm1_err_t M5PM1::irqGetBtnStatusEnum(m5pm1_btn_irq_t* btn_irq, return M5PM1_OK; } - -m5pm1_err_t M5PM1::irqSetGpioMask(m5pm1_gpio_num_t pin, m5pm1_irq_mask_ctrl_t mask) { +m5pm1_err_t M5PM1::irqSetGpioMask(m5pm1_gpio_num_t pin, m5pm1_irq_mask_ctrl_t mask) +{ if (!_isValidPin(pin)) return M5PM1_ERR_INVALID_ARG; if (!_initialized) { M5PM1_LOG_E(TAG, "Not initialized"); @@ -3265,7 +3379,8 @@ m5pm1_err_t M5PM1::irqSetGpioMask(m5pm1_gpio_num_t pin, m5pm1_irq_mask_ctrl_t ma return M5PM1_OK; } -m5pm1_err_t M5PM1::irqGetGpioMask(m5pm1_gpio_num_t pin, m5pm1_irq_mask_ctrl_t* mask) { +m5pm1_err_t M5PM1::irqGetGpioMask(m5pm1_gpio_num_t pin, m5pm1_irq_mask_ctrl_t* mask) +{ if (mask == nullptr) return M5PM1_ERR_INVALID_ARG; if (!_isValidPin(pin)) return M5PM1_ERR_INVALID_ARG; if (!_initialized) { @@ -3280,7 +3395,8 @@ m5pm1_err_t M5PM1::irqGetGpioMask(m5pm1_gpio_num_t pin, m5pm1_irq_mask_ctrl_t* m return M5PM1_OK; } -m5pm1_err_t M5PM1::irqSetGpioMaskAll(uint8_t mask) { +m5pm1_err_t M5PM1::irqSetGpioMaskAll(uint8_t mask) +{ if (!_initialized) { M5PM1_LOG_E(TAG, "Not initialized"); return M5PM1_ERR_NOT_INIT; @@ -3293,7 +3409,8 @@ m5pm1_err_t M5PM1::irqSetGpioMaskAll(uint8_t mask) { return M5PM1_OK; } -m5pm1_err_t M5PM1::irqGetGpioMaskAll(uint8_t* mask) { +m5pm1_err_t M5PM1::irqGetGpioMaskAll(uint8_t* mask) +{ if (mask == nullptr) return M5PM1_ERR_INVALID_ARG; if (!_initialized) { M5PM1_LOG_E(TAG, "Not initialized"); @@ -3303,7 +3420,8 @@ m5pm1_err_t M5PM1::irqGetGpioMaskAll(uint8_t* mask) { return M5PM1_OK; } -m5pm1_err_t M5PM1::irqSetSysMask(uint8_t event, m5pm1_irq_mask_ctrl_t mask) { +m5pm1_err_t M5PM1::irqSetSysMask(uint8_t event, m5pm1_irq_mask_ctrl_t mask) +{ if (event > 5) return M5PM1_ERR_INVALID_ARG; if (!_initialized) { M5PM1_LOG_E(TAG, "Not initialized"); @@ -3327,7 +3445,8 @@ m5pm1_err_t M5PM1::irqSetSysMask(uint8_t event, m5pm1_irq_mask_ctrl_t mask) { return M5PM1_OK; } -m5pm1_err_t M5PM1::irqGetSysMask(uint8_t event, m5pm1_irq_mask_ctrl_t* mask) { +m5pm1_err_t M5PM1::irqGetSysMask(uint8_t event, m5pm1_irq_mask_ctrl_t* mask) +{ if (mask == nullptr) return M5PM1_ERR_INVALID_ARG; if (event > 5) return M5PM1_ERR_INVALID_ARG; if (!_initialized) { @@ -3342,7 +3461,8 @@ m5pm1_err_t M5PM1::irqGetSysMask(uint8_t event, m5pm1_irq_mask_ctrl_t* mask) { return M5PM1_OK; } -m5pm1_err_t M5PM1::irqSetSysMaskAll(uint8_t mask) { +m5pm1_err_t M5PM1::irqSetSysMaskAll(uint8_t mask) +{ if (!_initialized) { M5PM1_LOG_E(TAG, "Not initialized"); return M5PM1_ERR_NOT_INIT; @@ -3355,7 +3475,8 @@ m5pm1_err_t M5PM1::irqSetSysMaskAll(uint8_t mask) { return M5PM1_OK; } -m5pm1_err_t M5PM1::irqGetSysMaskAll(uint8_t* mask) { +m5pm1_err_t M5PM1::irqGetSysMaskAll(uint8_t* mask) +{ if (mask == nullptr) return M5PM1_ERR_INVALID_ARG; if (!_initialized) { M5PM1_LOG_E(TAG, "Not initialized"); @@ -3365,11 +3486,11 @@ m5pm1_err_t M5PM1::irqGetSysMaskAll(uint8_t* mask) { return M5PM1_OK; } -m5pm1_err_t M5PM1::irqSetBtnMask(m5pm1_btn_irq_t type, m5pm1_irq_mask_ctrl_t mask) { +m5pm1_err_t M5PM1::irqSetBtnMask(m5pm1_btn_irq_t type, m5pm1_irq_mask_ctrl_t mask) +{ // 验证参数:type 必须是有效的位掩码 // Validate parameter: type must be a valid bitmask - if (type != M5PM1_BTN_IRQ_CLICK && type != M5PM1_BTN_IRQ_WAKEUP && - type != M5PM1_BTN_IRQ_DOUBLE) { + if (type != M5PM1_BTN_IRQ_CLICK && type != M5PM1_BTN_IRQ_WAKEUP && type != M5PM1_BTN_IRQ_DOUBLE) { return M5PM1_ERR_INVALID_ARG; } if (!_initialized) { @@ -3396,12 +3517,12 @@ m5pm1_err_t M5PM1::irqSetBtnMask(m5pm1_btn_irq_t type, m5pm1_irq_mask_ctrl_t mas return M5PM1_OK; } -m5pm1_err_t M5PM1::irqGetBtnMask(m5pm1_btn_irq_t type, m5pm1_irq_mask_ctrl_t* mask) { +m5pm1_err_t M5PM1::irqGetBtnMask(m5pm1_btn_irq_t type, m5pm1_irq_mask_ctrl_t* mask) +{ if (mask == nullptr) return M5PM1_ERR_INVALID_ARG; // 验证参数:type 必须是有效的位掩码 // Validate parameter: type must be a valid bitmask - if (type != M5PM1_BTN_IRQ_CLICK && type != M5PM1_BTN_IRQ_WAKEUP && - type != M5PM1_BTN_IRQ_DOUBLE) { + if (type != M5PM1_BTN_IRQ_CLICK && type != M5PM1_BTN_IRQ_WAKEUP && type != M5PM1_BTN_IRQ_DOUBLE) { return M5PM1_ERR_INVALID_ARG; } if (!_initialized) { @@ -3418,7 +3539,8 @@ m5pm1_err_t M5PM1::irqGetBtnMask(m5pm1_btn_irq_t type, m5pm1_irq_mask_ctrl_t* ma return M5PM1_OK; } -m5pm1_err_t M5PM1::irqSetBtnMaskAll(uint8_t mask) { +m5pm1_err_t M5PM1::irqSetBtnMaskAll(uint8_t mask) +{ if (!_initialized) { M5PM1_LOG_E(TAG, "Not initialized"); return M5PM1_ERR_NOT_INIT; @@ -3431,7 +3553,8 @@ m5pm1_err_t M5PM1::irqSetBtnMaskAll(uint8_t mask) { return M5PM1_OK; } -m5pm1_err_t M5PM1::irqGetBtnMaskAll(uint8_t* mask) { +m5pm1_err_t M5PM1::irqGetBtnMaskAll(uint8_t* mask) +{ if (mask == nullptr) return M5PM1_ERR_INVALID_ARG; if (!_initialized) { M5PM1_LOG_E(TAG, "Not initialized"); @@ -3446,7 +3569,8 @@ m5pm1_err_t M5PM1::irqGetBtnMaskAll(uint8_t* mask) { // System Commands // ============================ -m5pm1_err_t M5PM1::sysCmd(m5pm1_sys_cmd_t cmd) { +m5pm1_err_t M5PM1::sysCmd(m5pm1_sys_cmd_t cmd) +{ if (!_initialized) { M5PM1_LOG_E(TAG, "Not initialized"); return M5PM1_ERR_NOT_INIT; @@ -3458,19 +3582,23 @@ m5pm1_err_t M5PM1::sysCmd(m5pm1_sys_cmd_t cmd) { return M5PM1_OK; } -m5pm1_err_t M5PM1::shutdown() { +m5pm1_err_t M5PM1::shutdown() +{ return sysCmd(M5PM1_SYS_CMD_OFF); } -m5pm1_err_t M5PM1::reboot() { +m5pm1_err_t M5PM1::reboot() +{ return sysCmd(M5PM1_SYS_CMD_RESET); } -m5pm1_err_t M5PM1::enterDownloadMode() { +m5pm1_err_t M5PM1::enterDownloadMode() +{ return sysCmd(M5PM1_SYS_CMD_DL); } -m5pm1_err_t M5PM1::setDownloadLock(bool lock) { +m5pm1_err_t M5PM1::setDownloadLock(bool lock) +{ if (!_initialized) { M5PM1_LOG_E(TAG, "Not initialized"); return M5PM1_ERR_NOT_INIT; @@ -3492,7 +3620,8 @@ m5pm1_err_t M5PM1::setDownloadLock(bool lock) { return M5PM1_OK; } -m5pm1_err_t M5PM1::getDownloadLock(bool* lock) { +m5pm1_err_t M5PM1::getDownloadLock(bool* lock) +{ if (lock == nullptr) { M5PM1_LOG_E(TAG, "getDownloadLock lock is null"); return M5PM1_ERR_INVALID_ARG; @@ -3512,7 +3641,8 @@ m5pm1_err_t M5PM1::getDownloadLock(bool* lock) { // NeoPixel Functions // ============================ -m5pm1_err_t M5PM1::setLedCount(uint8_t count) { +m5pm1_err_t M5PM1::setLedCount(uint8_t count) +{ // 验证参数:count 必须在 1-31 范围内(5位寄存器限制) // Validate parameter: count must be in range 1-31 (5-bit register limit) if (count == 0 || count > 31) { @@ -3545,8 +3675,8 @@ m5pm1_err_t M5PM1::setLedCount(uint8_t count) { // Verify critical bits match bool countMatch = ((actualCfg & M5PM1_NEO_CFG_COUNT_MASK) == (cfg & M5PM1_NEO_CFG_COUNT_MASK)); if (!countMatch) { - M5PM1_LOG_E(TAG, "LED count verification failed: expected=%d, actual=%d", - count, actualCfg & M5PM1_NEO_CFG_COUNT_MASK); + M5PM1_LOG_E(TAG, "LED count verification failed: expected=%d, actual=%d", count, + actualCfg & M5PM1_NEO_CFG_COUNT_MASK); return M5PM1_FAIL; } @@ -3555,7 +3685,8 @@ m5pm1_err_t M5PM1::setLedCount(uint8_t count) { return M5PM1_OK; } -m5pm1_err_t M5PM1::setLedColor(uint8_t index, uint8_t r, uint8_t g, uint8_t b) { +m5pm1_err_t M5PM1::setLedColor(uint8_t index, uint8_t r, uint8_t g, uint8_t b) +{ if (index >= M5PM1_MAX_LED_COUNT) { M5PM1_LOG_E(TAG, "Invalid LED index: %d", index); return M5PM1_ERR_INVALID_ARG; @@ -3588,8 +3719,8 @@ m5pm1_err_t M5PM1::setLedColor(uint8_t index, uint8_t r, uint8_t g, uint8_t b) { // 验证关键位是否匹配 // Verify critical bits match if (actualRgb565 != rgb565) { - M5PM1_LOG_E(TAG, "LED color verification failed for index %d: expected=0x%04X, actual=0x%04X", - index, rgb565, actualRgb565); + M5PM1_LOG_E(TAG, "LED color verification failed for index %d: expected=0x%04X, actual=0x%04X", index, rgb565, + actualRgb565); return M5PM1_FAIL; } @@ -3597,11 +3728,13 @@ m5pm1_err_t M5PM1::setLedColor(uint8_t index, uint8_t r, uint8_t g, uint8_t b) { return M5PM1_OK; } -m5pm1_err_t M5PM1::setLedColor(uint8_t index, m5pm1_rgb_t color) { +m5pm1_err_t M5PM1::setLedColor(uint8_t index, m5pm1_rgb_t color) +{ return setLedColor(index, color.r, color.g, color.b); } -m5pm1_err_t M5PM1::refreshLeds() { +m5pm1_err_t M5PM1::refreshLeds() +{ if (!_initialized) { M5PM1_LOG_E(TAG, "Not initialized"); return M5PM1_ERR_NOT_INIT; @@ -3622,7 +3755,8 @@ m5pm1_err_t M5PM1::refreshLeds() { return M5PM1_OK; } -m5pm1_err_t M5PM1::disableLeds() { +m5pm1_err_t M5PM1::disableLeds() +{ if (!_initialized) { M5PM1_LOG_E(TAG, "Not initialized"); return M5PM1_ERR_NOT_INIT; @@ -3655,8 +3789,8 @@ m5pm1_err_t M5PM1::disableLeds() { return M5PM1_OK; } -m5pm1_err_t M5PM1::setLeds(const m5pm1_rgb_t* colors, uint8_t arraySize, - uint8_t count, bool autoRefresh) { +m5pm1_err_t M5PM1::setLeds(const m5pm1_rgb_t* colors, uint8_t arraySize, uint8_t count, bool autoRefresh) +{ if (!_initialized) { M5PM1_LOG_E(TAG, "Device not initialized"); return M5PM1_ERR_NOT_INIT; @@ -3685,10 +3819,9 @@ m5pm1_err_t M5PM1::setLeds(const m5pm1_rgb_t* colors, uint8_t arraySize, uint8_t data[M5PM1_MAX_LED_COUNT * 2]; for (uint8_t i = 0; i < count; i++) { - uint16_t rgb565 = ((uint16_t)(colors[i].r & 0xF8) << 8) - | ((uint16_t)(colors[i].g & 0xFC) << 3) - | (colors[i].b >> 3); - data[i * 2] = (uint8_t)(rgb565 & 0xFF); + uint16_t rgb565 = + ((uint16_t)(colors[i].r & 0xF8) << 8) | ((uint16_t)(colors[i].g & 0xFC) << 3) | (colors[i].b >> 3); + data[i * 2] = (uint8_t)(rgb565 & 0xFF); data[i * 2 + 1] = (uint8_t)((rgb565 >> 8) & 0xFF); } @@ -3714,8 +3847,8 @@ m5pm1_err_t M5PM1::setLeds(const m5pm1_rgb_t* colors, uint8_t arraySize, // AW8737A Pulse Functions // ============================ -m5pm1_err_t M5PM1::setAw8737aPulse(m5pm1_gpio_num_t pin, m5pm1_aw8737a_pulse_t num, - m5pm1_aw8737a_refresh_t refresh) { +m5pm1_err_t M5PM1::setAw8737aPulse(m5pm1_gpio_num_t pin, m5pm1_aw8737a_pulse_t num, m5pm1_aw8737a_refresh_t refresh) +{ if (!_initialized) { M5PM1_LOG_E(TAG, "Device not initialized"); return M5PM1_ERR_NOT_INIT; @@ -3759,19 +3892,20 @@ m5pm1_err_t M5PM1::setAw8737aPulse(m5pm1_gpio_num_t pin, m5pm1_aw8737a_pulse_t n // 验证关键位是否匹配 // Verify critical bits match uint8_t expectedValue = regValue & 0x7F; - uint8_t actualValue = actualReg & 0x7F; + uint8_t actualValue = actualReg & 0x7F; if (actualValue != expectedValue) { - M5PM1_LOG_E(TAG, "AW8737A pulse verification failed: expected=0x%02X, actual=0x%02X", - expectedValue, actualValue); + M5PM1_LOG_E(TAG, "AW8737A pulse verification failed: expected=0x%02X, actual=0x%02X", expectedValue, + actualValue); return M5PM1_FAIL; } - M5PM1_LOG_I(TAG, "AW8737A pulse set and verified: pin=%d, num=%d, refresh=%d (reg=0x%02X)", - pin, num, refresh, regValue); + M5PM1_LOG_I(TAG, "AW8737A pulse set and verified: pin=%d, num=%d, refresh=%d (reg=0x%02X)", pin, num, refresh, + regValue); return M5PM1_OK; } -m5pm1_err_t M5PM1::refreshAw8737aPulse() { +m5pm1_err_t M5PM1::refreshAw8737aPulse() +{ if (!_initialized) { M5PM1_LOG_E(TAG, "Device not initialized"); return M5PM1_ERR_NOT_INIT; @@ -3801,9 +3935,9 @@ m5pm1_err_t M5PM1::refreshAw8737aPulse() { // RTC RAM Functions // ============================ -m5pm1_err_t M5PM1::writeRtcRAM(uint8_t offset, const uint8_t* data, uint8_t len) { - if (data == nullptr || offset >= M5PM1_RTC_RAM_SIZE || len == 0 || - (offset + len) > M5PM1_RTC_RAM_SIZE) { +m5pm1_err_t M5PM1::writeRtcRAM(uint8_t offset, const uint8_t* data, uint8_t len) +{ + if (data == nullptr || offset >= M5PM1_RTC_RAM_SIZE || len == 0 || (offset + len) > M5PM1_RTC_RAM_SIZE) { return M5PM1_ERR_INVALID_ARG; } if (!_initialized) { @@ -3831,8 +3965,8 @@ m5pm1_err_t M5PM1::writeRtcRAM(uint8_t offset, const uint8_t* data, uint8_t len) // Verify critical bits match for (uint8_t i = 0; i < len; i++) { if (actualData[i] != data[i]) { - M5PM1_LOG_E(TAG, "RTC_RAM verification failed at offset %d: expected=0x%02X, actual=0x%02X", - offset + i, data[i], actualData[i]); + M5PM1_LOG_E(TAG, "RTC_RAM verification failed at offset %d: expected=0x%02X, actual=0x%02X", offset + i, + data[i], actualData[i]); return M5PM1_FAIL; } } @@ -3841,9 +3975,9 @@ m5pm1_err_t M5PM1::writeRtcRAM(uint8_t offset, const uint8_t* data, uint8_t len) return M5PM1_OK; } -m5pm1_err_t M5PM1::readRtcRAM(uint8_t offset, uint8_t* data, uint8_t len) { - if (data == nullptr || offset >= M5PM1_RTC_RAM_SIZE || len == 0 || - (offset + len) > M5PM1_RTC_RAM_SIZE) { +m5pm1_err_t M5PM1::readRtcRAM(uint8_t offset, uint8_t* data, uint8_t len) +{ + if (data == nullptr || offset >= M5PM1_RTC_RAM_SIZE || len == 0 || (offset + len) > M5PM1_RTC_RAM_SIZE) { return M5PM1_ERR_INVALID_ARG; } if (!_initialized) { @@ -3859,7 +3993,8 @@ m5pm1_err_t M5PM1::readRtcRAM(uint8_t offset, uint8_t* data, uint8_t len) { // I2C Configuration // ============================ - m5pm1_err_t M5PM1::setI2cConfig(uint8_t sleepTime, m5pm1_i2c_speed_t speed) { +m5pm1_err_t M5PM1::setI2cConfig(uint8_t sleepTime, m5pm1_i2c_speed_t speed) +{ if (sleepTime > 15) { M5PM1_LOG_E(TAG, "Invalid I2C sleep time: %u", sleepTime); return M5PM1_ERR_INVALID_ARG; @@ -3870,7 +4005,7 @@ m5pm1_err_t M5PM1::readRtcRAM(uint8_t offset, uint8_t* data, uint8_t len) { } uint32_t targetFreq = (speed == M5PM1_I2C_SPEED_400K) ? M5PM1_I2C_FREQ_400K : M5PM1_I2C_FREQ_100K; - bool speedChanged = (targetFreq != _requestedSpeed); + bool speedChanged = (targetFreq != _requestedSpeed); uint8_t cfg = (sleepTime & M5PM1_I2C_CFG_SLEEP_MASK); if (speed == M5PM1_I2C_SPEED_400K) { @@ -3891,11 +4026,10 @@ m5pm1_err_t M5PM1::readRtcRAM(uint8_t offset, uint8_t* data, uint8_t len) { } uint8_t expectedSleep = sleepTime & M5PM1_I2C_CFG_SLEEP_MASK; - uint8_t actualSleep = actualCfg & M5PM1_I2C_CFG_SLEEP_MASK; - bool actualSpeed400k = (actualCfg & M5PM1_I2C_CFG_SPEED_400K) != 0; + uint8_t actualSleep = actualCfg & M5PM1_I2C_CFG_SLEEP_MASK; + bool actualSpeed400k = (actualCfg & M5PM1_I2C_CFG_SPEED_400K) != 0; - if (actualSleep != expectedSleep || - actualSpeed400k != (speed == M5PM1_I2C_SPEED_400K)) { + if (actualSleep != expectedSleep || actualSpeed400k != (speed == M5PM1_I2C_SPEED_400K)) { M5PM1_LOG_E(TAG, "I2C_CFG verification failed: expected=0x%02X, actual=0x%02X", cfg, actualCfg); return M5PM1_FAIL; } @@ -3909,20 +4043,21 @@ m5pm1_err_t M5PM1::readRtcRAM(uint8_t offset, uint8_t* data, uint8_t len) { _i2cConfig.sleepTime = sleepTime; _i2cConfig.speed400k = (speed == M5PM1_I2C_SPEED_400K); - _i2cConfigValid = true; - _i2cSleepTime = sleepTime; + _i2cConfigValid = true; + _i2cSleepTime = sleepTime; if (sleepTime > 0 && !_autoWakeEnabled) { setAutoWakeEnable(true); M5PM1_LOG_W(TAG, "I2C sleep enabled, auto-wake automatically enabled"); } - M5PM1_LOG_I(TAG, "I2C config set and verified: sleep=%u, speed=%s", - sleepTime, speed == M5PM1_I2C_SPEED_400K ? "400K" : "100K"); + M5PM1_LOG_I(TAG, "I2C config set and verified: sleep=%u, speed=%s", sleepTime, + speed == M5PM1_I2C_SPEED_400K ? "400K" : "100K"); return M5PM1_OK; } -m5pm1_err_t M5PM1::getI2cSpeed(m5pm1_i2c_speed_t* speed) { +m5pm1_err_t M5PM1::getI2cSpeed(m5pm1_i2c_speed_t* speed) +{ if (speed == nullptr) { M5PM1_LOG_E(TAG, "getI2cSpeed speed is null"); return M5PM1_ERR_INVALID_ARG; @@ -3938,13 +4073,14 @@ m5pm1_err_t M5PM1::getI2cSpeed(m5pm1_i2c_speed_t* speed) { } _i2cConfig.speed400k = (cfg & M5PM1_I2C_CFG_SPEED_400K) != 0; - _i2cConfigValid = true; + _i2cConfigValid = true; *speed = _i2cConfig.speed400k ? M5PM1_I2C_SPEED_400K : M5PM1_I2C_SPEED_100K; return M5PM1_OK; } -m5pm1_err_t M5PM1::setI2cSleepTime(uint8_t seconds) { +m5pm1_err_t M5PM1::setI2cSleepTime(uint8_t seconds) +{ if (seconds > 15) { M5PM1_LOG_E(TAG, "Invalid I2C sleep time: %u", seconds); return M5PM1_ERR_INVALID_ARG; @@ -3975,14 +4111,13 @@ m5pm1_err_t M5PM1::setI2cSleepTime(uint8_t seconds) { uint8_t actualSleep = actualCfg & M5PM1_I2C_CFG_SLEEP_MASK; if (actualSleep != seconds) { - M5PM1_LOG_E(TAG, "I2C_CFG sleep time verification failed: expected=%u, actual=%u", - seconds, actualSleep); + M5PM1_LOG_E(TAG, "I2C_CFG sleep time verification failed: expected=%u, actual=%u", seconds, actualSleep); return M5PM1_FAIL; } _i2cConfig.sleepTime = seconds; - _i2cConfigValid = true; - _i2cSleepTime = seconds; + _i2cConfigValid = true; + _i2cSleepTime = seconds; M5PM1_LOG_I(TAG, "I2C sleep time set and verified to %u", seconds); if (seconds > 0 && !_autoWakeEnabled) { @@ -3992,7 +4127,8 @@ m5pm1_err_t M5PM1::setI2cSleepTime(uint8_t seconds) { return M5PM1_OK; } -m5pm1_err_t M5PM1::getI2cSleepTime(uint8_t* seconds) { +m5pm1_err_t M5PM1::getI2cSleepTime(uint8_t* seconds) +{ if (seconds == nullptr) { M5PM1_LOG_E(TAG, "getI2cSleepTime seconds is null"); return M5PM1_ERR_INVALID_ARG; @@ -4008,14 +4144,15 @@ m5pm1_err_t M5PM1::getI2cSleepTime(uint8_t* seconds) { } _i2cConfig.sleepTime = cfg & M5PM1_I2C_CFG_SLEEP_MASK; - _i2cConfigValid = true; - _i2cSleepTime = _i2cConfig.sleepTime; + _i2cConfigValid = true; + _i2cSleepTime = _i2cConfig.sleepTime; *seconds = _i2cConfig.sleepTime; return M5PM1_OK; } -m5pm1_err_t M5PM1::switchI2cSpeed(m5pm1_i2c_speed_t speed) { +m5pm1_err_t M5PM1::switchI2cSpeed(m5pm1_i2c_speed_t speed) +{ if (!_initialized) { M5PM1_LOG_E(TAG, "Cannot switch I2C speed: device not initialized"); return M5PM1_ERR_NOT_INIT; @@ -4033,9 +4170,8 @@ m5pm1_err_t M5PM1::switchI2cSpeed(m5pm1_i2c_speed_t speed) { return M5PM1_ERR_I2C_COMM; } - uint8_t originalCfg = i2cCfg; - uint32_t originalFreq = (i2cCfg & M5PM1_I2C_CFG_SPEED_400K) - ? M5PM1_I2C_FREQ_400K : M5PM1_I2C_FREQ_100K; + uint8_t originalCfg = i2cCfg; + uint32_t originalFreq = (i2cCfg & M5PM1_I2C_CFG_SPEED_400K) ? M5PM1_I2C_FREQ_400K : M5PM1_I2C_FREQ_100K; if (speed == M5PM1_I2C_SPEED_400K) { i2cCfg |= M5PM1_I2C_CFG_SPEED_400K; @@ -4075,18 +4211,19 @@ m5pm1_err_t M5PM1::switchI2cSpeed(m5pm1_i2c_speed_t speed) { i2c_device_config_t dev_config = { .dev_addr_length = I2C_ADDR_BIT_LEN_7, - .device_address = _addr, - .scl_speed_hz = targetFreq, - .scl_wait_us = 0, - .flags = { - .disable_ack_check = false, - }, + .device_address = _addr, + .scl_speed_hz = targetFreq, + .scl_wait_us = 0, + .flags = + { + .disable_ack_check = false, + }, }; ret = i2c_master_bus_add_device(_i2c_master_bus, &dev_config, &_i2c_master_dev); if (ret != ESP_OK) { - M5PM1_LOG_E(TAG, "Failed to add I2C device at %lu Hz: %s", - (unsigned long)targetFreq, esp_err_to_name(ret)); + M5PM1_LOG_E(TAG, "Failed to add I2C device at %lu Hz: %s", (unsigned long)targetFreq, + esp_err_to_name(ret)); dev_config.scl_speed_hz = originalFreq; i2c_master_bus_add_device(_i2c_master_bus, &dev_config, &_i2c_master_dev); _writeReg(M5PM1_REG_I2C_CFG, originalCfg); @@ -4119,8 +4256,7 @@ m5pm1_err_t M5PM1::switchI2cSpeed(m5pm1_i2c_speed_t speed) { uint8_t id = 0; if (!_readReg(M5PM1_REG_DEVICE_ID, &id)) { - M5PM1_LOG_E(TAG, "Communication failed after switching to %lu Hz, reverting", - (unsigned long)targetFreq); + M5PM1_LOG_E(TAG, "Communication failed after switching to %lu Hz, reverting", (unsigned long)targetFreq); #ifdef ARDUINO _wire->end(); @@ -4135,10 +4271,10 @@ m5pm1_err_t M5PM1::switchI2cSpeed(m5pm1_i2c_speed_t speed) { i2c_master_bus_rm_device(_i2c_master_dev); i2c_device_config_t dev_config = { .dev_addr_length = I2C_ADDR_BIT_LEN_7, - .device_address = _addr, - .scl_speed_hz = originalFreq, - .scl_wait_us = 0, - .flags = { .disable_ack_check = false }, + .device_address = _addr, + .scl_speed_hz = originalFreq, + .scl_wait_us = 0, + .flags = {.disable_ack_check = false}, }; i2c_master_bus_add_device(_i2c_master_bus, &dev_config, &_i2c_master_dev); } @@ -4159,10 +4295,10 @@ m5pm1_err_t M5PM1::switchI2cSpeed(m5pm1_i2c_speed_t speed) { } _requestedSpeed = targetFreq; - _lastCommTime = M5PM1_GET_TIME_MS(); + _lastCommTime = M5PM1_GET_TIME_MS(); _i2cConfig.speed400k = (speed == M5PM1_I2C_SPEED_400K); - _i2cConfigValid = true; + _i2cConfigValid = true; M5PM1_LOG_I(TAG, "Successfully switched to %lu Hz I2C mode", (unsigned long)targetFreq); return M5PM1_OK; @@ -4173,18 +4309,21 @@ m5pm1_err_t M5PM1::switchI2cSpeed(m5pm1_i2c_speed_t speed) { // Auto Wake Feature // ============================ -void M5PM1::setAutoWakeEnable(bool enable) { +void M5PM1::setAutoWakeEnable(bool enable) +{ _autoWakeEnabled = enable; if (enable) { _lastCommTime = M5PM1_GET_TIME_MS(); } } -bool M5PM1::isAutoWakeEnabled() const { +bool M5PM1::isAutoWakeEnabled() const +{ return _autoWakeEnabled; } - m5pm1_err_t M5PM1::sendWakeSignal() { +m5pm1_err_t M5PM1::sendWakeSignal() +{ #ifdef ARDUINO M5PM1_I2C_SEND_WAKE(_wire, _addr); return M5PM1_OK; @@ -4192,11 +4331,9 @@ bool M5PM1::isAutoWakeEnabled() const { switch (_i2cDriverType) { case M5PM1_I2C_DRIVER_SELF_CREATED: case M5PM1_I2C_DRIVER_MASTER: - return M5PM1_I2C_MASTER_SEND_WAKE(_i2c_master_bus, _addr) == ESP_OK - ? M5PM1_OK : M5PM1_ERR_I2C_COMM; + return M5PM1_I2C_MASTER_SEND_WAKE(_i2c_master_bus, _addr) == ESP_OK ? M5PM1_OK : M5PM1_ERR_I2C_COMM; case M5PM1_I2C_DRIVER_BUS: - return M5PM1_I2C_SEND_WAKE(_i2c_device, M5PM1_REG_HW_REV) == ESP_OK - ? M5PM1_OK : M5PM1_ERR_I2C_COMM; + return M5PM1_I2C_SEND_WAKE(_i2c_device, M5PM1_REG_HW_REV) == ESP_OK ? M5PM1_OK : M5PM1_ERR_I2C_COMM; default: return M5PM1_ERR_INTERNAL; } @@ -4208,15 +4345,18 @@ bool M5PM1::isAutoWakeEnabled() const { // State Snapshot Functions // ============================ -void M5PM1::setAutoSnapshot(bool enable) { +void M5PM1::setAutoSnapshot(bool enable) +{ _autoSnapshot = enable; } -bool M5PM1::isAutoSnapshotEnabled() const { +bool M5PM1::isAutoSnapshotEnabled() const +{ return _autoSnapshot; } -m5pm1_err_t M5PM1::updateSnapshot() { +m5pm1_err_t M5PM1::updateSnapshot() +{ if (!_initialized) return M5PM1_ERR_NOT_INIT; return _snapshotAll() ? M5PM1_OK : M5PM1_ERR_I2C_COMM; } @@ -4226,11 +4366,10 @@ m5pm1_err_t M5PM1::updateSnapshot() { // Snapshot Verification // ============================ -m5pm1_snapshot_verify_t M5PM1::verifySnapshot() { - m5pm1_snapshot_verify_t result = { - true, false, false, false, false, false, false, false, false, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - }; +m5pm1_snapshot_verify_t M5PM1::verifySnapshot() +{ + m5pm1_snapshot_verify_t result = {true, false, false, false, false, false, false, false, false, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; if (!_initialized) { result.consistent = false; @@ -4239,12 +4378,11 @@ m5pm1_snapshot_verify_t M5PM1::verifySnapshot() { if (_cacheValid) { uint8_t actualMode = 0; - uint8_t actualOut = 0; + uint8_t actualOut = 0; - if (_readReg(M5PM1_REG_GPIO_MODE, &actualMode) && - _readReg(M5PM1_REG_GPIO_OUT, &actualOut)) { + if (_readReg(M5PM1_REG_GPIO_MODE, &actualMode) && _readReg(M5PM1_REG_GPIO_OUT, &actualOut)) { uint8_t expectedMode = 0; - uint8_t expectedOut = 0; + uint8_t expectedOut = 0; for (uint8_t i = 0; i < M5PM1_MAX_GPIO_PINS; i++) { if (_pinStatus[i].mode == M5PM1_GPIO_MODE_OUTPUT) { expectedMode |= (1 << i); @@ -4255,14 +4393,14 @@ m5pm1_snapshot_verify_t M5PM1::verifySnapshot() { } result.expected_gpio_mode = expectedMode; - result.actual_gpio_mode = actualMode & 0x1F; - result.expected_gpio_out = expectedOut; - result.actual_gpio_out = actualOut & 0x1F; + result.actual_gpio_mode = actualMode & 0x1F; + result.expected_gpio_out = expectedOut; + result.actual_gpio_out = actualOut & 0x1F; if (result.expected_gpio_mode != result.actual_gpio_mode || result.expected_gpio_out != result.actual_gpio_out) { result.gpio_mismatch = true; - result.consistent = false; + result.consistent = false; } } else { result.consistent = false; @@ -4274,7 +4412,7 @@ m5pm1_snapshot_verify_t M5PM1::verifySnapshot() { if (_readReg16(M5PM1_REG_PWM_FREQ_L, &actualFreq)) { if (actualFreq != _pwmFrequency) { result.pwm_mismatch = true; - result.consistent = false; + result.consistent = false; } } else { result.consistent = false; @@ -4283,7 +4421,7 @@ m5pm1_snapshot_verify_t M5PM1::verifySnapshot() { for (uint8_t ch = 0; ch < M5PM1_MAX_PWM_CHANNELS; ch++) { uint8_t regL = (ch == 0) ? M5PM1_REG_PWM0_L : M5PM1_REG_PWM1_L; uint8_t regH = (ch == 0) ? M5PM1_REG_PWM0_HC : M5PM1_REG_PWM1_HC; - uint8_t low = 0; + uint8_t low = 0; uint8_t high = 0; if (!_readReg(regL, &low) || !_readReg(regH, &high)) { @@ -4292,31 +4430,27 @@ m5pm1_snapshot_verify_t M5PM1::verifySnapshot() { } uint16_t actualDuty = (uint16_t)(low | ((high & 0x0F) << 8)); - bool actualEnabled = (high & 0x10) != 0; + bool actualEnabled = (high & 0x10) != 0; bool actualPolarity = (high & 0x20) != 0; - if (actualDuty != _pwmStates[ch].duty12 || - actualEnabled != _pwmStates[ch].enabled || + if (actualDuty != _pwmStates[ch].duty12 || actualEnabled != _pwmStates[ch].enabled || actualPolarity != _pwmStates[ch].polarity) { result.pwm_mismatch = true; - result.consistent = false; + result.consistent = false; } } } if (_adcStateValid) { - uint8_t ctrl = 0; + uint8_t ctrl = 0; uint16_t value = 0; - if (_readReg(M5PM1_REG_ADC_CTRL, &ctrl) && - _readReg16(M5PM1_REG_ADC_RES_L, &value)) { + if (_readReg(M5PM1_REG_ADC_CTRL, &ctrl) && _readReg16(M5PM1_REG_ADC_RES_L, &value)) { uint8_t actualChannel = (ctrl >> 1) & 0x07; - bool actualBusy = (ctrl & 0x01) != 0; + bool actualBusy = (ctrl & 0x01) != 0; - if (actualChannel != _adcState.channel || - actualBusy != _adcState.busy || - value != _adcState.lastValue) { + if (actualChannel != _adcState.channel || actualBusy != _adcState.busy || value != _adcState.lastValue) { result.adc_mismatch = true; - result.consistent = false; + result.consistent = false; } } else { result.consistent = false; @@ -4324,18 +4458,17 @@ m5pm1_snapshot_verify_t M5PM1::verifySnapshot() { } if (_powerConfigValid) { - uint8_t actualPwr = 0; + uint8_t actualPwr = 0; uint8_t actualHold = 0; - if (_readReg(M5PM1_REG_PWR_CFG, &actualPwr) && - _readReg(M5PM1_REG_HOLD_CFG, &actualHold)) { - result.expected_pwr_cfg = _powerCfg; - result.actual_pwr_cfg = actualPwr; + if (_readReg(M5PM1_REG_PWR_CFG, &actualPwr) && _readReg(M5PM1_REG_HOLD_CFG, &actualHold)) { + result.expected_pwr_cfg = _powerCfg; + result.actual_pwr_cfg = actualPwr; result.expected_hold_cfg = _holdCfg; - result.actual_hold_cfg = actualHold; + result.actual_hold_cfg = actualHold; if (_powerCfg != actualPwr || _holdCfg != actualHold) { result.power_mismatch = true; - result.consistent = false; + result.consistent = false; } } else { result.consistent = false; @@ -4345,11 +4478,10 @@ m5pm1_snapshot_verify_t M5PM1::verifySnapshot() { if (_btnConfigValid) { uint8_t actualCfg1 = 0; uint8_t actualCfg2 = 0; - if (_readReg(M5PM1_REG_BTN_CFG_1, &actualCfg1) && - _readReg(M5PM1_REG_BTN_CFG_2, &actualCfg2)) { + if (_readReg(M5PM1_REG_BTN_CFG_1, &actualCfg1) && _readReg(M5PM1_REG_BTN_CFG_2, &actualCfg2)) { if (_btnCfg1 != actualCfg1 || _btnCfg2 != actualCfg2) { result.button_mismatch = true; - result.consistent = false; + result.consistent = false; } } else { result.consistent = false; @@ -4360,12 +4492,11 @@ m5pm1_snapshot_verify_t M5PM1::verifySnapshot() { uint8_t actualMask1 = 0; uint8_t actualMask2 = 0; uint8_t actualMask3 = 0; - if (_readReg(M5PM1_REG_IRQ_MASK1, &actualMask1) && - _readReg(M5PM1_REG_IRQ_MASK2, &actualMask2) && + if (_readReg(M5PM1_REG_IRQ_MASK1, &actualMask1) && _readReg(M5PM1_REG_IRQ_MASK2, &actualMask2) && _readReg(M5PM1_REG_IRQ_MASK3, &actualMask3)) { if (_irqMask1 != actualMask1 || _irqMask2 != actualMask2 || _irqMask3 != actualMask3) { result.irq_mask_mismatch = true; - result.consistent = false; + result.consistent = false; } } else { result.consistent = false; @@ -4382,11 +4513,11 @@ m5pm1_snapshot_verify_t M5PM1::verifySnapshot() { uint8_t actualMasked = actualCfg & (M5PM1_I2C_CFG_SLEEP_MASK | M5PM1_I2C_CFG_SPEED_400K); result.expected_i2c_cfg = expectedCfg; - result.actual_i2c_cfg = actualMasked; + result.actual_i2c_cfg = actualMasked; if (expectedCfg != actualMasked) { result.i2c_mismatch = true; - result.consistent = false; + result.consistent = false; } } else { result.consistent = false; @@ -4396,15 +4527,15 @@ m5pm1_snapshot_verify_t M5PM1::verifySnapshot() { if (_neoConfigValid) { uint8_t actualCfg = 0; if (_readReg(M5PM1_REG_NEO_CFG, &actualCfg)) { - uint8_t expectedCfg = _neoCfg & M5PM1_NEO_CFG_COUNT_MASK; + uint8_t expectedCfg = _neoCfg & M5PM1_NEO_CFG_COUNT_MASK; uint8_t actualMasked = actualCfg & M5PM1_NEO_CFG_COUNT_MASK; result.expected_neo_cfg = expectedCfg; - result.actual_neo_cfg = actualMasked; + result.actual_neo_cfg = actualMasked; if (expectedCfg != actualMasked) { result.neo_mismatch = true; - result.consistent = false; + result.consistent = false; } } else { result.consistent = false; @@ -4419,7 +4550,8 @@ m5pm1_snapshot_verify_t M5PM1::verifySnapshot() { // Configuration Validation // ============================ -m5pm1_validation_t M5PM1::validateConfig(uint8_t pin, m5pm1_config_type_t configType, bool enable) { +m5pm1_validation_t M5PM1::validateConfig(uint8_t pin, m5pm1_config_type_t configType, bool enable) +{ m5pm1_validation_t result = {false, {0}, 0xFF}; if (!_isValidPin(pin)) { @@ -4441,51 +4573,42 @@ m5pm1_validation_t M5PM1::validateConfig(uint8_t pin, m5pm1_config_type_t config case M5PM1_CONFIG_GPIO_INPUT: case M5PM1_CONFIG_GPIO_OUTPUT: if (_hasActivePwm(pin)) { - snprintf(result.error_msg, sizeof(result.error_msg), - "Pin %d is used for PWM", pin); + snprintf(result.error_msg, sizeof(result.error_msg), "Pin %d is used for PWM", pin); return result; } if (_hasActiveAdc(pin)) { - snprintf(result.error_msg, sizeof(result.error_msg), - "Pin %d is used for ADC", pin); + snprintf(result.error_msg, sizeof(result.error_msg), "Pin %d is used for ADC", pin); return result; } if (_hasActiveNeo(pin)) { - snprintf(result.error_msg, sizeof(result.error_msg), - "Pin %d is used for LED_EN", pin); + snprintf(result.error_msg, sizeof(result.error_msg), "Pin %d is used for LED_EN", pin); return result; } if (_hasActiveIrq(pin)) { - snprintf(result.error_msg, sizeof(result.error_msg), - "Pin %d has IRQ enabled", pin); + snprintf(result.error_msg, sizeof(result.error_msg), "Pin %d has IRQ enabled", pin); return result; } if (_hasActiveWake(pin)) { - snprintf(result.error_msg, sizeof(result.error_msg), - "Pin %d has WAKE enabled", pin); + snprintf(result.error_msg, sizeof(result.error_msg), "Pin %d has WAKE enabled", pin); return result; } break; case M5PM1_CONFIG_GPIO_INTERRUPT: if (_hasActivePwm(pin)) { - snprintf(result.error_msg, sizeof(result.error_msg), - "Pin %d is used for PWM", pin); + snprintf(result.error_msg, sizeof(result.error_msg), "Pin %d is used for PWM", pin); return result; } if (_hasActiveAdc(pin)) { - snprintf(result.error_msg, sizeof(result.error_msg), - "Pin %d is used for ADC", pin); + snprintf(result.error_msg, sizeof(result.error_msg), "Pin %d is used for ADC", pin); return result; } if (_hasActiveNeo(pin)) { - snprintf(result.error_msg, sizeof(result.error_msg), - "Pin %d is used for LED_EN", pin); + snprintf(result.error_msg, sizeof(result.error_msg), "Pin %d is used for LED_EN", pin); return result; } if (_hasActiveWake(pin)) { - snprintf(result.error_msg, sizeof(result.error_msg), - "Pin %d has WAKE enabled", pin); + snprintf(result.error_msg, sizeof(result.error_msg), "Pin %d has WAKE enabled", pin); return result; } break; @@ -4494,115 +4617,96 @@ m5pm1_validation_t M5PM1::validateConfig(uint8_t pin, m5pm1_config_type_t config // GPIO1 不支持 WAKE(与 SDA 共用中断线) // GPIO1 does not support WAKE (shares interrupt line with SDA) if (pin == M5PM1_GPIO_NUM_1) { - snprintf(result.error_msg, sizeof(result.error_msg), - "GPIO1 does not support WAKE"); + snprintf(result.error_msg, sizeof(result.error_msg), "GPIO1 does not support WAKE"); return result; } // GPIO0/GPIO2 WAKE 互斥(共用中断线) // GPIO0/GPIO2 WAKE mutual exclusion (share interrupt line) if (pin == M5PM1_GPIO_NUM_0 && _hasActiveWake(M5PM1_GPIO_NUM_2)) { - snprintf(result.error_msg, sizeof(result.error_msg), - "GPIO0/GPIO2 WAKE conflict"); + snprintf(result.error_msg, sizeof(result.error_msg), "GPIO0/GPIO2 WAKE conflict"); result.conflicting_pin = M5PM1_GPIO_NUM_2; return result; } if (pin == M5PM1_GPIO_NUM_2 && _hasActiveWake(M5PM1_GPIO_NUM_0)) { - snprintf(result.error_msg, sizeof(result.error_msg), - "GPIO0/GPIO2 WAKE conflict"); + snprintf(result.error_msg, sizeof(result.error_msg), "GPIO0/GPIO2 WAKE conflict"); result.conflicting_pin = M5PM1_GPIO_NUM_0; return result; } // GPIO3/GPIO4 WAKE 互斥(共用中断线) // GPIO3/GPIO4 WAKE mutual exclusion (share interrupt line) if (pin == M5PM1_GPIO_NUM_3 && _hasActiveWake(M5PM1_GPIO_NUM_4)) { - snprintf(result.error_msg, sizeof(result.error_msg), - "GPIO3/GPIO4 WAKE conflict"); + snprintf(result.error_msg, sizeof(result.error_msg), "GPIO3/GPIO4 WAKE conflict"); result.conflicting_pin = M5PM1_GPIO_NUM_4; return result; } if (pin == M5PM1_GPIO_NUM_4 && _hasActiveWake(M5PM1_GPIO_NUM_3)) { - snprintf(result.error_msg, sizeof(result.error_msg), - "GPIO3/GPIO4 WAKE conflict"); + snprintf(result.error_msg, sizeof(result.error_msg), "GPIO3/GPIO4 WAKE conflict"); result.conflicting_pin = M5PM1_GPIO_NUM_3; return result; } if (_hasActivePwm(pin)) { - snprintf(result.error_msg, sizeof(result.error_msg), - "Pin %d is used for PWM", pin); + snprintf(result.error_msg, sizeof(result.error_msg), "Pin %d is used for PWM", pin); return result; } if (_hasActiveAdc(pin)) { - snprintf(result.error_msg, sizeof(result.error_msg), - "Pin %d is used for ADC", pin); + snprintf(result.error_msg, sizeof(result.error_msg), "Pin %d is used for ADC", pin); return result; } if (_hasActiveNeo(pin)) { - snprintf(result.error_msg, sizeof(result.error_msg), - "Pin %d is used for LED_EN", pin); + snprintf(result.error_msg, sizeof(result.error_msg), "Pin %d is used for LED_EN", pin); return result; } if (_hasActiveIrq(pin)) { - snprintf(result.error_msg, sizeof(result.error_msg), - "Pin %d has IRQ enabled", pin); + snprintf(result.error_msg, sizeof(result.error_msg), "Pin %d has IRQ enabled", pin); return result; } break; case M5PM1_CONFIG_ADC: if (!_isAdcPin(pin)) { - snprintf(result.error_msg, sizeof(result.error_msg), - "Pin %d does not support ADC", pin); + snprintf(result.error_msg, sizeof(result.error_msg), "Pin %d does not support ADC", pin); return result; } if (_cacheValid && _pinStatus[pin].mode == M5PM1_GPIO_MODE_OUTPUT) { - snprintf(result.error_msg, sizeof(result.error_msg), - "Pin %d is configured as output", pin); + snprintf(result.error_msg, sizeof(result.error_msg), "Pin %d is configured as output", pin); return result; } if (_hasActiveIrq(pin)) { - snprintf(result.error_msg, sizeof(result.error_msg), - "Pin %d has IRQ enabled", pin); + snprintf(result.error_msg, sizeof(result.error_msg), "Pin %d has IRQ enabled", pin); return result; } if (_hasActiveWake(pin)) { - snprintf(result.error_msg, sizeof(result.error_msg), - "Pin %d has WAKE enabled", pin); + snprintf(result.error_msg, sizeof(result.error_msg), "Pin %d has WAKE enabled", pin); return result; } break; case M5PM1_CONFIG_PWM: if (!_isPwmPin(pin)) { - snprintf(result.error_msg, sizeof(result.error_msg), - "Pin %d does not support PWM", pin); + snprintf(result.error_msg, sizeof(result.error_msg), "Pin %d does not support PWM", pin); return result; } if (_hasActiveIrq(pin)) { - snprintf(result.error_msg, sizeof(result.error_msg), - "Pin %d has IRQ enabled", pin); + snprintf(result.error_msg, sizeof(result.error_msg), "Pin %d has IRQ enabled", pin); return result; } if (_hasActiveWake(pin)) { - snprintf(result.error_msg, sizeof(result.error_msg), - "Pin %d has WAKE enabled", pin); + snprintf(result.error_msg, sizeof(result.error_msg), "Pin %d has WAKE enabled", pin); return result; } break; case M5PM1_CONFIG_NEOPIXEL: if (!_isNeoPin(pin)) { - snprintf(result.error_msg, sizeof(result.error_msg), - "NeoPixel only supported on GPIO0"); + snprintf(result.error_msg, sizeof(result.error_msg), "NeoPixel only supported on GPIO0"); return result; } if (_hasActiveIrq(pin)) { - snprintf(result.error_msg, sizeof(result.error_msg), - "GPIO0 has IRQ enabled"); + snprintf(result.error_msg, sizeof(result.error_msg), "GPIO0 has IRQ enabled"); return result; } if (_hasActiveWake(pin)) { - snprintf(result.error_msg, sizeof(result.error_msg), - "GPIO0 has WAKE enabled"); + snprintf(result.error_msg, sizeof(result.error_msg), "GPIO0 has WAKE enabled"); return result; } break; @@ -4621,45 +4725,50 @@ m5pm1_validation_t M5PM1::validateConfig(uint8_t pin, m5pm1_config_type_t config // Cached State Query Functions // ============================ -m5pm1_err_t M5PM1::getCachedPwmFrequency(uint16_t* frequency) { +m5pm1_err_t M5PM1::getCachedPwmFrequency(uint16_t* frequency) +{ if (frequency == nullptr) return M5PM1_ERR_INVALID_ARG; if (!_pwmStatesValid) return M5PM1_FAIL; *frequency = _pwmFrequency; return M5PM1_OK; } -m5pm1_err_t M5PM1::getCachedPwmState(m5pm1_pwm_channel_t channel, uint16_t* duty12, bool* enable, bool* polarity) { +m5pm1_err_t M5PM1::getCachedPwmState(m5pm1_pwm_channel_t channel, uint16_t* duty12, bool* enable, bool* polarity) +{ if (channel > M5PM1_PWM_CH_1 || duty12 == nullptr || enable == nullptr || polarity == nullptr) { return M5PM1_ERR_INVALID_ARG; } if (!_pwmStatesValid) return M5PM1_FAIL; - *duty12 = _pwmStates[channel].duty12; - *enable = _pwmStates[channel].enabled; + *duty12 = _pwmStates[channel].duty12; + *enable = _pwmStates[channel].enabled; *polarity = _pwmStates[channel].polarity; return M5PM1_OK; } -m5pm1_err_t M5PM1::getCachedAdcState(m5pm1_adc_channel_t* channel, bool* busy, uint16_t* lastValue) { +m5pm1_err_t M5PM1::getCachedAdcState(m5pm1_adc_channel_t* channel, bool* busy, uint16_t* lastValue) +{ if (channel == nullptr || busy == nullptr || lastValue == nullptr) return M5PM1_ERR_INVALID_ARG; if (!_adcStateValid) return M5PM1_FAIL; - *channel = (m5pm1_adc_channel_t)_adcState.channel; - *busy = _adcState.busy; + *channel = (m5pm1_adc_channel_t)_adcState.channel; + *busy = _adcState.busy; *lastValue = _adcState.lastValue; return M5PM1_OK; } -m5pm1_err_t M5PM1::getCachedPowerConfig(uint8_t* pwrCfg, uint8_t* holdCfg) { +m5pm1_err_t M5PM1::getCachedPowerConfig(uint8_t* pwrCfg, uint8_t* holdCfg) +{ if (pwrCfg == nullptr || holdCfg == nullptr) return M5PM1_ERR_INVALID_ARG; if (!_powerConfigValid) return M5PM1_FAIL; - *pwrCfg = _powerCfg; + *pwrCfg = _powerCfg; *holdCfg = _holdCfg; return M5PM1_OK; } -m5pm1_err_t M5PM1::getCachedButtonConfig(uint8_t* cfg1, uint8_t* cfg2) { +m5pm1_err_t M5PM1::getCachedButtonConfig(uint8_t* cfg1, uint8_t* cfg2) +{ if (cfg1 == nullptr || cfg2 == nullptr) return M5PM1_ERR_INVALID_ARG; if (!_btnConfigValid) return M5PM1_FAIL; @@ -4668,7 +4777,8 @@ m5pm1_err_t M5PM1::getCachedButtonConfig(uint8_t* cfg1, uint8_t* cfg2) { return M5PM1_OK; } -m5pm1_err_t M5PM1::getCachedIrqMasks(uint8_t* mask1, uint8_t* mask2, uint8_t* mask3) { +m5pm1_err_t M5PM1::getCachedIrqMasks(uint8_t* mask1, uint8_t* mask2, uint8_t* mask3) +{ if (mask1 == nullptr || mask2 == nullptr || mask3 == nullptr) return M5PM1_ERR_INVALID_ARG; if (!_irqMaskValid) return M5PM1_FAIL; @@ -4678,10 +4788,11 @@ m5pm1_err_t M5PM1::getCachedIrqMasks(uint8_t* mask1, uint8_t* mask2, uint8_t* ma return M5PM1_OK; } -m5pm1_err_t M5PM1::getCachedIrqStatus(uint8_t* status1, uint8_t* status2, uint8_t* status3) { +m5pm1_err_t M5PM1::getCachedIrqStatus(uint8_t* status1, uint8_t* status2, uint8_t* status3) +{ if (status1 == nullptr || status2 == nullptr || status3 == nullptr) return M5PM1_ERR_INVALID_ARG; if (!_irqStatusValid) return M5PM1_FAIL; - + *status1 = _irqStatus1; *status2 = _irqStatus2; *status3 = _irqStatus3; diff --git a/src/M5PM1.h b/src/M5PM1.h index 73756fb..8bc0f1e 100644 --- a/src/M5PM1.h +++ b/src/M5PM1.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2025 M5Stack Technology CO LTD + * SPDX-FileCopyrightText: 2026 M5Stack Technology CO LTD * * SPDX-License-Identifier: MIT */ @@ -42,52 +42,52 @@ // Error Codes // ============================ typedef enum { - M5PM1_OK = 0, // 成功 - // Success - M5PM1_FAIL = -1, // 一般失败 - // General failure - M5PM1_ERR_I2C_CONFIG = -2, // I2C 配置错误 (如频率不支持) - // I2C configuration error - M5PM1_ERR_RULE_VIOLATION = -3, // 条件规则错误 (如引脚冲突,互斥功能) - // Condition rule violation - M5PM1_ERR_INVALID_ARG = -4, // 无效参数 - // Invalid argument - M5PM1_ERR_TIMEOUT = -5, // 超时 - // Timeout - M5PM1_ERR_NOT_SUPPORTED = -6, // 不支持的功能 - // Function not supported - M5PM1_ERR_I2C_COMM = -7, // I2C 通信错误 - // I2C communication error - M5PM1_ERR_NOT_INIT = -8, // 设备未初始化 - // Device not initialized - M5PM1_ERR_INTERNAL = -9, // 内部错误 - // Internal error - M5PM1_ERR_VERIFY_FAILED = -10, // 配置校验失败(读回值与缓存不匹配) - // Configuration verification failed + M5PM1_OK = 0, // 成功 + // Success + M5PM1_FAIL = -1, // 一般失败 + // General failure + M5PM1_ERR_I2C_CONFIG = -2, // I2C 配置错误 (如频率不支持) + // I2C configuration error + M5PM1_ERR_RULE_VIOLATION = -3, // 条件规则错误 (如引脚冲突,互斥功能) + // Condition rule violation + M5PM1_ERR_INVALID_ARG = -4, // 无效参数 + // Invalid argument + M5PM1_ERR_TIMEOUT = -5, // 超时 + // Timeout + M5PM1_ERR_NOT_SUPPORTED = -6, // 不支持的功能 + // Function not supported + M5PM1_ERR_I2C_COMM = -7, // I2C 通信错误 + // I2C communication error + M5PM1_ERR_NOT_INIT = -8, // 设备未初始化 + // Device not initialized + M5PM1_ERR_INTERNAL = -9, // 内部错误 + // Internal error + M5PM1_ERR_VERIFY_FAILED = -10, // 配置校验失败(读回值与缓存不匹配) + // Configuration verification failed } m5pm1_err_t; // ============================ // 设备常量 // Device Constants // ============================ -#define M5PM1_DEFAULT_ADDR 0x6E // 默认I2C地址 / Default I2C address -#define M5PM1_MAX_GPIO_PINS 5 // GPIO0-GPIO4,共5个引脚 / GPIO0-GPIO4, total 5 pins -#define M5PM1_MAX_PWM_CHANNELS 2 // PWM0(GPIO3),PWM1(GPIO4) / PWM0 (GPIO3), PWM1 (GPIO4) -#define M5PM1_MAX_ADC_CHANNELS 3 // ADC1(GPIO1),ADC2(GPIO2),温度 / ADC1 (GPIO1), ADC2 (GPIO2), TEMP -#define M5PM1_MAX_LED_COUNT 32 // 最大NeoPixel LED数量 / Maximum NeoPixel LED count -#define M5PM1_RTC_RAM_SIZE 32 // RTC RAM大小(睡眠保持) / RTC RAM size in bytes (retained in sleep) +#define M5PM1_DEFAULT_ADDR 0x6E // 默认I2C地址 / Default I2C address +#define M5PM1_MAX_GPIO_PINS 5 // GPIO0-GPIO4,共5个引脚 / GPIO0-GPIO4, total 5 pins +#define M5PM1_MAX_PWM_CHANNELS 2 // PWM0(GPIO3),PWM1(GPIO4) / PWM0 (GPIO3), PWM1 (GPIO4) +#define M5PM1_MAX_ADC_CHANNELS 3 // ADC1(GPIO1),ADC2(GPIO2),温度 / ADC1 (GPIO1), ADC2 (GPIO2), TEMP +#define M5PM1_MAX_LED_COUNT 32 // 最大NeoPixel LED数量 / Maximum NeoPixel LED count +#define M5PM1_RTC_RAM_SIZE 32 // RTC RAM大小(睡眠保持) / RTC RAM size in bytes (retained in sleep) // ============================ // I2C 频率常量 // I2C Frequency Constants // ============================ -#define M5PM1_I2C_FREQ_100K 100000 // 标准模式 / Standard mode -#define M5PM1_I2C_FREQ_400K 400000 // 快速模式 / Fast mode -#define M5PM1_I2C_FREQ_DEFAULT M5PM1_I2C_FREQ_100K +#define M5PM1_I2C_FREQ_100K 100000 // 标准模式 / Standard mode +#define M5PM1_I2C_FREQ_400K 400000 // 快速模式 / Fast mode +#define M5PM1_I2C_FREQ_DEFAULT M5PM1_I2C_FREQ_100K // I2C 重试参数 // I2C retry settings -#define M5PM1_I2C_RETRY_COUNT 2 -#define M5PM1_I2C_RETRY_DELAY_MS 2 +#define M5PM1_I2C_RETRY_COUNT 2 +#define M5PM1_I2C_RETRY_DELAY_MS 2 // ============================ // 寄存器地址 @@ -96,260 +96,294 @@ typedef enum { // ---- 系统寄存器 ---- // ---- System Registers ---- -#define M5PM1_REG_DEVICE_ID 0x00 // R [7:0] 设备ID / Device ID -#define M5PM1_REG_DEVICE_MODEL 0x01 // R [7:0] 设备型号 / Device Model -#define M5PM1_REG_HW_REV 0x02 // R [7:0] 硬件版本 / Hardware version -#define M5PM1_REG_SW_REV 0x03 // R [7:0] 固件版本 / Software/Firmware version +#define M5PM1_REG_DEVICE_ID 0x00 // R [7:0] 设备ID / Device ID +#define M5PM1_REG_DEVICE_MODEL 0x01 // R [7:0] 设备型号 / Device Model +#define M5PM1_REG_HW_REV 0x02 // R [7:0] 硬件版本 / Hardware version +#define M5PM1_REG_SW_REV 0x03 // R [7:0] 固件版本 / Software/Firmware version // ---- 电源状态寄存器 ---- // ---- Power Status Registers ---- -#define M5PM1_REG_PWR_SRC 0x04 // R [2:0] 当前供电源 / Power source - // 5VIN(USB/DC输入) - // 0: 5VIN (USB/DC input) - // 5VINOUT(双向端口) - // 1: 5VINOUT (bidirectional port) - // 电池 - // 2: BAT (battery) -#define M5PM1_REG_WAKE_SRC 0x05 // R/W [6:0] 唤醒源标志(写0清除) / Wake source flags (write 0 to clear) - // [6] 5VINOUT插入唤醒 - // 5VINOUT insertion wake - // [5] 外部GPIO唤醒 - // External GPIO wake - // [4] 命令复位唤醒 - // Command reset wake - // [3] 复位按钮唤醒 - // Reset button wake - // [2] 电源按钮唤醒 - // Power button wake - // [1] VIN插入唤醒 - // VIN insertion wake - // [0] 定时器唤醒 - // Timer wake +#define M5PM1_REG_PWR_SRC \ + 0x04 // R [2:0] 当前供电源 / Power source + // 5VIN(USB/DC输入) + // 0: 5VIN (USB/DC input) + // 5VINOUT(双向端口) + // 1: 5VINOUT (bidirectional port) + // 电池 + // 2: BAT (battery) +#define M5PM1_REG_WAKE_SRC \ + 0x05 // R/W [6:0] 唤醒源标志(写0清除) / Wake source flags (write 0 to clear) + // [6] 5VINOUT插入唤醒 + // 5VINOUT insertion wake + // [5] 外部GPIO唤醒 + // External GPIO wake + // [4] 命令复位唤醒 + // Command reset wake + // [3] 复位按钮唤醒 + // Reset button wake + // [2] 电源按钮唤醒 + // Power button wake + // [1] VIN插入唤醒 + // VIN insertion wake + // [0] 定时器唤醒 + // Timer wake // ---- 电源配置 ---- // ---- Power Configuration ---- -#define M5PM1_REG_PWR_CFG 0x06 // R/W [7-5] Reserved 保留 - // [4] LED_EN 默认电平状态: 0=低电平 1=高电平 - // [3] 5V_INOUT - 5V双向端口: 0=输入模式 1=输出模式(由DCDC供电) - // [2] LDO_EN - 3.3V LDO使能: 0=关闭 1=开启 - // [1] DCDC_EN - 5V DCDC使能: 0=关闭 1=开启 - // [0] CHG_EN - 充电使能: 0=关闭 1=开启 - // 注意:下载模式或复位事件时自动清零 - // Note: Auto-clears on download mode or reset events +#define M5PM1_REG_PWR_CFG \ + 0x06 // R/W [7-5] Reserved 保留 + // [4] LED_EN 默认电平状态: 0=低电平 1=高电平 + // [3] 5V_INOUT - 5V双向端口: 0=输入模式 1=输出模式(由DCDC供电) + // [2] LDO_EN - 3.3V LDO使能: 0=关闭 1=开启 + // [1] DCDC_EN - 5V DCDC使能: 0=关闭 1=开启 + // [0] CHG_EN - 充电使能: 0=关闭 1=开启 + // 注意:下载模式或复位事件时自动清零 + // Note: Auto-clears on download mode or reset events -#define M5PM1_REG_HOLD_CFG 0x07 // R/W 电源保持配置 / Power hold configuration - // [7] Reserved 保留 - // [6] DCDC(5V) - DCDC电源保持 - // [5] LDO(3.3V) - LDO电源保持 - // [4] GPIO4 - GPIO4输出状态保持 - // [3] GPIO3 - GPIO3输出状态保持 - // [2] GPIO2 - GPIO2输出状态保持 - // [1] GPIO1 - GPIO1输出状态保持 - // [0] GPIO0 - GPIO0输出状态保持 - // 注意:复位/下载模式/关机时自动清零为0x00 - // Note: Auto-clears to 0x00 on reset/download/shutdown +#define M5PM1_REG_HOLD_CFG \ + 0x07 // R/W 电源保持配置 / Power hold configuration + // [7] Reserved 保留 + // [6] DCDC(5V) - DCDC电源保持 + // [5] LDO(3.3V) - LDO电源保持 + // [4] GPIO4 - GPIO4输出状态保持 + // [3] GPIO3 - GPIO3输出状态保持 + // [2] GPIO2 - GPIO2输出状态保持 + // [1] GPIO1 - GPIO1输出状态保持 + // [0] GPIO0 - GPIO0输出状态保持 + // 注意:复位/下载模式/关机时自动清零为0x00 + // Note: Auto-clears to 0x00 on reset/download/shutdown -#define M5PM1_REG_BATT_LVP 0x08 // R/W 电池低压保护阈值 / Battery low voltage protection threshold - // 电压(mV) = 2000 + n * 7.81 - // Value = (voltage_mV - 2000) / 7.81 - // 范围:2000mV ~ 4000mV - // Range: 2000mV ~ 4000mV +#define M5PM1_REG_BATT_LVP \ + 0x08 // R/W 电池低压保护阈值 / Battery low voltage protection threshold + // 电压(mV) = 2000 + n * 7.81 + // Value = (voltage_mV - 2000) / 7.81 + // 范围:2000mV ~ 4000mV + // Range: 2000mV ~ 4000mV -#define M5PM1_REG_I2C_CFG 0x09 // R/W I2C配置 / I2C configuration - // [7-5] Reserved 保留 - // [4] SPD - I2C速度: 0=100KHz 1=400KHz - // [3:0] SLP_TO - I2C睡眠超时(秒): 0=禁用 1-15=1-15秒 - // 注意:I2C空闲超时后PM1进入睡眠模式 - // Note: PM1 enters sleep after I2C idle timeout +#define M5PM1_REG_I2C_CFG \ + 0x09 // R/W I2C配置 / I2C configuration + // [7-5] Reserved 保留 + // [4] SPD - I2C速度: 0=100KHz 1=400KHz + // [3:0] SLP_TO - I2C睡眠超时(秒): 0=禁用 1-15=1-15秒 + // 注意:I2C空闲超时后PM1进入睡眠模式 + // Note: PM1 enters sleep after I2C idle timeout // ---- 看门狗寄存器 ---- // ---- Watchdog Registers ---- -#define M5PM1_REG_WDT_CNT 0x0A // R/W 看门狗倒计时(秒) / Watchdog countdown (seconds) - // 0=禁用 - // 0 = disabled - // 1-255=超时秒数 - // 1-255 = timeout in seconds - // 系统复位当倒计时到0 - // System resets when countdown reaches 0 -#define M5PM1_REG_WDT_KEY 0x0B // W 写入0xA5喂狗 / Write 0xA5 to feed watchdog -#define M5PM1_REG_SYS_CMD 0x0C // W 系统命令 / System command - // 密钥必须为0xA - // [7:4] KEY must be 0xA - // [3:2] Reserved 保留 - // [1:0] CMD - 00:无操作 01:关机 10:复位 11:下载模式 +#define M5PM1_REG_WDT_CNT \ + 0x0A // R/W 看门狗倒计时(秒) / Watchdog countdown (seconds) + // 0=禁用 + // 0 = disabled + // 1-255=超时秒数 + // 1-255 = timeout in seconds + // 系统复位当倒计时到0 + // System resets when countdown reaches 0 +#define M5PM1_REG_WDT_KEY 0x0B // W 写入0xA5喂狗 / Write 0xA5 to feed watchdog +#define M5PM1_REG_SYS_CMD \ + 0x0C // W 系统命令 / System command + // 密钥必须为0xA + // [7:4] KEY must be 0xA + // [3:2] Reserved 保留 + // [1:0] CMD - 00:无操作 01:关机 10:复位 11:下载模式 // ---- GPIO寄存器 ---- // ---- GPIO Registers ---- -#define M5PM1_REG_GPIO_MODE 0x10 // R/W [4:0] GPIO方向 / GPIO direction - // 每bit对应一个GPIO: 1=输出 0=输入 - // Each bit: 1=output, 0=input -#define M5PM1_REG_GPIO_OUT 0x11 // R/W [4:0] GPIO输出电平 / GPIO output level - // 每bit对应一个GPIO: 1=高 0=低 - // Each bit: 1=high, 0=low -#define M5PM1_REG_GPIO_IN 0x12 // R [4:0] GPIO输入状态 / GPIO input state - // 每bit对应一个GPIO的当前输入电平 - // Each bit: current input level of GPIO -#define M5PM1_REG_GPIO_DRV 0x13 // R/W GPIO驱动模式 / GPIO drive mode - // [7-6] Reserved 保留 - // [5] LED_EN_DRV - LED使能引脚驱动: 0=推挽 1=开漏 - // GPIO驱动: 1=开漏 0=推挽 - // [4:0] GPIO drive -#define M5PM1_REG_GPIO_PUPD0 0x14 // R/W GPIO0-3上下拉配置 / Pull-up/down for GPIO0-3 - // 每GPIO占2bit: 00=无 01=上拉 10=下拉 11=保留 - // [7:6] GPIO3, [5:4] GPIO2, [3:2] GPIO1, [1:0] GPIO0 -#define M5PM1_REG_GPIO_PUPD1 0x15 // R/W GPIO4上下拉配置 / Pull-up/down for GPIO4 - // [1:0] GPIO4: 00=无 01=上拉 10=下拉 11=保留 -#define M5PM1_REG_GPIO_FUNC0 0x16 // R/W GPIO0-3功能选择 / GPIO0-3 function - // 每GPIO占2bit: 00=GPIO 01=IRQ 10=WAKE 11=特殊功能 - // GPIO0: 11=LED_EN (NeoPixel使能) - // GPIO1: 11=ADC1 - // GPIO2: 11=ADC2 - // GPIO3: 11=PWM0 -#define M5PM1_REG_GPIO_FUNC1 0x17 // R/W GPIO4功能选择 / GPIO4 function - // [1:0] GPIO4: 00=GPIO 01=IRQ 10=WAKE 11=PWM1 -#define M5PM1_REG_GPIO_WAKE_EN 0x18 // R/W [4:0] GPIO唤醒使能 / GPIO wake enable - // 每bit使能对应GPIO的唤醒功能 - // Each bit enables wake function for corresponding GPIO -#define M5PM1_REG_GPIO_WAKE_CFG 0x19 // R/W [4:0] GPIO唤醒边沿配置 / GPIO wake edge config - // 每bit: 0=下降沿唤醒 1=上升沿唤醒 - // Each bit: 0=falling edge, 1=rising edge +#define M5PM1_REG_GPIO_MODE \ + 0x10 // R/W [4:0] GPIO方向 / GPIO direction + // 每bit对应一个GPIO: 1=输出 0=输入 + // Each bit: 1=output, 0=input +#define M5PM1_REG_GPIO_OUT \ + 0x11 // R/W [4:0] GPIO输出电平 / GPIO output level + // 每bit对应一个GPIO: 1=高 0=低 + // Each bit: 1=high, 0=low +#define M5PM1_REG_GPIO_IN \ + 0x12 // R [4:0] GPIO输入状态 / GPIO input state + // 每bit对应一个GPIO的当前输入电平 + // Each bit: current input level of GPIO +#define M5PM1_REG_GPIO_DRV \ + 0x13 // R/W GPIO驱动模式 / GPIO drive mode + // [7-6] Reserved 保留 + // [5] LED_EN_DRV - LED使能引脚驱动: 0=推挽 1=开漏 + // GPIO驱动: 1=开漏 0=推挽 + // [4:0] GPIO drive +#define M5PM1_REG_GPIO_PUPD0 \ + 0x14 // R/W GPIO0-3上下拉配置 / Pull-up/down for GPIO0-3 + // 每GPIO占2bit: 00=无 01=上拉 10=下拉 11=保留 + // [7:6] GPIO3, [5:4] GPIO2, [3:2] GPIO1, [1:0] GPIO0 +#define M5PM1_REG_GPIO_PUPD1 \ + 0x15 // R/W GPIO4上下拉配置 / Pull-up/down for GPIO4 + // [1:0] GPIO4: 00=无 01=上拉 10=下拉 11=保留 +#define M5PM1_REG_GPIO_FUNC0 \ + 0x16 // R/W GPIO0-3功能选择 / GPIO0-3 function + // 每GPIO占2bit: 00=GPIO 01=IRQ 10=WAKE 11=特殊功能 + // GPIO0: 11=LED_EN (NeoPixel使能) + // GPIO1: 11=ADC1 + // GPIO2: 11=ADC2 + // GPIO3: 11=PWM0 +#define M5PM1_REG_GPIO_FUNC1 \ + 0x17 // R/W GPIO4功能选择 / GPIO4 function + // [1:0] GPIO4: 00=GPIO 01=IRQ 10=WAKE 11=PWM1 +#define M5PM1_REG_GPIO_WAKE_EN \ + 0x18 // R/W [4:0] GPIO唤醒使能 / GPIO wake enable + // 每bit使能对应GPIO的唤醒功能 + // Each bit enables wake function for corresponding GPIO +#define M5PM1_REG_GPIO_WAKE_CFG \ + 0x19 // R/W [4:0] GPIO唤醒边沿配置 / GPIO wake edge config + // 每bit: 0=下降沿唤醒 1=上升沿唤醒 + // Each bit: 0=falling edge, 1=rising edge // ---- 电压读取寄存器 ---- // ---- Voltage Reading Registers ---- -#define M5PM1_REG_VREF_L 0x20 // R 参考电压低字节 / VREF low byte (mV) -#define M5PM1_REG_VREF_H 0x21 // R 参考电压高字节 / VREF high byte -#define M5PM1_REG_VBAT_L 0x22 // R 电池电压低字节 / Battery voltage low byte (mV) -#define M5PM1_REG_VBAT_H 0x23 // R 电池电压高4位 / Battery voltage high 4 bits -#define M5PM1_REG_VIN_L 0x24 // R VIN电压低字节 / VIN voltage low byte (mV) -#define M5PM1_REG_VIN_H 0x25 // R VIN电压高4位 / VIN voltage high 4 bits -#define M5PM1_REG_5VINOUT_L 0x26 // R 5VINOUT电压低字节 / 5VINOUT voltage low byte (mV) -#define M5PM1_REG_5VINOUT_H 0x27 // R 5VINOUT电压高4位 / 5VINOUT voltage high 4 bits -#define M5PM1_REG_ADC_RES_L 0x28 // R ADC结果低字节 / ADC result low byte (mV) -#define M5PM1_REG_ADC_RES_H 0x29 // R ADC结果高4位 / ADC result high 4 bits -#define M5PM1_REG_ADC_CTRL 0x2A // R/W ADC控制 / ADC control - // [7-4] Reserved 保留 - // 通道: 1=ADC1(GPIO1) 2=ADC2(GPIO2) 6=芯片内部温度 - // [3:1] Channel - // [0] START - 写1启动转换 - // Write 1 to start conversion +#define M5PM1_REG_VREF_L 0x20 // R 参考电压低字节 / VREF low byte (mV) +#define M5PM1_REG_VREF_H 0x21 // R 参考电压高字节 / VREF high byte +#define M5PM1_REG_VBAT_L 0x22 // R 电池电压低字节 / Battery voltage low byte (mV) +#define M5PM1_REG_VBAT_H 0x23 // R 电池电压高4位 / Battery voltage high 4 bits +#define M5PM1_REG_VIN_L 0x24 // R VIN电压低字节 / VIN voltage low byte (mV) +#define M5PM1_REG_VIN_H 0x25 // R VIN电压高4位 / VIN voltage high 4 bits +#define M5PM1_REG_5VINOUT_L 0x26 // R 5VINOUT电压低字节 / 5VINOUT voltage low byte (mV) +#define M5PM1_REG_5VINOUT_H 0x27 // R 5VINOUT电压高4位 / 5VINOUT voltage high 4 bits +#define M5PM1_REG_ADC_RES_L 0x28 // R ADC结果低字节 / ADC result low byte (mV) +#define M5PM1_REG_ADC_RES_H 0x29 // R ADC结果高4位 / ADC result high 4 bits +#define M5PM1_REG_ADC_CTRL \ + 0x2A // R/W ADC控制 / ADC control + // [7-4] Reserved 保留 + // 通道: 1=ADC1(GPIO1) 2=ADC2(GPIO2) 6=芯片内部温度 + // [3:1] Channel + // [0] START - 写1启动转换 + // Write 1 to start conversion // ---- PWM寄存器 ---- // ---- PWM Registers ---- -#define M5PM1_REG_PWM0_L 0x30 // R/W PWM0占空比低字节 / PWM0 duty low byte -#define M5PM1_REG_PWM0_HC 0x31 // R/W PWM0高字节+控制 / PWM0 high byte + control - // [7-6] Reserved 保留 - // [5] POL - 极性: 0=正常 1=反转 - // [4] EN - 使能: 0=关闭 1=开启 - // 占空比高4位 - // [3:0] Duty high 4 bits - // 12位占空比 - // 12-bit duty: 0-4095 (0-100%) -#define M5PM1_REG_PWM1_L 0x32 // R/W PWM1占空比低字节 / PWM1 duty low byte -#define M5PM1_REG_PWM1_HC 0x33 // R/W PWM1高字节+控制 / PWM1 high byte + control - // 格式同PWM0_HC - // Same format as PWM0_HC -#define M5PM1_REG_PWM_FREQ_L 0x34 // R/W PWM频率低字节 / PWM frequency low byte (Hz) -#define M5PM1_REG_PWM_FREQ_H 0x35 // R/W PWM频率高字节 / PWM frequency high byte - // 范围:1-65535 Hz - // Range: 1-65535 Hz +#define M5PM1_REG_PWM0_L 0x30 // R/W PWM0占空比低字节 / PWM0 duty low byte +#define M5PM1_REG_PWM0_HC \ + 0x31 // R/W PWM0高字节+控制 / PWM0 high byte + control + // [7-6] Reserved 保留 + // [5] POL - 极性: 0=正常 1=反转 + // [4] EN - 使能: 0=关闭 1=开启 + // 占空比高4位 + // [3:0] Duty high 4 bits + // 12位占空比 + // 12-bit duty: 0-4095 (0-100%) +#define M5PM1_REG_PWM1_L 0x32 // R/W PWM1占空比低字节 / PWM1 duty low byte +#define M5PM1_REG_PWM1_HC \ + 0x33 // R/W PWM1高字节+控制 / PWM1 high byte + control + // 格式同PWM0_HC + // Same format as PWM0_HC +#define M5PM1_REG_PWM_FREQ_L 0x34 // R/W PWM频率低字节 / PWM frequency low byte (Hz) +#define M5PM1_REG_PWM_FREQ_H \ + 0x35 // R/W PWM频率高字节 / PWM frequency high byte + // 范围:1-65535 Hz + // Range: 1-65535 Hz // ---- 定时器寄存器 ---- // ---- Timer Registers ---- -#define M5PM1_REG_TIM_CNT_0 0x38 // R/W 定时器计数字节0 / Timer counter byte 0 (LSB) -#define M5PM1_REG_TIM_CNT_1 0x39 // R/W 定时器计数字节1 / Timer counter byte 1 -#define M5PM1_REG_TIM_CNT_2 0x3A // R/W 定时器计数字节2 / Timer counter byte 2 -#define M5PM1_REG_TIM_CNT_3 0x3B // R/W 定时器计数字节3(bit 6:0,最大31位) / Timer counter byte 3 (bit 6:0, max 31 bits) - // 31位定时器,单位秒,最大约68年 - // 31-bit timer in seconds, max ~68 years -#define M5PM1_REG_TIM_CFG 0x3C // R/W 定时器配置 / Timer configuration - // [7-4] Reserved 保留 - // [3] ARM - 自动重装: 0=单次 1=自动重装 - // [2:0] ACTION - 超时动作: - // 000=停止 001=标志 010=复位 011=开机 100=关机 -#define M5PM1_REG_TIM_KEY 0x3D // W 写入0xA5重载定时器 / Write 0xA5 to reload timer +#define M5PM1_REG_TIM_CNT_0 0x38 // R/W 定时器计数字节0 / Timer counter byte 0 (LSB) +#define M5PM1_REG_TIM_CNT_1 0x39 // R/W 定时器计数字节1 / Timer counter byte 1 +#define M5PM1_REG_TIM_CNT_2 0x3A // R/W 定时器计数字节2 / Timer counter byte 2 +#define M5PM1_REG_TIM_CNT_3 \ + 0x3B // R/W 定时器计数字节3(bit 6:0,最大31位) / Timer counter byte 3 (bit 6:0, max 31 bits) + // 31位定时器,单位秒,最大约68年 + // 31-bit timer in seconds, max ~68 years +#define M5PM1_REG_TIM_CFG \ + 0x3C // R/W 定时器配置 / Timer configuration + // [7-4] Reserved 保留 + // [3] ARM - 自动重装: 0=单次 1=自动重装 + // [2:0] ACTION - 超时动作: + // 000=停止 001=标志 010=复位 011=开机 100=关机 +#define M5PM1_REG_TIM_KEY 0x3D // W 写入0xA5重载定时器 / Write 0xA5 to reload timer // ---- 中断寄存器 ---- // ---- IRQ Registers ---- // 注意:状态寄存器写0清除对应位 // Note: Write 0 to clear status bits -#define M5PM1_REG_IRQ_STATUS1 0x40 // R/W [4:0] GPIO中断状态 / GPIO interrupt status - // 触发条件:GPIO配置为IRQ功能时的边沿触发 - // Trigger: Edge trigger when GPIO configured as IRQ -#define M5PM1_REG_IRQ_STATUS2 0x41 // R/W 系统中断状态 / System interrupt status - // [7-6] Reserved 保留 - // [5] 电池移除 - // Battery removed - // [4] 电池插入 - // Battery inserted - // [3] 5VINOUT移除 - // 5VINOUT removed - // [2] 5VINOUT插入 - // 5VINOUT inserted - // [1] 5VIN移除 - // 5VIN removed - // [0] 5VIN插入 - // 5VIN inserted - // 备注:电池事件仅充电使能时有效,5VINOUT事件仅输入模式时有效 - // Note: Battery events only when charging enabled - // 5VINOUT events only when in input mode -#define M5PM1_REG_IRQ_STATUS3 0x42 // R/W 按钮中断状态 / Button interrupt status - // [7-3] Reserved 保留 - // [2] 双击事件 - // Double click event - // [1] 唤醒事件 - // Wakeup event - // [0] 单击事件 - // Single click event -#define M5PM1_REG_IRQ_MASK1 0x43 // R/W GPIO中断屏蔽 / GPIO interrupt mask - // [4:0] 每bit: 0=使能中断 1=屏蔽中断 -#define M5PM1_REG_IRQ_MASK2 0x44 // R/W 系统中断屏蔽 / System interrupt mask -#define M5PM1_REG_IRQ_MASK3 0x45 // R/W 按钮中断屏蔽 / Button interrupt mask +#define M5PM1_REG_IRQ_STATUS1 \ + 0x40 // R/W [4:0] GPIO中断状态 / GPIO interrupt status + // 触发条件:GPIO配置为IRQ功能时的边沿触发 + // Trigger: Edge trigger when GPIO configured as IRQ +#define M5PM1_REG_IRQ_STATUS2 \ + 0x41 // R/W 系统中断状态 / System interrupt status + // [7-6] Reserved 保留 + // [5] 电池移除 + // Battery removed + // [4] 电池插入 + // Battery inserted + // [3] 5VINOUT移除 + // 5VINOUT removed + // [2] 5VINOUT插入 + // 5VINOUT inserted + // [1] 5VIN移除 + // 5VIN removed + // [0] 5VIN插入 + // 5VIN inserted + // 备注:电池事件仅充电使能时有效,5VINOUT事件仅输入模式时有效 + // Note: Battery events only when charging enabled + // 5VINOUT events only when in input mode +#define M5PM1_REG_IRQ_STATUS3 \ + 0x42 // R/W 按钮中断状态 / Button interrupt status + // [7-3] Reserved 保留 + // [2] 双击事件 + // Double click event + // [1] 唤醒事件 + // Wakeup event + // [0] 单击事件 + // Single click event +#define M5PM1_REG_IRQ_MASK1 \ + 0x43 // R/W GPIO中断屏蔽 / GPIO interrupt mask + // [4:0] 每bit: 0=使能中断 1=屏蔽中断 +#define M5PM1_REG_IRQ_MASK2 0x44 // R/W 系统中断屏蔽 / System interrupt mask +#define M5PM1_REG_IRQ_MASK3 0x45 // R/W 按钮中断屏蔽 / Button interrupt mask // ---- 按钮寄存器 ---- // ---- Button Registers ---- -#define M5PM1_REG_BTN_STATUS 0x48 // R 按钮状态 / Button status - // [7] BTN_FLAG - 按钮曾被按下标志(读取后自动清除) - // [6-1] Reserved 保留 - // [0] BTN_STATE - 当前按钮状态: 0=释放 1=按下 -#define M5PM1_REG_BTN_CFG_1 0x49 // R/W 按钮配置 / Button configuration - // [7] DL_LOCK - 下载模式锁定: 0=正常 1=锁定(禁止进入下载模式) - // [6:5] DBL_DLY - 双击间隔: 00=125ms 01=250ms 10=500ms 11=1s - // [4:3] LONG_DLY - 长按延时: 00=1s 01=2s 10=3s 11=4s - // [2:1] CLK_DLY - 单击延时: 00=125ms 01=250ms 10=500ms 11=1s - // [0] SINGLE_RST_DIS - 单击复位禁用: 0=使能 1=禁用 -#define M5PM1_REG_BTN_CFG_2 0x4A // R/W 按钮配置2 / Button configuration 2 - // [7-1] Reserved 保留 - // [0] DOUBLE_OFF_DIS - 双击关机禁用: 0=使能 1=禁用 +#define M5PM1_REG_BTN_STATUS \ + 0x48 // R 按钮状态 / Button status + // [7] BTN_FLAG - 按钮曾被按下标志(读取后自动清除) + // [6-1] Reserved 保留 + // [0] BTN_STATE - 当前按钮状态: 0=释放 1=按下 +#define M5PM1_REG_BTN_CFG_1 0x49 // R/W 按钮配置 / Button configuration +// [7] DL_LOCK - 下载模式锁定: 0=正常 1=锁定(禁止进入下载模式) +// [6:5] DBL_DLY - 双击间隔: 00=125ms 01=250ms 10=500ms 11=1s +// [4:3] LONG_DLY - 长按延时: 00=1s 01=2s 10=3s 11=4s +// [2:1] CLK_DLY - 单击延时: 00=125ms 01=250ms 10=500ms 11=1s +// [0] SINGLE_RST_DIS - 单击复位禁用: 0=使能 1=禁用 +#define M5PM1_REG_BTN_CFG_2 \ + 0x4A // R/W 按钮配置2 / Button configuration 2 + // [7-1] Reserved 保留 + // [0] DOUBLE_OFF_DIS - 双击关机禁用: 0=使能 1=禁用 // ---- NeoPixel寄存器 ---- // ---- NeoPixel Registers ---- -#define M5PM1_REG_NEO_CFG 0x50 // R/W NeoPixel配置 / NeoPixel configuration - // [7-6] Reserved 保留 - // [5] REFRESH - 写1刷新LED - // Write 1 to refresh LEDs - // [4:0] LED_CNT - LED数量 (1-31,5位寄存器限制) - // LED count (1-31, 5-bit register limit) -#define M5PM1_REG_AW8737A_PULSE 0x53 // R/W AW8737A脉冲控制 / AW8737A pulse control - // 用于控制AW8737A音频放大器增益 - // For controlling AW8737A audio amplifier gain - // [7] REFRESH - 写1执行脉冲 - // Write 1 to execute pulse - // [6:5] NUM - 脉冲数量: 00=0 01=1 10=2 11=3 - // [4:0] GPIO - 输出GPIO引脚号 +#define M5PM1_REG_NEO_CFG \ + 0x50 // R/W NeoPixel配置 / NeoPixel configuration + // [7-6] Reserved 保留 + // [5] REFRESH - 写1刷新LED + // Write 1 to refresh LEDs + // [4:0] LED_CNT - LED数量 (1-31,5位寄存器限制) + // LED count (1-31, 5-bit register limit) +#define M5PM1_REG_AW8737A_PULSE \ + 0x53 // R/W AW8737A脉冲控制 / AW8737A pulse control + // 用于控制AW8737A音频放大器增益 + // For controlling AW8737A audio amplifier gain + // [7] REFRESH - 写1执行脉冲 + // Write 1 to execute pulse + // [6:5] NUM - 脉冲数量: 00=0 01=1 10=2 11=3 + // [4:0] GPIO - 输出GPIO引脚号 // ---- NeoPixel数据区 ---- // ---- NeoPixel Data Area ---- -#define M5PM1_REG_NEO_DATA_START 0x60 // R/W 数据起始地址 / NeoPixel RGB565 data start -#define M5PM1_REG_NEO_DATA_END 0x9F // R/W 数据结束地址 / NeoPixel RGB565 data end - // 每LED占2字节(RGB565格式), 共32个LED - // Each LED: 2 bytes (RGB565), total 32 LEDs +#define M5PM1_REG_NEO_DATA_START 0x60 // R/W 数据起始地址 / NeoPixel RGB565 data start +#define M5PM1_REG_NEO_DATA_END \ + 0x9F // R/W 数据结束地址 / NeoPixel RGB565 data end + // 每LED占2字节(RGB565格式), 共32个LED + // Each LED: 2 bytes (RGB565), total 32 LEDs // ---- RTC RAM区域 ---- // ---- RTC RAM Area ---- -#define M5PM1_REG_RTC_RAM_START 0xA0 // R/W RTC RAM起始 / RTC RAM start (32 bytes) -#define M5PM1_REG_RTC_RAM_END 0xBF // R/W RTC RAM结束 / RTC RAM end - // 睡眠期间数据保持,可用于存储小量重要数据 - // Data retained during sleep, for storing small important data +#define M5PM1_REG_RTC_RAM_START 0xA0 // R/W RTC RAM起始 / RTC RAM start (32 bytes) +#define M5PM1_REG_RTC_RAM_END \ + 0xBF // R/W RTC RAM结束 / RTC RAM end + // 睡眠期间数据保持,可用于存储小量重要数据 + // Data retained during sleep, for storing small important data // ============================ // 位定义 @@ -358,27 +392,29 @@ typedef enum { // ---- I2C配置寄存器位 ---- // ---- I2C_CFG Register Bits ---- -#define M5PM1_I2C_CFG_SLEEP_MASK 0x0F // I2C睡眠超时掩码 / I2C sleep timeout mask - // 0=禁用 1-15=1-15秒 -#define M5PM1_I2C_CFG_SPEED_400K (1 << 4) // I2C速度选择 / I2C speed select - // 0=100KHz 1=400KHz +#define M5PM1_I2C_CFG_SLEEP_MASK \ + 0x0F // I2C睡眠超时掩码 / I2C sleep timeout mask + // 0=禁用 1-15=1-15秒 +#define M5PM1_I2C_CFG_SPEED_400K \ + (1 << 4) // I2C速度选择 / I2C speed select + // 0=100KHz 1=400KHz // ---- 系统命令寄存器值 ---- // ---- SYS_CMD Register Values ---- -#define M5PM1_SYS_CMD_KEY 0xA0 // 命令密钥 / Command key (must be 0xA in high nibble) -#define M5PM1_SYS_CMD_SHUTDOWN 0x01 // 关机命令 / Shutdown command -#define M5PM1_SYS_CMD_REBOOT 0x02 // 复位命令 / Reboot command -#define M5PM1_SYS_CMD_JTAG 0x03 // 下载模式命令 / Download mode command +#define M5PM1_SYS_CMD_KEY 0xA0 // 命令密钥 / Command key (must be 0xA in high nibble) +#define M5PM1_SYS_CMD_SHUTDOWN 0x01 // 关机命令 / Shutdown command +#define M5PM1_SYS_CMD_REBOOT 0x02 // 复位命令 / Reboot command +#define M5PM1_SYS_CMD_JTAG 0x03 // 下载模式命令 / Download mode command // ---- 密钥值 ---- // ---- Key Values ---- -#define M5PM1_WDT_FEED_KEY 0xA5 // 喂狗密钥 / Watchdog feed key -#define M5PM1_TIM_RELOAD_KEY 0xA5 // 定时器重载密钥 / Timer reload key +#define M5PM1_WDT_FEED_KEY 0xA5 // 喂狗密钥 / Watchdog feed key +#define M5PM1_TIM_RELOAD_KEY 0xA5 // 定时器重载密钥 / Timer reload key // ---- NeoPixel配置寄存器位 ---- // ---- NEO_CFG Register Bits ---- -#define M5PM1_NEO_CFG_REFRESH (1 << 5) // 刷新标志 / Refresh flag (write 1 to update LEDs) -#define M5PM1_NEO_CFG_COUNT_MASK 0x1F // LED数量掩码 / LED count mask (0-31) +#define M5PM1_NEO_CFG_REFRESH (1 << 5) // 刷新标志 / Refresh flag (write 1 to update LEDs) +#define M5PM1_NEO_CFG_COUNT_MASK 0x1F // LED数量掩码 / LED count mask (0-31) // ============================ // 枚举类型 @@ -394,18 +430,18 @@ typedef enum { * GPIO4: PWM1功能 / PWM1 function */ typedef enum { - M5PM1_GPIO_NUM_0 = 0, // GPIO0 (可用于LED_EN) - // (can be LED_EN) - M5PM1_GPIO_NUM_1 = 1, // GPIO1 (可用于ADC1) - // (can be ADC1) - M5PM1_GPIO_NUM_2 = 2, // GPIO2 (可用于ADC2) - // (can be ADC2) - M5PM1_GPIO_NUM_3 = 3, // GPIO3 (可用于PWM0) - // (can be PWM0) - M5PM1_GPIO_NUM_4 = 4, // GPIO4 (可用于PWM1) - // (can be PWM1) - M5PM1_GPIO_NUM_NC = 255 // 未连接 - // Not connected + M5PM1_GPIO_NUM_0 = 0, // GPIO0 (可用于LED_EN) + // (can be LED_EN) + M5PM1_GPIO_NUM_1 = 1, // GPIO1 (可用于ADC1) + // (can be ADC1) + M5PM1_GPIO_NUM_2 = 2, // GPIO2 (可用于ADC2) + // (can be ADC2) + M5PM1_GPIO_NUM_3 = 3, // GPIO3 (可用于PWM0) + // (can be PWM0) + M5PM1_GPIO_NUM_4 = 4, // GPIO4 (可用于PWM1) + // (can be PWM1) + M5PM1_GPIO_NUM_NC = 255 // 未连接 + // Not connected } m5pm1_gpio_num_t; /** @@ -429,26 +465,26 @@ typedef enum { * - GPIO4: PWM1 (脉宽调制输出) */ typedef enum { - M5PM1_GPIO_FUNC_GPIO = 0b00, // 普通GPIO功能 - // Normal GPIO function - M5PM1_GPIO_FUNC_IRQ = 0b01, // 中断触发功能 - // Interrupt trigger function - M5PM1_GPIO_FUNC_WAKE = 0b10, // 唤醒功能 - // Wake function - M5PM1_GPIO_FUNC_OTHER = 0b11 // 特殊功能(LED/PWM/ADC) - // Special function + M5PM1_GPIO_FUNC_GPIO = 0b00, // 普通GPIO功能 + // Normal GPIO function + M5PM1_GPIO_FUNC_IRQ = 0b01, // 中断触发功能 + // Interrupt trigger function + M5PM1_GPIO_FUNC_WAKE = 0b10, // 唤醒功能 + // Wake function + M5PM1_GPIO_FUNC_OTHER = 0b11 // 特殊功能(LED/PWM/ADC) + // Special function } m5pm1_gpio_func_t; /** * @brief GPIO上下拉配置 / GPIO pull-up/pull-down configuration */ typedef enum { - M5PM1_GPIO_PULL_NONE = 0b00, // 无上下拉 - // No pull - M5PM1_GPIO_PULL_UP = 0b01, // 上拉使能 - // Pull-up enabled - M5PM1_GPIO_PULL_DOWN = 0b10 // 下拉使能 - // Pull-down enabled + M5PM1_GPIO_PULL_NONE = 0b00, // 无上下拉 + // No pull + M5PM1_GPIO_PULL_UP = 0b01, // 上拉使能 + // Pull-up enabled + M5PM1_GPIO_PULL_DOWN = 0b10 // 下拉使能 + // Pull-down enabled } m5pm1_gpio_pull_t; /** @@ -465,10 +501,10 @@ typedef enum { * @brief GPIO唤醒边沿配置 / GPIO wake edge configuration */ typedef enum { - M5PM1_GPIO_WAKE_FALLING = 0, // 下降沿唤醒 - // Wake on falling edge - M5PM1_GPIO_WAKE_RISING = 1 // 上升沿唤醒 - // Wake on rising edge + M5PM1_GPIO_WAKE_FALLING = 0, // 下降沿唤醒 + // Wake on falling edge + M5PM1_GPIO_WAKE_RISING = 1 // 上升沿唤醒 + // Wake on rising edge } m5pm1_gpio_wake_edge_t; /** @@ -477,12 +513,12 @@ typedef enum { * GPIO must be configured as FUNC_OTHER (0b11) to use ADC function */ typedef enum { - M5PM1_ADC_CH_1 = 1, // ADC通道1 (GPIO1) - // ADC channel 1 (GPIO1) - M5PM1_ADC_CH_2 = 2, // ADC通道2 (GPIO2) - // ADC channel 2 (GPIO2) - M5PM1_ADC_CH_TEMP = 6 // 内部温度传感器 - // Internal temperature sensor + M5PM1_ADC_CH_1 = 1, // ADC通道1 (GPIO1) + // ADC channel 1 (GPIO1) + M5PM1_ADC_CH_2 = 2, // ADC通道2 (GPIO2) + // ADC channel 2 (GPIO2) + M5PM1_ADC_CH_TEMP = 6 // 内部温度传感器 + // Internal temperature sensor } m5pm1_adc_channel_t; /** @@ -491,24 +527,24 @@ typedef enum { * GPIO must be configured as FUNC_OTHER (0b11) to use PWM function */ typedef enum { - M5PM1_PWM_CH_0 = 0, // PWM通道0 (GPIO3) - // PWM channel 0 (GPIO3) - M5PM1_PWM_CH_1 = 1 // PWM通道1 (GPIO4) - // PWM channel 1 (GPIO4) + M5PM1_PWM_CH_0 = 0, // PWM通道0 (GPIO3) + // PWM channel 0 (GPIO3) + M5PM1_PWM_CH_1 = 1 // PWM通道1 (GPIO4) + // PWM channel 1 (GPIO4) } m5pm1_pwm_channel_t; /** * @brief 当前供电源 / Current power source */ typedef enum { - M5PM1_PWR_SRC_5VIN = 0, // USB/DC 5V输入 - // USB/DC 5V input - M5PM1_PWR_SRC_5VINOUT = 1, // 5V双向端口输入 - // 5V bidirectional port input - M5PM1_PWR_SRC_BAT = 2, // 电池供电 - // Battery power - M5PM1_PWR_SRC_UNKNOWN = 3 // 未知/无供电 - // Unknown/no power + M5PM1_PWR_SRC_5VIN = 0, // USB/DC 5V输入 + // USB/DC 5V input + M5PM1_PWR_SRC_5VINOUT = 1, // 5V双向端口输入 + // 5V bidirectional port input + M5PM1_PWR_SRC_BAT = 2, // 电池供电 + // Battery power + M5PM1_PWR_SRC_UNKNOWN = 3 // 未知/无供电 + // Unknown/no power } m5pm1_pwr_src_t; /** @@ -517,20 +553,20 @@ typedef enum { * 写1清除对应唤醒标志 / Write 1 to clear corresponding flag */ typedef enum { - M5PM1_WAKE_SRC_TIM = 0x01, // 定时器唤醒 - // Timer wake - M5PM1_WAKE_SRC_VIN = 0x02, // VIN插入唤醒 - // VIN insertion wake - M5PM1_WAKE_SRC_PWRBTN = 0x04, // 电源按钮唤醒 - // Power button wake - M5PM1_WAKE_SRC_RSTBTN = 0x08, // 复位按钮唤醒 - // Reset button wake - M5PM1_WAKE_SRC_CMD_RST = 0x10, // 命令复位唤醒 - // Command reset wake - M5PM1_WAKE_SRC_EXT_WAKE = 0x20, // 外部GPIO唤醒 - // External GPIO wake - M5PM1_WAKE_SRC_5VINOUT = 0x40 // 5VINOUT插入唤醒 - // 5VINOUT insertion wake + M5PM1_WAKE_SRC_TIM = 0x01, // 定时器唤醒 + // Timer wake + M5PM1_WAKE_SRC_VIN = 0x02, // VIN插入唤醒 + // VIN insertion wake + M5PM1_WAKE_SRC_PWRBTN = 0x04, // 电源按钮唤醒 + // Power button wake + M5PM1_WAKE_SRC_RSTBTN = 0x08, // 复位按钮唤醒 + // Reset button wake + M5PM1_WAKE_SRC_CMD_RST = 0x10, // 命令复位唤醒 + // Command reset wake + M5PM1_WAKE_SRC_EXT_WAKE = 0x20, // 外部GPIO唤醒 + // External GPIO wake + M5PM1_WAKE_SRC_5VINOUT = 0x40 // 5VINOUT插入唤醒 + // 5VINOUT insertion wake } m5pm1_wake_src_t; /** @@ -539,56 +575,56 @@ typedef enum { * Command needs to be combined with key (0xA0) */ typedef enum { - M5PM1_SYS_CMD_NONE = 0x00, // 无操作 - // No operation - M5PM1_SYS_CMD_OFF = 0x01, // 关机 - // Shutdown - M5PM1_SYS_CMD_RESET = 0x02, // 复位 - // Reset - M5PM1_SYS_CMD_DL = 0x03 // 进入下载模式 - // Enter download mode + M5PM1_SYS_CMD_NONE = 0x00, // 无操作 + // No operation + M5PM1_SYS_CMD_OFF = 0x01, // 关机 + // Shutdown + M5PM1_SYS_CMD_RESET = 0x02, // 复位 + // Reset + M5PM1_SYS_CMD_DL = 0x03 // 进入下载模式 + // Enter download mode } m5pm1_sys_cmd_t; /** * @brief 定时器超时动作 / Timer timeout action */ typedef enum { - M5PM1_TIM_ACTION_STOP = 0b000, // 停止,无动作 - // Stop, no action - M5PM1_TIM_ACTION_FLAG = 0b001, // 仅设置标志 - // Set flag only - M5PM1_TIM_ACTION_REBOOT = 0b010, // 系统复位 - // System reboot - M5PM1_TIM_ACTION_POWERON = 0b011, // 开机 - // Power on - M5PM1_TIM_ACTION_POWEROFF = 0b100 // 关机 - // Power off + M5PM1_TIM_ACTION_STOP = 0b000, // 停止,无动作 + // Stop, no action + M5PM1_TIM_ACTION_FLAG = 0b001, // 仅设置标志 + // Set flag only + M5PM1_TIM_ACTION_REBOOT = 0b010, // 系统复位 + // System reboot + M5PM1_TIM_ACTION_POWERON = 0b011, // 开机 + // Power on + M5PM1_TIM_ACTION_POWEROFF = 0b100 // 关机 + // Power off } m5pm1_tim_action_t; /** * @brief 按钮事件类型 / Button event type */ typedef enum { - M5PM1_BTN_TYPE_CLICK = 0, // 单击 - // Single click - M5PM1_BTN_TYPE_DOUBLE = 1, // 双击 - // Double click - M5PM1_BTN_TYPE_LONG = 2 // 长按 - // Long press + M5PM1_BTN_TYPE_CLICK = 0, // 单击 + // Single click + M5PM1_BTN_TYPE_DOUBLE = 1, // 双击 + // Double click + M5PM1_BTN_TYPE_LONG = 2 // 长按 + // Long press } m5pm1_btn_type_t; /** * @brief 按钮延时配置 / Button delay/timeout configuration */ typedef enum { - M5PM1_BTN_DELAY_125MS = 0, // 125毫秒 - // 125 milliseconds - M5PM1_BTN_DELAY_250MS = 1, // 250毫秒 - // 250 milliseconds - M5PM1_BTN_DELAY_500MS = 2, // 500毫秒 - // 500 milliseconds - M5PM1_BTN_DELAY_1000MS = 3 // 1000毫秒 - // 1000 milliseconds + M5PM1_BTN_DELAY_125MS = 0, // 125毫秒 + // 125 milliseconds + M5PM1_BTN_DELAY_250MS = 1, // 250毫秒 + // 250 milliseconds + M5PM1_BTN_DELAY_500MS = 2, // 500毫秒 + // 500 milliseconds + M5PM1_BTN_DELAY_1000MS = 3 // 1000毫秒 + // 1000 milliseconds } m5pm1_btn_delay_t; /** @@ -596,26 +632,26 @@ typedef enum { * @note 用于 IRQ_STATUS3 寄存器的位掩码 / For IRQ_STATUS3 register bitmask */ typedef enum { - M5PM1_BTN_IRQ_CLICK = 0x01, // 单击中断 (bit 0) - // Single click interrupt (bit 0) - M5PM1_BTN_IRQ_WAKEUP = 0x02, // 唤醒中断 (bit 1) - // Wakeup interrupt (bit 1) - M5PM1_BTN_IRQ_DOUBLE = 0x04, // 双击中断 (bit 2) - // Double click interrupt (bit 2) - M5PM1_BTN_IRQ_ALL = 0x07, // 所有按钮中断 - // All button interrupts - M5PM1_BTN_IRQ_NONE = 0x00 // 无中断 - // No interrupt + M5PM1_BTN_IRQ_CLICK = 0x01, // 单击中断 (bit 0) + // Single click interrupt (bit 0) + M5PM1_BTN_IRQ_WAKEUP = 0x02, // 唤醒中断 (bit 1) + // Wakeup interrupt (bit 1) + M5PM1_BTN_IRQ_DOUBLE = 0x04, // 双击中断 (bit 2) + // Double click interrupt (bit 2) + M5PM1_BTN_IRQ_ALL = 0x07, // 所有按钮中断 + // All button interrupts + M5PM1_BTN_IRQ_NONE = 0x00 // 无中断 + // No interrupt } m5pm1_btn_irq_t; /** * @brief 中断屏蔽控制类型 / IRQ Mask Control Types */ typedef enum { - M5PM1_IRQ_MASK_DISABLE = 0x00, // 不屏蔽中断(允许中断) - // Don't mask (Enable interrupt) - M5PM1_IRQ_MASK_ENABLE = 0x01 // 屏蔽中断(禁止中断) - // Mask interrupt (Disable interrupt) + M5PM1_IRQ_MASK_DISABLE = 0x00, // 不屏蔽中断(允许中断) + // Don't mask (Enable interrupt) + M5PM1_IRQ_MASK_ENABLE = 0x01 // 屏蔽中断(禁止中断) + // Mask interrupt (Disable interrupt) } m5pm1_irq_mask_ctrl_t; /** @@ -625,10 +661,10 @@ typedef enum { * writing config first then re-initializing I2C */ typedef enum { - M5PM1_I2C_SPEED_100K = 0, // 100KHz 标准模式 - // Standard mode - M5PM1_I2C_SPEED_400K = 1 // 400KHz 快速模式 - // Fast mode + M5PM1_I2C_SPEED_100K = 0, // 100KHz 标准模式 + // Standard mode + M5PM1_I2C_SPEED_400K = 1 // 400KHz 快速模式 + // Fast mode } m5pm1_i2c_speed_t; // 日志级别定义 @@ -654,24 +690,24 @@ typedef enum { * AW8737A is an audio power amplifier, gain is set by pulse count */ typedef enum { - M5PM1_AW8737A_PULSE_0 = 0, // 0个脉冲 (静音) - // 0 pulses (mute) - M5PM1_AW8737A_PULSE_1 = 1, // 1个脉冲 - // 1 pulse - M5PM1_AW8737A_PULSE_2 = 2, // 2个脉冲 - // 2 pulses - M5PM1_AW8737A_PULSE_3 = 3 // 3个脉冲 - // 3 pulses + M5PM1_AW8737A_PULSE_0 = 0, // 0个脉冲 (静音) + // 0 pulses (mute) + M5PM1_AW8737A_PULSE_1 = 1, // 1个脉冲 + // 1 pulse + M5PM1_AW8737A_PULSE_2 = 2, // 2个脉冲 + // 2 pulses + M5PM1_AW8737A_PULSE_3 = 3 // 3个脉冲 + // 3 pulses } m5pm1_aw8737a_pulse_t; /** * @brief AW8737A pulse refresh mode / AW8737A脉冲刷新模式 */ typedef enum { - M5PM1_AW8737A_REFRESH_WAIT = 0, // 等待手动刷新 - // Wait for manual refresh - M5PM1_AW8737A_REFRESH_NOW = 1 // 立即执行 - // Execute immediately + M5PM1_AW8737A_REFRESH_WAIT = 0, // 等待手动刷新 + // Wait for manual refresh + M5PM1_AW8737A_REFRESH_NOW = 1 // 立即执行 + // Execute immediately } m5pm1_aw8737a_refresh_t; // ============================ @@ -685,12 +721,12 @@ typedef enum { * Used for getWakeSource(), irqGetGpioStatus(), irqGetSysStatus(), irqGetBtnStatus() */ typedef enum { - M5PM1_CLEAN_NONE = 0x00, // 不清除 - // No clean - M5PM1_CLEAN_ONCE = 0x01, // 清除一位(从低位往高位逐个清除) - // Clean one bit (from low to high, one at a time) - M5PM1_CLEAN_ALL = 0x02 // 清除所有位 - // Clean all bits + M5PM1_CLEAN_NONE = 0x00, // 不清除 + // No clean + M5PM1_CLEAN_ONCE = 0x01, // 清除一位(从低位往高位逐个清除) + // Clean one bit (from low to high, one at a time) + M5PM1_CLEAN_ALL = 0x02 // 清除所有位 + // Clean all bits } m5pm1_clean_type_t; // ============================ @@ -704,22 +740,41 @@ typedef enum { * Used for irqGetGpioStatus(), irqClearGpio() */ typedef enum { - M5PM1_IRQ_GPIO0 = (1 << 0), // GPIO0 中断标志 - // GPIO0 interrupt flag - M5PM1_IRQ_GPIO1 = (1 << 1), // GPIO1 中断标志 - // GPIO1 interrupt flag - M5PM1_IRQ_GPIO2 = (1 << 2), // GPIO2 中断标志 - // GPIO2 interrupt flag - M5PM1_IRQ_GPIO3 = (1 << 3), // GPIO3 中断标志 - // GPIO3 interrupt flag - M5PM1_IRQ_GPIO4 = (1 << 4), // GPIO4 中断标志 - // GPIO4 interrupt flag - M5PM1_IRQ_GPIO_ALL = 0x1F, // 所有 GPIO 中断标志 - // All GPIO interrupt flags - M5PM1_IRQ_GPIO_NONE = 0x00 // 无中断 - // No interrupt + M5PM1_IRQ_GPIO0 = (1 << 0), // GPIO0 中断标志 + // GPIO0 interrupt flag + M5PM1_IRQ_GPIO1 = (1 << 1), // GPIO1 中断标志 + // GPIO1 interrupt flag + M5PM1_IRQ_GPIO2 = (1 << 2), // GPIO2 中断标志 + // GPIO2 interrupt flag + M5PM1_IRQ_GPIO3 = (1 << 3), // GPIO3 中断标志 + // GPIO3 interrupt flag + M5PM1_IRQ_GPIO4 = (1 << 4), // GPIO4 中断标志 + // GPIO4 interrupt flag + M5PM1_IRQ_GPIO_ALL = 0x1F, // 所有 GPIO 中断标志 + // All GPIO interrupt flags + M5PM1_IRQ_GPIO_NONE = 0x00 // 无中断 + // No interrupt } m5pm1_irq_gpio_t; +/** + * @brief 按钮中断状态位掩码 + * Button interrupt status bitmask + * @note 用于 irqGetBtnStatus(), irqSetBtnMask(), irqGetBtnMask() + * Used for irqGetBtnStatus(), irqSetBtnMask(), irqGetBtnMask() + */ +typedef enum { + M5PM1_IRQ_BTN_CLICK = (1 << 0), // 单击事件 + // Single click event + M5PM1_IRQ_BTN_WAKE = (1 << 1), // 唤醒事件 + // Wakeup event + M5PM1_IRQ_BTN_DOUBLE = (1 << 2), // 双击事件 + // Double click event + M5PM1_IRQ_BTN_ALL = 0x07, // 所有按钮中断标志 + // All button interrupt flags + M5PM1_IRQ_BTN_NONE = 0x00 // 无中断 + // No interrupt +} m5pm1_irq_btn_t; + // ============================ // 系统中断标志枚举 // System IRQ Flag Enumeration @@ -731,22 +786,22 @@ typedef enum { * Used for irqGetSysStatus(), irqClearSys() */ typedef enum { - M5PM1_IRQ_SYS_5VIN_INSERT = (1 << 0), // 5VIN 插入 - // 5VIN insertion - M5PM1_IRQ_SYS_5VIN_REMOVE = (1 << 1), // 5VIN 移除 - // 5VIN removal - M5PM1_IRQ_SYS_5VINOUT_INSERT = (1 << 2), // 5VINOUT 插入 - // 5VINOUT insertion - M5PM1_IRQ_SYS_5VINOUT_REMOVE = (1 << 3), // 5VINOUT 移除 - // 5VINOUT removal - M5PM1_IRQ_SYS_BAT_INSERT = (1 << 4), // 电池插入 - // Battery insertion - M5PM1_IRQ_SYS_BAT_REMOVE = (1 << 5), // 电池移除 - // Battery removal - M5PM1_IRQ_SYS_ALL = 0x3F, // 所有系统中断标志 - // All system interrupt flags - M5PM1_IRQ_SYS_NONE = 0x00 // 无中断 - // No interrupt + M5PM1_IRQ_SYS_5VIN_INSERT = (1 << 0), // 5VIN 插入 + // 5VIN insertion + M5PM1_IRQ_SYS_5VIN_REMOVE = (1 << 1), // 5VIN 移除 + // 5VIN removal + M5PM1_IRQ_SYS_5VINOUT_INSERT = (1 << 2), // 5VINOUT 插入 + // 5VINOUT insertion + M5PM1_IRQ_SYS_5VINOUT_REMOVE = (1 << 3), // 5VINOUT 移除 + // 5VINOUT removal + M5PM1_IRQ_SYS_BAT_INSERT = (1 << 4), // 电池插入 + // Battery insertion + M5PM1_IRQ_SYS_BAT_REMOVE = (1 << 5), // 电池移除 + // Battery removal + M5PM1_IRQ_SYS_ALL = 0x3F, // 所有系统中断标志 + // All system interrupt flags + M5PM1_IRQ_SYS_NONE = 0x00 // 无中断 + // No interrupt } m5pm1_irq_sys_t; // ============================ @@ -783,10 +838,10 @@ typedef enum { * Used for gpioSetOutput() */ typedef enum { - M5PM1_GPIO_STATE_LOW = 0, // 低电平 - // Low level - M5PM1_GPIO_STATE_HIGH = 1 // 高电平 - // High level + M5PM1_GPIO_STATE_LOW = 0, // 低电平 + // Low level + M5PM1_GPIO_STATE_HIGH = 1 // 高电平 + // High level } m5pm1_gpio_state_t; // ============================ @@ -794,10 +849,10 @@ typedef enum { // GPIO Level Definitions // ============================ #ifndef LOW -#define LOW 0 +#define LOW 0 #endif #ifndef HIGH -#define HIGH 1 +#define HIGH 1 #endif // ============================ @@ -805,31 +860,31 @@ typedef enum { // GPIO Mode Definitions (Arduino-compatible) // ============================ #ifndef INPUT -#define INPUT 0x01 +#define INPUT 0x01 #endif #ifndef OUTPUT -#define OUTPUT 0x03 +#define OUTPUT 0x03 #endif #ifndef PULLUP -#define PULLUP 0x04 +#define PULLUP 0x04 #endif #ifndef INPUT_PULLUP -#define INPUT_PULLUP 0x05 +#define INPUT_PULLUP 0x05 #endif #ifndef PULLDOWN -#define PULLDOWN 0x08 +#define PULLDOWN 0x08 #endif #ifndef INPUT_PULLDOWN -#define INPUT_PULLDOWN 0x09 +#define INPUT_PULLDOWN 0x09 #endif #ifndef OPEN_DRAIN -#define OPEN_DRAIN 0x10 +#define OPEN_DRAIN 0x10 #endif #ifndef OUTPUT_OPEN_DRAIN #define OUTPUT_OPEN_DRAIN 0x13 #endif #ifndef ANALOG -#define ANALOG 0xC0 +#define ANALOG 0xC0 #endif // ============================ @@ -852,14 +907,14 @@ typedef struct { * This structure maintains software-level pin state to reduce I2C transactions */ typedef struct { - m5pm1_gpio_func_t func; ///< GPIO 功能 / GPIO function (GPIO/IRQ/WAKE/OTHER) - m5pm1_gpio_mode_t mode; ///< 方向 / Direction (INPUT/OUTPUT) - uint8_t output; ///< 输出值 / Output value (0/1) - m5pm1_gpio_pull_t pull; ///< 上下拉 / Pull-up/pull-down (NONE/UP/DOWN) - bool wake_en; ///< 唤醒使能 / Wake enabled - m5pm1_gpio_wake_edge_t wake_edge; ///< 唤醒边沿 / Wake edge (RISING/FALLING) - m5pm1_gpio_drive_t drive; ///< 驱动模式 / Drive mode (PUSHPULL/OPENDRAIN) - bool power_hold; ///< 电源保持状态 / Power hold state + m5pm1_gpio_func_t func; ///< GPIO 功能 / GPIO function (GPIO/IRQ/WAKE/OTHER) + m5pm1_gpio_mode_t mode; ///< 方向 / Direction (INPUT/OUTPUT) + uint8_t output; ///< 输出值 / Output value (0/1) + m5pm1_gpio_pull_t pull; ///< 上下拉 / Pull-up/pull-down (NONE/UP/DOWN) + bool wake_en; ///< 唤醒使能 / Wake enabled + m5pm1_gpio_wake_edge_t wake_edge; ///< 唤醒边沿 / Wake edge (RISING/FALLING) + m5pm1_gpio_drive_t drive; ///< 驱动模式 / Drive mode (PUSHPULL/OPENDRAIN) + bool power_hold; ///< 电源保持状态 / Power hold state } m5pm1_pin_status_t; // ============================ @@ -908,48 +963,48 @@ typedef struct { // Snapshot Verification Result // ============================ typedef struct { - bool consistent; // 缓存与寄存器一致时为 true - // True if cached values match registers - bool gpio_mismatch; // GPIO 快照不一致 - // GPIO snapshot mismatch - bool pwm_mismatch; // PWM 快照不一致 - // PWM snapshot mismatch - bool adc_mismatch; // ADC 快照不一致 - // ADC snapshot mismatch - bool power_mismatch; // 电源配置快照不一致 - // Power config snapshot mismatch - bool button_mismatch; // 按钮配置快照不一致 - // Button config snapshot mismatch - bool irq_mask_mismatch; // IRQ 掩码快照不一致 - // IRQ mask snapshot mismatch - bool i2c_mismatch; // I2C 配置快照不一致 - // I2C config snapshot mismatch - bool neo_mismatch; // Neo 配置快照不一致 - // Neo config snapshot mismatch - uint8_t expected_gpio_mode; // 缓存的 GPIO 模式值 - // Cached GPIO mode value - uint8_t actual_gpio_mode; // 实际的 GPIO 模式值 - // Actual GPIO mode value - uint8_t expected_gpio_out; // 缓存的 GPIO 输出值 - // Cached GPIO output value - uint8_t actual_gpio_out; // 实际的 GPIO 输出值 - // Actual GPIO output value - uint8_t expected_pwr_cfg; // 缓存的 PWR_CFG 值 - // Cached PWR_CFG value - uint8_t actual_pwr_cfg; // 实际的 PWR_CFG 值 - // Actual PWR_CFG value - uint8_t expected_hold_cfg; // 缓存的 HOLD_CFG 值 - // Cached HOLD_CFG value - uint8_t actual_hold_cfg; // 实际的 HOLD_CFG 值 - // Actual HOLD_CFG value - uint8_t expected_i2c_cfg; // 缓存的 I2C_CFG 值 - // Cached I2C_CFG value - uint8_t actual_i2c_cfg; // 实际的 I2C_CFG 值 - // Actual I2C_CFG value - uint8_t expected_neo_cfg; // 缓存的 NEO_CFG 值 - // Cached NEO_CFG value - uint8_t actual_neo_cfg; // 实际的 NEO_CFG 值 - // Actual NEO_CFG value + bool consistent; // 缓存与寄存器一致时为 true + // True if cached values match registers + bool gpio_mismatch; // GPIO 快照不一致 + // GPIO snapshot mismatch + bool pwm_mismatch; // PWM 快照不一致 + // PWM snapshot mismatch + bool adc_mismatch; // ADC 快照不一致 + // ADC snapshot mismatch + bool power_mismatch; // 电源配置快照不一致 + // Power config snapshot mismatch + bool button_mismatch; // 按钮配置快照不一致 + // Button config snapshot mismatch + bool irq_mask_mismatch; // IRQ 掩码快照不一致 + // IRQ mask snapshot mismatch + bool i2c_mismatch; // I2C 配置快照不一致 + // I2C config snapshot mismatch + bool neo_mismatch; // Neo 配置快照不一致 + // Neo config snapshot mismatch + uint8_t expected_gpio_mode; // 缓存的 GPIO 模式值 + // Cached GPIO mode value + uint8_t actual_gpio_mode; // 实际的 GPIO 模式值 + // Actual GPIO mode value + uint8_t expected_gpio_out; // 缓存的 GPIO 输出值 + // Cached GPIO output value + uint8_t actual_gpio_out; // 实际的 GPIO 输出值 + // Actual GPIO output value + uint8_t expected_pwr_cfg; // 缓存的 PWR_CFG 值 + // Cached PWR_CFG value + uint8_t actual_pwr_cfg; // 实际的 PWR_CFG 值 + // Actual PWR_CFG value + uint8_t expected_hold_cfg; // 缓存的 HOLD_CFG 值 + // Cached HOLD_CFG value + uint8_t actual_hold_cfg; // 实际的 HOLD_CFG 值 + // Actual HOLD_CFG value + uint8_t expected_i2c_cfg; // 缓存的 I2C_CFG 值 + // Cached I2C_CFG value + uint8_t actual_i2c_cfg; // 实际的 I2C_CFG 值 + // Actual I2C_CFG value + uint8_t expected_neo_cfg; // 缓存的 NEO_CFG 值 + // Cached NEO_CFG value + uint8_t actual_neo_cfg; // 实际的 NEO_CFG 值 + // Actual NEO_CFG value } m5pm1_snapshot_verify_t; // ============================ @@ -984,9 +1039,9 @@ public: * @return 成功返回 M5PM1_OK,否则返回错误码 * Return M5PM1_OK on success, error code otherwise */ - m5pm1_err_t begin(TwoWire *wire = &Wire, uint8_t addr = M5PM1_DEFAULT_ADDR, - int8_t sda = -1, int8_t scl = -1, uint32_t speed = M5PM1_I2C_FREQ_100K); -#else // ESP-IDF + m5pm1_err_t begin(TwoWire* wire = &Wire, uint8_t addr = M5PM1_DEFAULT_ADDR, int8_t sda = -1, int8_t scl = -1, + uint32_t speed = M5PM1_I2C_FREQ_100K); +#else // ESP-IDF /** * @brief Initialize with self-created I2C bus (ESP-IDF) * @param port I2C port number @@ -997,8 +1052,8 @@ public: * @return 成功返回 M5PM1_OK,否则返回错误码 * Return M5PM1_OK on success, error code otherwise */ - m5pm1_err_t begin(i2c_port_t port = I2C_NUM_0, uint8_t addr = M5PM1_DEFAULT_ADDR, - int sda = 21, int scl = 22, uint32_t speed = M5PM1_I2C_FREQ_100K); + m5pm1_err_t begin(i2c_port_t port = I2C_NUM_0, uint8_t addr = M5PM1_DEFAULT_ADDR, int sda = 21, int scl = 22, + uint32_t speed = M5PM1_I2C_FREQ_100K); /** * @brief Initialize with existing i2c_master_bus handle (ESP-IDF native) @@ -1019,8 +1074,7 @@ public: * @return 成功返回 M5PM1_OK,否则返回错误码 * Return M5PM1_OK on success, error code otherwise */ - m5pm1_err_t begin(i2c_bus_handle_t bus, uint8_t addr = M5PM1_DEFAULT_ADDR, - uint32_t speed = M5PM1_I2C_FREQ_100K); + m5pm1_err_t begin(i2c_bus_handle_t bus, uint8_t addr = M5PM1_DEFAULT_ADDR, uint32_t speed = M5PM1_I2C_FREQ_100K); #endif /** @@ -1180,8 +1234,8 @@ public: * @param drive Drive mode: M5PM1_GPIO_DRIVE_PUSHPULL / OPENDRAIN * @return M5PM1_OK if successful, error code otherwise */ - m5pm1_err_t gpioSet(m5pm1_gpio_num_t pin, m5pm1_gpio_mode_t mode, - uint8_t value, m5pm1_gpio_pull_t pull, m5pm1_gpio_drive_t drive); + m5pm1_err_t gpioSet(m5pm1_gpio_num_t pin, m5pm1_gpio_mode_t mode, uint8_t value, m5pm1_gpio_pull_t pull, + m5pm1_gpio_drive_t drive); /** * @brief 设置 GPIO 功能模式 @@ -1410,7 +1464,8 @@ public: * @brief 读取 ADC 通道值 * Read ADC channel value * @param channel ADC 通道:M5PM1_ADC_CH_1 (GPIO1) / M5PM1_ADC_CH_2 (GPIO2) / M5PM1_ADC_CH_TEMP (温度传感器) - * ADC channel: M5PM1_ADC_CH_1 (GPIO1) / M5PM1_ADC_CH_2 (GPIO2) / M5PM1_ADC_CH_TEMP (temperature sensor) + * ADC channel: M5PM1_ADC_CH_1 (GPIO1) / M5PM1_ADC_CH_2 (GPIO2) / M5PM1_ADC_CH_TEMP (temperature + * sensor) * @param value 输出参数,存储读取的 ADC 值 (0-4095, 12位) * Output parameter, stores the read ADC value (0-4095, 12-bit) * @return 成功返回 M5PM1_OK,否则返回错误码 @@ -1498,8 +1553,7 @@ public: * @note GPIO 必须配置为 FUNC_OTHER 才能使用 PWM 功能 * GPIO must be configured as FUNC_OTHER to use PWM function */ - m5pm1_err_t setPwmDuty(m5pm1_pwm_channel_t channel, uint8_t duty, - bool polarity = false, bool enable = true); + m5pm1_err_t setPwmDuty(m5pm1_pwm_channel_t channel, uint8_t duty, bool polarity = false, bool enable = true); /** * @brief 获取 PWM 占空比(百分比 0-100) @@ -1515,8 +1569,7 @@ public: * @return 成功返回 M5PM1_OK,否则返回错误码 * Return M5PM1_OK on success, error code otherwise */ - m5pm1_err_t getPwmDuty(m5pm1_pwm_channel_t channel, uint8_t* duty, - bool* polarity, bool* enable); + m5pm1_err_t getPwmDuty(m5pm1_pwm_channel_t channel, uint8_t* duty, bool* polarity, bool* enable); /** * @brief 设置 PWM 占空比(12位精度) @@ -1534,8 +1587,8 @@ public: * @note GPIO 必须配置为 FUNC_OTHER 才能使用 PWM 功能 * GPIO must be configured as FUNC_OTHER to use PWM function */ - m5pm1_err_t setPwmDuty12bit(m5pm1_pwm_channel_t channel, uint16_t duty12, - bool polarity = false, bool enable = true); + m5pm1_err_t setPwmDuty12bit(m5pm1_pwm_channel_t channel, uint16_t duty12, bool polarity = false, + bool enable = true); /** * @brief 获取 PWM 占空比(12位精度) @@ -1551,8 +1604,7 @@ public: * @return 成功返回 M5PM1_OK,否则返回错误码 * Return M5PM1_OK on success, error code otherwise */ - m5pm1_err_t getPwmDuty12bit(m5pm1_pwm_channel_t channel, uint16_t* duty12, - bool* polarity, bool* enable); + m5pm1_err_t getPwmDuty12bit(m5pm1_pwm_channel_t channel, uint16_t* duty12, bool* polarity, bool* enable); /** * @brief Configure PWM in one call * 一次性配置 PWM 参数 @@ -1573,8 +1625,8 @@ public: * @note Changing frequency affects all channels * 变更频率会影响所有通道 */ - m5pm1_err_t setPwmConfig(m5pm1_pwm_channel_t channel, bool enable, bool polarity, - uint16_t frequency, uint16_t duty12); + m5pm1_err_t setPwmConfig(m5pm1_pwm_channel_t channel, bool enable, bool polarity, uint16_t frequency, + uint16_t duty12); /** * @brief 设置 PWM 输出(Arduino 兼容) @@ -1657,8 +1709,9 @@ public: /** * @brief 获取当前电源来源 * Get current power source - * @param src 输出参数,存储电源来源:M5PM1_PWR_SRC_5VIN / M5PM1_PWR_SRC_5VINOUT / M5PM1_PWR_SRC_BAT / M5PM1_PWR_SRC_UNKNOWN - * Output parameter, stores power source: M5PM1_PWR_SRC_5VIN / M5PM1_PWR_SRC_5VINOUT / M5PM1_PWR_SRC_BAT / M5PM1_PWR_SRC_UNKNOWN + * @param src 输出参数,存储电源来源:M5PM1_PWR_SRC_5VIN / M5PM1_PWR_SRC_5VINOUT / M5PM1_PWR_SRC_BAT / + * M5PM1_PWR_SRC_UNKNOWN Output parameter, stores power source: M5PM1_PWR_SRC_5VIN / M5PM1_PWR_SRC_5VINOUT / + * M5PM1_PWR_SRC_BAT / M5PM1_PWR_SRC_UNKNOWN * @return 成功返回 M5PM1_OK,否则返回错误码 * Return M5PM1_OK on success, error code otherwise */ @@ -1860,7 +1913,8 @@ public: * @brief 配置按钮事件类型和延时 * Configure button event type and delay * @param type 按钮事件类型:M5PM1_BTN_TYPE_CLICK (单击) / M5PM1_BTN_TYPE_DOUBLE (双击) / M5PM1_BTN_TYPE_LONG (长按) - * Button event type: M5PM1_BTN_TYPE_CLICK (single click) / M5PM1_BTN_TYPE_DOUBLE (double click) / M5PM1_BTN_TYPE_LONG (long press) + * Button event type: M5PM1_BTN_TYPE_CLICK (single click) / M5PM1_BTN_TYPE_DOUBLE (double click) / + * M5PM1_BTN_TYPE_LONG (long press) * @param delay 延时配置:M5PM1_BTN_DELAY_125MS / 250MS / 500MS / 1000MS * Delay configuration: M5PM1_BTN_DELAY_125MS / 250MS / 500MS / 1000MS * 注意:长按类型的实际延时为 1s/2s/3s/4s(对应枚举值 0/1/2/3) @@ -2052,8 +2106,7 @@ public: * @note 如果没有中断,返回 M5PM1_IRQ_GPIO_NONE * Returns M5PM1_IRQ_GPIO_NONE if no interrupt */ - m5pm1_err_t irqGetGpioStatusEnum(m5pm1_irq_gpio_t* gpio_num, - m5pm1_clean_type_t cleanType = M5PM1_CLEAN_NONE); + m5pm1_err_t irqGetGpioStatusEnum(m5pm1_irq_gpio_t* gpio_num, m5pm1_clean_type_t cleanType = M5PM1_CLEAN_NONE); /** * @brief 读取系统中断状态(返回枚举值,用户友好) @@ -2077,8 +2130,7 @@ public: * @note 如果没有中断,返回 M5PM1_IRQ_SYS_NONE * Returns M5PM1_IRQ_SYS_NONE if no interrupt */ - m5pm1_err_t irqGetSysStatusEnum(m5pm1_irq_sys_t* sys_irq, - m5pm1_clean_type_t cleanType = M5PM1_CLEAN_NONE); + m5pm1_err_t irqGetSysStatusEnum(m5pm1_irq_sys_t* sys_irq, m5pm1_clean_type_t cleanType = M5PM1_CLEAN_NONE); /** * @brief 读取按钮中断状态(返回枚举值,用户友好) @@ -2102,9 +2154,7 @@ public: * @note 如果没有中断,返回 M5PM1_BTN_IRQ_NONE * Returns M5PM1_BTN_IRQ_NONE if no interrupt */ - m5pm1_err_t irqGetBtnStatusEnum(m5pm1_btn_irq_t* btn_irq, - m5pm1_clean_type_t cleanType = M5PM1_CLEAN_NONE); - + m5pm1_err_t irqGetBtnStatusEnum(m5pm1_btn_irq_t* btn_irq, m5pm1_clean_type_t cleanType = M5PM1_CLEAN_NONE); /** * @brief Set single GPIO pin interrupt mask @@ -2122,7 +2172,8 @@ public: * @param pin GPIO 引脚号 (0-4) * GPIO pin number (0-4) * @param mask 输出参数,存储屏蔽状态:M5PM1_IRQ_MASK_DISABLE (未屏蔽) / M5PM1_IRQ_MASK_ENABLE (已屏蔽) - * Output parameter, stores mask state: M5PM1_IRQ_MASK_DISABLE (unmasked) / M5PM1_IRQ_MASK_ENABLE (masked) + * Output parameter, stores mask state: M5PM1_IRQ_MASK_DISABLE (unmasked) / M5PM1_IRQ_MASK_ENABLE + * (masked) * @return 成功返回 M5PM1_OK,否则返回错误码 * Return M5PM1_OK on success, error code otherwise */ @@ -2162,7 +2213,8 @@ public: * @param event 事件位 (0-5): 0=5VIN_IN, 1=5VIN_OUT, 2=5VINOUT_IN, 3=5VINOUT_OUT, 4=BAT_IN, 5=BAT_OUT * Event bit (0-5): 0=5VIN_IN, 1=5VIN_OUT, 2=5VINOUT_IN, 3=5VINOUT_OUT, 4=BAT_IN, 5=BAT_OUT * @param mask 输出参数,存储屏蔽状态:M5PM1_IRQ_MASK_DISABLE (未屏蔽) / M5PM1_IRQ_MASK_ENABLE (已屏蔽) - * Output parameter, stores mask state: M5PM1_IRQ_MASK_DISABLE (unmasked) / M5PM1_IRQ_MASK_ENABLE (masked) + * Output parameter, stores mask state: M5PM1_IRQ_MASK_DISABLE (unmasked) / M5PM1_IRQ_MASK_ENABLE + * (masked) * @return 成功返回 M5PM1_OK,否则返回错误码 * Return M5PM1_OK on success, error code otherwise */ @@ -2202,7 +2254,8 @@ public: * @param type 按钮事件类型:M5PM1_BTN_IRQ_CLICK / WAKEUP / DOUBLE * Button event type: M5PM1_BTN_IRQ_CLICK / WAKEUP / DOUBLE * @param mask 输出参数,存储屏蔽状态:M5PM1_IRQ_MASK_DISABLE (未屏蔽) / M5PM1_IRQ_MASK_ENABLE (已屏蔽) - * Output parameter, stores mask state: M5PM1_IRQ_MASK_DISABLE (unmasked) / M5PM1_IRQ_MASK_ENABLE (masked) + * Output parameter, stores mask state: M5PM1_IRQ_MASK_DISABLE (unmasked) / M5PM1_IRQ_MASK_ENABLE + * (masked) * @return 成功返回 M5PM1_OK,否则返回错误码 * Return M5PM1_OK on success, error code otherwise */ @@ -2297,8 +2350,7 @@ public: * @return 成功返回 M5PM1_OK,否则返回错误码 * Return M5PM1_OK on success, error code otherwise */ - m5pm1_err_t setLeds(const m5pm1_rgb_t* colors, uint8_t arraySize, uint8_t count, - bool autoRefresh = true); + m5pm1_err_t setLeds(const m5pm1_rgb_t* colors, uint8_t arraySize, uint8_t count, bool autoRefresh = true); /** * @brief 设置 NeoPixel LED 数量 @@ -2364,8 +2416,6 @@ public: */ m5pm1_err_t disableLeds(); - - // ======================== // AW8737A 脉冲功能 // AW8737A Pulse Functions @@ -2383,7 +2433,7 @@ public: * Return M5PM1_OK on success, error code otherwise */ m5pm1_err_t setAw8737aPulse(m5pm1_gpio_num_t pin, m5pm1_aw8737a_pulse_t num, - m5pm1_aw8737a_refresh_t refresh = M5PM1_AW8737A_REFRESH_NOW); + m5pm1_aw8737a_refresh_t refresh = M5PM1_AW8737A_REFRESH_NOW); /** * @brief 刷新 AW8737A 脉冲配置 * Refresh AW8737A pulse configuration @@ -2444,8 +2494,7 @@ public: * @note 切换到 400KHz 后需要重新初始化 I2C 总线 * Need to re-initialize I2C bus after switching to 400KHz */ - m5pm1_err_t setI2cConfig(uint8_t sleepTime, - m5pm1_i2c_speed_t speed = M5PM1_I2C_SPEED_100K); + m5pm1_err_t setI2cConfig(uint8_t sleepTime, m5pm1_i2c_speed_t speed = M5PM1_I2C_SPEED_100K); /** * @brief 切换 I2C 速度 @@ -2738,10 +2787,10 @@ private: // Pin 状态缓存 // Pin status cache m5pm1_pin_status_t _pinStatus[M5PM1_MAX_GPIO_PINS]; // Cached status for GPIO0-4 - bool _cacheValid; // 缓存有效性标志 / Cache validity flag + bool _cacheValid; // 缓存有效性标志 / Cache validity flag #ifdef ARDUINO - TwoWire *_wire; + TwoWire* _wire; int8_t _sda; int8_t _scl; #else @@ -2820,4 +2869,4 @@ private: bool _readBtnStatus(uint8_t* rawValue); }; -#endif // _M5PM1_H_ +#endif // _M5PM1_H_ diff --git a/src/M5PM1_i2c_compat.h b/src/M5PM1_i2c_compat.h index f3b62ae..62857be 100644 --- a/src/M5PM1_i2c_compat.h +++ b/src/M5PM1_i2c_compat.h @@ -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 #include // ESP-IDF native i2c_master driver -#include // esp-idf-lib i2c_bus component +#include // 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__