ESP32. How to use external interrupts with Arduino code

Learn to use the external interrupts of theESP32with Arduino code. Compatible GPIO pins, move function to RAM with IRAM
Table of Contents

The ESP32 has 26 digital pins which can be used to trigger the execution of a function using an external interrupt. An interrupt is a process that is triggered asynchronously by an external event. Interrupts make it possible to detect an event in real time while leaving the microcontroller’s processor to do other tasks.


The use of external interrupts simplifies the programming of events.

The ESP32 also has 4 Timers which allow you to program the triggering of alarms. Everything is explained in detail in this tutorial

Install the ESP-IDF SDK for ESP32 on IDE Arduino and PlatformIO

If you are new to ESP32 development boards you must first install the ESP-IDF development kit. Here are two tutorials to get started depending on your code editor

Follow the instructions in this tutorial for the Arduino IDE

Read Also
ESP32. Getting started with ESP32-Arduino on IDE Arduino, macOS, Windows, Linux

And this one for PlatformIO (ideally with VSCode)

Read Also
Getting started with PlatformIO IDE on VSCode (Windows, macOS, Raspbian, Linux)

Introduction to interrupts (external)

The classic way to program when you want to trigger an event using a digital input is to test its value regularly in the loop (). Depending on its value, we execute the code corresponding to the state

void loop() { 
  // Read the value of the switch 
  button_state = digitalRead(PIN_BUTTON); 
  // if the button is pressed, changes the state of the output to HIGH, otherwise LOW 
  if (button_state == HIGH) { 
    // Switch on the LED 
    digitalWrite(PIN_LED, HIGH); 
  } else { 
    // Switch off the LED 
    digitalWrite(PIN_LED, LOW); 

This way of programming is suitable most of the time but poses problems in the following cases:

  • We want to slow down the loop loop with a delay()
  • Sleep and wake it up when an external event occurs. For example, motion detection, pressing a button or a touch key …

This is where interrupts are useful.

As the interrupt is triggered from an event external to the processors, it is an external interrupt.

ESP32 GPIO pins compatible with interrupts

Interrupts only work with digital inputs. The digital inputs that can trigger an interrupt are circled in the diagram below.

esp32 Digital inputs compatible Interrupts

Be careful, however, because some pins go high (HIGH) or emit PWM signals at start-up or during reset. Other pins are used by the system to access flash memory or upload the program.

Do not use pins colored orange or red. Your program might behave unexpectedly while using these.

GPIO pin Digital input Note
0 PULL UP Sends a PWM signal at startup.
1 TX Debug output at startup
2 Connected to the on-board LED
3 Takes the HIGH state at startup
5 Sends a PWM signal at startup
6 Used for SPI flash memory
7 Used for SPI flash memory
8 Used for SPI flash memory
9 Used for SPI flash memory
10 Used for SPI flash memory
11 Used for SPI flash memory
12 Fail to start if in PULLUP mode
14 Sends a PWM signal at startup
15 Sends a PWM signal at startup

Data collected from official documentation.

Configure the digital input of the ESP32

To be able to read on a digital input of the GPIO, you must first configure the pin as an input using the pinMode() function like this

pinMode(pin, mode);

The pinMode method has two arguments

  • The pin number
  • The mode

3 modes are available to configure the spindle as a digital input

  • INPUT Depending on the input device used, the circuit must be adapted. For example, when a Momentary Switch type push button is used, a pull-up or pull-down  resistor must be integrated into the circuit. Without a pull-up or pull-down resistor, the ESP32 input is floating. The logic level is undefined which can lead to erratic operation of the program. For example not detecting the pressure on a button or on the contrary detecting that it is pressed when it is not.
  • INPUT_PULLUP We use the pulling resistance (PULL UP) of the ESP32
  • INPUT_PULLDOWN  We use the pull-down resistor (PULL DOWN) of the ESP32

To read a digital input – like a button – we use the digitalRead() function, which takes the GPIO pin number as argument.


Use the previous diagram and table to choose the GPIO pins for your project.

Each pull-up or pull-down resistor has a value of 45 kΩ according to the DC Characteristics table (3.3V, 25°C) of technical documentation.

How to add an external interrupt to an ESP32 project?

Then we assign a function that will be executed as soon as an event is detected on the spindle using the attachInterrupt (GPIO, FUNCTION, MODE) method. The method requires 3 arguments

  • GPIO The pin that triggers the event. This is the pin that we configured previously
  • FUNCTION the function to execute when an event occurs
  • MODE trigger mode

5 trigger modes are possible

  • LOW to trigger the interrupt whenever the spindle is low (LOW)
  • HIGH to trigger the interrupt whenever the pin is high (HIGH)
  • CHANGE  to trigger the interrupt whenever the pin changes state. For example when it goes from HIGH to LOW or LOW to HIGH
  • FALLING for when the spindle goes from HIGH to LOW. This is the detection of the rising edge.
  • RISING to trigger when the spindle goes from LOW to HIGH. This is the detection of the falling edge.

Note, it is no longer necessary to declare the pin using the digitalPinToInterrupt method

Declare the function to be executed in the IRAM (IRAM_ATTR)

The execution of a function called by an interrupt is blocking, ie it is necessary to wait for the end of its execution so that the rest of the code can continue.

Usually the code is executed directly on the flash memory of the development board. It is possible to move the function to the internal RAM of the ESP32 which is much faster.

To do this, simply place the IRAM_ATTR attribute just before the name of the function like this

void IRAM_ATTR myfastfunction(){

This is not mandatory and you can also test it yourself with the code offered at the end of the tutorial. However, it is strongly recommended to place in the RAM of the ESP32 all the functions called by the interrupts for a real project.

Example for triggering an interrupt using a switch

Now let’s move on to a concrete example. The number of times the user presses a push button (momentary switch) is counted using an interrupt. As soon as the counter reaches 5 clicks, an LED is lit for 5 seconds using a Timer then the interruption is released.

There are many solutions to trigger an external event:

Whatever equipment is used, we will always receive a LOW / HIGH type signal. So whatever your project, the code will remain perfectly the same

Here we will be using a push button. It is equipped with a return spring which returns the button to the LOW state as soon as it is released.


The push button is connected to digital input 4. The LED is connected to output 32.

You can test the operation of the program in the absence of a pull resistor (PULL_UP). You can test using the ESP32’s internal pull-up resistor (PULL_UP) or add a resistor to the circuit (10kΩ for example).

esp32 gpio io input output digital led button

The LED must be protected by a resistor, the value of which depends on the output voltage and current of the pin (3.3V – 40mA) and the maximum supply voltage of the LED.

You can use this calculator to determine the required resistance value for your circuit.

Series resistance calculator for one or more LEDs
Supply Voltage in Volt
Forward Tension in Volt
Current in mA
Resistor calculated in Ω
Estimated Power in W

This calculator is used to determine the resistance required to drive one or more LEDs connected in series from a voltage source at a specified current level.

Note. It is preferable to supply the circuit with a nominal power between 2 and 10 times the calculated value in order to avoid overheating.
calculateur resistance serie led resistor calculator
Color Wavelength (nm) Voltage (V) for ⌀3mm LED Volatge (V) for ⌀5mm LED
Red 625-630  1,9-2,1 2,1-2,2
Blue 460-470 3,0-3,2 3,2-3,4
Green 520-525 2,0-2,2 2,0-2,2
Yellow 585-595 2,0-2,2 3,0-3,2
White 460-470 3,0-3,2 1,9-2,1

And buy a resistor assortment

See other assortments

Upload the Arduino code of the project

Create a new sketch on the Arduino IDE or a new PlatformIO project.

On the Arduino IDE you can remove the first line #include <Arduino.h> .

#include <Arduino.h>

// Filtre anti-rebond (debouncer)
#define DEBOUNCE_TIME 250
volatile uint32_t DebounceTimer = 0;

// Pin to which the button, PIR motion detector or radar is connected
#define PIN_BUTTON 4
uint32_t button_count = 0;

// LED to indicate the end of the program
#define PIN_LED 32
#define DELAY_LED 2000

// Uncomment to not put the function in the RAM of the ESP32
//void buttonpressed() {
// The function is placed in the RAM of the ESP32. 
void IRAM_ATTR buttonpressed() {
  if ( millis() - DEBOUNCE_TIME  >= DebounceTimer ) {
    DebounceTimer = millis();
    button_count += 1;
    Serial.printf("Button has been pressed %u times\n", button_count);

void setup() {
  attachInterrupt(PIN_BUTTON, buttonpressed, RISING);

  // Configure LED output
  pinMode(PIN_LED, OUTPUT);

void loop() {
  //Detach interruption after 5 clicks 
  if ( button_count >= 5) {
    Serial.println("Interrupt Detached!");
    // reset click counter to avoid re-enter here
    button_count = 0;
    // Lights up the LED to indicate that the interrupt is detached
    digitalWrite(PIN_LED, HIGH);
    digitalWrite(PIN_LED, LOW);

After uploading the program, open the serial monitor and do a RESET of the board to follow the progress

Button has been pressed 1 times
Button has been pressed 2 times
Button has been pressed 3 times
Button has been pressed 4 times
Button has been pressed 5 times
Interrupt Detached!

PlatformIO configuration for a LoLin D32

Here is an example platformio.ini configuration file for a LoLin D32 Pro development board

platform = espressif32
board = lolin_d32_pro
framework = arduino
monitor_speed = 115200

Explanation of the code

On initialization (setup function ), we declare that the input is a digital input. The internal pull-down resistor of the ESP32 is used which saves a resistance in the circuit. We attach the button to an interrupt. We execute the buttonpressed function as soon as we press the button by detecting the rising edge (RISING).

attachInterrupt(PIN_BUTTON, buttonpressed, RISING);

If we execute the function as is as soon as we press the button, we will have multiple executions which can cause slowdown problems or unnecessary requests on a remote server.

To do this, it suffices to wait a certain time before executing the function, this operation is called Debounce.

There are complex libraries to do this, but here it is unnecessary. All you have to do is initialize a DEBOUNCE_TIME variable which contains the timestamp of the last execution. The time elapsed since the last pass in the buttonpressed function must be at least equal to the bounce time. Here it is set at 250ms at the start of the program. You can adjust the value according to your electronics.

To be sure that the function will be executed in priority and quickly, it is placed in the RAM of the ESP32 using the argument IRAM_ATTR.

The function is rudimentary and just increments a counter.

void IRAM_ATTR buttonpressed() {
  if ( millis() - DEBOUNCE_TIME  >= DebounceTimer ) {
    DebounceTimer = millis();
    button_count += 1;

The interruption is detached after 10 clicks on the button.

if ( button_count >= 10) { 
  // reset click counter to avoid re-enter here 
  button_count = 0; 


5/10/2020 Publication of the article

Click to rate this post!
[Total: 2 Average: 5]

Thanks for your reading

Did you like this project ? Don't miss any more projects by subscribing to our weekly newsletter!

Are you having a problem with this topic?

Maybe someone has already found the solution, visit the forum before asking your question
We will be happy to hear your thoughts

Leave a Reply

Read more
DIY Projects
DIY Projects