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.
This commit is contained in:
Jason K 2017-09-29 09:17:13 -04:00 committed by Me No Dev
parent 10ff1def6d
commit 0cd62852da
4 changed files with 47 additions and 3 deletions

View File

@ -18,6 +18,7 @@
#include "freertos/task.h" #include "freertos/task.h"
#include "freertos/semphr.h" #include "freertos/semphr.h"
#include "rom/ets_sys.h" #include "rom/ets_sys.h"
#include "driver/periph_ctrl.h"
#include "soc/i2c_reg.h" #include "soc/i2c_reg.h"
#include "soc/i2c_struct.h" #include "soc/i2c_struct.h"
#include "soc/dport_reg.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(); 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) { while(dataLen) {
uint8_t willSend = (dataLen > 32)?32:dataLen; uint8_t willSend = (dataLen > 32)?32:dataLen;
uint8_t dataSend = willSend; 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 //Transmission did not finish and ACK_ERR is set
if(i2c->dev->int_raw.ack_err) { if(i2c->dev->int_raw.ack_err) {
//log_w("Ack Error! Addr: %x", address >> 1); //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(); I2C_MUTEX_UNLOCK();
return I2C_ERROR_ACK; 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(); 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); i2cResetFiFo(i2c);
i2cResetCmd(i2c); i2cResetCmd(i2c);
@ -445,7 +460,25 @@ void i2cInitFix(i2c_t * i2c){
i2c->dev->fifo_data.data = 0; i2c->dev->fifo_data.data = 0;
i2cSetCmd(i2c, 1, I2C_CMD_WRITE, 1, false, false, false); i2cSetCmd(i2c, 1, I2C_CMD_WRITE, 1, false, false, false);
i2cSetCmd(i2c, 2, I2C_CMD_STOP, 0, 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; 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(); 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();
}

View File

@ -27,7 +27,8 @@ typedef enum {
I2C_ERROR_DEV, I2C_ERROR_DEV,
I2C_ERROR_ACK, I2C_ERROR_ACK,
I2C_ERROR_TIMEOUT, I2C_ERROR_TIMEOUT,
I2C_ERROR_BUS I2C_ERROR_BUS,
I2C_ERROR_BUSY
} i2c_err_t; } i2c_err_t;
struct i2c_struct_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 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); 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 #ifdef __cplusplus
} }

View File

@ -211,4 +211,11 @@ void TwoWire::flush(void)
txLength = 0; txLength = 0;
} }
void TwoWire::reset(void)
{
i2cReset( i2c );
i2c = NULL;
begin( sda, scl );
}
TwoWire Wire = TwoWire(0); TwoWire Wire = TwoWire(0);

View File

@ -72,6 +72,8 @@ public:
int peek(void); int peek(void);
void flush(void); void flush(void);
void reset(void);
inline size_t write(const char * s) inline size_t write(const char * s)
{ {
return write((uint8_t*) s, strlen(s)); return write((uint8_t*) s, strlen(s));