Skip to content

uPesy only delivers currently in France.

Contents Menu Expand Light mode Dark mode Auto light/dark mode

Create ESP32 GPIO Interrupts to reduce CPU usage

An interrupt is a process triggered asynchronously by an external event, which instantly interrupts the execution of the current code to execute more critical code.

What’s the point?

Imagine you wanted to light up a LED when you press a button connected to a GPIO pin of the ESP32. The easiest is to constantly look in the loop() function if you have pressed the button:

const int buttonPin = 33;
const int ledPin =  2;

// Etat du bouton poussoir
int buttonState = 0;

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

    //Configuration du pin en entrée pullup
    pinMode(buttonPin, INPUT_PULLUP);
    pinMode(ledPin, OUTPUT);
}

void loop() {
    buttonState = digitalRead(buttonPin);

    if (buttonState == LOW) {
        digitalWrite(ledPin, HIGH);
    } else if(buttonState == HIGH){
        digitalWrite(ledPin, LOW);
    }
}

The problem is that the microcontroller’s processor is totally occupied with this task. So we can tell the microcontroller to do other tasks in the loop() , but in this case, the microcontroller will only look at the state of the button once at each iteration of the``loop()`` function. We may miss an event. We cannot process in real-time external events.Interrupts are used to detect an event in real-time while leaving the microcontroller’s processor to do other tasks. Thus the operation of an interrupt is as follows:Detection of an event -> Interruption of the main program -> Execution of the interrupt code -> The processor resumes where it left off.

Note

With interrupts, there is no longer any need to constantly look at the value of a pin. When a change is detected, a function is executed.

Detection modes

The detection of an event is based on the shape of the signal arriving at the pin.

My beautiful legend0

Different detection modes

You can choose the interrupt detection mode:
  • LOW : Triggers the interrupt as soon as the signal is at 0V

  • HIGH : Triggers the interrupt as soon as the signal is at 3.3V

  • RISING : Triggers the interrupt as soon as the signal goes from LOW to HIGH (0 to 3.3V)

  • FALLING : Triggers the interrupt as soon as the signal goes from HIGH to LOW (3.3V to 0)

  • CHANGE : Triggers the interrupt as soon as the signal changes from LOW to HIGH or from HIGH to LOW .

Note

The RISING and FALLING modes are the most used. Note that if you use the LOW and HIGH modes, the interrupt will loop as long as the signal does not change state.

Use on ESP32

Using interrupts on the ESP32 is similar to using the Arduino with the attachInterrupt() function. Any GPIO pin can be used for interrupts.

So to create an interrupt on a pin, you have to:
  • Assign a pin to detect the interrupt attachInterrupt()

    attachInterrupt(GPIOPin, fonction_ISR, Mode);
    

    With Mode , the detection mode which can be LOW , HIGH , RISING , FALLING or CHANGE

  • Create the function that will be executed when the interrupt is triggered:

    void IRAM_ATTR function_ISR () {
        // Content of the function
    }
    

    Note

    It is recommended to add the IRAM_ATTR flag to store the function code in RAM (and not in Flash) to run faster.

    The entire code will look like this:

    void IRAM_ATTR fonction_ISR() {
         // Code de la fonction
     }
    
    void setup() {
         Serial.begin(115200);
         pinMode(23, INPUT_PULLUP);
         attachInterrupt(23, fonction_ISR, FALLING);
     }
    
    void loop() {
     }
    

    As soon as the voltage drops from 3.3V to 0V, the function_ISR() function will be executed. We can then do other tasks in the loop() function.

It must be kept in mind that the function of an interrupt must be executed as quickly as possible so as not to disturb the main program. The code must be as concise as possible. It is not recommended to dialogue via SPI, I2C, UART from an interrupt.

Warning

You cannot use the delay() or Serial.println() function with an interrupt. You can nevertheless display messages in the serial monitor by replacing Serial.println() by ets_printf() which is compatible with interrupts.

The code below displays “Button pressed” when pressing a button connected to pin 33.

void IRAM_ATTR fonction_ISR() {
    ets_printf("Boutton pressé\n");
    // Code de la fonction
}

void setup() {
    Serial.begin(115200);
    pinMode(33, INPUT_PULLUP);
    attachInterrupt(33, fonction_ISR, FALLING);
}

void loop() {
}

Project

We will redo the first mini-project, which consists of making a LED blink when you press a button. We will use the interrupts to handle the event and free the processor to do other tasks.

Schematic

seo

Schematic

Try to write the program by yourself!

Solution

const int buttonPin = 32;
const int ledPin =  23;
int buttonState = 0;
int lastMillis = 0;

void IRAM_ATTR fonction_ISR() {
    if(millis() - lastMillis > 10){ // Software debouncing buton
        ets_printf("ISR triggered\n");
        buttonState = !buttonState;
        digitalWrite(ledPin,buttonState);
    }
    lastMillis = millis();
}

void setup() {
    Serial.begin(115200);
    pinMode(buttonPin, INPUT_PULLUP);
    pinMode(ledPin,OUTPUT);
    attachInterrupt(buttonPin, fonction_ISR, CHANGE);
    digitalWrite(ledPin, buttonState);
}

void loop() {
    // Code ...
}

We use cookies to make your visit to the site as pleasant as possible. Privacy Policy