How to trigger serial interrupts in ESP8266

Hi. I need to trigger an interrupt every time a new character is received in ESP8266. I need to be able to read rx buffer whenever a new character is received. I'm using HardwareSerial library.

I figured I should attach an interrupt routine to ESP8266 using attachInterrupt() function, the question is, which pin on ESP8266 should I attach interrupt to? I used "0" as the first argument but apparently it's not working.

Here's my code:

#include <HardwareSerial.h>

char input;

void handleRxInterrupt()
{
  input = Serial.read();
}

void setup()
{
  Serial.begin(115200);
  attachInterrupt(0, handleRxInterrupt, CHANGE);
}

void loop() {
}

Also, how can I access rx buffer to save the incoming data? I used Serial.read and I don't know if that's fine.

Thanks in advance

I figured I should attach an interrupt routine to ESP8266 using attachInterrupt() function

You figured wrong. There is already an interrupt handler triggered when serial data arrives. it copies the byte from the serial port and puts it in the incoming buffer if there is room.

It is almost never useful to read the character the nanosecond it arrives, in your code.

Also, how can I access rx buffer to save the incoming data?

You don't need to. The existing interrupt handler copies the data there.

I used Serial.read and I don't know if that's fine.

Serial.read() does NOT read the byte that triggered the interrupt handler. It just gets the next byte from the incoming serial data buffer.

You don't need to attach interrupts to access the serial port. Just poll the port, when you need to.
In other words, if you're expecting input on an irregular and unpredictable basis just look to see if there is anything there to process.

I'd suggest reading this post on serial input basics. While it is aimed at the arduino, the concepts (and code, bar pin assignments) are applicable to the ESP8266 as well.

Thanks, the problem is, I'm going to put other stuff in my loop(), and I don't want to do polling in order to read incoming serial data, in fact I need the data to be buffered somewhere, and I access it whenever I need to.

So is it correct that serial data is being buffered automatically and all I need to do is to call Serial.read() to get the next buffered data? (Of course if buffer does not overflow.)

I don't want to do polling in order to read incoming serial data

Get over it.

in fact I need the data to be buffered somewhere

Already handled.

and I access it whenever I need to

That you can.

While you may be doing other stuff in your loop(), try to structure it in such a way that nothing 'blocks' execution.
That means avoid using things like delay(), or anything that makes the arduino stop while it waits for something else to happen.
That way you can easily check to see if there is something in the serial buffer and move the data somewhere until you require it and/or enough data has arrived for you to be able to do something with it.

If you work all the way through that post I pointed you to, you'll see that you can be doing a lot of other stuff while waiting for serial data to arrive (if you structure your code properly).

@OP

1. The pictorial view of a typical (NodeMCU 1.0(ESP-12E Module)


Figure-1: Pictorial view of NodeMCU Board

2. The UART Port (RX, TX) is connected with Serial Monitor/Arduino IDE via an on-board UART/USB converter chip (CP2102).

3. I am not sure if there is any other hardware UART Port in the NodeMCU. Therefore, let us create a Software UART Port (SUART) for serial data communication. You can create a SURT Port by including the following codes in your sketch. All commands/methods of UART Port are equally applicable for SUART Port except that the void serialEvent() procedure is reserved for hardware UART Port.

#include<SoftwareSerial.h>
SoftwareSerial mySUART(4, 5); //(SRX, STX) = (GPIO4, GPIO5) = (D2, D1)
mySUART.begin(115200);

4. If you are using Arduino IDE Environment for the NodeMCU, then you can enjoy all the resources provided by the SoftwareSerial.h Library of the Arduino IDE for exchanging serial data (from 1-character to 64-character in one .print() command).

5. This is how the SUART Port/Interface works under the supervision of SoftwareSerial.h Library.
(1) In serial communication, data exchange takes place one character at a time in ASCII frame. An ASCII frame is composed of 1-START Bit, 8-bit ASCII Code for the character, 1-parity Bit (optional), and 1-STOP Bit.

(2) When a character arrives at the Receiver Section of the NodeMCU, the MCU is immediately interrupted; the MCU goes to the ISR (Interrupt Service Routine), reads the data byte from the receiver and saves into an unseen 64-byte wide FIFO buffer. This process happens in the background.

(3) The number of characters currently present in the FIFO buffer can be known by executing this instruction: byte x = Serial.available();.

(4) The character that has entered first in the buffer can be read using this instruction: byte x = Serial.read();,

(5) Data transmission also happens on interrupt basis one character at a time. The user program puts the character(s) into the transmit buffer from which the character enters into transmitter through interrupt process.

6. An Example
uartNode.png
Figure-2: SUART connection between NodeMCU and UNO

Sender Codes (tested)

#include<SoftwareSerial.h>
SoftwareSerial mySUART(4, 5);  //D2, D1

void setup()
{
  Serial.begin(115200);
  mySUART.begin(115200);
}

void loop()
{
  if(Serial.available()>0)
  {
    byte x = Serial.read();
    mySUART.write(x);
  }
  if(mySUART.available()>0)
  {
    Serial.write((char)mySUART.read());
  }
}

Receiver Codes (tested)

#include<SoftwareSerial.h>
SoftwareSerial mySUART(4, 5);  //D2, D1

void setup()
{
  Serial.begin(115200);
  mySUART.begin(115200);
}

void loop()
{
  if(Serial.available()>0)
  {
    byte x = Serial.read();
    mySUART.write(x);
  }
  if(mySUART.available()>0)
  {
    Serial.write((char)mySUART.read());
  }
}

uartNode.png

One simple trick:
Connect RX-Pin with another Input-Pin.
For that Pin you get an attached interrupt with the start of a new incomming data byte.
Do not forget to disable that interrupt until the character has received completly.
The interupt comes with the first edge of the incomming character!
You will be able to test with Serial.available in that very short time.
Or you may delay - dependent on baudrate - for some microseconds.
Save the character and reenable Interrupts.

With all other methods you have to poll Serial.available all the time.