Button counter with interrupt

DEsp3286
Posts: 13
Joined: Sat Sep 29, 2018 11:30 am

Button counter with interrupt

Postby DEsp3286 » Thu Apr 02, 2020 11:53 am

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?

User avatar
martinayotte
Posts: 141
Joined: Fri Nov 13, 2015 4:27 pm

Re: Button counter with interrupt

Postby martinayotte » Fri Apr 03, 2020 2:05 pm

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) {

DEsp3286
Posts: 13
Joined: Sat Sep 29, 2018 11:30 am

Re: Button counter with interrupt

Postby DEsp3286 » Sat Apr 04, 2020 8:41 am

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

DEsp3286
Posts: 13
Joined: Sat Sep 29, 2018 11:30 am

Re: Button counter with interrupt

Postby DEsp3286 » Fri Apr 10, 2020 6:16 am

Any advice?
Thanks

ESP_Sprite
Posts: 9766
Joined: Thu Nov 26, 2015 4:08 am

Re: Button counter with interrupt

Postby ESP_Sprite » Fri Apr 10, 2020 7:29 am

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.

DEsp3286
Posts: 13
Joined: Sat Sep 29, 2018 11:30 am

Re: Button counter with interrupt

Postby DEsp3286 » Tue Apr 14, 2020 6:46 am

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

ESP_Sprite
Posts: 9766
Joined: Thu Nov 26, 2015 4:08 am

Re: Button counter with interrupt

Postby ESP_Sprite » Tue Apr 14, 2020 2:53 pm

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.

Who is online

Users browsing this forum: No registered users and 139 guests