arduino / arduino/ArduinoCore-samd
enableWire() Needs to check SCL and SDA before setting bus state to idle
- Dominant language
- C
- Stars
- 502
- Forks
- 740
- PR merge metrics
- No merged PRs in 30d
Description
https://github.com/arduino/ArduinoCore-samd/blob/993398cb7a23a4e0f821a73501ae98053773165b/cores/arduino/SERCOM.cpp#L398
I have a multimaster I2C system running the Arduino Wire library on a SAMD21 MKR1000 that uses general call for message broadcasts. Each device runs in slave mode and then switches to master briefly to send a message.
I found many hangs, `BUSERR`, `ARBLOST`, and `RXNACK` problems when bus traffic was heavy. The problem is that `enableWire()` in the Arduino `SERCOM.cpp` library (called from `Wire.begin`) blindly sets the bus state to `IDLE`.
While you can place checks on `isBusBusyWIRE` before `beginTransmission` and `endTransmission` to avoid collisions in your Arduino sketch, those checks will fail if the bus has been set to `IDLE` when it is actually busy. The master will come up and if there is a message on the bus it will get overwritten. (Note the SERCOM library itself uses these checks in critical locations within the code.)
The answer is to check the bus to see if it is actually idle before setting the bus state to `IDLE` in `enableWire()`. Here is the workaround using the Arduino Sketch before calling `Wire.begin()`:
```cpp
//Wire.begin sets bus to idle. Make sure bus is actually idle first.
pinMode(SCL_PIN, INPUT);
pinMode(SDA_PIN, INPUT);
int start_time = micros();
int idle_time = 0;
while (idle_time < 50) {
//Each clock cycle is about 10uS. These digitalRead calls take a few uS each.
if ((digitalRead(SCL_PIN) == LOW) || (digitalRead(SDA_PIN) == LOW)) {
start_time = micros();
}
idle_time = micros() - start_time;
}
Wire.begin();
```
The correct place for this check is within `enableWire()`.
Contributor guide
No contributing guide indexed for this repository
Research direction
Start in cores/arduino/SERCOM.cpp at enableWire(), referenced near line 398, and trace how Wire.begin() sets the bus state. Check SCL and SDA before declaring the bus idle, then verify the change against the reported multimaster behavior on the SAMD21 MKR1000 under active traffic.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- arduino, cpp
- Domain
- embedded-iot
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 52/100