When I've developed for the ESP32, I've always included the linker attribute IRAM_ATTR when I've declared functions called from interrupts. This is based on https://docs.espressif.com/projects/esp-idf/en/v4.2/esp32s2/api-guides/general-notes.html :
Interrupt handlers must be placed into IRAM if ESP_INTR_FLAG_IRAM is used when registering the interrupt handler. In this case, ISR may only call functions placed into IRAM or functions present in ROM
To better understand how attachInterrupt intRoutine callback is used.This std::function is called from an internal function:
static void ARDUINO_ISR_ATTR __onPinInterrupt(void * arg) {
 InterruptHandle_t * isr = (InterruptHandle_t*)arg;
 if(isr->fn) {
 if(isr->arg){
 ((voidFuncPtrArg)isr->fn)(isr->arg);
 } else {
 isr->fn();
 }
 }
}
Where ARDUINO_ISR_ATTR is defined as:
#if CONFIG_ARDUINO_ISR_IRAM
#define ARDUINO_ISR_ATTR IRAM_ATTR
#define ARDUINO_ISR_FLAG ESP_INTR_FLAG_IRAM
#else
#define ARDUINO_ISR_ATTR
#define ARDUINO_ISR_FLAG (0)
#endif
I'm not sure where CONFIG_ARDUINO_ISR_IRAM is set for the Arduino tool chain, but looking at the PlatformIO framework-arduinoespressif32/tools/sdk/esp32*/sdkconfig files, it does not appear to be set for any of them.
Does this mean that generally the Arduino interrupts aren't being loaded into the IRAM for ESP32 targets?
1 Answer 1
It appears that the Arduino library does not place its external interrupt handler in IRAM.
So I checked with both the Arduino IDE (esp32 board version 3.3.0) and PlatformIO (framework-arduinoespressif32 @ 3.20017.241212) that the __onPinInterrupt function is not placed into IRAM. I did this by generating a map file (adding -Wl,-Map,output.map to the build arguments) and looking where the functions were being placed.
My callback with IRAM_ATTR looks like:
 .iram1.0 0x400811bc 0x1f C:\Users\feros\AppData\Local\arduino\sketches2189円D6248A4BEC430F3ABA605F7D1065\sketch\encoder_test.ino.cpp.o
 0x400811bc handleEncoderInterrupt()
while __onPinInterrupt looks like:
 .text.__onPinInterrupt
 0x400f21e0 0x17 C:\Users\feros\AppData\Local\arduino\cores\eaa94e01c7ef80d31535561863eab262\core.a(esp32-hal-gpio.c.o)
Where the .text memory region is normal flash. Also as mentioned in the previous documentation snippet, IRAM is 0x40080000 to 0x400A0000.
I can modify the build flags with -DCONFIG_ARDUINO_ISR_IRAM=1 which does change this, but I guess now I'm a little confused why the Arduino library doesn't do this by default since this seems like it might impact interrupt latency.
Comments
Explore related questions
See similar questions with these tags.
CONFIG_ARDUINO_ISR_IRAMin a sketch? For example, you could useSerial.println(CONFIG_ARDUINO_ISR_IRAM);