reset I2C bus to prevent stuck bytes on warm boot

This commit is contained in:
mverch67 committed 2026-09-25 16:05:29 +02:00
1 parent 57937c5ccc
commit badef2c26f
2 files changed
+37

No files matched your search

@@ -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
@@ -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()