-
Notifications
You must be signed in to change notification settings - Fork 7.6k
[ESP32] I2C Interrupt problem since uprade to Espressif 1.1.0 #1588
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
Wrong assignment, re-opened this issue at |
Platformio owner pointed me back to here, so i reopen this issue here. |
@cyberman54 I just answered your issue on the platformio repo 107 Chuck. |
@stickbreaker Problem with the confusing debug messages is now solved, thanks to your pull request. |
@cyberman54 the injection error is showing that the ISR was call, but the control structure was not configured for operation, there is a
Of these three sections of code, the first one was the source I traced down when I cannot imagine how the second could result in an injection event. (it happens during interrupt context) The Third could only happen if the timeout expired, the foreground task started cleaning up the timeout, but before it output the log messages of the failure (Gross timeout, Bus Busy) an i2c interrupt triggered. I cannot see this happening: here is the code. The interrupt would have to trigger before } 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
}
}
Code that generated the Debug message "injection": // sync between dispatch(i2cProcQueue) and worker(i2c_isr_handler_default)
typedef enum {
//I2C_NONE=0,
I2C_STARTUP=1,
I2C_RUNNING,
I2C_DONE
} I2C_STAGE_t;
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;
} As you can see this I don't have a clue how the ISR was called out of sequence. Chuck. |
Hmm, sounds difficult. As my application code runs under espressif32 v1.0.2 without this i2c problem, i assume that this behaviour is caused by something that came in by upgrade Espressif32 to v1.1.x. In my application code i don't use Wire() directly. But i am using u8g2 library to control an OLED I2C display. The author of u8g2 pointed out, that his library is using Wire.h in Arduino style. My application uses RTos tasks, but u8g2 calls are centralized in one main task. But the main task will be interrupted by other tasks (which don't call Wire()). |
@cyberman54 are you using ANY other i2c code? mixing IDF i2c and Arduino i2c? Chuck. |
No. Only I2C component is the OLED display, controlled by u8g2 library. |
I have exactly the same problem. One I2C display that is controlled from a separate FreeRTOS task. |
@cyberman54 @bartoszbielawski are you both using Platformio? I use Arduino. Can either or both of you make a small /simple example that shows this problem? If I need to set up a Platformio environment I will, but I will probably need some help 😁 Chuck. |
Chuck, you may just look to my repo: https://github.com/cyberman54/ESP32-Paxcounter/tree/development?files=1 |
@stickbreaker The screen itself has some extra random dots and the printed number sometime jump few pixels back and forth + the error messages - check the end of the gist. |
@bartoszbielawski try changing the xTaskCreate to:
You are starting this task at priority 5, the basic Arduino loop runs at 1. And possibly the interrupt is triggering on the wrong core? Chuck. |
@bartoszbielawski can you make a change in if(p_i2c->stage==I2C_DONE) { //get Out
log_e("eject int=%p, ena=%p core=%d",activeInt,p_i2c->dev->int_ena.va,xPortGetCoreID());
p_i2c->dev->int_ena.val = 0;
p_i2c->dev->int_clr.val = activeInt; //0x1FFF;
return;
} Changing the Chuck. |
@stickbreaker
I guess I will reduce I2C speed to the regular 400 kHz. |
@bartoszbielawski let me think about this. So, when you pin it to core1 the Eject says core=1 and if you pin it to core0, eject says core=0. I have ran my test bed that has 10 i2c devices on a 18" bus at 1,000,000hz for 10k+ operations. But I haven't tried from a separate task, just the prime arduino core. No, the ISR responds to the interrupts, if they are slower it just takes longer. The ISR is designed to handle concurrent interrupts. the ESP32 won't dispatch while it is in an interrupt. The Stage==Done is saying Either it completed or a Timeout happened. another change: if(p_i2c->stage==I2C_DONE) { //get Out
log_e("eject int=%p, ena=%p",activeInt,p_i2c->dev->int_ena.val);
i2cDumpInts(p_i2c->num);
p_i2c->dev->int_ena.val = 0;
p_i2c->dev->int_clr.val = activeInt; //0x1FFF;
return; Chuck |
@stickbreaker I added both of your above debug modifications to
|
sorry, i forgot the
So, code runs on core1. This is as expected, since i control the i2c display from arduino main loop, and this runs on core1 with RTos. |
And after some seconds i get a Guru Meditation Error:
The dump resolves to:
|
That is weird, nothing is showing up a wrong, just that you are seeing a unserviced interrupt. More Debug, lets see the time frame between the last interrupt and this spurious interrupt. if(p_i2c->stage==I2C_DONE) { //get Out
log_e("eject tick=0x%8x int=%p, ena=%p core=%d", xTaskGetTickCountFromISR(),activeInt,p_i2c->dev->int_ena.val,xPortGetCoreID());
i2cDumpInts(p_i2c->num);
p_i2c->dev->int_ena.val = 0;
p_i2c->dev->int_clr.val = activeInt; //0x1FFF;
return; Chuck |
@bartoszbielawski ignore the core dump, too much debug output during an interrupt, Watchdog died of starvation. |
Sorry guys, I'm out for today. I have a long drive tomorrow and have to be
rested...
Bartosz
|
@bartoszbielawski Thanks for trying. Chuck. |
i will check tommorow. |
@bartoszbielawski Thru more research we might be having a pullup problem. if this is your board Heltec WiFi kit 32 It shows only 10k pullups on the SDA and SCL lines. Try adding 3.3k pullups. That should drop the effective pullups to 2.3k. We might be having pullup issues at higher data rates. Chuck. |
@bartoszbielawski does is work with Espressif32 v1.0.2 and same.board? @stickbreaker SDA/SCL are muxed in the ESP32 and can be switched to different GPIOs |
@cyberman54 It does work on 1.0.2 on the same board. |
Hi Chuck, I have seen in the Adafruit_Si7021 multiple Wire.endTransmission(false), without a reason for the false. I removed the false parameter and the I2C works again. I will continue testing with your patch. |
Update: |
@helmut64 are you seeing any error messages? Chuck. |
The Adafruit_Si7021 is very simple, the code is here: https://github.com/adafruit/Adafruit_Si7021 |
@helmut64 Post the compile errors, I can't fix what I can't see. Looking through that si7021 library, I can see why it doesn't work. float Adafruit_Si7021::readHumidity(void) {
Wire.beginTransmission(_i2caddr);
Wire.write((uint8_t)SI7021_MEASRH_NOHOLD_CMD);
Wire.endTransmission(false);
delay(25);
Wire.requestFrom(_i2caddr, 3);
uint16_t hum = Wire.read();
hum <<= 8;
hum |= Wire.read();
uint8_t chxsum = Wire.read();
float humidity = hum;
humidity *= 125;
humidity /= 65536;
humidity -= 6;
return humidity;
} This code will not react as assumed. The i2c subsystem will queue the Wire.endTransmission(false);
bool done = false;
uint32_t timeout = millis();
while((millis()-timeout<1000)&&( !done)){ // 1sec timeout
done = (Wire.requestFrom(_i2caddr, 3) ==3);
delay(2); // give other tasks a bit of time while sensor samples
}
if (done){
uint16_t hum = Wire.read();
hum <<= 8;
hum |= Wire.read();
uint8_t chxsum = Wire.read();
float humidity = hum;
humidity *= 125;
humidity /= 65536;
humidity -= 6;
return humidity;
}
else { // error
return -1.0; // error
}
} This is only one problem, there are more, when I get a chance I'll go through the rest of the library. Chuck. |
The Compiler problem you see only when you switch within the Arduino IDE the menu the "Core Debug-Level" level to Verbose and click on compile. |
@helmut64 It compiles without any errors on my system using Arduino 1.8.5, Core Debug Level NONE -> VERBOSE . I'm not seeing any problems, capture the Arduino's compile window. Without it I can't do anything. Chuck. |
@cyberman54 If this fix works for you, close this issue. me-no-dev just merged it into the main repo. So, lets see if any new errors crop up. Chuck. |
@stickbreaker meanwhile i did some tests with my app, comparing running it unter Espressif 1.0.2 and Espressif 1.1.2 including latest pull requests, also yours. Result is:
So, result is that i will continue sticking to Espressif core 1.0.2, until i get rid this performance hit :-( |
@stickbreaker i did another test and took out the display driver from my app, so that no i2c communication is used. Result is, that the performance issues disappear, i.e. LED blinking is back to normal. |
@cyberman54 can you post your display driver code? I need something to test. ssd1306_128x64_i2c.zip The SSD1306.zip is a modified AdaFruit_SSD1306 that only sends changed bits to the display. One of the tests "testStar()" takes 3610ms using Adafruit_SSD1306 only 865ms with SSD1306. Have you went through your U8X8_SSD1306_128X64_NONAME_HW_I2C verifying that it handles ReSTARTS correctly? Chuck. |
@stickbreaker i'm using u8x8.cpp from the u8g2 library. Did not write any display driver code on my own. |
@cyberman54 can you give me a basic sketch that uses this library? Looking through this code is a nightmare. I need a place to start. Chuck. |
The Updated SI7021 Sensor library works, I understand your while loop around the Wire.requestFrom().
Thank you for helping out here. |
@helmut64 my timing was taken from here: I don't know what you meant here:
I don't have one of these sensors, so I am basing my code on my understanding of the datasheet. I guess, if my code doesn't fit your purpose you'll have to write better code 😀 If you have a library that produces accurate values, just modify it to work with the esp32. Chuck. |
Chuck, you do a great job, and I love to see better I2C support, thank you for your support. I was talking about the missing functions:
I will do further testing and integrate your changes. You need a set of our ESP32 ECO Power boards with the sensor, please contact me (via the radioshuttle.de website) with your contact details. |
@helmut64 just tried the contact link from your website
substituted "XXXXXXXX" to protect you address Chuck. |
@stickbreaker [email protected] should work. |
Hi Chuck, I have another problem with I2C using the Rodan DS3231 RTC driver. The driver is not great, no C++, however it works with D21 MCUs and well with AVRs, it was working with the ESP32 until your patch. There is no endTransmission(false) in this, I plan to use a scope to trace what is going on. Maybe you see something and can point to it. |
@helmut64 that is the email i used. On the Rtc, I'll look at it tomorrow or saturday. Today was 20+ hrs I'm blitzed. Chuck |
@helmut64 got it. |
FYI: For the Rodan DS3231 library I fixed the I2C ESP32 support, basically via a timeout loop around the Wire.requestFrom() as proposed by you. A "Wire.available()" check is an alternate option I tested, however the timeout loop is better because it avoids hangs. The new Rodan DS3231 library (tested on ARV, D21 and ESP32) is available now. |
espressif#1869 exposed a resource exhaustion issue. The current HAL layer for I2C support is designed to use a shared interrupt, But, during debugging to solve the interrupt overloading condition identified in espressif#1588, and the generation of pr espressif#1717, the interrupt allocation parameters were changed. This change was unnecessary, the code will work successfully with shared interrupts. So, there is no need to assign a private interrupt for each I2C peripheral.
#1869 exposed a resource exhaustion issue. The current HAL layer for I2C support is designed to use a shared interrupt, But, during debugging to solve the interrupt overloading condition identified in #1588, and the generation of pr #1717, the interrupt allocation parameters were changed. This change was unnecessary, the code will work successfully with shared interrupts. So, there is no need to assign a private interrupt for each I2C peripheral.
Fixed on #1767 =) |
I'm using u8x8 on ESP32 boards, programmed with Arduino Espressif32 core.
I2C display handling using driver
U8X8_SSD1306_128X64_NONAME_HW_I2C
This worked perfectly until last days the Espressif32 core was updated from v1.0.2 to v1.1.0.
Since then i get this error during runtime:
[E][esp32-hal-i2c.c:594] i2c_isr_handler_default(): eject int=0x0, ena=0x0
And the display write speed is significantly reduced.
I'm not sure if this is a problem with u8x8 or the Espressif32 core. I'm not using any other I2C communication on the board.
Cross reference to u8x8:
olikraus/u8g2#646 (comment)
The text was updated successfully, but these errors were encountered: