From a230cd82f0e15cdd3ab1e38616697a1f0317155c Mon Sep 17 00:00:00 2001 From: ainyan03 Date: Fri, 7 Aug 2026 08:01:08 +0000 Subject: [PATCH 1/3] Reset a low power I2C port through its own reset register The HP helper i2c_ll_reset_register() indexes the PCR I2C register array with the port number, and a low power port number is out of range for that array (it holds only the high power ports), so a forced stop on the low power port was resetting an unrelated register. Route low power ports to lp_i2c_ll_reset_register() instead. --- src/lgfx/v1/platforms/esp32/common.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/lgfx/v1/platforms/esp32/common.cpp b/src/lgfx/v1/platforms/esp32/common.cpp index bf22c21c..b8528dde 100644 --- a/src/lgfx/v1/platforms/esp32/common.cpp +++ b/src/lgfx/v1/platforms/esp32/common.cpp @@ -1149,6 +1149,13 @@ namespace lgfx __attribute__ ((unused)) static void i2c_periph_reset(int i2c_num) { +#if LGFX_LP_I2C_NUM > 0 + if (isLpPort(i2c_num)) + { // HP 用の i2c_ll_reset_register は SoC の PCR I2C 配列を範囲外参照するため LP 専用関数を使う; + lp_i2c_ll_reset_register(i2c_num - LGFX_HP_I2C_NUM); + return; + } +#endif I2C_RCC_ATOMIC() { i2c_ll_reset_register(i2c_num); (void)__DECLARE_RCC_ATOMIC_ENV; From 52638d0f18fc0b44bafc478a06514b120f0a7f0c Mon Sep 17 00:00:00 2001 From: ainyan03 Date: Fri, 7 Aug 2026 08:01:48 +0000 Subject: [PATCH 2/3] Keep an errored I2C transaction on the forced stop path i2c_wait() chose between the normal STOP command and the forced stop by reading int_raw, which was never initialized when the ack-wait stage had been skipped, so the choice was undefined after a failed read. The normal STOP path waits for a completion interrupt that never fires on a peripheral that has already been force-stopped by the error handling, costing the full 14ms timeout on every failed transaction. Initialize int_raw, treat an errored context as needing the forced stop, and skip the redundant hardware stop when the error handler has already issued one. --- src/lgfx/v1/platforms/esp32/common.cpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/lgfx/v1/platforms/esp32/common.cpp b/src/lgfx/v1/platforms/esp32/common.cpp index b8528dde..593071f7 100644 --- a/src/lgfx/v1/platforms/esp32/common.cpp +++ b/src/lgfx/v1/platforms/esp32/common.cpp @@ -1498,6 +1498,7 @@ namespace lgfx if (i2c_context[i2c_port].state == i2c_context_t::state_disconnect) { return res; } auto dev = getDev(i2c_port); typeof(dev->int_raw) int_raw; + int_raw.val = dev->int_raw.val; // ACK待ちステージをスキップした場合も後段の分岐で参照されるため必ず初期化する; static constexpr uint32_t intmask = I2C_ACK_ERR_INT_RAW_M | I2C_END_DETECT_INT_RAW_M | I2C_ARBITRATION_LOST_INT_RAW_M; if (i2c_context[i2c_port].wait_ack_stage) @@ -1541,12 +1542,17 @@ namespace lgfx if (flg_stop || res.has_error()) { #if defined ( CONFIG_IDF_TARGET_ESP32C2 ) || defined ( CONFIG_IDF_TARGET_ESP32S3 ) || defined ( CONFIG_IDF_TARGET_ESP32C5 ) || defined ( CONFIG_IDF_TARGET_ESP32C6 ) || defined ( CONFIG_IDF_TARGET_ESP32C61 ) || defined ( CONFIG_IDF_TARGET_ESP32P4 ) || defined ( CONFIG_IDF_TARGET_ESP32H2 ) - if (res.has_error() || i2c_context[i2c_port].state == i2c_context_t::state_read || !int_raw.end_detect_int_raw) +// エラー発生後はペリフェラルが強制停止済みの場合があり、通常のSTOPコマンド発行では完了割り込みが来ずタイムアウトまで待たされるため強制STOP側へ分岐する; + if (res.has_error() || i2c_context[i2c_port].state.has_error() || i2c_context[i2c_port].state == i2c_context_t::state_read || !int_raw.end_detect_int_raw) #else - if (res.has_error() || i2c_context[i2c_port].state == i2c_context_t::state_read || !int_raw.end_detect) + if (res.has_error() || i2c_context[i2c_port].state.has_error() || i2c_context[i2c_port].state == i2c_context_t::state_read || !int_raw.end_detect) #endif { // force stop - i2c_stop(i2c_port); + // state が既にエラーの場合はエラー検出箇所で停止済みのため再停止しない (res のエラーはこの呼び出しで検出されたもので未停止); + if (res.has_error() || !i2c_context[i2c_port].state.has_error()) + { + i2c_stop(i2c_port); + } } else { From 98a68f5cc3a10b2207246bf4fb13f90d0be7aae0 Mon Sep 17 00:00:00 2001 From: ainyan03 Date: Fri, 7 Aug 2026 08:02:13 +0000 Subject: [PATCH 3/3] Report a pure address NACK on read as NACK instead of timeout A read from an absent address ended in the "read timeout" warning, although the NACK is the expected outcome when probing for devices, and printing the warning costs several milliseconds per probe on a 115200bps console, slowing bus scans considerably. Report it at verbose level as a NACK, but only when neither the timeout flag nor the arbitration-lost flag accompanies it. --- src/lgfx/v1/platforms/esp32/common.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/lgfx/v1/platforms/esp32/common.cpp b/src/lgfx/v1/platforms/esp32/common.cpp index 593071f7..272e2460 100644 --- a/src/lgfx/v1/platforms/esp32/common.cpp +++ b/src/lgfx/v1/platforms/esp32/common.cpp @@ -2150,8 +2150,17 @@ namespace lgfx if (0 == getRxFifoCount(dev)) { + uint32_t int_raw_val = dev->int_raw.val; i2c_stop(i2c_port); - ESP_LOGW("LGFX", "i2c read error : read timeout"); + if ((int_raw_val & I2C_ACK_ERR_INT_RAW_M) + && !(int_raw_val & (I2C_TIME_OUT_INT_RAW_M | I2C_ARBITRATION_LOST_INT_RAW_M))) + { // Pure address NACK means no device is present: not a timeout, so no warning. + ESP_LOGV("LGFX", "i2c read error : nack"); + } + else + { + ESP_LOGW("LGFX", "i2c read error : read timeout"); + } res = cpp::fail(error_t::connection_lost); i2c_context[i2c_port].state = cpp::fail(error_t::connection_lost); i2c_context[i2c_port].wait_ack_stage = 0;