Skip to content

Commit bb24e52

Browse files
authored
Merge pull request #25 from stickbreaker/stickbreaker-Busy-Glitch
With this merge, `Wire()` can handle a bus fault, Grounding SDA and or SCL is now recoverable. The signal glitch that was created when attaching pins to the i2c peripheral has now been solved! A bus_busy status is now auto-magically cleared. When this status is detected upon entry into the hal layer i2cProcQueue(), i2cProcQueue() immediately returns I2C_ERROR_BUSY which cause TwoWire() to attempt to clear the bus, first is re-inits the i2c peripheral(hardware reset!), then it attempts to cycle the i2c bus manually. TwoWire() then retries the transaction once. This branch should handle both I2C peripherals at the same time, UnTESTED, but, it should work.
2 parents 0f79fa0 + 3027a03 commit bb24e52

File tree

4 files changed

+146
-95
lines changed

4 files changed

+146
-95
lines changed

cores/esp32/esp32-hal-i2c.c

+76-57
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,7 @@ i2c_err_t i2cAttachSCL(i2c_t * i2c, int8_t scl)
176176
return I2C_ERROR_DEV;
177177
}
178178
digitalWrite(scl, HIGH);
179-
pinMode(scl, OPEN_DRAIN | PULLUP);
179+
pinMode(scl, OPEN_DRAIN | PULLUP | INPUT | OUTPUT);
180180
pinMatrixOutAttach(scl, I2C_SCL_IDX(i2c->num), false, false);
181181
pinMatrixInAttach(scl, I2C_SCL_IDX(i2c->num), false);
182182
return I2C_ERROR_OK;
@@ -189,7 +189,7 @@ i2c_err_t i2cDetachSCL(i2c_t * i2c, int8_t scl)
189189
}
190190
pinMatrixOutDetach(scl, false, false);
191191
pinMatrixInDetach(I2C_SCL_IDX(i2c->num), false, false);
192-
pinMode(scl, INPUT);
192+
pinMode(scl, INPUT | PULLUP);
193193
return I2C_ERROR_OK;
194194
}
195195

@@ -199,7 +199,7 @@ i2c_err_t i2cAttachSDA(i2c_t * i2c, int8_t sda)
199199
return I2C_ERROR_DEV;
200200
}
201201
digitalWrite(sda, HIGH);
202-
pinMode(sda, OPEN_DRAIN | PULLUP);
202+
pinMode(sda, OPEN_DRAIN | PULLUP | INPUT | OUTPUT );
203203
pinMatrixOutAttach(sda, I2C_SDA_IDX(i2c->num), false, false);
204204
pinMatrixInAttach(sda, I2C_SDA_IDX(i2c->num), false);
205205
return I2C_ERROR_OK;
@@ -212,7 +212,7 @@ i2c_err_t i2cDetachSDA(i2c_t * i2c, int8_t sda)
212212
}
213213
pinMatrixOutDetach(sda, false, false);
214214
pinMatrixInDetach(I2C_SDA_IDX(i2c->num), false, false);
215-
pinMode(sda, INPUT);
215+
pinMode(sda, INPUT | PULLUP);
216216
return I2C_ERROR_OK;
217217
}
218218

@@ -287,8 +287,13 @@ uint32_t i2cGetFrequency(i2c_t * i2c)
287287
if(i2c == NULL){
288288
return 0;
289289
}
290-
291-
return APB_CLK_FREQ/(i2c->dev->scl_low_period.period+i2c->dev->scl_high_period.period);
290+
uint32_t result = 0;
291+
uint32_t old_count = (i2c->dev->scl_low_period.period+i2c->dev->scl_high_period.period);
292+
if(old_count>0){
293+
result = APB_CLK_FREQ / old_count;
294+
}
295+
else result = 0;
296+
return result;
292297
}
293298

294299
/*
@@ -297,7 +302,7 @@ uint32_t i2cGetFrequency(i2c_t * i2c)
297302
* addr_10bit_en - enable slave 10bit address mode.
298303
* */
299304
// 24Nov17 only supports Master Mode
300-
i2c_t * i2cInit(uint8_t i2c_num)
305+
i2c_t * i2cInit(uint8_t i2c_num) //before this is called, pins should be detached, else glitch
301306
{
302307
if(i2c_num > 1){
303308
return NULL;
@@ -313,16 +318,18 @@ i2c_t * i2cInit(uint8_t i2c_num)
313318
}
314319
}
315320
#endif
321+
I2C_MUTEX_LOCK();
322+
uint32_t old_clock = i2cGetFrequency(i2c);
316323

317324
if(i2c_num == 0) {
325+
DPORT_SET_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG,DPORT_I2C_EXT0_RST); //reset hardware
318326
DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG,DPORT_I2C_EXT0_CLK_EN);
319-
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG,DPORT_I2C_EXT0_RST);
327+
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG,DPORT_I2C_EXT0_RST);// release reset
320328
} else {
329+
DPORT_SET_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG,DPORT_I2C_EXT1_RST); //reset Hardware
321330
DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG,DPORT_I2C_EXT1_CLK_EN);
322331
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG,DPORT_I2C_EXT1_RST);
323332
}
324-
325-
I2C_MUTEX_LOCK();
326333
i2c->dev->ctr.val = 0;
327334
i2c->dev->ctr.ms_mode = 1;
328335
i2c->dev->ctr.sda_force_out = 1 ;
@@ -336,6 +343,8 @@ i2c_t * i2cInit(uint8_t i2c_num)
336343

337344
i2c->dev->slave_addr.val = 0;
338345
I2C_MUTEX_UNLOCK();
346+
347+
if(old_clock) i2cSetFrequency(i2c,old_clock); // reconfigure
339348

340349
return i2c;
341350
}
@@ -376,10 +385,10 @@ void i2cReset(i2c_t* i2c){
376385

377386
/* Stickbreaker ISR mode debug support
378387
*/
379-
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_ERROR
388+
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO
380389
#define INTBUFFMAX 64
381-
static uint32_t intBuff[INTBUFFMAX][3];
382-
static uint32_t intPos=0;
390+
static uint32_t intBuff[INTBUFFMAX][3][2];
391+
static uint32_t intPos[2]={0,0};
383392
#endif
384393

385394
/* Stickbreaker ISR mode debug support
@@ -645,13 +654,10 @@ enable txEmpty, filltx fires, but the SM has already sent a bogus byte out the B
645654
overlap is not an issue, just keep them full/empty the status_reg.xx_fifo_cnt
646655
tells the truth. And the INT's fire correctly
647656
*/
648-
bool readEncountered = false; // 12/01/2017 this needs to be removed
649-
// it is nolonger necessary, the fifo's are independent. Run thru the dq's
650-
// until the cmd[] is full or the txFifo is full.
651657
uint16_t a=i2c->queuePos; // currently executing dq,
652658
bool full=!(i2c->dev->status_reg.tx_fifo_cnt<31);
653659
uint8_t cnt;
654-
while((a < i2c->queueCount)&&!(full || readEncountered)){
660+
while((a < i2c->queueCount) && !full){
655661
I2C_DATA_QUEUE_t *tdq = &i2c->dq[a];
656662
cnt=0;
657663
// add to address to fifo ctrl.addr already has R/W bit positioned correctly
@@ -697,22 +703,19 @@ while((a < i2c->queueCount)&&!(full || readEncountered)){
697703
}
698704
}
699705
}
700-
//11/23/2017 overlap tx/rx/tx
701-
// else readEncountered = true;
702-
703-
if(full) readEncountered =false; //tx possibly needs more
704706

705-
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_ERROR
707+
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO
706708

707709
// update debug buffer tx counts
708-
cnt += intBuff[intPos][1]>>16;
709-
intBuff[intPos][1] = (intBuff[intPos][1]&0xFFFF)|(cnt<<16);
710+
cnt += intBuff[intPos[i2c->num]][1][i2c->num]>>16;
711+
intBuff[intPos[i2c->num]][1][i2c->num] = (intBuff[intPos[i2c->num]][1][i2c->num]&0xFFFF)|(cnt<<16);
712+
710713
#endif
711714

712-
if(!(full||readEncountered)) a++; // check next buffer for tx
715+
if(!full) a++; // check next buffer for tx
713716
}
714717

715-
if((!full) || readEncountered || (a >= i2c->queueCount)){// disable IRQ, the next dq will re-enable it
718+
if(!full || (a >= i2c->queueCount)){// disable IRQ, the next dq will re-enable it
716719
i2c->dev->int_ena.tx_fifo_empty=0;
717720
}
718721

@@ -746,10 +749,10 @@ if(tdq->ctrl.mode==1) { // read
746749
moveCnt = (tdq->length - tdq->position);
747750
}
748751
}
749-
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_ERROR
752+
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO
750753
// update Debug rxCount
751-
cnt += (intBuff[intPos][1])&&0xffFF;
752-
intBuff[intPos][1] = (intBuff[intPos][1]&0xFFFF0000)|cnt;
754+
cnt += (intBuff[intPos[i2c->num]][1][i2c->num])&&0xffFF;
755+
intBuff[intPos[i2c->num]][1][i2c->num] = (intBuff[intPos[i2c->num]][1][i2c->num]&0xFFFF0000)|cnt;
753756
#endif
754757
}
755758
else {
@@ -813,23 +816,22 @@ if(p_i2c->stage==I2C_DONE){ //get Out
813816
log_e("eject int=%p, ena=%p",activeInt,p_i2c->dev->int_ena.val);
814817
p_i2c->dev->int_ena.val = 0;
815818
p_i2c->dev->int_clr.val = activeInt; //0x1FFF;
816-
// i2cDumpI2c(p_i2c);
817-
// i2cDumpInts();
818819
return;
819820
}
820821
while (activeInt != 0) { // Ordering of 'if(activeInt)' statements is important, don't change
821-
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_ERROR
822-
if(activeInt==(intBuff[intPos][0]&0x1fff)){
823-
intBuff[intPos][0] = (((intBuff[intPos][0]>>16)+1)<<16)|activeInt;
822+
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO
823+
if(activeInt==(intBuff[intPos[p_i2c->num]][0][p_i2c->num]&0x1fff)){
824+
intBuff[intPos[p_i2c->num]][0][p_i2c->num] = (((intBuff[intPos[p_i2c->num]][0][p_i2c->num]>>16)+1)<<16)|activeInt;
824825
}
825826
else{
826-
intPos++;
827-
intPos %= INTBUFFMAX;
828-
intBuff[intPos][0]=(1<<16)|activeInt;
829-
intBuff[intPos][1] = 0;
827+
intPos[p_i2c->num]++;
828+
intPos[p_i2c->num] %= INTBUFFMAX;
829+
intBuff[intPos[p_i2c->num]][0][p_i2c->num] = (1<<16) | activeInt;
830+
intBuff[intPos[p_i2c->num]][1][p_i2c->num] = 0;
830831
}
831832

832-
intBuff[intPos][2] = xTaskGetTickCountFromISR(); // when IRQ fired
833+
intBuff[intPos[p_i2c->num]][2][p_i2c->num] = xTaskGetTickCountFromISR(); // when IRQ fired
834+
833835
#endif
834836
uint32_t oldInt =activeInt;
835837

@@ -940,13 +942,13 @@ while (activeInt != 0) { // Ordering of 'if(activeInt)' statements is important,
940942
}
941943
}
942944

943-
void i2cDumpInts(){
944-
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_ERROR
945+
void i2cDumpInts(uint8_t num){
946+
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO
945947
uint32_t b;
946-
log_e("row count INTR TX RX");
948+
log_e("%u row count INTR TX RX",num);
947949
for(uint32_t a=1;a<=INTBUFFMAX;a++){
948-
b=(a+intPos)%INTBUFFMAX;
949-
if(intBuff[b][0]!=0) log_e("[%02d] 0x%04x 0x%04x 0x%04x 0x%04x 0x%08x",b,((intBuff[b][0]>>16)&0xFFFF),(intBuff[b][0]&0xFFFF),((intBuff[b][1]>>16)&0xFFFF),(intBuff[b][1]&0xFFFF),intBuff[b][2]);
950+
b=(a+intPos[num])%INTBUFFMAX;
951+
if(intBuff[b][0][num]!=0) log_e("[%02d] 0x%04x 0x%04x 0x%04x 0x%04x 0x%08x",b,((intBuff[b][0][num]>>16)&0xFFFF),(intBuff[b][0][num]&0xFFFF),((intBuff[b][1][num]>>16)&0xFFFF),(intBuff[b][1][num]&0xFFFF),intBuff[b][2][num]);
950952
}
951953
#else
952954
log_n("enable Core Debug Level \"Error\"");
@@ -965,7 +967,10 @@ i2c_err_t i2cProcQueue(i2c_t * i2c, uint32_t *readCount, uint16_t timeOutMillis)
965967
if(i2c == NULL){
966968
return I2C_ERROR_DEV;
967969
}
968-
970+
if (i2c->dev->status_reg.bus_busy){ // return error, let TwoWire() handle resetting the hardware.
971+
log_i("Bus busy, reinit");
972+
return I2C_ERROR_BUSY;
973+
}
969974
I2C_MUTEX_LOCK();
970975
/* what about co-existance with SLAVE mode?
971976
Should I check if a slaveMode xfer is in progress and hang
@@ -974,9 +979,13 @@ I2C_MUTEX_LOCK();
974979
*/
975980
i2c->stage = I2C_DONE; // until ready
976981

977-
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_ERROR
978-
memset(intBuff,0,sizeof(intBuff));
979-
intPos=0;
982+
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO
983+
for(uint16_t i=0;i<INTBUFFMAX;i++){
984+
intBuff[i][0][i2c->num] = 0;
985+
intBuff[i][1][i2c->num] = 0;
986+
intBuff[i][2][i2c->num] = 0;
987+
}
988+
intPos[i2c->num] = 0;
980989
#endif
981990
// EventGroup is used to signal transmisison completion from ISR
982991
// not always reliable. Sometimes, the FreeRTOS scheduler is maxed out and refuses request
@@ -1063,9 +1072,19 @@ i2c->dev->int_ena.val =
10631072
I2C_TXFIFO_EMPTY_INT_ENA | // (BIT(1)) triggers fillTxFifo()
10641073
I2C_RXFIFO_FULL_INT_ENA; // (BIT(0)) trigger emptyRxFifo()
10651074

1066-
if(!i2c->intr_handle){ // create ISR I2C_0 only,
1067-
// log_e("create ISR");
1068-
uint32_t ret = esp_intr_alloc(ETS_I2C_EXT0_INTR_SOURCE, 0, &i2c_isr_handler_default, i2c, &i2c->intr_handle);
1075+
if(!i2c->intr_handle){ // create ISR for either peripheral
1076+
log_i("create ISR");
1077+
uint32_t ret;
1078+
switch(i2c->num){
1079+
case 0:
1080+
ret = esp_intr_alloc(ETS_I2C_EXT0_INTR_SOURCE, 0, &i2c_isr_handler_default, i2c, &i2c->intr_handle);
1081+
break;
1082+
case 1:
1083+
ret = esp_intr_alloc(ETS_I2C_EXT1_INTR_SOURCE, 0, &i2c_isr_handler_default, i2c, &i2c->intr_handle);
1084+
break;
1085+
default :;
1086+
}
1087+
10691088
if(ret!=ESP_OK){
10701089
log_e("install interrupt handler Failed=%d",ret);
10711090
I2C_MUTEX_UNLOCK();
@@ -1101,11 +1120,11 @@ if(i2c->exitCode!=eBits){ // try to recover from O/S failure
11011120
}
11021121

11031122
if(!(eBits==EVENT_DONE)&&(eBits&~(EVENT_ERROR_NAK|EVENT_ERROR_DATA_NAK|EVENT_ERROR|EVENT_DONE))){ // not only Done, therefore error, exclude ADDR NAK, DATA_NAK
1104-
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_ERROR
1123+
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO
11051124
i2cDumpI2c(i2c);
1106-
i2cDumpInts();
1125+
i2cDumpInts(i2c->num);
11071126
#else
1108-
log_n("I2C exitCode=%u",eBits);
1127+
log_n("I2C exitCode=0x%x",eBits);
11091128
#endif
11101129
}
11111130

@@ -1116,7 +1135,7 @@ if(eBits&EVENT_DONE){ // no gross timeout
11161135
// expected can be zero due to small packets
11171136
log_e("TimeoutRecovery: expected=%ums, actual=%ums",expected,(tAfter-tBefore));
11181137
i2cDumpI2c(i2c);
1119-
i2cDumpInts();
1138+
i2cDumpInts(i2c->num);
11201139
}
11211140
#endif
11221141
switch(i2c->error){
@@ -1152,7 +1171,7 @@ else { // GROSS timeout, shutdown ISR , report Timeout
11521171
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_ERROR
11531172
log_e(" Busy Timeout start=0x%x, end=0x%x, =%d, max=%d error=%d",tBefore,tAfter,(tAfter-tBefore),ticksTimeOut,i2c->error);
11541173
i2cDumpI2c(i2c);
1155-
i2cDumpInts();
1174+
i2cDumpInts(i2c->num);
11561175
#endif
11571176
}
11581177
else { // just a timeout, some data made it out or in.
@@ -1162,7 +1181,7 @@ else { // GROSS timeout, shutdown ISR , report Timeout
11621181
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_ERROR
11631182
log_e(" Gross Timeout Dead start=0x%x, end=0x%x, =%d, max=%d error=%d",tBefore,tAfter,(tAfter-tBefore),ticksTimeOut,i2c->error);
11641183
i2cDumpI2c(i2c);
1165-
i2cDumpInts();
1184+
i2cDumpInts(i2c->num);
11661185
#endif
11671186
}
11681187
}

cores/esp32/esp32-hal-i2c.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@ i2c_err_t i2cAddQueueRead(i2c_t *i2c, uint16_t i2cDeviceAddr, uint8_t *dataPtr,
169169
i2c_err_t i2cFreeQueue(i2c_t *i2c);
170170
i2c_err_t i2cReleaseISR(i2c_t *i2c);
171171
//stickbreaker debug support
172-
void i2cDumpInts();
172+
void i2cDumpInts(uint8_t num);
173173
void i2cDumpI2c(i2c_t *i2c);
174174

175175
#ifdef __cplusplus

0 commit comments

Comments
 (0)