-
Notifications
You must be signed in to change notification settings - Fork 99
Description
Summary / 概述
Ex_I2C (Grove Port A, I2C_NUM_0) is completely non-functional on M5StickS3 with ESP-IDF 5.5.3. All operations fail: scanID, write, read, stop. Same hardware works fine with standard ESP-IDF i2c_master API and GPIO bit-bang. In_I2C (I2C_NUM_1) is unaffected.
M5StickS3 上使用 ESP-IDF 5.5.3 时,Ex_I2C(Grove Port A, I2C_NUM_0)的所有操作全部失败:scanID、write、read、stop。同样的硬件和引脚,标准 ESP-IDF i2c_master API 和 GPIO bit-bang 通信正常。In_I2C(I2C_NUM_1)不受影响。
Environment / 环境
| Item | Value |
|---|---|
| Board | M5StickS3 (ESP32-S3-PICO-1 rev v0.2) |
| Sensor | Sensirion SGP41 (I2C addr 0x59) via Grove Port A |
| ESP-IDF | v5.5.3 |
| M5Unified | a6256725 (latest master) |
| M5GFX | 53a71846 (latest master) |
Test Results / 测试结果
Ex_I2C (Port 0, GPIO9/10) — ❌ All FAIL / 全部失败
| Operation | Result | Note |
|---|---|---|
scanID(0x59) |
❌ NOT FOUND | 0/10 passes, all frequencies (10k-400k) |
start(0x59) |
False positive — start(0x48) (non-existent) also returns ACK! |
|
stop() |
❌ FAIL | Always fails after start() |
write(data) |
❌ FAIL | All data writes fail |
read(data) |
❌ FAIL | All data reads fail |
In_I2C (Port 1, GPIO47/48) — ✅ All OK / 全部正常
| Operation | Result |
|---|---|
scanID(0x6E) |
✅ FOUND (PMIC) |
scanID(0x18) |
✅ FOUND (IMU) |
scanID(0x68) |
✅ FOUND (IMU) |
Standard API after release() — ✅ All OK / 全部正常
M5.Ex_I2C.release();
i2c_new_master_bus → ESP_OK ✅
i2c_master_probe(0x59) → ESP_OK ✅
SGP41 serial/self-test/VOC/NOx → all OK ✅
Root Cause / 根因
In common.cpp, init() calls i2c_new_master_bus() (line ~1401), which gives ESP-IDF driver exclusive control of the I2C peripheral. But beginTransaction() (line ~1566) then directly writes hardware registers (dev->ctr, dev->fifo_conf, dev->ctr.trans_start), bypassing the driver.
在 common.cpp 中,init() 调用 i2c_new_master_bus()(约第 1401 行),ESP-IDF 驱动接管了 I2C 外设。但 beginTransaction()(约第 1566 行)直接写硬件寄存器(dev->ctr、dev->fifo_conf、dev->ctr.trans_start),绕过了驱动层。
These two layers corrupt each other's state:
- ACK detection broken (non-existent addresses return ACK)
- FIFO operations fail (write/read always error)
nack_int_rawresidue causes stop() to always fail
两层互相破坏状态:
- ACK 检测失效(不存在的地址也返回 ACK)
- FIFO 操作失败(write/read 总是报错)
nack_int_raw残留导致 stop() 总是失败
In_I2C (Port 1) is unaffected — likely due to different init timing for PMIC/IMU devices.
In_I2C(Port 1)不受影响 — 可能因为 PMIC/IMU 设备的初始化时序不同。
Workaround / 临时解决方案
M5.begin(cfg);
M5.Power.setExtOutput(true);
M5.Ex_I2C.release(); // Release broken I2C port
i2c_master_bus_config_t bus_cfg = {
.i2c_port = I2C_NUM_0,
.sda_io_num = GPIO_NUM_9, .scl_io_num = GPIO_NUM_10,
.clk_source = I2C_CLK_SRC_DEFAULT,
.glitch_ignore_cnt = 7,
.flags = { .enable_internal_pullup = true },
};
i2c_master_bus_handle_t bus;
i2c_new_master_bus(&bus_cfg, &bus); // Works ✅Suggested Fix / 建议修复
-
Stop mixing APIs — since
i2c_new_master_busis called, usei2c_master_transmit/receiveinstead of direct register manipulation.
停止混用 API — 既然调用了i2c_new_master_bus,应使用i2c_master_transmit/receive而非直接操作寄存器。 -
Expose bus handle — add
getBusHandle()so users can pass the handle to third-party drivers.
暴露 bus handle — 提供getBusHandle()让用户传给第三方驱动。
Full Test Logs / 完整测试日志
Round 1: Problem Isolation (6 tests)
I bug_test: [Test 1] Ex_I2C.scanID(0x59): NOT FOUND
I bug_test: [Test 2] Ex_I2C.start(0x59)+stop(): ACK
I bug_test: [Test 3] Full Ex_I2C scan 0x08-0x77: 0 devices
I bug_test: [Test 4] Bit-bang probe(0x59) BEFORE release: FOUND
I bug_test: [Test 5] StdAPI AFTER release: i2c_master_probe ESP_OK, 1 device
I bug_test: [Test 6] Bit-bang probe(0x59) AFTER release: FOUND
Round 2: Deep Analysis (7 tests)
Test 1 - start/stop isolated:
start(0x59, write): ACK | stop(): FAIL
start(0x59, read): ACK | stop(): FAIL
Test 2 - Non-existent address:
start(0x48, write): ACK(!) | stop(): FAIL
Test 3 - 10x consecutive scanID: 0/10 passed
Test 4 - Frequencies: 10k/50k/100k/400k all NOT FOUND
Test 5 - In_I2C comparison:
In_I2C found: 0x18, 0x68, 0x6E (3 devices, all correct)
Test 6 - Data communication (SGP41 cmd 0x3682):
start: ACK | write: FAIL | read: FAIL
Test 7 - SGP41 conditioning (cmd 0x2612):
start: ACK | write(8 bytes): FAIL | read(3 bytes): FAIL