From 786bacf3304dd1cd5da9a99addc165115f2042b5 Mon Sep 17 00:00:00 2001 From: onexs-xsi <850559025@qq.com> Date: Thu, 26 Feb 2026 17:43:21 +0800 Subject: [PATCH] 1. Optimize the description of i2c_bus-related usage --- README.md | 4 +++ src/M5IOE1_i2c_compat.h | 66 +++++++++++++++++++---------------------- 2 files changed, 35 insertions(+), 35 deletions(-) diff --git a/README.md b/README.md index 4f6de83..39aae13 100644 --- a/README.md +++ b/README.md @@ -36,6 +36,10 @@ If used alongside `M5Unified`, include it **before** `M5IOE1`: > > Alternatively, enable `CONFIG_I2C_BUS_BACKWARD_CONFIG` in menuconfig to remove the restriction. +### i2c_bus mode is not supported when M5GFX / M5Unified is present + +Use `begin(&M5.In_I2C, addr, freq)` instead — M5GFX already owns the I2C bus and the two drivers cannot share it. + ## License - [M5IOE1 - MIT](LICENSE) diff --git a/src/M5IOE1_i2c_compat.h b/src/M5IOE1_i2c_compat.h index 59466b0..fa67f50 100644 --- a/src/M5IOE1_i2c_compat.h +++ b/src/M5IOE1_i2c_compat.h @@ -152,36 +152,17 @@ static inline void M5IOE1_I2C_ARDUINO_SEND_WAKE(TwoWire *wire, uint8_t addr) // Detect if i2c_bus is available // // ESP-IDF < 5.3.0 -// 未启用 BACKWARD_CONFIG -// → 不支持 i2c_bus,使用传统 driver/i2c.h Legacy API -// 启用 BACKWARD_CONFIG -// → i2c_bus.h 内部回退到 driver/i2c.h,可安全使用 +// Without BACKWARD_CONFIG: i2c_bus not supported; use legacy driver/i2c.h API. +// With BACKWARD_CONFIG: i2c_bus.h falls back to driver/i2c.h internally, safe to use. // // ESP-IDF >= 5.3.0 -// 启用 BACKWARD_CONFIG -// → i2c_bus.h 内部使用 driver/i2c.h,无冲突风险 -// 未启用 BACKWARD_CONFIG -// driver/i2c.h 已被其他组件提前包含(_DRIVER_I2C_H_ 已定义) -// → i2c_bus.h 会自定义 i2c_config_t,与已定义的版本冲突 → 禁用 -// driver/i2c.h 尚未被包含(_DRIVER_I2C_H_ 未定义) -// → 无冲突风险,按默认配置启用 i2c_bus -// -// Detection logic: -// ESP-IDF < 5.3.0: -// Without BACKWARD_CONFIG: i2c_bus not supported; use legacy driver/i2c.h API. -// With BACKWARD_CONFIG: i2c_bus.h falls back to driver/i2c.h internally, safe to use. -// ESP-IDF >= 5.3.0: -// With BACKWARD_CONFIG: i2c_bus.h uses driver/i2c.h internally, always conflict-free. -// Without BACKWARD_CONFIG: -// _DRIVER_I2C_H_ defined (driver/i2c.h already included by another component) -// → i2c_bus.h would define its own i2c_config_t, conflicting with the existing one → disabled. -// _DRIVER_I2C_H_ not defined (driver/i2c.h not yet included) -// → no conflict risk, enable i2c_bus with default config. -// -// Note: _DRIVER_I2C_H_ is the include guard of driver/i2c.h (ESP-IDF legacy I2C header). -// Checking it at preprocessor time reflects whether driver/i2c.h was included -// BEFORE this header. Inclusion after this header cannot be detected here; -// in that case the user is responsible for ensuring no conflict (or enabling BACKWARD_CONFIG). +// [Highest priority] M5GFX or M5Unified is present: +// -> i2c_bus mode is NEVER safe (runtime conflict), disabled with #error if detected. +// Fix: use ioe1.begin(&M5.In_I2C, addr, freq) instead. +// With BACKWARD_CONFIG (no M5GFX/M5Unified): i2c_bus.h uses driver/i2c.h internally, safe. +// Without BACKWARD_CONFIG (no M5GFX/M5Unified): +// _DRIVER_I2C_H_ defined: i2c_config_t typedef conflict risk, disabled. +// _DRIVER_I2C_H_ not defined: no conflict risk, enable i2c_bus. #if __has_include() #if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 3, 0) #if defined(CONFIG_I2C_BUS_BACKWARD_CONFIG) @@ -191,14 +172,29 @@ static inline void M5IOE1_I2C_ARDUINO_SEND_WAKE(TwoWire *wire, uint8_t addr) #endif #else // IDF >= 5.3.0 -#if defined(CONFIG_I2C_BUS_BACKWARD_CONFIG) -#define M5IOE1_HAS_I2C_BUS 1 // BACKWARD_CONFIG:i2c_bus.h 使用 driver/i2c.h,无冲突 / no conflict -#elif defined(_DRIVER_I2C_H_) || (defined(__cplusplus) && __has_include()) -#define M5IOE1_HAS_I2C_BUS \ - 0 // driver/i2c.h 已包含或 M5Unified 可用(将包含 driver/i2c.h)→ i2c_config_t 冲突风险,禁用 - // driver/i2c.h already included or M5Unified available (will include driver/i2c.h) → conflict risk, disabled +// +// Runtime conflict (highest priority): +// M5GFX calls i2c_new_master_bus() (driver_ng) during global construction. +// espressif__i2c_bus conflicts with it on both code paths: +// BACKWARD_CONFIG=y -> i2c_bus.c calls i2c_driver_install() (legacy) -> runtime abort() +// BACKWARD_CONFIG=n -> i2c_bus_v2.c calls i2c_new_master_bus() on the same port -> undefined behaviour +// Therefore, i2c_bus mode MUST be disabled whenever M5GFX or M5Unified is in the project. +#if __has_include() || __has_include() +#if defined(_I2C_BUS_H_) +#error \ + "[M5IOE1] i2c_bus cannot be used together with M5GFX/M5Unified. " \ + "M5GFX registers driver_ng via i2c_new_master_bus() during global construction. " \ + "BACKWARD_CONFIG=y: i2c_bus.c calls i2c_driver_install() (legacy driver) -> runtime abort() in check_i2c_driver_conflict(). " \ + "BACKWARD_CONFIG=n: i2c_bus_v2.c calls i2c_new_master_bus() on the same port -> undefined behaviour. " \ + "Fix: use ioe1.begin(&M5.In_I2C, addr, freq) and set I2C_USE_MODE=0." +#endif +#define M5IOE1_HAS_I2C_BUS 0 +#elif defined(CONFIG_I2C_BUS_BACKWARD_CONFIG) +#define M5IOE1_HAS_I2C_BUS 1 // BACKWARD_CONFIG, no M5GFX/M5Unified: compatible +#elif defined(_DRIVER_I2C_H_) +#define M5IOE1_HAS_I2C_BUS 0 // driver/i2c.h already included -> i2c_config_t typedef conflict risk, disabled #else -#define M5IOE1_HAS_I2C_BUS 1 // driver/i2c.h 尚未包含,无冲突风险 / driver/i2c.h not yet included, no conflict +#define M5IOE1_HAS_I2C_BUS 1 // no conflict risk #endif #endif #else