-
Notifications
You must be signed in to change notification settings - Fork 7.6k
ESP32 with Wifi messes up i2c bus reads (MPU6050) #1352
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
Comments
@echoGee Switch to the stickbreaker-i2c branch of this repo. And add the IRAM_ATTR to: void IRAM_ATTR dmpDataReady() {
mpuInterrupt = true;
} The main branch I2C subsystem is not very durable. Chuck. |
Attempting to use the stickbreaker-i2c branch on PlatformIO. I haven't been able to find a good way to do this yet using PlatformIO !! :( |
There's only five files that need to be replaced. https://desire.giesecke.tk/index.php/2018/04/20/how-to-use-stickbreakers-i2c-improved-code/ . The location should be ~/.platformio/packages/framework-arduinoespressif32 |
This works. However, I get an occassional log for
Corresponding code that logs this is in esp32-hal-i2c.c 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;
//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);
p_i2c->dev->int_ena.val = 0;
p_i2c->dev->int_clr.val = activeInt; //0x1FFF;
return;
}
.
.
.
|
That error is saying a i2c interrupt has been triggered before the ISR is correctly configured. So the ISR cleared the interrupt and exited.
int=0x0 is stating that no interrupt reason exists, and the ena=0x0 says no interrupts are enabled? What version of my code are you using? look in if(!i2c->intr_handle) { // create ISR for either peripheral
// log_i("create ISR %d",i2c->num);
uint32_t ret = 0;
uint32_t flags = ESP_INTR_FLAG_EDGE | //< Edge-triggered interrupt
ESP_INTR_FLAG_IRAM | //< ISR can be called if cache is disabled
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);
} 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);
} Chuck. |
I am using the latest code on https://github.com/espressif/arduino-esp32/tree/stickbreaker-i2c What do you mean by no interrupt reason exists?
The code snippet looks like this for me : if(!i2c->intr_handle) { // create ISR for either peripheral
// log_i("create ISR %d",i2c->num);
uint32_t ret = 0;
uint32_t flags = ESP_INTR_FLAG_EDGE | //< Edge-triggered interrupt
ESP_INTR_FLAG_IRAM | //< ISR can be called if cache is disabled
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);
} 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);
}
if(ret!=ESP_OK) {
log_e("install interrupt handler Failed=%d",ret);
I2C_MUTEX_UNLOCK();
return I2C_ERROR_MEMORY;
}
} |
int= is displaying the bit flags for which of the i2c interrupt condition was the source for this cycle. union {
struct {
uint32_t rx_fifo_full: 1; /*The masked interrupt status for rx_fifo_full_int interrupt.*/
uint32_t tx_fifo_empty: 1; /*The masked interrupt status for tx_fifo_empty_int interrupt.*/
uint32_t rx_fifo_ovf: 1; /*The masked interrupt status for rx_fifo_ovf_int interrupt.*/
uint32_t end_detect: 1; /*The masked interrupt status for end_detect_int interrupt.*/
uint32_t slave_tran_comp: 1; /*The masked interrupt status for slave_tran_comp_int interrupt.*/
uint32_t arbitration_lost: 1; /*The masked interrupt status for arbitration_lost_int interrupt.*/
uint32_t master_tran_comp: 1; /*The masked interrupt status for master_tran_comp_int interrupt.*/
uint32_t trans_complete: 1; /*The masked interrupt status for trans_complete_int interrupt.*/
uint32_t time_out: 1; /*The masked interrupt status for time_out_int interrupt.*/
uint32_t trans_start: 1; /*The masked interrupt status for trans_start_int interrupt.*/
uint32_t ack_err: 1; /*The masked interrupt status for ack_err_int interrupt.*/
uint32_t rx_rec_full: 1; /*The masked interrupt status for rx_rec_full_int interrupt.*/
uint32_t tx_send_empty: 1; /*The masked interrupt status for tx_send_empty_int interrupt.*/
uint32_t reserved13: 19;
};
uint32_t val;
} int_status; It should be a non Zero value in the range of 0x0001 to 0x1fff. somehow a interrupt is being generated without a corresponding source. Possibly my ISR is servicing the interrupt before the interrupt is generated. My ISR services all pending interrupts before is exits. It cycles through a at the Bottom of
comment out this line. That will make the ISR only handle pre-existing events. See if commenting out that line prevents that error message. I coded it this way to increase performance, I found that it was faster to service multiple interrupts at the same time, than to do each one separately. See if commenting out that line changes the behavior, I'll have to do some more thinking and testing. |
@stickbreaker , tried commenting at the Bottom of i2c_isr_default_handler(): activeInt = p_i2c->dev->int_status.val; // start all over if another interrupt happened There are many(around 1 a sec) errors Error 1
Error 2
Error 3
|
@echoGee increase you log level to info, and post. I'm getting confused. The Gross timeout error seem to be wrong.
start= and end= are millisecond markers, this message is saying the i2c process started at 0x1b4a and took less than 1ms, Maximum before timeout should have occurred is 51ms (50ms as default timeout, 1ms calculated for this data block). FOUND ERROR in stickbreaker-i2c, i2c->dev->ctr.trans_start=1; // go for it
uint32_t eBits = xEventGroupWaitBits(i2c->i2c_event,EVENT_DONE,pdFALSE,pdTRUE,ticksTimeOut);
//log_e("after WaitBits=%x @tick=%d",eBits,xTaskGetTickCount());
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_ERROR
portTickType tBefore=xTaskGetTickCount();
portTickType tAfter=xTaskGetTickCount();
#endif See that #ifdef ? i2c->dev->ctr.trans_start=1; // go for it
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_ERROR
portTickType tBefore=xTaskGetTickCount();
#endif
uint32_t eBits = xEventGroupWaitBits(i2c->i2c_event,EVENT_DONE,pdFALSE,pdTRUE,ticksTimeOut);
//log_e("after WaitBits=%x @tick=%d",eBits,xTaskGetTickCount());
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_ERROR
portTickType tAfter=xTaskGetTickCount();
#endif That will fix the error message, But, It won't fix your problem. Chuck. |
Attached is the INFO level logs with the changes
Error 2
|
@echoGee thanks for the debug output, Let me think about what is going wrong, The
Ok, decoding this dump, A There should be more interrupts, either some Timeouts, or the Stop (0x80). Are you using long critical sections in your code? Something shutdown interrupts for a long time. Something is either wrong in stickbreaker-i2c. |
None that I have implemented. I'm virtually using the code given in #1352 (comment) Is anything related to the Wifi call or any interrupt requests from Wifi the troublemaker ? Just reminding that |
@echoGee More debug: } else { // GROSS timeout, shutdown ISR , report Timeout
i2c->stage = I2C_DONE;
i2c->dev->int_ena.val =0;
i2c->dev->int_clr.val = 0x1FFF;
if((i2c->queuePos==0)&&(i2c->byteCnt==0)) { // Bus Busy no bytes Moved
reason = I2C_ERROR_BUSY;
eBits = eBits | EVENT_ERROR_BUS_BUSY|EVENT_ERROR|EVENT_DONE;
#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(i2c->num);
#endif
} else { // just a timeout, some data made it out or in.
reason = I2C_ERROR_TIMEOUT;
eBits = eBits | EVENT_ERROR_TIMEOUT|EVENT_ERROR|EVENT_DONE;
#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(i2c->num);
#endif
}
} add Chuck. |
@echoGee Try increasing the timeout with chuck. |
@echoGee Maybe the Wifi is disabling interrupts longer than 50ms and there is an interrupt pending. uint32_t eBits = xEventGroupWaitBits(i2c->i2c_event,EVENT_DONE,pdFALSE,pdTRUE,ticksTimeOut); times out and shuts down the ISR before it can receive the last interrupt and complete the transaction. The i2c hardware has successfully completed the data transfer, but the ISR has not processed the STOP. Chuck. |
@echoGee That would make sense with the original problem of no 'interrupt source'.
See if increasing the TimeOut fixes this problem. Chuck. |
Why would WiFi disable interrupts? If any, it would run an ISR that would take too long to complete. That what you mean ? |
Debugs with the i2cDumpI2c function . Note that the timeout has not been increased yet.
|
@stickbreaker Confirming that increasing the timeout to 1000ms has NOT removed the error. |
This error is showing that the ISR was unable to notify
Set your timeout to 1000, and set the debug level back to Error. The timeout Recovery message is just an Info level output. It is not actually an error. Chuck. |
@stickbreaker , commenting at the Bottom of i2c_isr_default_handler() is part of the fix, correct? activeInt = p_i2c->dev->int_status.val; // start all over if another interrupt happened |
Na, put that line back in. I think the only problem was too short of timeout. |
Fixed on #1767 =) |
Hardware:
Board: ESP32 DevKit V1 DoIT
Core Installation/update date: https://github.com/platformio/platform-espressif32/releases/tag/v0.12.0
IDE name: Platform.io
Flash Frequency: 80Mhz?
Upload Speed: unknown
Description:
Enabling Wifi using the
connectToWiFi(networkName, networkPswd);
messes up reading of the MPU6050 using the I2C bus. There are 3 different test cases.connectToWiFi(networkName, networkPswd);
in the sketch below: This reads the MPU6050 through i2c flawlessly(at ~100fps). Wifi obviously is disabled.connectToWiFi(networkName, networkPswd);
in the sketch below: This makes the bus unreliable and "panics" the core after sometime.connectToWiFi(networkName, networkPswd);
in the sketch below, and move the contents of the interrupt functionvoid dmpDataReady() {
to IRAM by modifying it tovoid IRAM_ATTR dmpDataReady() {
. This is in reference to an issue Guru Meditation Error: Core 1 panic'ed (Cache disabled but cached memory region accessed) ESP32 ARDUINO IDE #855. : This makes the bus unreliable and causes the bus to freeze after sometime. No core panic though.The debugs for the 3 test cases are given below
Sketch:
The sketch is a modification of the https://github.com/jrowberg/i2cdevlib/blob/master/Arduino/MPU6050/examples/MPU6050_DMP6_ESPWiFi/MPU6050_DMP6_ESPWiFi.ino to work for ESP32 and sending through wifi UDP.
Debug Messages:
Output from scenario 1
Output from scenario 2
Output from scenario 3
The text was updated successfully, but these errors were encountered: