Add Wire.setWireTimeout to avoid I2C bus hangs (closes #288) - #303
Merged
Conversation
If the I2C bus stops responding mid-transaction (noise, the display becomes disconnected, etc.), the underlying Wire library spins in an indefinite loop and the host MCU effectively hangs. The Arduino AVR core fixed this in ArduinoCore-avr@deea929 by exposing setWireTimeout(); cores that implement it define WIRE_HAS_TIMEOUT so callers can detect the feature at compile time. Use that detection: when periphBegin owns the wire->begin() call, follow it with a 25 ms timeout + reset on timeout. We only touch Wire's configuration when we performed the begin() ourselves; if the caller managed Wire externally, leave their configuration untouched. No behavioural change on cores without WIRE_HAS_TIMEOUT (the entire block is compiled out).
Member
|
ok! if it causes compilation issues in the future we may comment it out fyi |
Author
|
Thanks for the merge! Re: the future-compile-issue note — the Happy to send a follow-up if you ever want the timeout value made configurable instead of hard-coded to 25 ms. |
1 task
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #288.
Scope of the change
Adafruit_SSD1306::begin()(I2C path) now follows thewire->begin()call withwire->setWireTimeout(25000, true)when the compiler can see that the Wire library exposes the timeout API (WIRE_HAS_TIMEOUTdefined).That's the only change — three lines of code plus a short comment, all behind a
#ifdef WIRE_HAS_TIMEOUTguard.Why
The Arduino AVR Wire library historically had no timeout: a noisy or disconnected I2C bus would put
TWIinto an indefinite loop and lock the entire sketch. This was tracked in ArduinoCore-avr#42 and fixed by ArduinoCore-avr@deea929, which addedsetWireTimeout(uint32_t us, bool reset_with_timeout)and theWIRE_HAS_TIMEOUTfeature macro.The Adafruit_SSD1306 library never adopted the new API, so users on AVR cores still get hangs on SDA/SCL noise or display disconnect. Issue #288 asked for that.
Limitations
begin()path is touched. SPI is unchanged.periphBeginistrue— i.e. when this library performedwire->begin()itself. If the caller already calledWire.begin()(theperiphBegin=falsepath), their Wire configuration is left untouched on the assumption they're managing it explicitly.WIRE_HAS_TIMEOUT(older AVR cores, some non-AVR cores) compile out the entire block — no behavioural change there.Tests run locally
python3 ci/run-clang-format.py --clang-format-executable clang-format -e 'ci/*' -e 'bin/*' Adafruit_SSD1306.cpp→ cleanMaintainer signal
Per @ladyada's comment on #288: "ok can you submit a simple PR that passes CI?" — happy to iterate if anything here needs adjusting.