From 28a410dd503c2ae0f5bb82d471097b9abafe2e90 Mon Sep 17 00:00:00 2001 From: chuck todd Date: Thu, 12 Jul 2018 07:18:26 -0600 Subject: [PATCH] Spurious Interrupts Temporary fix 20180711 (#1625) the 'eject' ERROR is and indication of an interrupt triggering without an source. I am working to eliminate these serviceable interrupt. This update increase stability on a HelTek Wifi Lora 32 board. with a SSD1306 OLED. This update fixes a glaring error in the interrupt allocation code, the Interrupt mask was wrong. I also dynamically adjust the FiFo thresholds based on Bus clockrate. The change to FiFo thresholds has reduced the number for 'eject' events. I also change 'eject' from and ERROR to DEBUG. An 'eject' event does not compromise i2c transmissions. It happens after a transaction has completed. Chuck. --- cores/esp32/esp32-hal-i2c.c | 57 ++++++++++++++++++++++++++++--------- 1 file changed, 43 insertions(+), 14 deletions(-) diff --git a/cores/esp32/esp32-hal-i2c.c b/cores/esp32/esp32-hal-i2c.c index e6b21815..896e6595 100644 --- a/cores/esp32/esp32-hal-i2c.c +++ b/cores/esp32/esp32-hal-i2c.c @@ -491,6 +491,18 @@ static void IRAM_ATTR fillTxFifo(i2c_t * i2c) if(!full || (a >= i2c->queueCount)) { // disable IRQ, the next dq will re-enable it i2c->dev->int_ena.tx_fifo_empty=0; + + if(!full) { // add a byte to keep spurious tx_empty int + uint8_t filler=i2c->dev->fifo_conf.tx_fifo_empty_thrhd; + if(filler >( 31 - i2c->dev->status_reg.tx_fifo_cnt)){ + filler = ( 31 - i2c->dev->status_reg.tx_fifo_cnt); + } + + while(filler > 0){ + i2c->dev->fifo_data.val = 0xFE; // Just a dummy byte + filler--; + } + } } i2c->dev->int_clr.tx_fifo_empty=1; @@ -563,9 +575,9 @@ static void IRAM_ATTR i2cIsrExit(i2c_t * i2c,const uint32_t eventCode,bool Fatal if(i2c->dq[i2c->queuePos].ctrl.mode == 1) { emptyRxFifo(i2c); // grab last few characters } - +// log_d("raw=0x%05x status=0x%05x",i2c->dev->int_raw.val,i2c->dev->int_status.val); i2c->dev->int_ena.val = 0; // shutdown interrupts - i2c->dev->int_clr.val = 0x1FFFF; + i2c->dev->int_clr.val = 0x1FFF; i2c->stage = I2C_DONE; i2c->exitCode = exitCode; //true eventcode @@ -586,12 +598,16 @@ static void IRAM_ATTR i2cIsrExit(i2c_t * i2c,const uint32_t eventCode,bool Fatal static void IRAM_ATTR i2c_isr_handler_default(void* arg) { i2c_t* p_i2c = (i2c_t*) arg; // recover data - uint32_t activeInt = p_i2c->dev->int_status.val&0x1FFF; + uint32_t activeInt = p_i2c->dev->int_status.val&0x7FF; - //portBASE_TYPE HPTaskAwoken = pdFALSE,xResult; - - if(p_i2c->stage==I2C_DONE) { //get Out - log_e("eject int=%p, ena=%p",activeInt,p_i2c->dev->int_ena.val); + if(!activeInt){ //spurious interrupt, possibly bus relate 20180711 + log_d("raw=0x%05x status=0x%05x",p_i2c->dev->int_raw.val,p_i2c->dev->int_status.val); + } + if(p_i2c->stage==I2C_DONE) { //get Out, can't service, not configured + // this error is some kind of a race condition at high clock >400khz + // see #1588. it does not compromise i2c communications though, just + // a poke in the eye + log_d("eject raw=%p, int=%p",p_i2c->dev->int_raw.val,activeInt); p_i2c->dev->int_ena.val = 0; p_i2c->dev->int_clr.val = activeInt; //0x1FFF; return; @@ -610,8 +626,7 @@ static void IRAM_ATTR i2c_isr_handler_default(void* arg) intBuff[intPos[p_i2c->num]][2][p_i2c->num] = xTaskGetTickCountFromISR(); // when IRQ fired #endif - //uint32_t oldInt =activeInt; - + if (activeInt & I2C_TRANS_START_INT_ST_M) { // p_i2c->byteCnt=0; if(p_i2c->stage==I2C_STARTUP) { @@ -871,18 +886,21 @@ i2c_err_t i2cProcQueue(i2c_t * i2c, uint32_t *readCount, uint16_t timeOutMillis) f.rx_fifo_rst = 1; // fifo in reset f.tx_fifo_rst = 1; // fifo in reset f.nonfifo_en = 0; // use fifo mode + f.nonfifo_tx_thres =63; // need to adjust threshold based on I2C clock rate, at 100k, 30 usually works, // sometimes the emptyRx() actually moves 31 bytes // it hasn't overflowed yet, I cannot tell if the new byte is added while // emptyRX() is executing or before? - f.rx_fifo_full_thrhd = 30; // 30 bytes before INT is issued + // let i2cSetFrequency() set thrhds + // f.rx_fifo_full_thrhd = 30; // 30 bytes before INT is issued + // f.tx_fifo_empty_thrhd = 0; f.fifo_addr_cfg_en = 0; // no directed access i2c->dev->fifo_conf.val = f.val; // post them all f.rx_fifo_rst = 0; // release fifo f.tx_fifo_rst = 0; i2c->dev->fifo_conf.val = f.val; // post them all - + i2c->dev->int_clr.val = 0xFFFFFFFF; // kill them All! i2c->dev->ctr.ms_mode = 1; // master! i2c->queuePos=0; @@ -936,9 +954,9 @@ i2c_err_t i2cProcQueue(i2c_t * i2c, uint32_t *readCount, uint16_t timeOutMillis) ESP_INTR_FLAG_LOWMED; //< Low and medium prio interrupts. These can be handled in C. if(i2c->num) { - ret = esp_intr_alloc_intrstatus(ETS_I2C_EXT1_INTR_SOURCE, flags, (uint32_t)&i2c->dev->int_status.val, 0x1FFF, &i2c_isr_handler_default,i2c, &i2c->intr_handle); + ret = esp_intr_alloc_intrstatus(ETS_I2C_EXT1_INTR_SOURCE, flags, (uint32_t)&i2c->dev->int_status.val, 0x7FF, &i2c_isr_handler_default,i2c, &i2c->intr_handle); } else { - ret = esp_intr_alloc_intrstatus(ETS_I2C_EXT0_INTR_SOURCE, flags, (uint32_t)&i2c->dev->int_status.val, 0x1FFF, &i2c_isr_handler_default,i2c, &i2c->intr_handle); + ret = esp_intr_alloc_intrstatus(ETS_I2C_EXT0_INTR_SOURCE, flags, (uint32_t)&i2c->dev->int_status.val, 0x7FF, &i2c_isr_handler_default,i2c, &i2c->intr_handle); } if(ret!=ESP_OK) { @@ -1326,12 +1344,23 @@ i2c_err_t i2cSetFrequency(i2c_t * i2c, uint32_t clk_speed) if(i2c == NULL) { return I2C_ERROR_DEV; } - + I2C_FIFO_CONF_t f; + uint32_t period = (APB_CLK_FREQ/clk_speed) / 2; uint32_t halfPeriod = period/2; uint32_t quarterPeriod = period/4; I2C_MUTEX_LOCK(); + + // Adjust Fifo thresholds based on frequency + f.val = i2c->dev->fifo_conf.val; + uint32_t a = (clk_speed / 50000L )+1; + if (a > 24) a=24; + f.rx_fifo_full_thrhd = 32 - a; + f.tx_fifo_empty_thrhd = a; + i2c->dev->fifo_conf.val = f.val; // set thresholds + log_v("threshold=%d",a); + //the clock num during SCL is low level i2c->dev->scl_low_period.period = period; //the clock num during SCL is high level