Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merge I2C time stretch utility from ESP8266 Community Core #84

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 26 additions & 5 deletions cores/oak/core_esp8266_si2c.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@

unsigned char twi_dcount = 18;
static unsigned char twi_sda, twi_scl;
static uint32_t twi_clockStretchLimit;

#define SDA_LOW() (GPES = (1 << twi_sda)) //Enable SDA (becomes output and since GPO is 0 for the pin, it will pull the line low)
#define SDA_HIGH() (GPEC = (1 << twi_sda)) //Disable SDA (becomes input and since it has pullup it will go high)
Expand All @@ -37,9 +38,9 @@ static unsigned char twi_sda, twi_scl;
#endif

#if F_CPU == FCPU80
#define TWI_CLOCK_STRETCH 800
#define TWI_CLOCK_STRETCH_MULTIPLIER 3
#else
#define TWI_CLOCK_STRETCH 1600
#define TWI_CLOCK_STRETCH_MULTIPLIER 6
#endif

void twi_setClock(unsigned int freq){
Expand All @@ -60,12 +61,17 @@ void twi_setClock(unsigned int freq){
#endif
}

void twi_setClockStretchLimit(uint32_t limit){
twi_clockStretchLimit = limit * TWI_CLOCK_STRETCH_MULTIPLIER;
}

void twi_init(unsigned char sda, unsigned char scl){
twi_sda = esp8266_pinToGpio[sda];
twi_scl = esp8266_pinToGpio[scl];
pinMode(sda, INPUT_PULLUP);
pinMode(scl, INPUT_PULLUP);
twi_setClock(100000);
twi_setClockStretchLimit(230); // default value is 230 uS
}

void twi_stop(void){
Expand Down Expand Up @@ -98,7 +104,7 @@ static bool twi_write_stop(void){
SDA_LOW();
twi_delay(twi_dcount);
SCL_HIGH();
while (SCL_READ() == 0 && (i++) < TWI_CLOCK_STRETCH);// Clock stretching (up to 100us)
while (SCL_READ() == 0 && (i++) < twi_clockStretchLimit);// Clock stretching (up to 100us)
twi_delay(twi_dcount);
SDA_HIGH();
twi_delay(twi_dcount);
Expand All @@ -113,7 +119,7 @@ static bool twi_write_bit(bool bit) {
else SDA_LOW();
twi_delay(twi_dcount+1);
SCL_HIGH();
while (SCL_READ() == 0 && (i++) < TWI_CLOCK_STRETCH);// Clock stretching (up to 100us)
while (SCL_READ() == 0 && (i++) < twi_clockStretchLimit);// Clock stretching (up to 100us)
twi_delay(twi_dcount);
return true;
}
Expand All @@ -124,7 +130,7 @@ static bool twi_read_bit(void) {
SDA_HIGH();
twi_delay(twi_dcount+2);
SCL_HIGH();
while (SCL_READ() == 0 && (i++) < TWI_CLOCK_STRETCH);// Clock stretching (up to 100us)
while (SCL_READ() == 0 && (i++) < twi_clockStretchLimit);// Clock stretching (up to 100us)
bool bit = SDA_READ();
twi_delay(twi_dcount);
return bit;
Expand Down Expand Up @@ -190,3 +196,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
}
10 changes: 9 additions & 1 deletion cores/oak/twi.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,22 @@
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); // default value is 230 uS
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
}
#endif

#endif
#endif
12 changes: 11 additions & 1 deletion 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 All @@ -85,6 +89,10 @@ void TwoWire::setClock(uint32_t frequency){
twi_setClock(frequency);
}

void TwoWire::setClockStretchLimit(uint32_t limit){
twi_setClockStretchLimit(limit);
}

size_t TwoWire::requestFrom(uint8_t address, size_t size, bool sendStop){
if(size > BUFFER_LENGTH){
size = BUFFER_LENGTH;
Expand Down Expand Up @@ -243,4 +251,6 @@ void TwoWire::onRequest( void (*function)(void) ){

// Preinstantiate Objects //////////////////////////////////////////////////////

TwoWire Wire = TwoWire();
#if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_TWOWIRE)
TwoWire Wire;
#endif
4 changes: 4 additions & 0 deletions libraries/Wire/Wire.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,11 +56,13 @@ class TwoWire : public Stream
void begin(uint8_t);
void begin(int);
void setClock(uint32_t);
void setClockStretchLimit(uint32_t);
void beginTransmission(uint8_t);
void beginTransmission(int);
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 All @@ -83,7 +85,9 @@ class TwoWire : public Stream
using Print::write;
};

#if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_TWOWIRE)
extern TwoWire Wire;
#endif

#endif