From 3f15903566e0f6c4bcded7c0ea20e111d7beee44 Mon Sep 17 00:00:00 2001
From: mvdbro <mvdbro@zonnet.nl>
Date: Wed, 3 Feb 2016 17:05:04 +0100
Subject: [PATCH] Configurable I2C clock stretching limit

Use Wire.setClockStretchLimit(limit)
limit is in uSeconds
---
 cores/esp8266/core_esp8266_si2c.c | 23 +++++++++++++++--------
 cores/esp8266/twi.h               |  1 +
 libraries/Wire/Wire.cpp           |  4 ++++
 libraries/Wire/Wire.h             |  1 +
 libraries/Wire/keywords.txt       |  1 +
 5 files changed, 22 insertions(+), 8 deletions(-)

diff --git a/cores/esp8266/core_esp8266_si2c.c b/cores/esp8266/core_esp8266_si2c.c
index 4008c5c8f..52fdd21dd 100644
--- a/cores/esp8266/core_esp8266_si2c.c
+++ b/cores/esp8266/core_esp8266_si2c.c
@@ -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)
@@ -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){
@@ -60,14 +61,20 @@ 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 = sda;
   twi_scl = scl;
   pinMode(twi_sda, INPUT_PULLUP);
   pinMode(twi_scl, INPUT_PULLUP);
   twi_setClock(100000);
+  twi_setClockStretchLimit(230); // default value is 230 uS
 }
 
+
 void twi_stop(void){
   pinMode(twi_sda, INPUT);
   pinMode(twi_scl, INPUT);
@@ -93,12 +100,12 @@ static bool twi_write_start(void) {
 }
 
 static bool twi_write_stop(void){
-  unsigned int i = 0;
+  uint32_t i = 0;
   SCL_LOW();
   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
   twi_delay(twi_dcount);
   SDA_HIGH();
   twi_delay(twi_dcount);
@@ -107,24 +114,24 @@ static bool twi_write_stop(void){
 }
 
 static bool twi_write_bit(bool bit) {
-  unsigned int i = 0;
+  uint32_t i = 0;
   SCL_LOW();
   if (bit) SDA_HIGH();
   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
   twi_delay(twi_dcount);
   return true;
 }
 
 static bool twi_read_bit(void) {
-  unsigned int i = 0;
+  uint32_t i = 0;
   SCL_LOW();
   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
   bool bit = SDA_READ();
   twi_delay(twi_dcount);
   return bit;
diff --git a/cores/esp8266/twi.h b/cores/esp8266/twi.h
index 9e661e88e..f0f76e106 100644
--- a/cores/esp8266/twi.h
+++ b/cores/esp8266/twi.h
@@ -29,6 +29,7 @@ extern "C" {
 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);
 
diff --git a/libraries/Wire/Wire.cpp b/libraries/Wire/Wire.cpp
index c1f457aa4..1e7e2d560 100644
--- a/libraries/Wire/Wire.cpp
+++ b/libraries/Wire/Wire.cpp
@@ -85,6 +85,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;
diff --git a/libraries/Wire/Wire.h b/libraries/Wire/Wire.h
index 9fc8f9c76..fa20dbb31 100644
--- a/libraries/Wire/Wire.h
+++ b/libraries/Wire/Wire.h
@@ -56,6 +56,7 @@ 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);
diff --git a/libraries/Wire/keywords.txt b/libraries/Wire/keywords.txt
index ff3147592..3344011d4 100644
--- a/libraries/Wire/keywords.txt
+++ b/libraries/Wire/keywords.txt
@@ -12,6 +12,7 @@
 
 begin	KEYWORD2
 setClock	KEYWORD2
+setClockStretchLimit	KEYWORD2
 beginTransmission	KEYWORD2
 endTransmission	KEYWORD2
 requestFrom	KEYWORD2