Button Debounce routine

JL1946
Posts: 11
Joined: Mon Feb 25, 2019 3:46 pm

Button Debounce routine

Postby JL1946 » Tue Mar 02, 2021 6:19 pm

I implemented a debounce algorithm in my ESP32 code and would like to have some comments/ideas on the implementation. I am using 2 ESP32s (1 handles wifi while the other handles bluetooth classic). the wifi device has 3 inputs that change state with buttons and control 4 outputs which are interrupts to the bluetooth device. The interrupt routines for all inputs are simple and send a Freertos semaphore to a Freertos task which is designed to decide between a low-going glitch and an actual low button press. The Freertos tick frequency is set at 1000 Hz.

Important Note: For an ESP32, GPIO Inputs that are added to the underlying interrupt service driver become “shared interrupts” and will cause an interrupt to be generated for both a Negative Edge AND a Positive Edge (ANY EDGE). So, the code sees 2 interrupts for every button press/release regardless of the config setup. That’s just the way it is!!!!

wifi device code:
ISR:
  1. IRAM_ATTR static void ISR_Door_Sensor_Interrupt(void* arg)
  2. {
  3.        /* disable the interrupt to try to eliminate the reciprocal edge interrupt */
  4.        gpio_intr_disable(door_sensor);
  5.        xSemaphoreGiveFromISR(gpio_door_sensor_semaphore, NULL);
  6. }
TASK:
  1. static void TASK_Handle_GPIO_Door_Sensor_Interrupt(void* arg)
  2. {
  3.  
  4.     uint16_t door_history = 0b1111111111111111;
  5.     int check_count = 0;
  6.         int LOW = 0;
  7.         int HIGH = 1;
  8.  
  9.     for(;;)
  10.     {
  11.         if(xSemaphoreTake(gpio_door_sensor_semaphore, portMAX_DELAY) == pdTRUE)
  12.         {
  13.             check_count = 0;
  14.             door_history = 0b1111111111111111;
  15.  
  16.             while(check_count < 16)
  17.             {
  18.                 door_history = door_history << 1;
  19.                 door_history |= gpio_get_level(door_bell);
  20.  
  21.                 check_count += 1;
  22.                 vTaskDelay(5 / portTICK_PERIOD_MS);      
  23.                 /* total debounce time 80 mSec + instruction processing time */
  24.             }
  25.         }
  26.         /* only looking at the last four reads */
  27.         if((door_history & 0b0000000000001111) == 0b0000000000000000).  
  28.         {
  29.             TASK_Door_Handler(LOW);
  30.         }
  31.         else if((door_history & 0b0000000000001111) == 0b0000000000001111)
  32.         {
  33.             TASK_Door_Handler(HIGH);
  34.         }
  35.         /* Delay 1/2 second to eliminate the reciprocal interrupt (high-->low or low-->high)
  36.         vTaskDelay(500 / portTICK_PERIOD_MS);    
  37.         gpio_intr_enable(door_sensor);
  38.     }
  39. }
all of the interrupts generated by buttons follow the above logic. I am not sure if this will catch a single glitch caused by EMI or other perturbation. Please comment. Thanks…

Victoria Nope
Posts: 75
Joined: Fri Dec 04, 2020 9:56 pm

Re: Button Debounce routine

Postby Victoria Nope » Wed Mar 03, 2021 3:49 am

Do not disable the interrupt, as when you're having e.g. the button pressed and you release it right at the time before your TASK_Handle_GPIO_Door_Sensor_Interrupt finishes, you will loose this state switch.

JL1946
Posts: 11
Joined: Mon Feb 25, 2019 3:46 pm

Re: Button Debounce routine

Postby JL1946 » Wed Mar 03, 2021 7:41 pm

Each button press pulls the input low. I cannot eliminate the interrupt disable because if you look at an oscilloscope picture of a typical button press (See the attachment), you see that there are multiple transitions from high->low->high BEFORE a solid LOW, and since the time between the transitions is ~400 uSec, I would wind up getting multiple interrupts for each button press. I also wait a 1/2 second before enabling the interrupt to avoid the interrupt when the button is released. Thanks for your comment...
Attachments
button bounce.jpg
button bounce.jpg (184.52 KiB) Viewed 12087 times

Victoria Nope
Posts: 75
Joined: Fri Dec 04, 2020 9:56 pm

Re: Button Debounce routine

Postby Victoria Nope » Thu Mar 04, 2021 4:42 am

I see the bouncing effect and have noticed that delay.

Just if the button gets released and stays in a stable RELEASE logic level before you enable the interrupt (which may happen just during that delay), you will loose PRESS to RELEASE logic level state transition.

Or for example in pseudo-timeline (HW state, SW action):

Unstable PRESS -> Disable interrupt -> Stable RELEASE -> Delay -> Enable interrupt

JL1946
Posts: 11
Joined: Mon Feb 25, 2019 3:46 pm

Re: Button Debounce routine

Postby JL1946 » Fri Mar 05, 2021 10:30 pm

Good idea... I will incorporate the change... Thanks

Victoria Nope
Posts: 75
Joined: Fri Dec 04, 2020 9:56 pm

Re: Button Debounce routine

Postby Victoria Nope » Sat Mar 06, 2021 7:58 am

But of course you can disable the interrupt. Just right after you enable the interrupt back, read the current state (which might have been lost) and if it changed, process this event (store the current state and fire the state change routine).

Important is to make this after enabling the interrupt (because you may loose yet another state switch during that lost state change event routine execution) and modify the status in an interlocked way (otherwise the interrupt may execute the same handler routine in another thread).

Who is online

Users browsing this forum: jsmith56x, sterisa and 268 guests