I just wanted to quickly add a button with some timed debounce logic to my project when I came across a kind of unusal behavior.
To debounce my button I wanted an input pin to trigger at every edge and then read the logic level.
If the level is HIGH then it must be a LOW-HIGH edge and when the level is LOW it must be a HIGH-LOW edge as far as my simple logic goes.
Therefore when I simply print out the pin level at the time an interrupt has been invoked it should be something like 101010101010101 because auf the button bounce.
Unfortunately it looks more like 101000101111011001011100. This is kind of unexpected since I am triggering on the edges so there must be a change in logic levels. My guess would be that the signal ist too fast and changes between the interrupt invokation and the read out of the digital pin.
But is there a workaround for that? Maybe a way to freeze the input registers for the time of the interrupt?
Here is some code to reproduce the problem:
[EDIT]: The code below provides a rudimentary digital output with 0.5 HZ. If the output pin is connected to the button input pin the signal looks like the expected 101010... But if the actual button is used instead of the digital signal the problem occurs due to the fast bounces.
- #include <string.h>
- #include "time.h"
- #include "freertos/FreeRTOS.h"
- #include "freertos/task.h"
- #include "freertos/queue.h"
- #include "esp_err.h"
- #include "esp_log.h"
- #include "driver/gpio.h"
- static const int btn_number = 32;
- static const int sig_number = 33;
- QueueHandle_t test_queue_handle = NULL;
- int btn_lvl;
- static const char *TAG = "button";
- static bool ready = false;
- static bool output = false;
- static void IRAM_ATTR gpio_isr_handler(void* arg)
- {
- int btn = *(int*) arg;
- int current_level = gpio_get_level(btn);
- BaseType_t ContextSwitchRequest = pdFALSE;
- xQueueSendToBackFromISR(test_queue_handle,(void*)¤t_level,&ContextSwitchRequest);
- if(ContextSwitchRequest){
- taskYIELD();
- }
- }
- static void main_task(void *arg){
- gpio_install_isr_service(0);
- test_queue_handle = xQueueCreate(10,sizeof(btn_lvl));
- gpio_config_t io_conf;
- io_conf.intr_type = GPIO_PIN_INTR_ANYEDGE;
- io_conf.mode = GPIO_MODE_INPUT;
- io_conf.pull_down_en = false;
- io_conf.pull_up_en = false;
- io_conf.pin_bit_mask = (1ULL<<btn_number);
- gpio_config(&io_conf);
- io_conf.intr_type = GPIO_PIN_INTR_DISABLE;
- io_conf.mode = GPIO_MODE_OUTPUT;
- io_conf.pull_down_en = false;
- io_conf.pull_up_en = false;
- io_conf.pin_bit_mask = (1ULL<<sig_number);
- gpio_config(&io_conf);
- //attach isr handler
- gpio_isr_handler_add(btn_number, gpio_isr_handler, (void*) &btn_number);
- ready = true;
- vTaskDelete(NULL);
- }
- void app_main(void)
- {
- xTaskCreate(main_task, "Main Task", 1024 * 2, (void *)0, 10, NULL);
- while(1){
- if(ready && uxQueueMessagesWaiting(test_queue_handle)){
- printf("=======================================================\n");
- while(uxQueueMessagesWaiting(test_queue_handle)){
- int lvl;
- xQueueReceive(test_queue_handle,(void*)&lvl,10);
- ESP_LOGI(TAG,"state: %d",lvl);
- }
- }
- gpio_set_level(sig_number, output);
- output = !output;
- vTaskDelay(pdMS_TO_TICKS(1000));
- }
- }