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…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user