From badef2c26f1c27b93a260441ea97ff4e2c0874dd Mon Sep 17 00:00:00 2001 From: mverch67 Date: Fri, 25 Sep 2026 16:05:29 +0200 Subject: [PATCH] reset I2C bus to prevent stuck bytes on warm boot --- .../ELECROW-ThinkNode-M9/platformio.ini | 2 ++ .../esp32s3/ELECROW-ThinkNode-M9/variant.cpp | 35 +++++++++++++++++++ 2 files changed, 37 insertions(+) diff --git a/variants/esp32s3/ELECROW-ThinkNode-M9/platformio.ini b/variants/esp32s3/ELECROW-ThinkNode-M9/platformio.ini index 32ffda44eb..1fd304af8d 100644 --- a/variants/esp32s3/ELECROW-ThinkNode-M9/platformio.ini +++ b/variants/esp32s3/ELECROW-ThinkNode-M9/platformio.ini @@ -53,6 +53,8 @@ build_flags = -D HAS_TFT=1 -D USE_PACKET_API -D USE_PIN_BUZZER=PIN_BUZZER + -D SCAN_I2C_BUS_RESET + -D SCAN_I2C1_BUS_RESET -D LV_LVGL_H_INCLUDE_SIMPLE -D LV_CONF_INCLUDE_SIMPLE -D LV_COMP_CONF_INCLUDE_SIMPLE diff --git a/variants/esp32s3/ELECROW-ThinkNode-M9/variant.cpp b/variants/esp32s3/ELECROW-ThinkNode-M9/variant.cpp index fd802f7522..6d77e5ebd0 100644 --- a/variants/esp32s3/ELECROW-ThinkNode-M9/variant.cpp +++ b/variants/esp32s3/ELECROW-ThinkNode-M9/variant.cpp @@ -21,6 +21,41 @@ void earlyInitVariant() pinMode(GPS_RTC_INT, OUTPUT); digitalWrite(GPS_RTC_INT, LOW); delay(100); + + // After a warm reboot (RTC_SW_CPU_RST) I2C slaves-can be left mid-transaction, + // holding SDA low. This causes ESP_ERR_INVALID_STATE during the I2C scan, + // which leaves the I2C peripheral generating spurious interrupt requests. + // Fix: send 9 SCL clock pulses (enough to clock out any stuck byte) plus a + // STOP condition on both buses before the Wire driver initialises them. On + // a cold boot the SDA line is already high so the loop exits after the first + // check and the overhead is negligible (~10 µs). + auto recoverI2C = [](uint8_t sda, uint8_t scl) { + pinMode(scl, OUTPUT); + digitalWrite(scl, HIGH); + pinMode(sda, INPUT_PULLUP); + delayMicroseconds(5); + for (int i = 0; i < 9; i++) { + if (digitalRead(sda)) + break; // SDA released - slave is no longer driving the bus + digitalWrite(scl, LOW); + delayMicroseconds(5); + digitalWrite(scl, HIGH); + delayMicroseconds(5); + } + // STOP condition: SDA goes LOW then HIGH while SCL remains HIGH. + digitalWrite(scl, HIGH); + delayMicroseconds(2); + pinMode(sda, OUTPUT); + digitalWrite(sda, LOW); + delayMicroseconds(5); + digitalWrite(sda, HIGH); + delayMicroseconds(5); + // Release both pins so Wire.begin() can claim them as I2C. + pinMode(scl, INPUT); + pinMode(sda, INPUT); + }; + recoverI2C(I2C_SDA, I2C_SCL); + recoverI2C(I2C_SDA1, I2C_SCL1); } void initVariant()