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

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

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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