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.
This commit is contained in:
parent
ddfeae90d0
commit
28a410dd50
@ -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
|
if(!full || (a >= i2c->queueCount)) { // disable IRQ, the next dq will re-enable it
|
||||||
i2c->dev->int_ena.tx_fifo_empty=0;
|
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;
|
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) {
|
if(i2c->dq[i2c->queuePos].ctrl.mode == 1) {
|
||||||
emptyRxFifo(i2c); // grab last few characters
|
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_ena.val = 0; // shutdown interrupts
|
||||||
i2c->dev->int_clr.val = 0x1FFFF;
|
i2c->dev->int_clr.val = 0x1FFF;
|
||||||
i2c->stage = I2C_DONE;
|
i2c->stage = I2C_DONE;
|
||||||
i2c->exitCode = exitCode; //true eventcode
|
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)
|
static void IRAM_ATTR i2c_isr_handler_default(void* arg)
|
||||||
{
|
{
|
||||||
i2c_t* p_i2c = (i2c_t*) arg; // recover data
|
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(!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
|
}
|
||||||
log_e("eject int=%p, ena=%p",activeInt,p_i2c->dev->int_ena.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_ena.val = 0;
|
||||||
p_i2c->dev->int_clr.val = activeInt; //0x1FFF;
|
p_i2c->dev->int_clr.val = activeInt; //0x1FFF;
|
||||||
return;
|
return;
|
||||||
@ -610,7 +626,6 @@ static void IRAM_ATTR i2c_isr_handler_default(void* arg)
|
|||||||
intBuff[intPos[p_i2c->num]][2][p_i2c->num] = xTaskGetTickCountFromISR(); // when IRQ fired
|
intBuff[intPos[p_i2c->num]][2][p_i2c->num] = xTaskGetTickCountFromISR(); // when IRQ fired
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
//uint32_t oldInt =activeInt;
|
|
||||||
|
|
||||||
if (activeInt & I2C_TRANS_START_INT_ST_M) {
|
if (activeInt & I2C_TRANS_START_INT_ST_M) {
|
||||||
// p_i2c->byteCnt=0;
|
// p_i2c->byteCnt=0;
|
||||||
@ -871,11 +886,14 @@ i2c_err_t i2cProcQueue(i2c_t * i2c, uint32_t *readCount, uint16_t timeOutMillis)
|
|||||||
f.rx_fifo_rst = 1; // fifo in reset
|
f.rx_fifo_rst = 1; // fifo in reset
|
||||||
f.tx_fifo_rst = 1; // fifo in reset
|
f.tx_fifo_rst = 1; // fifo in reset
|
||||||
f.nonfifo_en = 0; // use fifo mode
|
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,
|
// need to adjust threshold based on I2C clock rate, at 100k, 30 usually works,
|
||||||
// sometimes the emptyRx() actually moves 31 bytes
|
// sometimes the emptyRx() actually moves 31 bytes
|
||||||
// it hasn't overflowed yet, I cannot tell if the new byte is added while
|
// it hasn't overflowed yet, I cannot tell if the new byte is added while
|
||||||
// emptyRX() is executing or before?
|
// 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
|
f.fifo_addr_cfg_en = 0; // no directed access
|
||||||
i2c->dev->fifo_conf.val = f.val; // post them all
|
i2c->dev->fifo_conf.val = f.val; // post them all
|
||||||
|
|
||||||
@ -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.
|
ESP_INTR_FLAG_LOWMED; //< Low and medium prio interrupts. These can be handled in C.
|
||||||
|
|
||||||
if(i2c->num) {
|
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 {
|
} 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) {
|
if(ret!=ESP_OK) {
|
||||||
@ -1326,12 +1344,23 @@ i2c_err_t i2cSetFrequency(i2c_t * i2c, uint32_t clk_speed)
|
|||||||
if(i2c == NULL) {
|
if(i2c == NULL) {
|
||||||
return I2C_ERROR_DEV;
|
return I2C_ERROR_DEV;
|
||||||
}
|
}
|
||||||
|
I2C_FIFO_CONF_t f;
|
||||||
|
|
||||||
uint32_t period = (APB_CLK_FREQ/clk_speed) / 2;
|
uint32_t period = (APB_CLK_FREQ/clk_speed) / 2;
|
||||||
uint32_t halfPeriod = period/2;
|
uint32_t halfPeriod = period/2;
|
||||||
uint32_t quarterPeriod = period/4;
|
uint32_t quarterPeriod = period/4;
|
||||||
|
|
||||||
I2C_MUTEX_LOCK();
|
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
|
//the clock num during SCL is low level
|
||||||
i2c->dev->scl_low_period.period = period;
|
i2c->dev->scl_low_period.period = period;
|
||||||
//the clock num during SCL is high level
|
//the clock num during SCL is high level
|
||||||
|
Loading…
Reference in New Issue
Block a user