Skip to content

Possible lockup-issue with i2c_write_blocking versus i2c_write_timeout_us (maybe conflicting with USB serial?) #1471

@ZodiusInfuser

Description

@ZodiusInfuser

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.

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:
image

Whereas my "debug" pin goes low after the I2C comms complete, for the i2c_write_timeout_us code path:
image

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions