Pin IRQ Debounce Messing with REPL
-
- Posts: 12
- Joined: Wed Mar 25, 2020 8:53 pm
Pin IRQ Debounce Messing with REPL
Hello,
I have a push button on my board and have written a debounce routine to debounce the button press. The debounce routine is working great. I have a print statement in the debounce routine to show the button debounce has happened and it is working as expected.
When I enable the interrupt and press the button, the callback function works as expected (print statement shows), however the REPL is no longer working. I will type some characters and see nothing on the terminal, then when I press the push button again, the characters I typed show up but again the REPL is not responsive. I am able to reset the board using Ctrl + D, enter and then press the push button. Hitting Ctrl + C does not bring the REPL out of this stuck state.
I have tried disabling and re-enabling the interrupts in the debounce function but the same problem exists.
Any ideas?
I have a push button on my board and have written a debounce routine to debounce the button press. The debounce routine is working great. I have a print statement in the debounce routine to show the button debounce has happened and it is working as expected.
When I enable the interrupt and press the button, the callback function works as expected (print statement shows), however the REPL is no longer working. I will type some characters and see nothing on the terminal, then when I press the push button again, the characters I typed show up but again the REPL is not responsive. I am able to reset the board using Ctrl + D, enter and then press the push button. Hitting Ctrl + C does not bring the REPL out of this stuck state.
I have tried disabling and re-enabling the interrupts in the debounce function but the same problem exists.
Any ideas?
Re: Pin IRQ Debounce Messing with REPL
Hi,
Could you please post your code (or at least a minimal example that shows what you're describing)? Otherwise we'll be just guessing.
But...my guess is that maybe you have some delays or loops in in your interrupt handler?
Could you please post your code (or at least a minimal example that shows what you're describing)? Otherwise we'll be just guessing.
But...my guess is that maybe you have some delays or loops in in your interrupt handler?
-
- Posts: 12
- Joined: Wed Mar 25, 2020 8:53 pm
Re: Pin IRQ Debounce Messing with REPL
Thanks for replying!
I do have some loops. The debounce routine appends switch.value() to a buffer until it is equal to another buffer of all 1's. Delaying 1 ms between switch.value() reads. I then do the same thing but looking for 0's to know the button has been pressed and released. I do limit the buffer size to a maximum.
I had another routine I was using but I was experiencing multiple callbacks and still lots of bounce even with long delays. This one used a simple time delay and checked to see if the button value remained the same after the delay.
I do have some loops. The debounce routine appends switch.value() to a buffer until it is equal to another buffer of all 1's. Delaying 1 ms between switch.value() reads. I then do the same thing but looking for 0's to know the button has been pressed and released. I do limit the buffer size to a maximum.
I had another routine I was using but I was experiencing multiple callbacks and still lots of bounce even with long delays. This one used a simple time delay and checked to see if the button value remained the same after the delay.
Re: Pin IRQ Debounce Messing with REPL
Unfortunately you just can't do delays or "waiting" in an interrupt handler.
Instead I would recommend making a timer that goes off every few milliseconds. Inside the timer callback, add one to a global variable if the button is down, otherwise set it to zero.
At the point it reaches some threshold (i.e. "if counter == 5:" then that's a button press.
Instead I would recommend making a timer that goes off every few milliseconds. Inside the timer callback, add one to a global variable if the button is down, otherwise set it to zero.
At the point it reaches some threshold (i.e. "if counter == 5:" then that's a button press.
-
- Posts: 12
- Joined: Wed Mar 25, 2020 8:53 pm
Re: Pin IRQ Debounce Messing with REPL
Thank you! I should be able to make that work like my debounce routine. Just need to adapt it to check for a series of 1's and then a release for a series of 0's before exiting.
Make a 1 ms timer and the callback will check the button value and add 1 to a global counter. Where do I run this timer? In the Pin interrupt routine?
I'm having a hard time figuring out the structuring to this.
Make a 1 ms timer and the callback will check the button value and add 1 to a global counter. Where do I run this timer? In the Pin interrupt routine?
I'm having a hard time figuring out the structuring to this.
Re: Pin IRQ Debounce Messing with REPL
No, in a new interrupt routine driven by a timer. On Pyboard you can use machine.Timer(-1) to easily create a "soft" timer. You don't need a pin interrupt handler.Duramaximizer wrote: ↑Thu Mar 26, 2020 1:38 pmMake a 1 ms timer and the callback will check the button value and add 1 to a global counter. Where do I run this timer? In the Pin interrupt routine?
Something like this: (untested)
Code: Select all
_DEBOUNCE_INTERVAL = const(5)
sw_counter = 0
def _debounce_timer(t):
global sw_counter
if sw.value():
if sw_counter <= _DEBOUNCE_INTERVAL:
sw_counter += 1
else:
sw_counter = 0
if sw_counter == _DEBOUNCE_INTERVAL:
button_down()
def button_down():
# your code here
t = machine.Timer(-1, mode=machine.Timer.PERIODIC, period=10, callback=_debounce_timer)
If you want to detect debounced presses and releases, then you can use two counters (one that counts "pressed" and resets when "released", and the other that counts "released" and resets when "pressed").
Edit: fixed a "dodgy typo" :p
-
- Posts: 12
- Joined: Wed Mar 25, 2020 8:53 pm
Re: Pin IRQ Debounce Messing with REPL
Interesting! This is what I've came up with using a rising edge pin.irq initialized before this which calls the debounce_handler, which in turn calls the callback function, simply machine.deepsleep().jimmo wrote: ↑Thu Mar 26, 2020 11:41 pmNo, in a new interrupt routine driven by a timer. On Pyboard you can use machine.Timer(-1) to easily create a "soft" timer. You don't need a pin interrupt handler.Duramaximizer wrote: ↑Thu Mar 26, 2020 1:38 pmMake a 1 ms timer and the callback will check the button value and add 1 to a global counter. Where do I run this timer? In the Pin interrupt routine?
Something like this: (untested)
You don't need to record the sequence, the counter idea achieves the same thing -- you're counting the number of ones (or zeros) in a row.Code: Select all
_DEBOUNCE_INTERVAL = const(5) sw_counter = 0 def _debounce_timer(t): global sw_counter if sw.value(): if sw_counter <= _DEBOUNCE_INTERVAL: sw_counter += 1 else: sw_cunter = 0 if sw_counter == _DEBOUNCE_INTERVAL: button_down() def button_down(): # your code here t = machine.Timer(-1, mode=machine.Timer.PERIODIC, period=10, callback=_debounce_timer)
If you want to detect debounced presses and releases, then you can use two counters (one that counts "pressed" and resets when "released", and the other that counts "released" and resets when "pressed").
I am still getting some weird behavior. When the board is running it does not like to go to sleep, sometimes I'll need to press the button several times even though it is being debounced.
Code: Select all
def debounce_handler(self, pin):
global count
global decount
if pin.value(): #switch needs to be high
count += 1
if count >= 5:
count = 5 # limit count to 5
if count == 5 and not pin.value(): # button has been constant for 5 calls, now needs to be low
decount = decount - 1
if count == 5 and decount == 0:
count = 0
decount = 5
self.call_callback(pin)
- pythoncoder
- Posts: 5956
- Joined: Fri Jul 18, 2014 8:01 am
- Location: UK
- Contact:
Re: Pin IRQ Debounce Messing with REPL
@jimmo Your algorithm should work (give or take a dodgy typo ) but it imposes a delay between the button being pushed and the callback occurring. This is unnecessary. You can run the callback immediately, with the timer preventing it from being called again until the bounce period has elapsed. This latency matters, for example in games.
@Duramaximizer I suggest you look at solutions based on uasyncio. Interrupts are overkill for a simple task like debouncing which doesn't need μs precision. See the Switch and Pushbutton classes here.
@Duramaximizer I suggest you look at solutions based on uasyncio. Interrupts are overkill for a simple task like debouncing which doesn't need μs precision. See the Switch and Pushbutton classes here.
Peter Hinch
Index to my micropython libraries.
Index to my micropython libraries.
Re: Pin IRQ Debounce Messing with REPL
@pythoncoder, thanks Fixed the typo! Yes you're right about the latency too. So for the OP, yes the other approach is to instead think of it as rate limiting the switch transitions... there are lots of ways to implement this (and you can adapt the above solution), depending on what sort of behavior you want.
Yes, seconded that asyncio is definitely a good idea here, and hopefully it'll flow through into making the rest of your program easier to write also!
Yes, seconded that asyncio is definitely a good idea here, and hopefully it'll flow through into making the rest of your program easier to write also!
-
- Posts: 12
- Joined: Wed Mar 25, 2020 8:53 pm
Re: Pin IRQ Debounce Messing with REPL
Thanks for the replies.
Unfortunately I don't have access to uasyncio on this board at the moment and would need my linux box to get it on.
I tried jimmo's code. The debounce works flawlessly however when I use it for my callback I'm running into issues. I'm starting to think there's a problem with putting the board to sleep.
I have the button on pin A0. This is the only way to wake up the micro in deepsleep (rising edge).
With the board running, I hit the button and the callback is simply just machine.deepsleep(). The board instantly wakes back up! I feel like I'm missing something here. I thought it was an issue with button bounce but now I'm thinking it's something else. I have a pin interrupt setup on rising edge to wake the board up out of deepsleep. This works well, maybe this wakeup interrupt is getting triggered with my go to sleep debounce button press?
Unfortunately I don't have access to uasyncio on this board at the moment and would need my linux box to get it on.
I tried jimmo's code. The debounce works flawlessly however when I use it for my callback I'm running into issues. I'm starting to think there's a problem with putting the board to sleep.
I have the button on pin A0. This is the only way to wake up the micro in deepsleep (rising edge).
With the board running, I hit the button and the callback is simply just machine.deepsleep(). The board instantly wakes back up! I feel like I'm missing something here. I thought it was an issue with button bounce but now I'm thinking it's something else. I have a pin interrupt setup on rising edge to wake the board up out of deepsleep. This works well, maybe this wakeup interrupt is getting triggered with my go to sleep debounce button press?