Repository navigation
machine/esp32xx: wait for the I2C bus to be free before a transaction - #5978
Conversation
deadprogram
left a comment
There was a problem hiding this comment.
@davecheney thank you for working on this. This is edited from an automated review.
I tested it on a XIAO ESP32-S3 with the Seeed XIAO expansion board, which has an SSD1306 at 0x3C and a PCF8563 at 0x51. I2C at 100 kHz, 3 rounds each.
| Test | dev | This PR |
|---|---|---|
| Read only scan 0x08 to 0x77 | every address after a NACK times out, 0x3C missed in round 1 | 0x3C and 0x51 found |
| 1 byte write scan 0x08 to 0x77 | same timeouts, 0x3C and 0x51 found | 0x3C and 0x51 found |
| 400 reads of 0x3C directly after a NACK from 0x3B | 400 timeouts | 0 failures |
| 400 reads of 0x51 directly after a NACK from 0x3B | 400 timeouts | 0 failures |
So the S3 has the same problem and this fixes it there too.
However, there is an issue if the bus stays busy. For example when a device holds SDA low, every Tx now waits 40 ms and returns errI2CBusReadyTimeout, and nothing gets it out of that state. ESP-IDF resets the FSM when the bus is busy at the start of a transaction, see https://github.com/espressif/esp-idf/blob/v4.4.8/components/driver/i2c.c#L1451. I think you should call i2c.resetMaster() before returning the timeout, so a later call can recover.
Any thoughts on that? Otherwise it looks and works as expected.
|
@davecheney did you see my last comment on this PR? |
|
I did, sorry, i'll get to this tomorrow, that hardware is in a mess at the moment |
|
Thanks. Added Tested on a XIAO ESP32-C3 by holding SDA low. While SDA is held, every call fails with a timeout. After release the next call succeeds. SCL held low behaved the same, tested without the reset. On the C3 the bus also recovered without the reset, but the reset matches ESP-IDF and costs nothing. The NACK test still has 0 failures in 1700 pairs. ESP-IDF also sends up to 9 SCL pulses to free a device that holds SDA. I left that out. A device stuck in the middle of a read would still need it. Builds for xiao-esp32c3, xiao-esp32c6 and xiao-esp32s3. Only the C3 was tested on hardware. |
After a NACK, the controller keeps the bus busy for approximately 12 us. If the next transaction starts in this time, it does not complete and gives a timeout. Thus a read only I2C scan finds no devices. Wait for SR.BUS_BUSY to clear before the transaction starts. If the bus stays busy, reset the FSM before returning the timeout, as ESP-IDF does.
cf0c3ed to
70bcf17
Compare
|
Stuck bus test on a XIAO ESP32-C3 with the squashed commit. A Tx to 0x3C runs every 100 ms. Each fault was held by hand, then released. While a fault is held, every Tx fails with a timeout. The first Tx after release succeeds. With SDA shorted to SCL, the controller clocks SCL at about 89 kHz until the short is removed. |
|
@davecheney your testing tools are quite impressive! |
They’re shop made |
deadprogram
left a comment
There was a problem hiding this comment.
Thanks @davecheney looking good! Now merging.

Problem
After a NACK,
runCommandsreturnserrI2CAckExpectedimmediately. But the controller keepsSR.BUS_BUSYset for approximately 12 µs (at 100 kHz). If the nextTxstarts in this time, it does not complete and givesi2c: timeout during readori2c: timeout during write. This occurs also when the device is on the bus.Thus an I2C scan with read only probes finds no devices, because each probe starts directly after a NACK from the previous address.
Fix
Wait for
SR.BUS_BUSYto clear at the start oftransmit. If the bus does not become free before the timeout, returnerrI2CBusReadyTimeout.Test
Hardware: XIAO ESP32-C3 with a PCF8574 LCD backpack at 0x27. Address 0x26 is empty.
Before the fix,
SR.BUS_BUSYwas 1 directly after the NACK error and became 0 after approximately 12 µs.Also built for
xiao-esp32c6. I did not test the ESP32-S3, but it uses the same code.Logic trace
XIAO ESP32-C3 with a device at 0x3C, I2C at 100 kHz. Each loop reads 0x3B, which has no device, then 0x3C. Captured with a DSLogic at 10 MS/s.
Before the fix, no START follows the NACK and the read of 0x3C times out after 40 ms. 100 of 100 reads failed. After the fix, the START comes 9.5 µs after the STOP and the read completes. 0 of 700 reads failed.