Page 1 of 1

Button counter with interrupt

Posted: Thu Apr 02, 2020 11:53 am
by DEsp3286
I want to increment a variable every second when an interrupt is triggered. Code on esp32, esp-idf. I have connected a button, when the button is pressed I want to count the number of seconds.

I did this using polling function, but I want to learn how to do it with interrupt, so counting and polling only when the button is pressed and not checking every second for a button pushed

Code: Untitled.c Select all

#include <stdio.h>
#include "driver/gpio.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/semphr.h"

#define ESP_INTR_FLAG_DEFAULT 0

#define BLINK_LED 13
#define GPIO_INPUT_IO_0 33
int buttonCount = 0;
int i = 0;

SemaphoreHandle_t xSemaphore = NULL;

TaskHandle_t printVariableTask = NULL;

void printVariable(void *pvParameter) {

int a = (int) pvParameter;
while (1) {

printf("A is a: %d \n", a++);
vTaskDelay(1000 / portTICK_RATE_MS);
}
}
// interrupt service routine, called when the button is pressed
void IRAM_ATTR button_isr_handler(void* arg) {

// notify the button task
xSemaphoreGiveFromISR(xSemaphore, NULL);

}
// task that will react to button clicks
void button_task(void* arg) {

// infinite loop
for(;;) {

// wait for the notification from the ISR
if(xSemaphoreTake(xSemaphore,portMAX_DELAY) == pdTRUE) {
int buttonState = gpio_get_level(GPIO_INPUT_IO_0);

while(buttonState == 1){ //code stucks here!!!!
buttonCount++;
printf("GPIO_INPUT_IO_0 %d\n", buttonState);
printf("Button pressed! %d \n", i++);
gpio_set_level(BLINK_LED, buttonState);
vTaskDelay(1000 / portTICK_RATE_MS);
}
}
}
}

void app_main()
{
// create the binary semaphore
xSemaphore = xSemaphoreCreateBinary();

// configure button and led pins as GPIO pins
gpio_pad_select_gpio(GPIO_INPUT_IO_0);
gpio_pad_select_gpio(BLINK_LED);

// set the correct direction
gpio_set_direction(GPIO_INPUT_IO_0, GPIO_MODE_INPUT);
gpio_set_direction(BLINK_LED, GPIO_MODE_OUTPUT);

// enable interrupt on falling (1->0) edge for button pin
gpio_set_intr_type(GPIO_INPUT_IO_0, GPIO_INTR_POSEDGE);

// start the task that will handle the button
xTaskCreate(button_task, "button_task", 2048, NULL, 10, NULL);

// install ISR service with default configuration
gpio_install_isr_service(ESP_INTR_FLAG_DEFAULT);

// attach the interrupt service routine
gpio_isr_handler_add(GPIO_INPUT_IO_0, button_isr_handler, NULL);

int pass = 25;
xTaskCreate(&printVariable, "printVariable", 2048, (void*) pass, 5, &printVariableTask);

}
It works, but when the code enter in the while(buttonState == 1) the loop never ends.

What am I doing wrong?

Re: Button counter with interrupt

Posted: Fri Apr 03, 2020 2:05 pm
by martinayotte
Your while loop doesn't check buttonState anymore after entering the loop ...
You should do that instead :

Code: Select all

            while(gpio_get_level(GPIO_INPUT_IO_0) == 1) {

Re: Button counter with interrupt

Posted: Sat Apr 04, 2020 8:41 am
by DEsp3286
OMG! what a stupid error!

Of course now it works correctly, thank you.
I would like to check the state of the button only when the interrupt is fired.

Is this a correct method to handle interrupt on a GPIO or in general call a function only when an interrupt is fired/triggered?

Thanks

Re: Button counter with interrupt

Posted: Fri Apr 10, 2020 6:16 am
by DEsp3286
Any advice?
Thanks

Re: Button counter with interrupt

Posted: Fri Apr 10, 2020 7:29 am
by Sprite
Your question doesn't quite make sense; I'm having a hard time figuring out what you want to know. Is it communication between an interrupt and a task? If so, you could take a look at semaphores, for instance.

Re: Button counter with interrupt

Posted: Tue Apr 14, 2020 6:46 am
by DEsp3286
Sorry for that.

I was wondering if this approach is correct.
I want to know when a button is pressed ( i.e. for 3 seconds and when it's pressed for more than 10 ).

I could poll every second and check for the status of the GPIO, or I could use interrupt.
My question is:

when the interrupt is triggered/fired ( void IRAM_ATTR button_isr_handler(void* arg) ), is it ok to call a function (void button_task(void* arg) ) and add a while conditions inside this function where i.e. I could increment a variable

Code: Select all

printf("Button pressed! %d \n", i++);
 gpio_set_level(BLINK_LED, buttonState);
 vTaskDelay(1000 / portTICK_RATE_MS
);

I mean, is it ok how the function are called in my code?

Hope is clear enough

thanks

Re: Button counter with interrupt

Posted: Tue Apr 14, 2020 2:53 pm
by Sprite
The biggest issue with that code is that you can't call blocking functions anywhere in an interrupt. vTaskDelay is blocking. Printf is also blocking. Suggest you solve this problem by spinning up a task that blocks on a semaphore, then give the semaphore from the interrupt. In a task, you *can* use vTaskDelay and printf without issues.

Re: Button counter with interrupt

Posted: Thu Dec 12, 2024 5:00 pm
by espmich
Too bad that ESP-IDF/examples/peripherals/gpio/generic_gpio/ doesn't use a semaphore, which would be perfect to solve the problem you are experiencing.