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:
parent
10ff1def6d
commit
0cd62852da
@ -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();
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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));
|
||||
|
Loading…
Reference in New Issue
Block a user