Skip to content

Commit a30de14

Browse files
stickbreakerCurclamas
authored andcommitted
Improve bus recovery (espressif#1767)
If the esp32 is reset during a i2c read cycle the slave device may be in control of the SDA line. If the SDA line is held low, the esp32 cannot issue a START or STOP to recover the bus. The previous code did not correctly configure the SCL output pin, and it cycled SCL 9 times with SDA Low. Since the slave device was in a READ cycle, it just continued outputting the bits of the current byte. When the ACK/NAK bit space occurred, The low output value of SDA was interpreted as ACK so the slave device continued with the next byte. It never terminated the READ cycle. This new code will correctly recover from an interrupted READ
1 parent 3291210 commit a30de14

File tree

1 file changed

+11
-12
lines changed

1 file changed

+11
-12
lines changed

Diff for: cores/esp32/esp32-hal-i2c.c

+11-12
Original file line numberDiff line numberDiff line change
@@ -1350,33 +1350,32 @@ static void i2cReleaseISR(i2c_t * i2c)
13501350
}
13511351

13521352
static bool i2cCheckLineState(int8_t sda, int8_t scl){
1353-
if(sda < 0 || scl < 0){
1354-
return true;//return true since there is nothing to do
1353+
if(sda < 0 || scl < 0){
1354+
return false;//return false since there is nothing to do
13551355
}
1356-
// if the bus is not 'clear' try the recommended recovery sequence, START, 9 Clocks, STOP
1356+
// if the bus is not 'clear' try the cycling SCL until SDA goes High or 9 cycles
13571357
digitalWrite(sda, HIGH);
13581358
digitalWrite(scl, HIGH);
1359-
pinMode(sda, PULLUP|OPEN_DRAIN|OUTPUT|INPUT);
1360-
pinMode(scl, PULLUP|OPEN_DRAIN|OUTPUT|INPUT);
1359+
pinMode(sda, PULLUP|OPEN_DRAIN|INPUT);
1360+
pinMode(scl, PULLUP|OPEN_DRAIN|OUTPUT);
13611361

13621362
if(!digitalRead(sda) || !digitalRead(scl)) { // bus in busy state
1363-
log_w("invalid state sda=%d, scl=%d\n", digitalRead(sda), digitalRead(scl));
1364-
digitalWrite(sda, HIGH);
1363+
log_w("invalid state sda(%d)=%d, scl(%d)=%d", sda, digitalRead(sda), scl, digitalRead(scl));
13651364
digitalWrite(scl, HIGH);
1366-
delayMicroseconds(5);
1367-
digitalWrite(sda, LOW);
13681365
for(uint8_t a=0; a<9; a++) {
13691366
delayMicroseconds(5);
13701367
digitalWrite(scl, LOW);
13711368
delayMicroseconds(5);
13721369
digitalWrite(scl, HIGH);
1370+
if(digitalRead(sda)){ // bus recovered
1371+
log_d("Recovered after %d Cycles",a+1);
1372+
break;
1373+
}
13731374
}
1374-
delayMicroseconds(5);
1375-
digitalWrite(sda, HIGH);
13761375
}
13771376

13781377
if(!digitalRead(sda) || !digitalRead(scl)) { // bus in busy state
1379-
log_e("Bus Invalid State, TwoWire() Can't init");
1378+
log_e("Bus Invalid State, TwoWire() Can't init sda=%d, scl=%d",digitalRead(sda),digitalRead(scl));
13801379
return false; // bus is busy
13811380
}
13821381
return true;

0 commit comments

Comments
 (0)