-
Notifications
You must be signed in to change notification settings - Fork 7.6k
"install interrupt handler Failed=261" when initializing two I2C buses #1869
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
I'll have to do some testing, I'll get back with you tomorrow. |
@AdrienFelon I haven't been able to duplicate your error.
Chuck. |
Huh. Thanks a lot for trying and validating this scenario. I'm working on the finding the minimal sketch that reproes this. |
I deleted my earlier post where I thought it was my code at fault, as I am now able to repro the issue with the sketch below that uses Arduino 1.8.5. It looks like initializing 2 HW timers and 2 Wire is required for the problem to happen. I'm wondering if I am just trying something not supported... #include <Wire.h>
#include <WiFi.h>
#define MSP_SDA 25
#define MSP_SCL 26
#define SENSOR_SDA 22
#define SENSOR_SCL 23
void scan(TwoWire & bus)
{
Serial.println("scan");
for (uint8_t i = 0; i <= 0x7F; ++i) {
bus.beginTransmission(i);
if (0 == bus.endTransmission(true)) // If a device exist on bus, it will reply with 0
{
Serial.print(" Found ");
Serial.println(i);
}
}
}
void IRAM_ATTR ISR_Timer_1Hz() { /* do something */}
void IRAM_ATTR ISR_Timer_50Hz() { /* do something else */}
hw_timer_t * _isrTimer1Hz;
hw_timer_t * _isrTimer50Hz;
void setup2Timers()
{
Serial.println("setup2Timers");
_isrTimer1Hz = timerBegin(0, 80, true);
_isrTimer50Hz = timerBegin(1, 80, true);
timerAttachInterrupt(_isrTimer1Hz, ISR_Timer_1Hz, true);
timerAttachInterrupt(_isrTimer50Hz, ISR_Timer_50Hz, true);
}
void setup2Wire()
{
Serial.println("setup2Wire");
Wire.begin(SENSOR_SDA, SENSOR_SCL, 400000);
Wire1.begin(MSP_SDA, MSP_SCL, 400000);
}
uint32_t nexpoll = 0;
void setup() {
Serial.begin(115200);
setup2Timers();
setup2Wire();
scan(Wire);
scan(Wire1);
}
void loop() {
} Yields the following output
|
Another version of the repro sketch with #define to illustrate crash in HW timer as well. #include <Wire.h>
#include <WiFi.h>
// Only define one of the 2 REPRO_X macro at a time
#define REPRO_FAILURE_IN_I2CPROCQUEUE
//#define REPRO_CRASH_IN_TIMERATTACHINTERRUPT
void IRAM_ATTR ISR_Timer_1() { /* do something */}
void IRAM_ATTR ISR_Timer_2() { /* do something */}
hw_timer_t * _isrTimer1;
hw_timer_t * _isrTimer2;
void setup1HwTimer()
{
Serial.println("setup1HwTimer");
_isrTimer1 = timerBegin(0, 80, true);
timerAttachInterrupt(_isrTimer1, ISR_Timer_1, true);
}
void setup2HwTimers()
{
Serial.println("setup2HwTimers");
_isrTimer1 = timerBegin(0, 80, true);
_isrTimer2 = timerBegin(1, 80, true);
timerAttachInterrupt(_isrTimer1, ISR_Timer_1, true);
timerAttachInterrupt(_isrTimer2, ISR_Timer_2, true);
}
void scan(TwoWire & bus)
{
Serial.println("scan");
for (uint8_t i = 0; i <= 0x7F; ++i) {
bus.beginTransmission(i);
if (0 == bus.endTransmission(true)) // If a device exist on bus, it will reply with 0
{
Serial.print(" Found ");
Serial.println(i);
}
}
}
void setup2Wire()
{
Serial.println("setup2Wire");
Wire.begin(22, 23, 400000);
Wire1.begin(25, 26, 400000);
}
void setup() {
Serial.begin(115200);
#ifdef REPRO_FAILURE_IN_I2CPROCQUEUE
Serial.println("REPRO_FAILURE_IN_I2CPROCQUEUE");
setup1HwTimer();
setup2Wire();
scan(Wire);
scan(Wire1);
#endif
#ifdef REPRO_CRASH_IN_TIMERATTACHINTERRUPT
Serial.println("REPRO_CRASH_IN_TIMERATTACHINTERRUPT");
setup2Wire();
scan(Wire);
scan(Wire1);
setup2HwTimers(); // -> Crashes while setting up the second timer
#endif
}
void loop() { } |
@AdrienFelon from esp-idf/esp_intr_alloc.h:
It looks like there are no available interrupts? in 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. to: uint32_t flags = 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.
ESP_INTR_FLAG_SHARED; // Share one interrupt, use i2c->dev->int_status.val to select Chuck. |
This seems to work. The repro sketch posted above does not repro any problem with these changes: no more "install interrupt handler Failed=261" and no more crashes in timerAttachInterrupt(). I also tested my app: both i2c buses seem operating just fine (I have yet to test HW timers). For what it's worth, esp_intr_alloc(intr_source, (int)(ESP_INTR_FLAG_IRAM|ESP_INTR_FLAG_LOWMED|ESP_INTR_FLAG_EDGE), __timerISR, NULL, &intr_handle); Thanks! |
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.
Hardware:
Board: Custom board
Core Installation/update date: Release 1.0.0
IDE name: Arduino IDE
Flash Frequency: 80Mhz
PSRAM enabled: no
Upload Speed: 115200
Computer OS: Windows 10
Description:
Hello,
I have a custom board with two I2C buses and have been happily using Stickbreaker’s fork (ie. release v.0.2.0 of https://github.com/stickbreaker/arduino-esp32 ) for quite a while. Things have been working great on this fork. Now I’d like to start using Release 1.0.0, since Stickbreaker’s work seems to have been integrated back into the main repo. However, I am hitting lots of error “install interrupt handler Failed=261” when initializing the second I2C bus, followed by a crash when setting an hw timer in my application code (cf traces below).
Would anybody have any idea of what I could be doing wrong? Is there something I need to change in my application code for it to work on Release 1.0.0?
From what I can tell, code 261 (0x105 ESP_ERR_NOT_FOUND I think) means “No free interrupt found with the specified flags”. Looking into the code where this error originates from (cores/esp32/esp32-hal-i2c.c, function i2cProcQueue) I think I see some differences between Release 1.0.0 (that gives me some trouble) and Stickbreaker’s fork (that works). Basically, the flags argument in the call to esp_intr_alloc_intrstatus() is now a combination of EPS_INTR_FLAG_xxx instead of just 0 in Stickbreaker’s fork. Now the crazy part: if I modify the 1.0.0 code to pass 0 as flags again (hum… yes, I tried that…), then everything seems to work (no more error, no more crash when setting up HW timer…).
References:
cores/esp32/esp32-hal-i2c.c
https://github.com/espressif/esp-idf/blob/master/components/esp32/include/esp_err.h
https://docs.espressif.com/projects/esp-idf/en/latest/api-reference/system/intr_alloc.html
https://github.com/espressif/esp-idf/blob/3276a13/components/esp32/include/esp_intr_alloc.h
Traces (esp32 + app):
The text was updated successfully, but these errors were encountered: