Skip to content

[Bug] Ex_I2C (I2C_NUM_0) completely broken on ESP32-S3 + ESP-IDF 5.5.3 — Ex_I2C(I2C_NUM_0)在 ESP32-S3 + ESP-IDF 5.5.3 上完全不可用 #186

@LOVECHEN

Description

@LOVECHEN

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) ⚠️ ACK False positivestart(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->ctrdev->fifo_confdev->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_raw residue 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 / 建议修复

  1. Stop mixing APIs — since i2c_new_master_bus is called, use i2c_master_transmit/receive instead of direct register manipulation.
    停止混用 API — 既然调用了 i2c_new_master_bus,应使用 i2c_master_transmit/receive 而非直接操作寄存器。

  2. 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

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions