Skip to content

improve Glitch prevention, Hardware RESET! #25

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 12 commits into from
Mar 14, 2018
133 changes: 76 additions & 57 deletions cores/esp32/esp32-hal-i2c.c
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ i2c_err_t i2cAttachSCL(i2c_t * i2c, int8_t scl)
return I2C_ERROR_DEV;
}
digitalWrite(scl, HIGH);
pinMode(scl, OPEN_DRAIN | PULLUP);
pinMode(scl, OPEN_DRAIN | PULLUP | INPUT | OUTPUT);
pinMatrixOutAttach(scl, I2C_SCL_IDX(i2c->num), false, false);
pinMatrixInAttach(scl, I2C_SCL_IDX(i2c->num), false);
return I2C_ERROR_OK;
Expand All @@ -189,7 +189,7 @@ i2c_err_t i2cDetachSCL(i2c_t * i2c, int8_t scl)
}
pinMatrixOutDetach(scl, false, false);
pinMatrixInDetach(I2C_SCL_IDX(i2c->num), false, false);
pinMode(scl, INPUT);
pinMode(scl, INPUT | PULLUP);
return I2C_ERROR_OK;
}

Expand All @@ -199,7 +199,7 @@ i2c_err_t i2cAttachSDA(i2c_t * i2c, int8_t sda)
return I2C_ERROR_DEV;
}
digitalWrite(sda, HIGH);
pinMode(sda, OPEN_DRAIN | PULLUP);
pinMode(sda, OPEN_DRAIN | PULLUP | INPUT | OUTPUT );
pinMatrixOutAttach(sda, I2C_SDA_IDX(i2c->num), false, false);
pinMatrixInAttach(sda, I2C_SDA_IDX(i2c->num), false);
return I2C_ERROR_OK;
Expand All @@ -212,7 +212,7 @@ i2c_err_t i2cDetachSDA(i2c_t * i2c, int8_t sda)
}
pinMatrixOutDetach(sda, false, false);
pinMatrixInDetach(I2C_SDA_IDX(i2c->num), false, false);
pinMode(sda, INPUT);
pinMode(sda, INPUT | PULLUP);
return I2C_ERROR_OK;
}

Expand Down Expand Up @@ -287,8 +287,13 @@ uint32_t i2cGetFrequency(i2c_t * i2c)
if(i2c == NULL){
return 0;
}

return APB_CLK_FREQ/(i2c->dev->scl_low_period.period+i2c->dev->scl_high_period.period);
uint32_t result = 0;
uint32_t old_count = (i2c->dev->scl_low_period.period+i2c->dev->scl_high_period.period);
if(old_count>0){
result = APB_CLK_FREQ / old_count;
}
else result = 0;
return result;
}

/*
Expand All @@ -297,7 +302,7 @@ uint32_t i2cGetFrequency(i2c_t * i2c)
* addr_10bit_en - enable slave 10bit address mode.
* */
// 24Nov17 only supports Master Mode
i2c_t * i2cInit(uint8_t i2c_num)
i2c_t * i2cInit(uint8_t i2c_num) //before this is called, pins should be detached, else glitch
{
if(i2c_num > 1){
return NULL;
Expand All @@ -313,16 +318,18 @@ i2c_t * i2cInit(uint8_t i2c_num)
}
}
#endif
I2C_MUTEX_LOCK();
uint32_t old_clock = i2cGetFrequency(i2c);

if(i2c_num == 0) {
DPORT_SET_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG,DPORT_I2C_EXT0_RST); //reset hardware
DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG,DPORT_I2C_EXT0_CLK_EN);
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG,DPORT_I2C_EXT0_RST);
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG,DPORT_I2C_EXT0_RST);// release reset
} else {
DPORT_SET_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG,DPORT_I2C_EXT1_RST); //reset Hardware
DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG,DPORT_I2C_EXT1_CLK_EN);
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG,DPORT_I2C_EXT1_RST);
}

I2C_MUTEX_LOCK();
i2c->dev->ctr.val = 0;
i2c->dev->ctr.ms_mode = 1;
i2c->dev->ctr.sda_force_out = 1 ;
Expand All @@ -336,6 +343,8 @@ i2c_t * i2cInit(uint8_t i2c_num)

i2c->dev->slave_addr.val = 0;
I2C_MUTEX_UNLOCK();

if(old_clock) i2cSetFrequency(i2c,old_clock); // reconfigure

return i2c;
}
Expand Down Expand Up @@ -376,10 +385,10 @@ void i2cReset(i2c_t* i2c){

/* Stickbreaker ISR mode debug support
*/
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_ERROR
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO
#define INTBUFFMAX 64
static uint32_t intBuff[INTBUFFMAX][3];
static uint32_t intPos=0;
static uint32_t intBuff[INTBUFFMAX][3][2];
static uint32_t intPos[2]={0,0};
#endif

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

if(full) readEncountered =false; //tx possibly needs more

#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_ERROR
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO

// update debug buffer tx counts
cnt += intBuff[intPos][1]>>16;
intBuff[intPos][1] = (intBuff[intPos][1]&0xFFFF)|(cnt<<16);
cnt += intBuff[intPos[i2c->num]][1][i2c->num]>>16;
intBuff[intPos[i2c->num]][1][i2c->num] = (intBuff[intPos[i2c->num]][1][i2c->num]&0xFFFF)|(cnt<<16);

#endif

if(!(full||readEncountered)) a++; // check next buffer for tx
if(!full) a++; // check next buffer for tx
}

if((!full) || readEncountered || (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;
}

Expand Down Expand Up @@ -746,10 +749,10 @@ if(tdq->ctrl.mode==1) { // read
moveCnt = (tdq->length - tdq->position);
}
}
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_ERROR
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO
// update Debug rxCount
cnt += (intBuff[intPos][1])&&0xffFF;
intBuff[intPos][1] = (intBuff[intPos][1]&0xFFFF0000)|cnt;
cnt += (intBuff[intPos[i2c->num]][1][i2c->num])&&0xffFF;
intBuff[intPos[i2c->num]][1][i2c->num] = (intBuff[intPos[i2c->num]][1][i2c->num]&0xFFFF0000)|cnt;
#endif
}
else {
Expand Down Expand Up @@ -813,23 +816,22 @@ if(p_i2c->stage==I2C_DONE){ //get Out
log_e("eject int=%p, ena=%p",activeInt,p_i2c->dev->int_ena.val);
p_i2c->dev->int_ena.val = 0;
p_i2c->dev->int_clr.val = activeInt; //0x1FFF;
// i2cDumpI2c(p_i2c);
// i2cDumpInts();
return;
}
while (activeInt != 0) { // Ordering of 'if(activeInt)' statements is important, don't change
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_ERROR
if(activeInt==(intBuff[intPos][0]&0x1fff)){
intBuff[intPos][0] = (((intBuff[intPos][0]>>16)+1)<<16)|activeInt;
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO
if(activeInt==(intBuff[intPos[p_i2c->num]][0][p_i2c->num]&0x1fff)){
intBuff[intPos[p_i2c->num]][0][p_i2c->num] = (((intBuff[intPos[p_i2c->num]][0][p_i2c->num]>>16)+1)<<16)|activeInt;
}
else{
intPos++;
intPos %= INTBUFFMAX;
intBuff[intPos][0]=(1<<16)|activeInt;
intBuff[intPos][1] = 0;
intPos[p_i2c->num]++;
intPos[p_i2c->num] %= INTBUFFMAX;
intBuff[intPos[p_i2c->num]][0][p_i2c->num] = (1<<16) | activeInt;
intBuff[intPos[p_i2c->num]][1][p_i2c->num] = 0;
}

intBuff[intPos][2] = xTaskGetTickCountFromISR(); // when IRQ fired
intBuff[intPos[p_i2c->num]][2][p_i2c->num] = xTaskGetTickCountFromISR(); // when IRQ fired

#endif
uint32_t oldInt =activeInt;

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

void i2cDumpInts(){
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_ERROR
void i2cDumpInts(uint8_t num){
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO
uint32_t b;
log_e("row count INTR TX RX");
log_e("%u row count INTR TX RX",num);
for(uint32_t a=1;a<=INTBUFFMAX;a++){
b=(a+intPos)%INTBUFFMAX;
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]);
b=(a+intPos[num])%INTBUFFMAX;
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]);
}
#else
log_n("enable Core Debug Level \"Error\"");
Expand All @@ -965,7 +967,10 @@ i2c_err_t i2cProcQueue(i2c_t * i2c, uint32_t *readCount, uint16_t timeOutMillis)
if(i2c == NULL){
return I2C_ERROR_DEV;
}

if (i2c->dev->status_reg.bus_busy){ // return error, let TwoWire() handle resetting the hardware.
log_i("Bus busy, reinit");
return I2C_ERROR_BUSY;
}
I2C_MUTEX_LOCK();
/* what about co-existance with SLAVE mode?
Should I check if a slaveMode xfer is in progress and hang
Expand All @@ -974,9 +979,13 @@ I2C_MUTEX_LOCK();
*/
i2c->stage = I2C_DONE; // until ready

#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_ERROR
memset(intBuff,0,sizeof(intBuff));
intPos=0;
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO
for(uint16_t i=0;i<INTBUFFMAX;i++){
intBuff[i][0][i2c->num] = 0;
intBuff[i][1][i2c->num] = 0;
intBuff[i][2][i2c->num] = 0;
}
intPos[i2c->num] = 0;
#endif
// EventGroup is used to signal transmisison completion from ISR
// not always reliable. Sometimes, the FreeRTOS scheduler is maxed out and refuses request
Expand Down Expand Up @@ -1063,9 +1072,19 @@ i2c->dev->int_ena.val =
I2C_TXFIFO_EMPTY_INT_ENA | // (BIT(1)) triggers fillTxFifo()
I2C_RXFIFO_FULL_INT_ENA; // (BIT(0)) trigger emptyRxFifo()

if(!i2c->intr_handle){ // create ISR I2C_0 only,
// log_e("create ISR");
uint32_t ret = esp_intr_alloc(ETS_I2C_EXT0_INTR_SOURCE, 0, &i2c_isr_handler_default, i2c, &i2c->intr_handle);
if(!i2c->intr_handle){ // create ISR for either peripheral
log_i("create ISR");
uint32_t ret;
switch(i2c->num){
case 0:
ret = esp_intr_alloc(ETS_I2C_EXT0_INTR_SOURCE, 0, &i2c_isr_handler_default, i2c, &i2c->intr_handle);
break;
case 1:
ret = esp_intr_alloc(ETS_I2C_EXT1_INTR_SOURCE, 0, &i2c_isr_handler_default, i2c, &i2c->intr_handle);
break;
default :;
}

if(ret!=ESP_OK){
log_e("install interrupt handler Failed=%d",ret);
I2C_MUTEX_UNLOCK();
Expand Down Expand Up @@ -1101,11 +1120,11 @@ if(i2c->exitCode!=eBits){ // try to recover from O/S failure
}

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
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_ERROR
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO
i2cDumpI2c(i2c);
i2cDumpInts();
i2cDumpInts(i2c->num);
#else
log_n("I2C exitCode=%u",eBits);
log_n("I2C exitCode=0x%x",eBits);
#endif
}

Expand All @@ -1116,7 +1135,7 @@ if(eBits&EVENT_DONE){ // no gross timeout
// expected can be zero due to small packets
log_e("TimeoutRecovery: expected=%ums, actual=%ums",expected,(tAfter-tBefore));
i2cDumpI2c(i2c);
i2cDumpInts();
i2cDumpInts(i2c->num);
}
#endif
switch(i2c->error){
Expand Down Expand Up @@ -1152,7 +1171,7 @@ else { // GROSS timeout, shutdown ISR , report Timeout
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_ERROR
log_e(" Busy Timeout start=0x%x, end=0x%x, =%d, max=%d error=%d",tBefore,tAfter,(tAfter-tBefore),ticksTimeOut,i2c->error);
i2cDumpI2c(i2c);
i2cDumpInts();
i2cDumpInts(i2c->num);
#endif
}
else { // just a timeout, some data made it out or in.
Expand All @@ -1162,7 +1181,7 @@ else { // GROSS timeout, shutdown ISR , report Timeout
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_ERROR
log_e(" Gross Timeout Dead start=0x%x, end=0x%x, =%d, max=%d error=%d",tBefore,tAfter,(tAfter-tBefore),ticksTimeOut,i2c->error);
i2cDumpI2c(i2c);
i2cDumpInts();
i2cDumpInts(i2c->num);
#endif
}
}
Expand Down
2 changes: 1 addition & 1 deletion cores/esp32/esp32-hal-i2c.h
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ i2c_err_t i2cAddQueueRead(i2c_t *i2c, uint16_t i2cDeviceAddr, uint8_t *dataPtr,
i2c_err_t i2cFreeQueue(i2c_t *i2c);
i2c_err_t i2cReleaseISR(i2c_t *i2c);
//stickbreaker debug support
void i2cDumpInts();
void i2cDumpInts(uint8_t num);
void i2cDumpI2c(i2c_t *i2c);

#ifdef __cplusplus
Expand Down
Loading