From 0cd62852da1a5f00fda596d0aa455044f978558e Mon Sep 17 00:00:00 2001 From: Jason K Date: Fri, 29 Sep 2017 09:17:13 -0400 Subject: [PATCH] I2c reset functionality (#678) * Addition of a i2cReset method and timeout handling for the case where the i2c hardware FSM (state machine) gets stuck in a busy state. * Use newly added i2cReset function within the wire library. --- cores/esp32/esp32-hal-i2c.c | 37 +++++++++++++++++++++++++++++++++++-- cores/esp32/esp32-hal-i2c.h | 4 +++- libraries/Wire/src/Wire.cpp | 7 +++++++ libraries/Wire/src/Wire.h | 2 ++ 4 files changed, 47 insertions(+), 3 deletions(-) diff --git a/cores/esp32/esp32-hal-i2c.c b/cores/esp32/esp32-hal-i2c.c index e5354b91..1bba266f 100644 --- a/cores/esp32/esp32-hal-i2c.c +++ b/cores/esp32/esp32-hal-i2c.c @@ -18,6 +18,7 @@ #include "freertos/task.h" #include "freertos/semphr.h" #include "rom/ets_sys.h" +#include "driver/periph_ctrl.h" #include "soc/i2c_reg.h" #include "soc/i2c_struct.h" #include "soc/dport_reg.h" @@ -154,6 +155,13 @@ i2c_err_t i2cWrite(i2c_t * i2c, uint16_t address, bool addr_10bit, uint8_t * dat I2C_MUTEX_LOCK(); + if (i2c->dev->status_reg.bus_busy == 1) + { + //log_w( "Busy Timeout! Addr: %x", address >> 1 ); + I2C_MUTEX_UNLOCK(); + return I2C_ERROR_BUSY; + } + while(dataLen) { uint8_t willSend = (dataLen > 32)?32:dataLen; uint8_t dataSend = willSend; @@ -221,7 +229,7 @@ i2c_err_t i2cWrite(i2c_t * i2c, uint16_t address, bool addr_10bit, uint8_t * dat //Transmission did not finish and ACK_ERR is set if(i2c->dev->int_raw.ack_err) { //log_w("Ack Error! Addr: %x", address >> 1); - while(i2c->dev->status_reg.bus_busy); + while((i2c->dev->status_reg.bus_busy) && ((millis() - startAt)>50)); I2C_MUTEX_UNLOCK(); return I2C_ERROR_ACK; } @@ -250,6 +258,13 @@ i2c_err_t i2cRead(i2c_t * i2c, uint16_t address, bool addr_10bit, uint8_t * data I2C_MUTEX_LOCK(); + if (i2c->dev->status_reg.bus_busy == 1) + { + //log_w( "Busy Timeout! Addr: %x", address >> 1 ); + I2C_MUTEX_UNLOCK(); + return I2C_ERROR_BUSY; + } + i2cResetFiFo(i2c); i2cResetCmd(i2c); @@ -445,7 +460,25 @@ void i2cInitFix(i2c_t * i2c){ i2c->dev->fifo_data.data = 0; i2cSetCmd(i2c, 1, I2C_CMD_WRITE, 1, false, false, false); i2cSetCmd(i2c, 2, I2C_CMD_STOP, 0, false, false, false); + if (i2c->dev->status_reg.bus_busy) // If this condition is true, the while loop will timeout as done will not be set + { + //log_e("Busy at initialization!"); + } i2c->dev->ctr.trans_start = 1; - while(!i2c->dev->command[2].done); + uint16_t count = 50000; + while ((!i2c->dev->command[2].done) && (--count > 0)); I2C_MUTEX_UNLOCK(); } + +void i2cReset(i2c_t* i2c){ + if(i2c == NULL){ + return; + } + I2C_MUTEX_LOCK(); + periph_module_t moduleId = (i2c == &_i2c_bus_array[0])?PERIPH_I2C0_MODULE:PERIPH_I2C1_MODULE; + periph_module_disable( moduleId ); + delay( 20 ); // Seems long but delay was chosen to ensure system teardown and setup without core generation + periph_module_enable( moduleId ); + I2C_MUTEX_UNLOCK(); +} + diff --git a/cores/esp32/esp32-hal-i2c.h b/cores/esp32/esp32-hal-i2c.h index 22486d76..3e988610 100644 --- a/cores/esp32/esp32-hal-i2c.h +++ b/cores/esp32/esp32-hal-i2c.h @@ -27,7 +27,8 @@ typedef enum { I2C_ERROR_DEV, I2C_ERROR_ACK, I2C_ERROR_TIMEOUT, - I2C_ERROR_BUS + I2C_ERROR_BUS, + I2C_ERROR_BUSY } i2c_err_t; struct i2c_struct_t; @@ -50,6 +51,7 @@ i2c_err_t i2cDetachSDA(i2c_t * i2c, int8_t sda); i2c_err_t i2cWrite(i2c_t * i2c, uint16_t address, bool addr_10bit, uint8_t * data, uint8_t len, bool sendStop); i2c_err_t i2cRead(i2c_t * i2c, uint16_t address, bool addr_10bit, uint8_t * data, uint8_t len, bool sendStop); +void i2cReset(i2c_t* i2c); #ifdef __cplusplus } diff --git a/libraries/Wire/src/Wire.cpp b/libraries/Wire/src/Wire.cpp index a3585284..ba670eaf 100644 --- a/libraries/Wire/src/Wire.cpp +++ b/libraries/Wire/src/Wire.cpp @@ -211,4 +211,11 @@ void TwoWire::flush(void) txLength = 0; } +void TwoWire::reset(void) +{ + i2cReset( i2c ); + i2c = NULL; + begin( sda, scl ); +} + TwoWire Wire = TwoWire(0); diff --git a/libraries/Wire/src/Wire.h b/libraries/Wire/src/Wire.h index 39d0ff72..d9a7a752 100644 --- a/libraries/Wire/src/Wire.h +++ b/libraries/Wire/src/Wire.h @@ -72,6 +72,8 @@ public: int peek(void); void flush(void); + void reset(void); + inline size_t write(const char * s) { return write((uint8_t*) s, strlen(s));