Button clicked, NEGEDGE interrupt fired multiple times

Piscenois
Posts: 11
Joined: Wed Nov 07, 2018 8:58 pm

Button clicked, NEGEDGE interrupt fired multiple times

Postby Piscenois » Wed Oct 30, 2019 8:31 pm

Hi !

I try to detect a button click and have adapted code from gpio example :

Code: Select all

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "driver/gpio.h"

#define GPIO_BTN	GPIO_NUM_13

#define ESP_INTR_FLAG_DEFAULT 0

volatile uint32_t nbInt = 0;

static TaskHandle_t xHandlerTask = NULL;

static void IRAM_ATTR btn_isr_handler(void *arg) {
	BaseType_t xHigherPriorityTaskWoken;
	xHigherPriorityTaskWoken = pdFALSE;
	nbInt++;
	vTaskNotifyGiveFromISR(xHandlerTask, &xHigherPriorityTaskWoken);
	portYIELD_FROM_ISR();
}

static void btn_task(void *pvParameters) {
	const TickType_t xMaxExpectedBlockTime = pdMS_TO_TICKS(20);
	uint32_t ulEventsToProcess;
	for (;;) {
		ulEventsToProcess = ulTaskNotifyTake( pdTRUE, xMaxExpectedBlockTime);
		if (ulEventsToProcess != 0) {
			printf("GPIO intr, val: %d, nb notif: %d\n", gpio_get_level(GPIO_BTN), ulEventsToProcess);
		}
	}
}

void app_main() {
	gpio_config_t io_conf;
	io_conf.intr_type = GPIO_PIN_INTR_NEGEDGE;
	io_conf.pin_bit_mask = 1UL << GPIO_BTN;
	io_conf.mode = GPIO_MODE_INPUT;
	io_conf.pull_up_en = GPIO_PULLUP_ENABLE;
	io_conf.pull_down_en = GPIO_PULLDOWN_DISABLE;
	gpio_config(&io_conf);

	xTaskCreate(btn_task, "btn_task", 2048, NULL, 10, &xHandlerTask);

	gpio_install_isr_service(ESP_INTR_FLAG_DEFAULT);
	gpio_isr_handler_add(GPIO_BTN, btn_isr_handler, (void*) GPIO_BTN);

	int cnt = 0;
	for (;;) {
		printf("cnt: %d, nb int: %d\n", cnt++, nbInt);
		vTaskDelay(1000 / portTICK_RATE_MS);
	}
}
When I push the button I get this trace :

Code: Select all

cnt: 0, nb int: 0
cnt: 1, nb int: 0
cnt: 2, nb int: 0
cnt: 3, nb int: 0
GPIO intr, val: 0, nb notif: 1 <-- button pressed
GPIO intr, val: 0, nb notif: 1 <-- button released immediatly
GPIO intr, val: 1, nb notif: 9
cnt: 4, nb int: 11
cnt: 5, nb int: 11
cnt: 6, nb int: 11
cnt: 7, nb int: 11
GPIO intr, val: 0, nb notif: 1 <-- button pressed
cnt: 8, nb int: 12
cnt: 9, nb int: 12
GPIO intr, val: 0, nb notif: 1 <-- button released after few millis
GPIO intr, val: 1, nb notif: 8
cnt: 10, nb int: 21
cnt: 11, nb int: 21
The interrupt is fired when I pressed the button and when I release it and several times again.

I use an RC filter (R = 1KHz and C = 0.1uF) to debounce the signal, liake this schematic (Rp1 of 10k is replaced by pull-up of ~45k).
It gives this signal :
button.png
button.png (27.8 KiB) Viewed 11257 times
It seems very clean.
I can't find what is my mistake.
If someone can help me ... :-)

Regards

Piscenois
Posts: 11
Joined: Wed Nov 07, 2018 8:58 pm

Re: Button clicked, NEGEDGE interrupt fired multiple times

Postby Piscenois » Sat Nov 02, 2019 3:25 pm

Hi !

I have some precisions. I have logged times of each interrupt.
I press the button at 0 usec, 2 falling interrupts occurred 234031 and 234093 usec later (62 usec between the last).
Oscilloscope gives a normal shape, without any bounce.

I tried other buttons, even a rotary one. Interrupts always here !
I tried to disable internal pullup. Interrupts always here !
I tried to disable RTC GPIO. Interrupts always here !

My esp32 is a Wemos D32 Pro, it is a WROVER.

I hope someone will understand the problem. :mrgreen:

WiFive
Posts: 3529
Joined: Tue Dec 01, 2015 7:35 am

Re: Button clicked, NEGEDGE interrupt fired multiple times

Postby WiFive » Sat Nov 02, 2019 4:28 pm

Edge interrupt is very sensitive. 62usec probably means very small bounce exactly at threshold voltage. So you can decide to filter interrupts closer than 10ms or something.

Piscenois
Posts: 11
Joined: Wed Nov 07, 2018 8:58 pm

Re: Button clicked, NEGEDGE interrupt fired multiple times

Postby Piscenois » Sat Nov 02, 2019 7:38 pm

Thank you WiFive !

You must be right. But 10msec filter seems too high, the problem already exists for a 1 millisecond one. After zooming I see very very small peaks with a width about 1-10 usec. With the current filter the rising slope is probably not enough vertical. The capacitor is too high. I'll try to use a 100 ohms resistor and test different capacitors. I fixed the CPU frequency to 80MHz to decrease the sampling and the risk of parasite interrupts.
I have some work to find the good settings :D

An other solution is to increase the CPU frequency and do the sampling with a FreeRTOS task (with software timer). But I prefer to find an hardware solution.

Regards

Aussie Susan
Posts: 45
Joined: Thu Aug 22, 2019 3:48 am

Re: Button clicked, NEGEDGE interrupt fired multiple times

Postby Aussie Susan » Mon Nov 04, 2019 4:30 am

I always do the debounce in firmware. Set up a timer interrupt for (say) between 1 and 5 mSec and sample the GPIO line(s). For each line (this technique can handle any number of switch/button inputs) zero a counter each time you detect that the state has changed from the last interrupt; or increment the timer if it is the same.
When a counter reaches a suitable value (say 10 for a 1mSec interrupt) then set a flag according to the state of the line.
In the main part of the code (perhaps in a RTOS task etc) you can simply test the state of the flag whenever you want to.
The interrupts generally run outside the RTOS environments and so this is can be considered a 'hardware' solution (at least as seen by an RTOS task) if you want to.
Susan

Piscenois
Posts: 11
Joined: Wed Nov 07, 2018 8:58 pm

Re: Button clicked, NEGEDGE interrupt fired multiple times

Postby Piscenois » Mon Nov 04, 2019 5:38 pm

Thank you Susan !

I will try timer interrupt ... one more think I need to learn ;)
I tried a software timer (with FreeRTOS). With a 20ms period I don't need to debounce. The task check the GPIO level and always get an already stable value.
But ... this doesn't work with the rotary button. The 2 signals have an interval of 5ms (when rotating fast) and I need to know which is first, my check period must be inferior to 5ms. I 'm not sure it's a good idea to do it with FreeRTOS, because I would need to use à tick of 1000Hz (from menuconfig help this seems inadvisable). Your solution must be fine in this case too.

I tried a complete hardware solution with CD4093 combined with RC filter. It works but has 2 cons : need place on PCB and implies about 10ms offset (=> can't manage rotary button).

Regards
Gabe

vonnieda
Posts: 145
Joined: Tue Nov 07, 2017 3:42 pm

Re: Button clicked, NEGEDGE interrupt fired multiple times

Postby vonnieda » Mon Nov 04, 2019 6:20 pm

For a rotary encoder, I recommend using a state machine such as the one described here: http://www.buxtronix.net/2011/10/rotary ... perly.html

It removes the need for debouncing and makes it much more reliable over all.

Jason

Piscenois
Posts: 11
Joined: Wed Nov 07, 2018 8:58 pm

Re: Button clicked, NEGEDGE interrupt fired multiple times

Postby Piscenois » Tue Nov 05, 2019 8:00 pm

Wow! This solution seems extremely elegant! :o Thank you.

Aussie Susan
Posts: 45
Joined: Thu Aug 22, 2019 3:48 am

Re: Button clicked, NEGEDGE interrupt fired multiple times

Postby Aussie Susan » Wed Nov 06, 2019 1:33 am

The first post mentioned pressing and releasing a button.
Then we suddenly start talking about a rotary encoder.
No wonder the solution is different!
Susan

vonnieda
Posts: 145
Joined: Tue Nov 07, 2017 3:42 pm

Re: Button clicked, NEGEDGE interrupt fired multiple times

Postby vonnieda » Wed Nov 06, 2019 3:51 pm

Aussie Susan wrote:
Wed Nov 06, 2019 1:33 am
The first post mentioned pressing and releasing a button.
Then we suddenly start talking about a rotary encoder.
No wonder the solution is different!
Susan
But ... this doesn't work with the rotary button. The 2 signals have an interval of 5ms (when rotating fast) and I need to know which is first, my check period must be inferior to 5ms. I 'm not sure it's a good idea to do it with FreeRTOS, because I would need to use à tick of 1000Hz (from menuconfig help this seems inadvisable). Your solution must be fine in this case too.
The fifth post in the thread, from the OP, mentioned a "rotary button". I took that to mean encoder. The other replies of course apply to normal button debouncing.

Jason

Who is online

Users browsing this forum: No registered users and 104 guests