Add Wire.setWireTimeout to avoid I2C bus hangs (closes #288)

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).
This commit is contained in:
aditya
2026-05-22 17:34:40 +05:30
parent 74cc197f48
commit 4d19dfb747
+12 -1
View File
@@ -522,8 +522,19 @@ bool Adafruit_SSD1306::begin(uint8_t vcs, uint8_t addr, bool reset,
// function if it has unusual circumstances (e.g. TWI variants that // function if it has unusual circumstances (e.g. TWI variants that
// can accept different SDA/SCL pins, or if two SSD1306 instances // can accept different SDA/SCL pins, or if two SSD1306 instances
// with different addresses -- only a single begin() is needed). // with different addresses -- only a single begin() is needed).
if (periphBegin) if (periphBegin) {
wire->begin(); wire->begin();
#ifdef WIRE_HAS_TIMEOUT
// Avoid indefinite hangs in the Wire library when the I2C bus stops
// responding (e.g. SDA/SCL noise or the display disconnects). The
// setWireTimeout() API is exposed by Arduino cores that define
// WIRE_HAS_TIMEOUT (Arduino AVR core >= 1.8.6, see ArduinoCore-avr#42).
// We only set the timeout when we owned the begin() call -- if the
// caller managed Wire themselves, leave their configuration untouched.
// See Adafruit_SSD1306 issue #288.
wire->setWireTimeout(25000 /* us */, true /* reset on timeout */);
#endif
}
} else { // Using one of the SPI modes, either soft or hardware } else { // Using one of the SPI modes, either soft or hardware
pinMode(dcPin, OUTPUT); // Set data/command pin as output pinMode(dcPin, OUTPUT); // Set data/command pin as output
pinMode(csPin, OUTPUT); // Same for chip select pinMode(csPin, OUTPUT); // Same for chip select