Language: EN

esp32-interrupciones-hardware

How to use interrupts on an ESP32

Hardware interrupts, or GPIO interrupts, allow the microcontroller to detect and respond to specific changes on input pins, even while the main program is running.

When an event that generates an interrupt occurs, the main program stops momentarily and the Callback function is executed. Once the Callback function is completed, the main program continues its execution.

This is especially useful in situations where we need to handle events very quickly, which we might not detect. Or, to avoid constantly checking the status of a sensor, for example.

However, we should not abuse them either. Keep in mind that during the time it is handling the interrupt, the processor is ignoring everything else. So use them wisely, and make sure the ISR is as short as possible.

Using GPIO interrupts on the ESP32

Using GPIO interrupts on the ESP32 with the Arduino IDE is very similar to using them with a “conventional” Arduino, but it has some peculiarities.

Define the callback function (ISR)

First, we define the callback function, which will be executed when the interrupt occurs on the GPIO pin. This function must have a void data type and should not take any arguments.

void IRAM_ATTR myInterruptFunction() {
  // Here you can add the code that will be executed when the interrupt occurs
}

Here comes one of the important differences, we have labeled the ISR with the IRAM_ATTR attribute. This tells the compiler to place the function code in the ESP32’s internal RAM.

Without this attribute, the function would go to the Flash, which is much slower. As we have said, we want the ISR to be as short and fast as possible. So we must add the

More information at:

Memory Types - ESP32 - — ESP-IDF Programming Guide latest documentation

3. Configure the interrupt

Once we have defined the callback function, we configure the interrupt on the desired GPIO pin using the attachInterrupt() function.

This function accepts three arguments: the GPIO pin number, the callback function, and the interrupt mode.

The interrupt mode determines when the interrupt will be activated. The possible modes are:

  • RISING: The interrupt is activated when the pin changes from low to high (rising edge).
  • FALLING: The interrupt is activated when the pin changes from high to low (falling edge).
  • CHANGE: The interrupt is activated on both rising and falling edges.

For example, to set up an interrupt on pin 12 that is activated on the rising edge:

const int interruptPin = 12; // GPIO pin to configure the interrupt

void setup() {
  pinMode(interruptPin, INPUT_PULLUP); // Configure the pin as an input with internal pull-up resistor
  attachInterrupt(digitalPinToInterrupt(interruptPin), myInterruptFunction, RISING); // Configure the interrupt
}

4. Disable the interrupt (optional)

If you ever want to disable the interrupt, you can use the detachInterrupt() function. This function takes the GPIO pin number where the interrupt was configured as an argument.

detachInterrupt(digitalPinToInterrupt(interruptPin)); // Disable the interrupt

Code Example

Next, we show you a complete example of how to use an interrupt on a button connected to pin 12 of the ESP32:

const int buttonPin = 12; // GPIO pin where the button is connected

volatile bool has_interrupted = false;
void IRAM_ATTR myInterruptFunction() {
  has_interrupted = true;
}

void setup() 
{
  Serial.begin(115200);
  pinMode(buttonPin, INPUT_PULLUP); // Configure the pin as an input with internal pull-up resistor
  attachInterrupt(digitalPinToInterrupt(buttonPin), myInterruptFunction, RISING); // Configure the interrupt
}

void loop() 
{
  if(has_interrupted)
  {
    Serial.println("Button pressed!");
    has_interrupted = false;
  }
}

In this example, when the button connected to pin 12 is pressed, the interrupt will be activated and the callback function myInterruptFunction() will be executed, which will print the message “Button pressed!” to the serial monitor.