Skip to content

Commit

Permalink
I2C bus reset with info to user
Browse files Browse the repository at this point in the history
I2C slave might stil have something to send when ESP826 starts I2C, thus
keeping the bus stuck.
Happens e.g. when power failure/reset during transmission.
Thanks to work of drmpf there is a solution.
Implemented as separate method so as not to interfere with existing.
Usage:

Wire.begin();
if (Wire.status() != I2C_OK) Serial.writeln("Something wrong with I2C
bus that cannot be recovered. Perform power cycle or search for other
masters on bus.";
  • Loading branch information
dave-prosee committed May 26, 2016
1 parent 5313c56 commit 099f3a4
Show file tree
Hide file tree
Showing 4 changed files with 27 additions and 0 deletions.
15 changes: 15 additions & 0 deletions cores/esp8266/core_esp8266_si2c.c
Original file line number Diff line number Diff line change
Expand Up @@ -197,3 +197,18 @@ unsigned char twi_readFrom(unsigned char address, unsigned char* buf, unsigned i
}
return 0;
}

uint8_t twi_status(){
if (SCL_READ()==0) return I2C_SCL_HELD_LOW; //SCL held low by another device, no procedure available to recover
int clockCount = 20;

while (SDA_READ()==0 && clockCount>0){ //if SDA low, read the bits slaves have to sent to a max
twi_read_bit();
if (SCL_READ()==0) return I2C_SCL_HELD_LOW_AFTER_READ; //I2C bus error. SCL held low beyond slave clock stretch time
}

if (SDA_READ()==0) return I2C_SDA_HELD_LOW; //I2C bus error. SDA line held low by slave/another_master after n bits.

if(!twi_write_start()) return I2C_SDA_HELD_LOW_AFTER_INIT; //line busy. SDA again held low by another device. 2nd master?
else return I2C_OK; //all ok
}
7 changes: 7 additions & 0 deletions cores/esp8266/twi.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,19 @@
extern "C" {
#endif

#define I2C_OK 0
#define I2C_SCL_HELD_LOW 1
#define I2C_SCL_HELD_LOW_AFTER_READ 2
#define I2C_SDA_HELD_LOW 3
#define I2C_SDA_HELD_LOW_AFTER_INIT 4

void twi_init(unsigned char sda, unsigned char scl);
void twi_stop(void);
void twi_setClock(unsigned int freq);
void twi_setClockStretchLimit(uint32_t limit);
uint8_t twi_writeTo(unsigned char address, unsigned char * buf, unsigned int len, unsigned char sendStop);
uint8_t twi_readFrom(unsigned char address, unsigned char * buf, unsigned int len, unsigned char sendStop);
uint8_t twi_status();

#ifdef __cplusplus
}
Expand Down
4 changes: 4 additions & 0 deletions libraries/Wire/Wire.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,10 @@ void TwoWire::begin(uint8_t address){
begin();
}

uint8_t TwoWire::status(){
return twi_status();
}

void TwoWire::begin(int address){
begin((uint8_t)address);
}
Expand Down
1 change: 1 addition & 0 deletions libraries/Wire/Wire.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ class TwoWire : public Stream
uint8_t endTransmission(void);
uint8_t endTransmission(uint8_t);
size_t requestFrom(uint8_t address, size_t size, bool sendStop);
uint8_t status();

uint8_t requestFrom(uint8_t, uint8_t);
uint8_t requestFrom(uint8_t, uint8_t, uint8_t);
Expand Down

3 comments on commit 099f3a4

@Frida854
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

https://github.com/esp8266/Arduino/blob/master/cores/esp8266/core_esp8266_si2c.c#L201-L208

Where are 'clockCount' countdown, as I see it, there is never countdown.

@vlast3k
Copy link

@vlast3k vlast3k commented on 099f3a4 Feb 5, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if it reaches this point it goes into loop, you need to make it counting down

@vlast3k
Copy link

@vlast3k vlast3k commented on 099f3a4 Feb 5, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

or submit a PR :)

Please sign in to comment.