I need to debounce a switch on a GPIO port. I tried using waiting on a semaphore, having a task post (release) the semaphore after the debounce time but that doesn't seem to work in an ISR. Which I guess is reasonable because it seems that the task scheduler interacts with the semaphore calls and the ISR is not a task... or is this an error on my side.
I considered lwevents but I think they are plagued by the same problem. Is there 'best practice' someone could recommend for syncing the ISR to the debounced IRQ?
in the GPIO ISR
Interrupt
process
wait on semaphore or event
...
resume
clear interrupt flag
return
Debounce Task
delay
post semaphore or event to ISR
time wait (ticks)
Or should I just
ISR
diasable the interrupts
wait for the debounce task to run,
delay,
re-enable interrupts to ISR
I can probably get the last method to work but it is not very elegant.
Thanks
Robert
Solved! Go to Solution.
You can't be waiting inside an ISR.
If you are going to have the pin trigger an interrupt then typical practice would be for the ISR to post an event to let the task know that the pin state has changed. In the task, block waiting for the event. When you get it, maybe wait for a short time then read the pin state. If it is still asserted, post an event to whatever other tasks need it.
If you have more than one input to scan (e.g. a keypad) then a more typical approach might be to just have the task scan all the keys say every 10ms. For each input have it maintain a record of the current physical state, the current logical state, and some counters. One of the counters would be the debounce counter; the logical state can change after the physical state has been constant for a short time. Other counters would handle short and long presses, auto-repeat, etc. The task can scan the inputs, post whatever events it has determined have happened, then sleep until the next scan.
You can't be waiting inside an ISR.
If you are going to have the pin trigger an interrupt then typical practice would be for the ISR to post an event to let the task know that the pin state has changed. In the task, block waiting for the event. When you get it, maybe wait for a short time then read the pin state. If it is still asserted, post an event to whatever other tasks need it.
If you have more than one input to scan (e.g. a keypad) then a more typical approach might be to just have the task scan all the keys say every 10ms. For each input have it maintain a record of the current physical state, the current logical state, and some counters. One of the counters would be the debounce counter; the logical state can change after the physical state has been constant for a short time. Other counters would handle short and long presses, auto-repeat, etc. The task can scan the inputs, post whatever events it has determined have happened, then sleep until the next scan.
I could not get event flags or semaphores to work correctly from the ISR. What I was wondering was whether the reason they would work was there is nothing to pause in an ISR?? The debounce task could be paused but there was no event/semaphore mechanism to syc the isr and cause it to suspend until the debounce task was resumed. I agree any wait in an ISR could be a fatal mistake.
I got this to work by creating a debounce task. In the ISR disable interrupts, then enable the selection of the specific switch in the debounce task via a flag I set in the ISR. Then re-enable the IRQ's in the debounce task, and once the debounce was complete.
Thanks for the reply and advice
Regards
Robert