From 6495ceb1c745c188872c99658edf3644a9457989 Mon Sep 17 00:00:00 2001 From: deadprogram Date: Tue, 29 Sep 2026 01:05:31 +0200 Subject: [PATCH] machine/esp32xx: clear the I2C bus with a GPIO STOP when configuring Without a bus clear, an MPU-6050 on a XIAO ESP32-C3 NACKs the first transaction after a chip reset. This does the same as the software i2c_master_clear_bus in ESP-IDF v4.4.8. SCL is clocked while SDA is held low, then a STOP is sent with the pins as GPIOs. --- src/machine/machine_esp32xx_i2c.go | 33 ++++++++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/src/machine/machine_esp32xx_i2c.go b/src/machine/machine_esp32xx_i2c.go index ab62cd063b..aeda5e0c74 100644 --- a/src/machine/machine_esp32xx_i2c.go +++ b/src/machine/machine_esp32xx_i2c.go @@ -44,6 +44,7 @@ func (i2c *I2C) Configure(config I2CConfig) error { i2c.initClock(config) i2c.initNoiseFilter() + i2c.clearBus(config) i2c.initPins(config) i2c.initFrequency(config) i2c.startMaster() @@ -72,6 +73,36 @@ func (i2c *I2C) initNoiseFilter() { i2c.Bus.FILTER_CFG.Set(0x377) } +// clearBus clocks SCL until SDA is released and then sends a STOP, both as GPIOs. +// Same as ESP-IDF https://github.com/espressif/esp-idf/blob/v4.4.8/components/driver/i2c.c#L579 +func (i2c *I2C) clearBus(config I2CConfig) { + const halfPeriodNS = 5000 + wait := func() { + end := nanotime() + halfPeriodNS + for nanotime() < end { + } + } + scl, sda := config.SCL, config.SDA + scl.Configure(PinConfig{Mode: PinOutput}) + scl.pinReg().SetBits(esp.GPIO_PIN_PAD_DRIVER) + sda.Configure(PinConfig{Mode: PinOutput}) + sda.pinReg().SetBits(esp.GPIO_PIN_PAD_DRIVER) + scl.Low() + sda.High() + wait() + for i := 0; i < 9 && !sda.Get(); i++ { + scl.High() + wait() + scl.Low() + wait() + } + sda.Low() + scl.High() + wait() + sda.High() + wait() +} + //go:inline func (i2c *I2C) initPins(config I2CConfig) { config.SDA.configure(PinConfig{Mode: PinOutput}, i2c.funcSDA) @@ -139,8 +170,6 @@ func (i2c *I2C) startMaster() { func (i2c *I2C) resetMaster() { // reset FSM i2c.Bus.SetCTR_FSM_RST(1) - // No bus clear (SCL_RST_SLV), a GT911 did not ACK the next transaction after it. - // ESP-IDF does not clear the bus on init either https://github.com/espressif/esp-idf/blob/v4.4.8/components/driver/i2c.c#L673 i2c.Bus.SetSCL_STRETCH_CONF_SLAVE_SCL_STRETCH_EN(1) i2c.Bus.SetCTR_CONF_UPGATE(1) i2c.Bus.FILTER_CFG.Set(0x377)