-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Description
Hi, I am working on a Pimoroni RP2040 product that involves regular communication with some onboard I2C devices at 400KHz.
During my testing I was encountering frequent lock-ups after a call to i2c_write_blocking
had completed. I checked this by setting a pin high before the call and to low afterwards. The pin would go low, suggesting the function had completed, then the lockup would occur before reaching my next line of code.
This was very strange to me, as I had successfully got the product working with a custom build of CircuitPython, which I had written C level drivers for. Checking how they implement I2C, I saw that i2c_write_timeout_us
was used, with a 1 second timeout.
Switching to this call in my code the lock-ups went away, without any timeouts actually getting triggered. Checking the pico-sdk, I see that both functions call i2c_write_blocking_internal
, with the latter having a callback that results in the below if statement getting executed.
pico-sdk/src/rp2_common/hardware_i2c/i2c.c
Lines 166 to 172 in 6a7db34
do { | |
if (timeout_check) { | |
timeout = timeout_check(ts); | |
abort |= timeout; | |
} | |
tight_loop_contents(); | |
} while (!timeout && !(i2c->hw->raw_intr_stat & I2C_IC_RAW_INTR_STAT_TX_EMPTY_BITS)); |
Suspecting that the longer loop time the timeout call was having a positive effect, I added a sleep_us(10)
as an else condition, and sure enough the lock-ups from i2c_write_blocking_internal
go away. Switching to a debug build also made the issue go away, thus ruling out SWD debugging.
Also, sending CTRL-C via the USB terminal would break the board out of the lock-up, though devices like PIO would not resume.
I am completely baffled by this!
For now I can switch my code to using the timeout function, and carry on. I just thought I would raise it in case there is an actual issue that needs resolving.
P.S: It may be inconsequential, but I have observed that my "debug" pin goes low before I2C comms complete, for the i2c_write_blocking
code path:
Whereas my "debug" pin goes low after the I2C comms complete, for the i2c_write_timeout_us
code path: