Hi everyone! I don’t know whether providing help to beginners is among the purposes of this forum. Sorry if this isn’t the case.
My board: ESP32-C3 mini
I asked ChatGpt to write a sketch to send a UDP multicast message whenever I press a button.
The provided code was clear and simple:
ISR on the negative edge for the button
FreeRTOS queue (size 10)
ISR routine enqueue a message to the queue
A FreeRTOS task for reading the queue
No weird stuff on the ISR… just a straight call to xQueueSendFromISR
The code for the ISR routine is:
static void gpio_task(void* arg) {
int io_num;
while (1) {
if (xQueueReceive(gpio_evt_queue, &io_num, portMAX_DELAY)) {
vTaskDelay(pdMS_TO_TICKS(50)); // Debounce delay
if (gpio_get_level(io_num) == 0) { // Button pressed
udp_send_packet();
}
}
}
}
It worked out of the box but hosts reading the UDP multicast were getting multiple messages.
The first thing I did was to increase the delay to 150 and so far it’s working (no bouncing)
But something kept bouncing (I know, bad joke) inside my head… How is that delay preventing the ISR from enqueueing multiple messages and just not just “delaying” the multiple send?
Most likely ISR enqueued multiple messages. You can confirm that by adding a log or counter in your task after xQueueReceive. If it turns out to be true, you may need to do debouncing in your ISR.
Hi RAc! Than you so much for taking the timer to read me. The queue is created with size 10. Here is the exact line:
gpio_evt_queue = xQueueCreate(10, sizeof(int));
Hi aggarg! Thank you for looking at this! Do you know why just increasing the delay could have solved my issue? As I said, “sleeping” on the task doesn’t seem like a valid solution… At least on OSs/Archs I have experience with… because it won’t prevent the ISR to enqueue multiple messages. But I don’t know esp32 nor FreeRTOS internals so here I’m asking… I don’t like to “fix” things without understanding what is happening.
One possible reason is that the check if (gpio_get_level(io_num) == 0) fails and you end up dropping the message here. It should be possible to confirm by adding a log/counter/breakpoint.
Your message made me realize I was missing the point. The delay in the task doesn’t avoid the bouncing but nullifies its effect. Forcing the task to sleep makes sure that by the time the messages from bounces are read from the queue, the GPIO state is already stabilized in 1.
One thing that we have done for cases like that is have the ISR disable itself, and then the task re-enables it after the time out. Thus really debouncing the system.