Skip to content

Commit c0f543e

Browse files
committed
1. Add support for m5::I2C_Class under Arduino
1 parent ed22640 commit c0f543e

4 files changed

Lines changed: 290 additions & 22 deletions

File tree

examples/gpio_pwm/gpio_pwm.ino

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -78,9 +78,7 @@ void setup()
7878

7979
// PWM_CH_0 对应 GPIO3,需要设为 OTHER 才能输出PWM。
8080
// PWM_CH_0 maps to GPIO3; set func to OTHER for PWM output.
81-
// 使用 ANALOG 模式将引脚功能设为 OTHER (适用于 PWM/ADC)
82-
// Use ANALOG mode to set pin function to OTHER (for PWM/ADC)
83-
pm1.pinMode(M5PM1_GPIO_NUM_3, ANALOG);
81+
pm1.pinMode(M5PM1_GPIO_NUM_3, OTHER);
8482
// PWM 频率全通道共享。
8583
// PWM frequency is shared across channels.
8684
pm1.setPwmFrequency(1000);

src/M5PM1.cpp

Lines changed: 179 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,10 @@ M5PM1::M5PM1()
158158
_wire = nullptr;
159159
_sda = -1;
160160
_scl = -1;
161+
#if M5PM1_HAS_M5UNIFIED_I2C
162+
_m5_i2c = nullptr;
163+
_commFreq = 0;
164+
#endif
161165
#else
162166
_i2cDriverType = M5PM1_I2C_DRIVER_NONE;
163167
#if M5PM1_HAS_I2C_MASTER
@@ -334,6 +338,83 @@ m5pm1_err_t M5PM1::begin(TwoWire* wire, uint8_t addr, int8_t sda, int8_t scl, ui
334338
return M5PM1_OK;
335339
}
336340

341+
#if M5PM1_HAS_M5UNIFIED_I2C
342+
m5pm1_err_t M5PM1::begin(m5::I2C_Class* i2c, uint8_t addr, uint32_t speed)
343+
{
344+
if (i2c == nullptr || !i2c->isEnabled()) {
345+
M5PM1_LOG_E(TAG, "M5Unified I2C_Class is null or not initialized");
346+
return M5PM1_ERR_I2C_CONFIG;
347+
}
348+
349+
_wire = nullptr;
350+
_m5_i2c = i2c;
351+
_addr = addr;
352+
_sda = -1;
353+
_scl = -1;
354+
355+
// 步骤1:校验用户频率并记录
356+
// Step 1: Validate requested speed
357+
if (!_isValidI2cFrequency(speed)) {
358+
M5PM1_LOG_W(TAG, "Invalid I2C frequency: %lu Hz. Falling back to 100KHz.", (unsigned long)speed);
359+
_requestedSpeed = M5PM1_I2C_FREQ_100K;
360+
} else {
361+
_requestedSpeed = speed;
362+
}
363+
364+
// 步骤2:以 100KHz 发送唤醒信号
365+
// Step 2: Send wake signal at 100KHz
366+
_commFreq = M5PM1_I2C_FREQ_100K;
367+
M5PM1_M5UNIFIED_SEND_WAKE(_m5_i2c, _addr, _commFreq);
368+
M5PM1_DELAY_MS(10);
369+
370+
// 步骤3:验证设备通信(失败则等待 800ms 重试一次)
371+
// Step 3: Verify device communication (retry once after 800ms)
372+
if (!_initDevice()) {
373+
M5PM1_LOG_W(TAG, "Device init failed, retrying after 800ms...");
374+
M5PM1_DELAY_MS(800);
375+
M5PM1_M5UNIFIED_SEND_WAKE(_m5_i2c, _addr, _commFreq);
376+
M5PM1_DELAY_MS(10);
377+
if (!_initDevice()) {
378+
// 100K 再次失败,尝试 400K
379+
// 100K failed again, try 400K
380+
M5PM1_LOG_W(TAG, "Device init failed at 100KHz (retry), trying 400KHz...");
381+
_commFreq = M5PM1_I2C_FREQ_400K;
382+
M5PM1_M5UNIFIED_SEND_WAKE(_m5_i2c, _addr, _commFreq);
383+
M5PM1_DELAY_MS(10);
384+
if (!_initDevice()) {
385+
M5PM1_LOG_E(TAG, "Failed at 100KHz (twice) and 400KHz");
386+
_m5_i2c = nullptr;
387+
return M5PM1_ERR_I2C_COMM;
388+
}
389+
}
390+
}
391+
_initialized = true;
392+
393+
// 步骤4:配置设备 I2C 参数(关闭睡眠 + 目标频率)
394+
// Step 4: Configure device I2C (disable sleep + target speed)
395+
m5pm1_i2c_speed_t targetSpeed =
396+
(_requestedSpeed == M5PM1_I2C_FREQ_400K) ? M5PM1_I2C_SPEED_400K : M5PM1_I2C_SPEED_100K;
397+
if (setI2cConfig(0, targetSpeed) != M5PM1_OK) {
398+
M5PM1_LOG_W(TAG, "Failed to set I2C config");
399+
}
400+
401+
// 步骤5:切换通信频率到目标值(M5Unified 无需重装驱动,直接更新 _commFreq)
402+
// Step 5: Switch to target frequency (no driver reinstall needed; update _commFreq only)
403+
_commFreq = _requestedSpeed;
404+
405+
// 步骤6:刷新快照并完成初始化
406+
// Step 6: Refresh snapshot and finish initialization
407+
_lastCommTime = M5PM1_GET_TIME_MS();
408+
if (!_snapshotAll()) {
409+
_clearAll();
410+
}
411+
412+
_initialized = true;
413+
M5PM1_LOG_I(TAG, "M5PM1 initialized at address 0x%02X (I2C: %lu Hz)", _addr, (unsigned long)_requestedSpeed);
414+
return M5PM1_OK;
415+
}
416+
#endif // M5PM1_HAS_M5UNIFIED_I2C
417+
337418
#else // ESP-IDF
338419

339420
m5pm1_err_t M5PM1::begin(i2c_port_t port, uint8_t addr, int sda, int scl, uint32_t speed)
@@ -1457,7 +1538,14 @@ bool M5PM1::_writeReg(uint8_t reg, uint8_t value)
14571538
bool success = false;
14581539
for (int attempt = 0; attempt < M5PM1_I2C_RETRY_COUNT; ++attempt) {
14591540
#ifdef ARDUINO
1460-
success = M5PM1_I2C_ARDUINO_WRITE_BYTE(_wire, _addr, reg, value);
1541+
#if M5PM1_HAS_M5UNIFIED_I2C
1542+
if (_m5_i2c) {
1543+
success = M5PM1_M5UNIFIED_WRITE_BYTE(_m5_i2c, _addr, reg, value, _commFreq);
1544+
} else
1545+
#endif
1546+
{
1547+
success = M5PM1_I2C_ARDUINO_WRITE_BYTE(_wire, _addr, reg, value);
1548+
}
14611549
#else
14621550
switch (_i2cDriverType) {
14631551
#if M5PM1_HAS_I2C_MASTER
@@ -1503,7 +1591,14 @@ bool M5PM1::_writeReg16(uint8_t reg, uint16_t value)
15031591
bool success = false;
15041592
for (int attempt = 0; attempt < M5PM1_I2C_RETRY_COUNT; ++attempt) {
15051593
#ifdef ARDUINO
1506-
success = M5PM1_I2C_ARDUINO_WRITE_REG16(_wire, _addr, reg, value);
1594+
#if M5PM1_HAS_M5UNIFIED_I2C
1595+
if (_m5_i2c) {
1596+
success = M5PM1_M5UNIFIED_WRITE_REG16(_m5_i2c, _addr, reg, value, _commFreq);
1597+
} else
1598+
#endif
1599+
{
1600+
success = M5PM1_I2C_ARDUINO_WRITE_REG16(_wire, _addr, reg, value);
1601+
}
15071602
#else
15081603
switch (_i2cDriverType) {
15091604
#if M5PM1_HAS_I2C_MASTER
@@ -1549,7 +1644,14 @@ bool M5PM1::_readReg(uint8_t reg, uint8_t* value)
15491644
bool success = false;
15501645
for (int attempt = 0; attempt < M5PM1_I2C_RETRY_COUNT; ++attempt) {
15511646
#ifdef ARDUINO
1552-
success = M5PM1_I2C_ARDUINO_READ_BYTE(_wire, _addr, reg, value);
1647+
#if M5PM1_HAS_M5UNIFIED_I2C
1648+
if (_m5_i2c) {
1649+
success = M5PM1_M5UNIFIED_READ_BYTE(_m5_i2c, _addr, reg, value, _commFreq);
1650+
} else
1651+
#endif
1652+
{
1653+
success = M5PM1_I2C_ARDUINO_READ_BYTE(_wire, _addr, reg, value);
1654+
}
15531655
#else
15541656
switch (_i2cDriverType) {
15551657
#if M5PM1_HAS_I2C_MASTER
@@ -1595,7 +1697,14 @@ bool M5PM1::_readReg16(uint8_t reg, uint16_t* value)
15951697
bool success = false;
15961698
for (int attempt = 0; attempt < M5PM1_I2C_RETRY_COUNT; ++attempt) {
15971699
#ifdef ARDUINO
1598-
success = M5PM1_I2C_ARDUINO_READ_REG16(_wire, _addr, reg, value);
1700+
#if M5PM1_HAS_M5UNIFIED_I2C
1701+
if (_m5_i2c) {
1702+
success = M5PM1_M5UNIFIED_READ_REG16(_m5_i2c, _addr, reg, value, _commFreq);
1703+
} else
1704+
#endif
1705+
{
1706+
success = M5PM1_I2C_ARDUINO_READ_REG16(_wire, _addr, reg, value);
1707+
}
15991708
#else
16001709
switch (_i2cDriverType) {
16011710
#if M5PM1_HAS_I2C_MASTER
@@ -1641,7 +1750,14 @@ bool M5PM1::_writeBytes(uint8_t reg, const uint8_t* data, uint8_t len)
16411750
bool success = false;
16421751
for (int attempt = 0; attempt < M5PM1_I2C_RETRY_COUNT; ++attempt) {
16431752
#ifdef ARDUINO
1644-
success = M5PM1_I2C_ARDUINO_WRITE_BYTES(_wire, _addr, reg, len, data);
1753+
#if M5PM1_HAS_M5UNIFIED_I2C
1754+
if (_m5_i2c) {
1755+
success = M5PM1_M5UNIFIED_WRITE_BYTES(_m5_i2c, _addr, reg, len, data, _commFreq);
1756+
} else
1757+
#endif
1758+
{
1759+
success = M5PM1_I2C_ARDUINO_WRITE_BYTES(_wire, _addr, reg, len, data);
1760+
}
16451761
#else
16461762
switch (_i2cDriverType) {
16471763
#if M5PM1_HAS_I2C_MASTER
@@ -1687,7 +1803,14 @@ bool M5PM1::_readBytes(uint8_t reg, uint8_t* data, uint8_t len)
16871803
bool success = false;
16881804
for (int attempt = 0; attempt < M5PM1_I2C_RETRY_COUNT; ++attempt) {
16891805
#ifdef ARDUINO
1690-
success = M5PM1_I2C_ARDUINO_READ_BYTES(_wire, _addr, reg, len, data);
1806+
#if M5PM1_HAS_M5UNIFIED_I2C
1807+
if (_m5_i2c) {
1808+
success = M5PM1_M5UNIFIED_READ_BYTES(_m5_i2c, _addr, reg, len, data, _commFreq);
1809+
} else
1810+
#endif
1811+
{
1812+
success = M5PM1_I2C_ARDUINO_READ_BYTES(_wire, _addr, reg, len, data);
1813+
}
16911814
#else
16921815
switch (_i2cDriverType) {
16931816
#if M5PM1_HAS_I2C_MASTER
@@ -1860,6 +1983,12 @@ void M5PM1::pinModeWithRes(uint8_t pin, uint8_t mode, m5pm1_err_t* err)
18601983
gpioMode = M5PM1_GPIO_MODE_INPUT;
18611984
pull = M5PM1_GPIO_PULL_NONE;
18621985
break;
1986+
case OTHER:
1987+
func = M5PM1_GPIO_FUNC_OTHER;
1988+
gpioMode = M5PM1_GPIO_MODE_OUTPUT;
1989+
pull = M5PM1_GPIO_PULL_NONE;
1990+
setDrive = true;
1991+
break;
18631992
default:
18641993
M5PM1_LOG_E(TAG, "Invalid mode: 0x%02X", mode);
18651994
localErr = M5PM1_ERR_INVALID_ARG;
@@ -4650,15 +4779,23 @@ m5pm1_err_t M5PM1::switchI2cSpeed(m5pm1_i2c_speed_t speed)
46504779
M5PM1_DELAY_MS(5);
46514780

46524781
#ifdef ARDUINO
4653-
_wire->end();
4654-
M5PM1_DELAY_MS(10);
4655-
if (!_wire->begin(_sda, _scl, targetFreq)) {
4656-
M5PM1_LOG_E(TAG, "Failed to re-initialize I2C bus at %lu Hz", (unsigned long)targetFreq);
4657-
_wire->begin(_sda, _scl, originalFreq);
4658-
_writeReg(M5PM1_REG_I2C_CFG, originalCfg);
4659-
return M5PM1_ERR_I2C_CONFIG;
4782+
#if M5PM1_HAS_M5UNIFIED_I2C
4783+
if (_m5_i2c) {
4784+
_commFreq = targetFreq;
4785+
M5PM1_LOG_I(TAG, "M5Unified I2C frequency updated to %lu Hz", (unsigned long)targetFreq);
4786+
} else
4787+
#endif
4788+
{
4789+
_wire->end();
4790+
M5PM1_DELAY_MS(10);
4791+
if (!_wire->begin(_sda, _scl, targetFreq)) {
4792+
M5PM1_LOG_E(TAG, "Failed to re-initialize I2C bus at %lu Hz", (unsigned long)targetFreq);
4793+
_wire->begin(_sda, _scl, originalFreq);
4794+
_writeReg(M5PM1_REG_I2C_CFG, originalCfg);
4795+
return M5PM1_ERR_I2C_CONFIG;
4796+
}
4797+
M5PM1_DELAY_MS(10);
46604798
}
4661-
M5PM1_DELAY_MS(10);
46624799
#else
46634800
esp_err_t ret;
46644801
switch (_i2cDriverType) {
@@ -4734,6 +4871,12 @@ m5pm1_err_t M5PM1::switchI2cSpeed(m5pm1_i2c_speed_t speed)
47344871
break;
47354872
}
47364873
#endif // !M5PM1_HAS_I2C_MASTER && !M5PM1_HAS_I2C_BUS
4874+
#if M5PM1_HAS_M5UNIFIED_I2C
4875+
case M5PM1_I2C_DRIVER_M5UNIFIED:
4876+
_commFreq = targetFreq;
4877+
M5PM1_LOG_I(TAG, "M5Unified I2C frequency updated to %lu Hz", (unsigned long)targetFreq);
4878+
break;
4879+
#endif
47374880
default:
47384881
M5PM1_LOG_E(TAG, "Unknown I2C driver type");
47394882
return M5PM1_ERR_INTERNAL;
@@ -4745,10 +4888,17 @@ m5pm1_err_t M5PM1::switchI2cSpeed(m5pm1_i2c_speed_t speed)
47454888
M5PM1_LOG_E(TAG, "Communication failed after switching to %lu Hz, reverting", (unsigned long)targetFreq);
47464889

47474890
#ifdef ARDUINO
4748-
_wire->end();
4749-
M5PM1_DELAY_MS(10);
4750-
_wire->begin(_sda, _scl, originalFreq);
4751-
M5PM1_DELAY_MS(10);
4891+
#if M5PM1_HAS_M5UNIFIED_I2C
4892+
if (_m5_i2c) {
4893+
_commFreq = originalFreq;
4894+
} else
4895+
#endif
4896+
{
4897+
_wire->end();
4898+
M5PM1_DELAY_MS(10);
4899+
_wire->begin(_sda, _scl, originalFreq);
4900+
M5PM1_DELAY_MS(10);
4901+
}
47524902
#else
47534903
switch (_i2cDriverType) {
47544904
#if M5PM1_HAS_I2C_MASTER
@@ -4790,6 +4940,11 @@ m5pm1_err_t M5PM1::switchI2cSpeed(m5pm1_i2c_speed_t speed)
47904940
break;
47914941
}
47924942
#endif // !M5PM1_HAS_I2C_MASTER && !M5PM1_HAS_I2C_BUS
4943+
#if M5PM1_HAS_M5UNIFIED_I2C
4944+
case M5PM1_I2C_DRIVER_M5UNIFIED:
4945+
_commFreq = originalFreq;
4946+
break;
4947+
#endif
47934948
default:
47944949
break;
47954950
}
@@ -4829,6 +4984,12 @@ bool M5PM1::isAutoWakeEnabled() const
48294984
m5pm1_err_t M5PM1::sendWakeSignal()
48304985
{
48314986
#ifdef ARDUINO
4987+
#if M5PM1_HAS_M5UNIFIED_I2C
4988+
if (_m5_i2c) {
4989+
M5PM1_M5UNIFIED_SEND_WAKE(_m5_i2c, _addr, _commFreq);
4990+
return M5PM1_OK;
4991+
}
4992+
#endif
48324993
M5PM1_I2C_ARDUINO_SEND_WAKE(_wire, _addr);
48334994
return M5PM1_OK;
48344995
#else

src/M5PM1.h

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -874,6 +874,9 @@ typedef enum {
874874
#ifndef ANALOG
875875
#define ANALOG 0xC0
876876
#endif
877+
#ifndef OTHER
878+
#define OTHER 0xFF
879+
#endif
877880

878881
// ============================
879882
// RGB 颜色结构
@@ -1036,7 +1039,21 @@ class M5PM1 {
10361039
*/
10371040
m5pm1_err_t begin(TwoWire* wire = &Wire, uint8_t addr = M5PM1_DEFAULT_ADDR, int8_t sda = -1, int8_t scl = -1,
10381041
uint32_t speed = M5PM1_I2C_FREQ_100K);
1039-
#else // ESP-IDF
1042+
#if M5PM1_HAS_M5UNIFIED_I2C
1043+
/**
1044+
* @brief Initialize with M5Unified I2C_Class instance (Arduino)
1045+
* @note The I2C bus must already be initialized (i2c->begin() called) by the caller.
1046+
* M5PM1 borrows the I2C_Class; caller retains ownership and lifecycle.
1047+
* 不负责驱动安装或释放,I2C 由调用方全程管理。
1048+
* @param i2c 已 begin() 的 m5::I2C_Class 指针
1049+
* Pointer to an already begin()-ed m5::I2C_Class
1050+
* @param addr I2C 地址 / I2C address (default 0x6E)
1051+
* @param speed I2C 速率(Hz,100000 或 400000)/ I2C speed in Hz (100000 or 400000)
1052+
* @return M5PM1_OK on success, error code otherwise
1053+
*/
1054+
m5pm1_err_t begin(m5::I2C_Class* i2c, uint8_t addr = M5PM1_DEFAULT_ADDR, uint32_t speed = M5PM1_I2C_FREQ_DEFAULT);
1055+
#endif // M5PM1_HAS_M5UNIFIED_I2C
1056+
#else // ESP-IDF
10401057
/**
10411058
* @brief Initialize with self-created I2C bus (ESP-IDF)
10421059
* @param port I2C port number
@@ -2900,6 +2917,11 @@ class M5PM1 {
29002917
TwoWire* _wire;
29012918
int8_t _sda;
29022919
int8_t _scl;
2920+
#if M5PM1_HAS_M5UNIFIED_I2C
2921+
m5::I2C_Class* _m5_i2c;
2922+
uint32_t _commFreq; // M5UNIFIED 路径专用:init 时从 100K 起,完成后切换至 _requestedSpeed
2923+
// M5UNIFIED path: starts at 100K during init, switches to _requestedSpeed after
2924+
#endif
29032925
#else
29042926
// I2C 驱动类型选择
29052927
// I2C driver type selection

0 commit comments

Comments
 (0)