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
  1. #include <stdio.h>
  2. #include "driver/gpio.h"
  3. #include "freertos/FreeRTOS.h"
  4. #include "freertos/task.h"
  5. #include "freertos/semphr.h"
  6.  
  7. #define ESP_INTR_FLAG_DEFAULT 0
  8.  
  9. #define BLINK_LED 13
  10. #define GPIO_INPUT_IO_0 33
  11. int buttonCount = 0;
  12. int i = 0;
  13.  
  14. SemaphoreHandle_t xSemaphore = NULL;
  15.  
  16. TaskHandle_t printVariableTask = NULL;
  17.  
  18. void printVariable(void *pvParameter) {
  19.  
  20.     int a = (int) pvParameter;
  21.     while (1) {
  22.  
  23.         printf("A is a: %d \n", a++);
  24.         vTaskDelay(1000 / portTICK_RATE_MS);
  25.     }
  26. }
  27. // interrupt service routine, called when the button is pressed
  28. void IRAM_ATTR button_isr_handler(void* arg) {
  29.  
  30.     // notify the button task
  31.     xSemaphoreGiveFromISR(xSemaphore, NULL);
  32.  
  33. }
  34. // task that will react to button clicks
  35. void button_task(void* arg) {
  36.  
  37.     // infinite loop
  38.     for(;;) {
  39.  
  40.         // wait for the notification from the ISR
  41.         if(xSemaphoreTake(xSemaphore,portMAX_DELAY) == pdTRUE) {
  42.             int buttonState = gpio_get_level(GPIO_INPUT_IO_0);
  43.  
  44.             while(buttonState == 1){ //code stucks here!!!!
  45.                 buttonCount++;
  46.                 printf("GPIO_INPUT_IO_0 %d\n", buttonState);
  47.                 printf("Button pressed! %d \n", i++);
  48.                 gpio_set_level(BLINK_LED, buttonState);
  49.                 vTaskDelay(1000 / portTICK_RATE_MS);
  50.                 }
  51.         }
  52.     }
  53. }
  54.  
  55. void app_main()
  56. {
  57.     // create the binary semaphore
  58.     xSemaphore = xSemaphoreCreateBinary();
  59.  
  60.     // configure button and led pins as GPIO pins
  61.     gpio_pad_select_gpio(GPIO_INPUT_IO_0);
  62.     gpio_pad_select_gpio(BLINK_LED);
  63.  
  64.     // set the correct direction
  65.     gpio_set_direction(GPIO_INPUT_IO_0, GPIO_MODE_INPUT);
  66.     gpio_set_direction(BLINK_LED, GPIO_MODE_OUTPUT);
  67.  
  68.     // enable interrupt on falling (1->0) edge for button pin
  69.     gpio_set_intr_type(GPIO_INPUT_IO_0, GPIO_INTR_POSEDGE);
  70.  
  71.     // start the task that will handle the button
  72.     xTaskCreate(button_task, "button_task", 2048, NULL, 10, NULL);
  73.  
  74.     // install ISR service with default configuration
  75.     gpio_install_isr_service(ESP_INTR_FLAG_DEFAULT);
  76.  
  77.     // attach the interrupt service routine
  78.     gpio_isr_handler_add(GPIO_INPUT_IO_0, button_isr_handler, NULL);
  79.  
  80.     int pass = 25;
  81.     xTaskCreate(&printVariable, "printVariable", 2048, (void*) pass, 5, &printVariableTask);
  82.  
  83. }
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 ESP_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 ESP_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.