Using interrupts with a Node MCU

Hi there,

I was using a NodeMCU a little while ago, but now that I've come back to it, any time I try to set up an interrupt in the arduino IDE I get the error "ISR not in IRAM".

Could anyone point me in the right direction of how to define/setup my ISRs?

Many thanks,
Henry

Could anyone point me in the right direction of how to define/setup my ISRs?

Some way other than whatever mysterious way you are doing it now.

Read the stickies.

I experienced the same issue on previously working code after updating to version 2.5.1 of the ESP8266 library. I was able to get around it by reverting back to 2.5.0.

Don't know if it's a bug in the update, or something that shouldn't have been allowed all along. I suspect it's a bug in the update.

1 Like

MechScientist:
I experienced the same issue on previously working code after updating to version 2.5.1 of the ESP8266 library. I was able to get around it by reverting back to 2.5.0.

Don't know if it's a bug in the update, or something that shouldn't have been allowed all along. I suspect it's a bug in the update.

I experienced the same issue and resolved the same way : downgrade to v2.5.0

1 Like

MechScientist:
Don't know if it's a bug in the update, or something that shouldn't have been allowed all along.

I've ran into the same issue... and it's actually something that we shouldn't have been allowed all along. A quick explanation here.

The proper way to do an ISR for ESP8266 is by placing it in the IRAM - instead of having it execute from Flash. The second option works most of the time but is not reliable, a few years ago I found that out the hard way as I had an ISR crash now and then. Adding the ICACHE_RAM_ATTR fixed this issue: it places the ISR in IRAM, and no more random crashes.

The new 2.5.2 core just enforces this more strictly.

I was also facing the same issue. But following code example would solve your issue.

/* This code is for executing the interrupt in ESP8266.

  • The main purpose is to solve the ISR not in RAM isssue.
  • ISR Function : The interrupt pin [GPIO5 ] once changes state from HIGH to LOW
  • ISR reads the value on GPIO4 and changes the state of the BUILTIN led based on the value read
    */

const byte pin5 = 5;
const byte pin4 = 4;

void ICACHE_RAM_ATTR ISRoutine ();

void setup () {
Serial.begin(115200);
pinMode(pin5,INPUT_PULLUP);
pinMode(LED_BUILTIN,OUTPUT);
attachInterrupt(digitalPinToInterrupt(pin5),ISRoutine,FALLING);
pinMode(pin4,INPUT);
}

void loop () {

// Repeatative code here

}

void ISRoutine () {
int value;
Serial.println("I am in ISR");
value = digitalRead(pin4);
Serial.print("Value read = ");
Serial.println(value);
digitalWrite(LED_BUILTIN,!value);
}

It's VERY bad practice to print from inside an ISR.

Can someone explain how to revert back to version 2.5.0 - in baby steps because I can't seem to get it right!
Please!!

MechScientist:
I experienced the same issue on previously working code after updating to version 2.5.1 of the ESP8266 library. I was able to get around it by reverting back to 2.5.0.

Don't know if it's a bug in the update, or something that shouldn't have been allowed all along. I suspect it's a bug in the update.

You can do that easily in the boards manager. Just select the version you want to install.

Thanks. So simple!

OMG Version 2.5.0 works like magic.. thank goodness for this thread - I was about to give up!

1 Like

Reverting to 2.5.0 to fix the IRAM issue for an ISR is the wrong approach.

Fix your code! Not having your ISR in IRAM means you risk mysterious and unpredictable crashes!

wvmarle:
It's VERY bad practice to print from inside an ISR.

Noted !

Thanks for the sharing.

hitanjali:
I was also facing the same issue. But following code example would solve your issue.

/* This code is for executing the interrupt in ESP8266.

  • The main purpose is to solve the ISR not in RAM isssue.
  • ISR Function : The interrupt pin [GPIO5 ] once changes state from HIGH to LOW
  • ISR reads the value on GPIO4 and changes the state of the BUILTIN led based on the value read
    */

const byte pin5 = 5;
const byte pin4 = 4;

void ICACHE_RAM_ATTR ISRoutine ();

void setup () {
Serial.begin(115200);
pinMode(pin5,INPUT_PULLUP);
pinMode(LED_BUILTIN,OUTPUT);
attachInterrupt(digitalPinToInterrupt(pin5),ISRoutine,FALLING);
pinMode(pin4,INPUT);
}

void loop () {

// Repeatative code here

}

void ISRoutine () {
int value;
Serial.println("I am in ISR");
value = digitalRead(pin4);
Serial.print("Value read = ");
Serial.println(value);
digitalWrite(LED_BUILTIN,!value);
}

1 Like

I used this approach surgested by Hitanjali, and it made the trick for me.
I assume this is the right way to ensure ISR is placed in IRAM!?!
Comments are welcome.
Thanks

hitanjali:
I was also facing the same issue. But following code example would solve your issue.

/* This code is for executing the interrupt in ESP8266.

  • The main purpose is to solve the ISR not in RAM isssue.
  • ISR Function : The interrupt pin [GPIO5 ] once changes state from HIGH to LOW
  • ISR reads the value on GPIO4 and changes the state of the BUILTIN led based on the value read
    */

void ICACHE_RAM_ATTR ISRoutine ();

void setup () {
Serial.begin(115200);
pinMode(pin5,INPUT_PULLUP);
pinMode(LED_BUILTIN,OUTPUT);
attachInterrupt(digitalPinToInterrupt(pin5),ISRoutine,FALLING);
pinMode(pin4,INPUT);
}

void loop () {

// Repeatative code here

}

void ISRoutine () {
int value;
Serial.println("I am in ISR");
value = digitalRead(pin4);
Serial.print("Value read = ");
Serial.println(value);
digitalWrite(LED_BUILTIN,!value);
}

kcpn:
I used this approach surgested by Hitanjali, and it made the trick for me.
I assume this is the right way to ensure ISR is placed in IRAM!?!

Yes - but it's a bad idea to use Serial.print() routines inside an ISR.

To be honest I don't know how the ESP8266 deals with this internally but the idea of keeping an ISR as short and fast as possible still applies.

hitanjali:
void ICACHE_RAM_ATTR ISRoutine ();

You can ignore the rest of the code. This is the only relevant part- letting the compiler know about where to put the function.

tedder:
You can ignore the rest of the code. This is the only relevant part- letting the compiler know about where to put the function.

This was all I needed.. thanks Sir.

wvmarle:
It's VERY bad practice to print from inside an ISR.

HI. Tell me please why is a bad idea.
Thanks

rmoggia:
HI. Tell me please why is a bad idea.
Thanks

Serial uses interrupts in the background to send/receive bytes as well as internal buffers to hold said bytes. During an ISR, interrupts are off so nothing will actually be sent/received, only transferred to the internal buffer in preparation for transmission.

If that buffer is full, the print() function will wait for it to empty enough to add the new data to the buffer but since interrupts are off, the buffer will never decrease and you end up in an infinite wait loop.

That is how it is done on avr chips, not sure if all this applies to the ESP8266