Skip to content

Commit 0cd6285

Browse files
lonerzzzme-no-dev
authored andcommitted
I2c reset functionality (espressif#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.
1 parent 10ff1de commit 0cd6285

File tree

4 files changed

+47
-3
lines changed

4 files changed

+47
-3
lines changed

Diff for: cores/esp32/esp32-hal-i2c.c

+35-2
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include "freertos/task.h"
1919
#include "freertos/semphr.h"
2020
#include "rom/ets_sys.h"
21+
#include "driver/periph_ctrl.h"
2122
#include "soc/i2c_reg.h"
2223
#include "soc/i2c_struct.h"
2324
#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
154155

155156
I2C_MUTEX_LOCK();
156157

158+
if (i2c->dev->status_reg.bus_busy == 1)
159+
{
160+
//log_w( "Busy Timeout! Addr: %x", address >> 1 );
161+
I2C_MUTEX_UNLOCK();
162+
return I2C_ERROR_BUSY;
163+
}
164+
157165
while(dataLen) {
158166
uint8_t willSend = (dataLen > 32)?32:dataLen;
159167
uint8_t dataSend = willSend;
@@ -221,7 +229,7 @@ i2c_err_t i2cWrite(i2c_t * i2c, uint16_t address, bool addr_10bit, uint8_t * dat
221229
//Transmission did not finish and ACK_ERR is set
222230
if(i2c->dev->int_raw.ack_err) {
223231
//log_w("Ack Error! Addr: %x", address >> 1);
224-
while(i2c->dev->status_reg.bus_busy);
232+
while((i2c->dev->status_reg.bus_busy) && ((millis() - startAt)>50));
225233
I2C_MUTEX_UNLOCK();
226234
return I2C_ERROR_ACK;
227235
}
@@ -250,6 +258,13 @@ i2c_err_t i2cRead(i2c_t * i2c, uint16_t address, bool addr_10bit, uint8_t * data
250258

251259
I2C_MUTEX_LOCK();
252260

261+
if (i2c->dev->status_reg.bus_busy == 1)
262+
{
263+
//log_w( "Busy Timeout! Addr: %x", address >> 1 );
264+
I2C_MUTEX_UNLOCK();
265+
return I2C_ERROR_BUSY;
266+
}
267+
253268
i2cResetFiFo(i2c);
254269
i2cResetCmd(i2c);
255270

@@ -445,7 +460,25 @@ void i2cInitFix(i2c_t * i2c){
445460
i2c->dev->fifo_data.data = 0;
446461
i2cSetCmd(i2c, 1, I2C_CMD_WRITE, 1, false, false, false);
447462
i2cSetCmd(i2c, 2, I2C_CMD_STOP, 0, false, false, false);
463+
if (i2c->dev->status_reg.bus_busy) // If this condition is true, the while loop will timeout as done will not be set
464+
{
465+
//log_e("Busy at initialization!");
466+
}
448467
i2c->dev->ctr.trans_start = 1;
449-
while(!i2c->dev->command[2].done);
468+
uint16_t count = 50000;
469+
while ((!i2c->dev->command[2].done) && (--count > 0));
450470
I2C_MUTEX_UNLOCK();
451471
}
472+
473+
void i2cReset(i2c_t* i2c){
474+
if(i2c == NULL){
475+
return;
476+
}
477+
I2C_MUTEX_LOCK();
478+
periph_module_t moduleId = (i2c == &_i2c_bus_array[0])?PERIPH_I2C0_MODULE:PERIPH_I2C1_MODULE;
479+
periph_module_disable( moduleId );
480+
delay( 20 ); // Seems long but delay was chosen to ensure system teardown and setup without core generation
481+
periph_module_enable( moduleId );
482+
I2C_MUTEX_UNLOCK();
483+
}
484+

Diff for: cores/esp32/esp32-hal-i2c.h

+3-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,8 @@ typedef enum {
2727
I2C_ERROR_DEV,
2828
I2C_ERROR_ACK,
2929
I2C_ERROR_TIMEOUT,
30-
I2C_ERROR_BUS
30+
I2C_ERROR_BUS,
31+
I2C_ERROR_BUSY
3132
} i2c_err_t;
3233

3334
struct i2c_struct_t;
@@ -50,6 +51,7 @@ i2c_err_t i2cDetachSDA(i2c_t * i2c, int8_t sda);
5051
i2c_err_t i2cWrite(i2c_t * i2c, uint16_t address, bool addr_10bit, uint8_t * data, uint8_t len, bool sendStop);
5152
i2c_err_t i2cRead(i2c_t * i2c, uint16_t address, bool addr_10bit, uint8_t * data, uint8_t len, bool sendStop);
5253

54+
void i2cReset(i2c_t* i2c);
5355

5456
#ifdef __cplusplus
5557
}

Diff for: libraries/Wire/src/Wire.cpp

+7
Original file line numberDiff line numberDiff line change
@@ -211,4 +211,11 @@ void TwoWire::flush(void)
211211
txLength = 0;
212212
}
213213

214+
void TwoWire::reset(void)
215+
{
216+
i2cReset( i2c );
217+
i2c = NULL;
218+
begin( sda, scl );
219+
}
220+
214221
TwoWire Wire = TwoWire(0);

Diff for: libraries/Wire/src/Wire.h

+2
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,8 @@ class TwoWire: public Stream
7272
int peek(void);
7373
void flush(void);
7474

75+
void reset(void);
76+
7577
inline size_t write(const char * s)
7678
{
7779
return write((uint8_t*) s, strlen(s));

0 commit comments

Comments
 (0)