Skip to content

Commit b3131f5

Browse files
author
Chuck Todd
committed
EventGroup fix
EventGroups are not completely reliable for ISR, It seems the WiFi library starves the FreeRTOS Timer Daemon. The Timer Daemon's command Queue overflows, so EventGroup changes from ISR fail to be executed. This patch changes how EventGroups are used for Signalling.
1 parent 123d257 commit b3131f5

File tree

2 files changed

+63
-77
lines changed

2 files changed

+63
-77
lines changed

cores/esp32/esp32-hal-i2c.c

Lines changed: 61 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ struct i2c_struct_t {
4848
uint16_t queueCount;
4949
uint16_t queuePos;
5050
uint16_t byteCnt;
51+
uint32_t exitCode;
5152

5253
};
5354

@@ -95,7 +96,7 @@ static i2c_err_t i2cAddQueue(i2c_t * i2c,uint8_t mode, uint16_t i2cDeviceAddr, u
9596
dqx.queueEvent = event;
9697

9798
if(event){// an eventGroup exist, so, initialize it
98-
xEventGroupClearBits(event, 0x3F); // all of them
99+
xEventGroupClearBits(event, EVENT_MASK); // all of them
99100
}
100101

101102
if(i2c->dq!=NULL){ // expand
@@ -1209,20 +1210,25 @@ static void IRAM_ATTR emptyRxFifo(i2c_t * i2c){
12091210
I2C_DATA_QUEUE_t *tdq =&i2c->dq[i2c->queuePos];
12101211

12111212
moveCnt = i2c->dev->status_reg.rx_fifo_cnt;//no need to check the reg until this many are read
1213+
if(moveCnt > (tdq->length - tdq->position)){ //makesure they go in this dq
1214+
// part of these reads go into the next dq
1215+
moveCnt = (tdq->length - tdq->position);
1216+
}
12121217

12131218
if(tdq->ctrl.mode==1) { // read
12141219
while(moveCnt > 0){
12151220
while(moveCnt > 0){
12161221
d = i2c->dev->fifo_data.val;
12171222
moveCnt--;
12181223
cnt++;
1219-
if(tdq->position < tdq->length) tdq->data[tdq->position++] = (d&0xFF);
1220-
else { // discard? what Happened to get more than requested?
1221-
log_e("discard 0x%x",d);
1222-
}
1224+
tdq->data[tdq->position++] = (d&0xFF);
12231225
}
12241226
// see if any more chars showed up while empting Fifo.
12251227
moveCnt = i2c->dev->status_reg.rx_fifo_cnt;
1228+
if(moveCnt > (tdq->length - tdq->position)){ //makesure they go in this dq
1229+
// part of these reads go into the next dq
1230+
moveCnt = (tdq->length - tdq->position);
1231+
}
12261232
}
12271233
cnt += (intBuff[intPos][1])&&0xffFF;
12281234
intBuff[intPos][1] = (intBuff[intPos][1]&0xFFFF0000)|cnt;
@@ -1235,6 +1241,7 @@ else {
12351241
}
12361242

12371243
static void i2cIsrExit(i2c_t * i2c,const uint32_t eventCode,bool Fatal){
1244+
12381245
switch(eventCode){
12391246
case EVENT_DONE:
12401247
i2c->error = I2C_OK;
@@ -1256,24 +1263,25 @@ switch(eventCode){
12561263
}
12571264
uint32_t exitCode = EVENT_DONE | eventCode |(Fatal?EVENT_ERROR:0);
12581265

1266+
if(i2c->dq[i2c->queuePos].ctrl.mode == 1) emptyRxFifo(i2c); // grab last few characters
1267+
12591268
i2c->dev->int_ena.val = 0; // shutdown interrupts
12601269
i2c->dev->int_clr.val = 0x1FFFF;
12611270
i2c->stage = I2C_DONE;
1271+
i2c->exitCode = exitCode; //true eventcode
12621272

1263-
portBASE_TYPE HPTaskAwoken = pdFALSE;
1264-
1265-
if(i2c->dq[i2c->queuePos].queueEvent){ // this data element has an event, use it.
1266-
HPTaskAwoken = pdFALSE;
1267-
xEventGroupClearBitsFromISR(i2c->dq[i2c->queuePos].queueEvent, EVENT_RUNNING);
1268-
xEventGroupSetBitsFromISR(i2c->dq[i2c->queuePos].queueEvent, exitCode,&HPTaskAwoken);
1269-
if(HPTaskAwoken == pdTRUE) portYIELD_FROM_ISR();
1270-
}
1271-
xEventGroupClearBitsFromISR(i2c->i2c_event, EVENT_RUNNING);
1273+
portBASE_TYPE HPTaskAwoken = pdFALSE,xResult;
1274+
// try to notify Dispatch we are done,
1275+
// else the 50ms timeout will recover the APP, just alittle slower
12721276
HPTaskAwoken = pdFALSE;
1273-
xEventGroupSetBitsFromISR(i2c->i2c_event, exitCode, &HPTaskAwoken);
1274-
if (HPTaskAwoken == pdTRUE) {//higher pri task has awoken, jump to it
1275-
portYIELD_FROM_ISR();
1277+
xResult = xEventGroupSetBitsFromISR(i2c->i2c_event, exitCode, &HPTaskAwoken);
1278+
if(xResult == pdPASS){
1279+
if(HPTaskAwoken==pdTRUE) {
1280+
portYIELD_FROM_ISR();
1281+
// log_e("Yield to Higher");
1282+
}
12761283
}
1284+
12771285
}
12781286

12791287
static void IRAM_ATTR i2c_isr_handler_default(void* arg){
@@ -1283,25 +1291,14 @@ uint32_t activeInt = p_i2c->dev->int_status.val&0x1FFF;
12831291
//log_e("int=%x",activeInt);
12841292
//dumpI2c(p_i2c);
12851293

1286-
portBASE_TYPE HPTaskAwoken = pdFALSE;
1287-
/* don't need this Event_in_irq
1288-
// be polite if someone more important wakes up.
1289-
//log_e("setbits(%p)=%p",p_i2c->i2c_event);
1290-
1291-
xEventGroupSetBitsFromISR(p_i2c->i2c_event, EVENT_IN_IRQ, &HPTaskAwoken);
1292-
if (HPTaskAwoken == pdTRUE) {//higher pri task has awoken, jump to it
1293-
portYIELD_FROM_ISR();
1294-
}
1295-
//log_e("stage");
1296-
*/
1294+
portBASE_TYPE HPTaskAwoken = pdFALSE,xResult;
12971295

12981296
if(p_i2c->stage==I2C_DONE){ //get Out
12991297
log_e("eject int=%p, ena=%p",activeInt,p_i2c->dev->int_ena.val);
13001298
p_i2c->dev->int_ena.val = 0;
13011299
p_i2c->dev->int_clr.val = activeInt; //0x1FFF;
13021300
dumpI2c(p_i2c);
13031301
i2cDumpInts();
1304-
// xEventGroupClearBitsFromISR(p_i2c->i2c_event, EVENT_IN_IRQ);
13051302
return;
13061303
}
13071304
while (activeInt != 0) { // Ordering of 'if(activeInt)' statements is important, don't change
@@ -1321,19 +1318,8 @@ while (activeInt != 0) { // Ordering of 'if(activeInt)' statements is important,
13211318
// p_i2c->byteCnt=0;
13221319
if(p_i2c->stage==I2C_STARTUP){
13231320
p_i2c->stage=I2C_RUNNING;
1324-
xEventGroupClearBitsFromISR(p_i2c->i2c_event, EVENT_DONE); //why?
1325-
if(p_i2c->dq[p_i2c->queuePos].queueEvent){ // this data element has an event, use it.
1326-
HPTaskAwoken = pdFALSE;
1327-
xEventGroupSetBitsFromISR(p_i2c->dq[p_i2c->queuePos].queueEvent, EVENT_RUNNING,
1328-
&HPTaskAwoken);
1329-
if(HPTaskAwoken == pdTRUE) portYIELD_FROM_ISR();
1330-
}
1331-
HPTaskAwoken = pdFALSE;
1332-
xEventGroupSetBitsFromISR(p_i2c->i2c_event, EVENT_RUNNING, &HPTaskAwoken);
1333-
if (HPTaskAwoken == pdTRUE) {//higher pri task has awoken, jump to it
1334-
portYIELD_FROM_ISR();
1335-
}
13361321
}
1322+
13371323
activeInt &=~I2C_TRANS_START_INT_ST_M;
13381324
p_i2c->dev->int_ena.trans_start = 1; // already enabled? why Again?
13391325
p_i2c->dev->int_clr.trans_start = 1; // so that will trigger after next 'END'
@@ -1367,23 +1353,8 @@ while (activeInt != 0) { // Ordering of 'if(activeInt)' statements is important,
13671353
p_i2c->dev->int_ena.rx_fifo_full=1;
13681354
}
13691355

1370-
if(p_i2c->dq[p_i2c->queuePos].queueEvent){ // this data element has an event, use it.
1371-
HPTaskAwoken = pdFALSE;
1372-
xEventGroupClearBitsFromISR(p_i2c->dq[p_i2c->queuePos].queueEvent, EVENT_RUNNING);
1373-
xEventGroupSetBitsFromISR(p_i2c->dq[p_i2c->queuePos].queueEvent, EVENT_DONE,
1374-
&HPTaskAwoken);
1375-
if(HPTaskAwoken == pdTRUE) portYIELD_FROM_ISR();
1376-
}
1377-
13781356
p_i2c->queuePos++; //inc to next dq
13791357

1380-
if(p_i2c->dq[p_i2c->queuePos].queueEvent){ // this data element has an event, use it.
1381-
HPTaskAwoken = pdFALSE;
1382-
xEventGroupSetBitsFromISR(p_i2c->dq[p_i2c->queuePos].queueEvent, EVENT_RUNNING,
1383-
&HPTaskAwoken);
1384-
if(HPTaskAwoken == pdTRUE) portYIELD_FROM_ISR();
1385-
}
1386-
13871358
if(p_i2c->queuePos < p_i2c->queueCount) // load next dq address field + data
13881359
p_i2c->dev->int_ena.tx_fifo_empty=1;
13891360

@@ -1408,7 +1379,6 @@ while (activeInt != 0) { // Ordering of 'if(activeInt)' statements is important,
14081379
}
14091380

14101381
if (activeInt & I2C_TRANS_COMPLETE_INT_ST_M) {
1411-
if(p_i2c->dq[p_i2c->queuePos].ctrl.mode == 1) emptyRxFifo(p_i2c); // grab last few characters
14121382
i2cIsrExit(p_i2c,EVENT_DONE,false);
14131383
return; // no more work to do
14141384
/*
@@ -1430,39 +1400,29 @@ while (activeInt != 0) { // Ordering of 'if(activeInt)' statements is important,
14301400
}
14311401

14321402
if (activeInt & I2C_END_DETECT_INT_ST_M) {
1433-
HPTaskAwoken = pdFALSE;
1434-
xEventGroupSetBitsFromISR(p_i2c->i2c_event, EVENT_IN_END, &HPTaskAwoken);
1435-
if (HPTaskAwoken == pdTRUE) {//higher pri task has awoken, jump to it
1436-
portYIELD_FROM_ISR();
1437-
}
14381403
p_i2c->dev->int_ena.end_detect = 0;
14391404
p_i2c->dev->int_clr.end_detect = 1;
14401405
p_i2c->dev->ctr.trans_start=0;
14411406
fillCmdQueue(p_i2c,0,true);
14421407
p_i2c->dev->ctr.trans_start=1; // go for it
14431408
activeInt&=~I2C_END_DETECT_INT_ST_M;
14441409
// What about Tx, RX fifo fill?
1445-
xEventGroupClearBitsFromISR(p_i2c->i2c_event, EVENT_IN_END);
14461410
}
14471411

14481412
if (activeInt & I2C_RXFIFO_OVF_INT_ST_M) { //should never happen, I always use Fifo
14491413
p_i2c->dev->int_clr.rx_fifo_ovf = 1;
1414+
p_i2c->dev->int_ena.rx_fifo_ovf = 0; // disable it
14501415
}
14511416

14521417
if(activeInt){ // clear unhandled if possible? What about Disabling interrupt?
14531418
p_i2c->dev->int_clr.val = activeInt;
14541419
log_e("unknown int=%x",activeInt);
1420+
// disable unhandled IRQ,
1421+
p_i2c->dev->int_ena.val = p_i2c->dev->int_ena.val & (~activeInt);
14551422
}
14561423

14571424
activeInt = p_i2c->dev->int_status.val; // start all over if another interrupt happened
1458-
/* if((activeInt&oldInt)==oldInt){
1459-
log_e("dup int old=%p, new=%p dup=%p",oldInt,activeInt,(oldInt&activeInt));
1460-
}
1461-
*/
14621425
}
1463-
1464-
//xEventGroupClearBitsFromISR(p_i2c->i2c_event, EVENT_IN_IRQ);
1465-
// and we're out!
14661426
}
14671427

14681428
void i2cDumpInts(){
@@ -1506,10 +1466,12 @@ if(!i2c->i2c_event){
15061466
}
15071467
if(i2c->i2c_event) {
15081468
uint32_t ret=xEventGroupClearBits(i2c->i2c_event, 0xFF);
1469+
15091470
// log_e("after clearBits(%p)=%p",i2c->i2c_event,ret);
15101471
}
15111472
else {// failed to create EventGroup
15121473
log_e("eventCreate failed=%p",i2c->i2c_event);
1474+
I2C_MUTEX_UNLOCK();
15131475
return I2C_ERROR_MEMORY;
15141476
}
15151477

@@ -1561,6 +1523,7 @@ i2c->queuePos=0;
15611523
fillCmdQueue(i2c,0,false); // start adding command[], END irq will keep it full
15621524
//Data Fifo will be filled after trans_start is issued
15631525

1526+
i2c->exitCode=0;
15641527
i2c->stage = I2C_STARTUP; // everything configured, now start the I2C StateMachine, and
15651528
// As soon as interrupts are enabled, the ISR will start handling them.
15661529
// it should receive a TXFIFO_EMPTY immediately, even before it
@@ -1584,6 +1547,7 @@ if(!i2c->intr_handle){ // create ISR I2C_0 only,
15841547
uint32_t ret = esp_intr_alloc(ETS_I2C_EXT0_INTR_SOURCE, 0, &i2c_isr_handler_default, i2c, &i2c->intr_handle);
15851548
if(ret!=ESP_OK){
15861549
log_e("install interrupt handler Failed=%d",ret);
1550+
I2C_MUTEX_UNLOCK();
15871551
return I2C_ERROR_MEMORY;
15881552
}
15891553
}
@@ -1593,6 +1557,8 @@ if(!i2c->intr_handle){ // create ISR I2C_0 only,
15931557
// how many ticks should it take to transfer totalBytes thru the I2C hardware,
15941558
// add 50ms just for kicks
15951559

1560+
1561+
15961562
portTickType ticksTimeOut = ((totalBytes /(i2cGetFrequency(i2c)/(10*1000)))+50)/portTICK_PERIOD_MS;
15971563
portTickType tBefore=xTaskGetTickCount();
15981564

@@ -1607,6 +1573,14 @@ uint32_t eBits = xEventGroupWaitBits(i2c->i2c_event,EVENT_DONE,pdFALSE,pdTRUE,ti
16071573
portTickType tAfter=xTaskGetTickCount();
16081574

16091575
uint32_t b;
1576+
// if xEventGroupSetBitsFromISR() failed, the ISR could have succeeded but never been
1577+
// able to mark the success
1578+
1579+
if(i2c->exitCode!=eBits){ // try to recover from O/S failure
1580+
// log_e("EventGroup Failed:%p!=%p",eBits,i2c->exitCode);
1581+
eBits=i2c->exitCode;
1582+
}
1583+
16101584
if(!(eBits==EVENT_DONE)&&(eBits&~(EVENT_ERROR_NAK|EVENT_ERROR|EVENT_DONE))){ // not only Done, therefore error, exclude ADDR NAK
16111585
dumpI2c(i2c);
16121586
i2cDumpInts();
@@ -1647,15 +1621,28 @@ else { // GROSS timeout, shutdown ISR , report Timeout
16471621
i2cDumpInts();
16481622
}
16491623

1624+
// offloading all EventGroups to dispatch, EventGroups in ISR is not always successful
1625+
// 11/20/2017
16501626
// if error, need to trigger all succeeding dataQueue events with the EVENT_ERROR_PREV
1651-
if(eBits&EVENT_ERROR){// every dq past the error point needs it's EventGroup Released
1652-
b=i2c->queuePos + 1;
1653-
while(b < i2c->queueCount){
1627+
1628+
b = 0;
1629+
while(b < i2c->queueCount){
1630+
if(b < i2c->queuePos){ // before any error
1631+
if(i2c->dq[b].queueEvent){ // this data queue element has an EventGroup
1632+
xEventGroupSetBits(i2c->dq[b].queueEvent,EVENT_DONE);
1633+
}
1634+
}
1635+
else if(b == i2c->queuePos){ // last processed queue
1636+
if(i2c->dq[b].queueEvent){ // this data queue element has an EventGroup
1637+
xEventGroupSetBits(i2c->dq[b].queueEvent,eBits);
1638+
}
1639+
}
1640+
else{ // never processed queues
16541641
if(i2c->dq[b].queueEvent){ // this data queue element has an EventGroup
16551642
xEventGroupSetBits(i2c->dq[b].queueEvent,eBits|EVENT_ERROR_PREV);
16561643
}
1657-
b++;
16581644
}
1645+
b++;
16591646
}
16601647

16611648
I2C_MUTEX_UNLOCK();

cores/esp32/esp32-hal-i2c.h

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@ typedef enum {
3535
I2C_ERROR_BUSY,
3636
I2C_ERROR_MEMORY,
3737
I2C_ERROR_CONTINUE,
38-
I2C_ERROR_MISSING_WRITE,
3938
I2C_ERROR_NO_BEGIN
4039
} i2c_err_t;
4140

@@ -67,14 +66,14 @@ typedef enum {
6766
// i2c_event bits
6867
#define EVENT_ERROR_NAK (BIT(0))
6968
#define EVENT_ERROR (BIT(1))
70-
#define EVENT_RUNNING (BIT(3))
69+
//#define EVENT_RUNNING (BIT(3))
7170
#define EVENT_DONE (BIT(4))
7271
#define EVENT_IN_END (BIT(5))
7372
#define EVENT_ERROR_PREV (BIT(6))
7473
#define EVENT_ERROR_TIMEOUT (BIT(7))
7574
#define EVENT_ERROR_ARBITRATION (BIT(8))
7675
#define EVENT_ERROR_DATA_NAK (BIT(9))
77-
76+
#define EVENT_MASK 0x3F
7877
typedef union{
7978
struct {
8079
uint32_t addr: 16; // I2C address, if 10bit must have 0x7800 mask applied, else 8bit

0 commit comments

Comments
 (0)