Many years ago while I was learning to program an Intel 8085 in assembly code, One day, I finally learned how to create an Interrupt with a timer. It was an Erika moment. It seemed so many jobs back then needed precise timing. and I was having no fun creating timing loops. Once I could create a 10 mSec timer interrupt, I could time anything very nicely. That day, I told myself that I could now control anything. And, it turned out true. Learn these timer, interrupt operations and you will put these pico controllers into a whole new world of control. Thanks Chris for sharing!
Good morning neildodson915, Thanks for sharing your experiences, it certainly helps others understand the importance of all functions of a microcontroller and how we can control things. Cheers! Chris
Hi Chris - often folks complain about LED projects as they are so basic. However, once you get the concept that signals are just merely being passed and the same philosophy can be applied. Understanding the concept instead of this being an isolated solution you can really make some progress in your own code. After watching your video I rewrote my code for my wheel encoders and set both IRQ and Timers to make a more efficient and elegant solution. Many thanks!!
Hi @Steven-jf4cs, Awesome! I am glad to hear you worked up a more elegant and efficient solution. That is always a rewarding experience in programming. Cheers! Chris
I've watched a couple of your videos now and they are excellent. So many RPi Pico/MicroPython videos are so introductory they never cover poweful features like IQR or component issues like switch bounce.
Hello Chris I have been playing with interrupt driven encoders using interrupt and you have some “features “ in your code. When you initialise the ISR you set up Rising or Falling edges. Note if you don’t specify rising and falling in your code it defaults to this without setting it explicitly. Secondly you probably don’t need to stop the interrupt in the handler given that interrupt in micropython based on a scheduler and are not a true interrupt. I haven’t tested this but I doubt you can enter it multiple times. Finally when you re-initialise the interrupt at the end of the handler you have forgotten to explicitly set if you want rising or falling. In your case you got lucky as not explicitly setting it gave you the functionality required. Note I found all this out trying to detect a rising edge. It worked first time but then defaulted to interrupt on the rising and falling edges. Hopefully this makes sense and comments made in good faith to aid our learning. Best regards Chris
@@MakingStuffwithChrisDeHutQuestion. I believe the MP interrupts are hardware based not software based. So there isn't any software scheduler involved. Also, I think some of MPs interrupt handling g has been updated since you last updated this. Any chance you will get making an update in the near future? Would be good to get the info on MPs current interrupt handling functionality. Thanks.
@@christopherlyons7613 I recall looking into that a few months back and the interrupts were still software based. However, I can't tell you what I had for lunch yesterday so I will look into it again when I have a bit of time. Cheers! Chris
This is perfect and shows how to elegantly solve common problems with interupts. The program runs right away without any changes on my Pico with exactly the same behaviour as presented in the video. Great learnings in less than 30 minutes. 😀
Excellent tutorial. IRQs are something of an enigma to most developers outside of embedded systems development and your tutorial explains and demonstrates the subject elegantly. Thank you for taking the time to create such a great resource. More please!
Hello Mark, Thanks you very much for the kind words!!!!! Currently there are about 100 videos on the Raspberry Pi Pico on my channel and I am adding 1 a week. Even with a very low view count, it is still a lot of fun sharing and the viewers have been super grateful. Cheers! Chris
In your example you have a 'while True' loop that only has a very short delay of .0001 seconds. This delay is very important due to the way that interrupts work in MicroPython. Under the hood there is a two stage process: when a pin change is detected an internal interrupt handler sets a flag. A scheduler will see this flag and call the users interrupt handler. Without the short delay in the 'while True' loop, a 'busy loop' is created that never gives the scheduler a chance to run and the users handler will not be called. To let the scheduler run, loops should have a call to utime.sleep() or machine.idle(). I discovered this the hard way!
You are correct, it is always a good idea to have some sort of delay in a loop. It appears to be more of a problem in Python that in any other language I have programmed in. Thanks for sharing your experience. Cheers! Chris
in the micropython irq handler you can do :: state = machine.disable_irq() global x,y,z ... other code ... at the end do :: machine.enable_irq(state) to stop any interrupt interfering also in the handler you can find out which situation called the handler, when using IRQ_RISING|IRQ_FALLING combo print( pin.irq().flags() ) will show if it was Rising or Falling if you need your code to act differently on each ... flag returns a number (4/8/12), test it out ( might need to do short press and long press testing )
Thank you, very clear to understand. I am still wondering weather it would be "faster" to avoid as much tests as possible, maybe by defining two specific handlers, one for the OFF transistion, the other for the ON ? I made a few tests, nothing obvious.
Hello @tjeanneret, I don't know if there is any advantages one way or the other either. Recently I have been discovering little odds and ends in MicroPython that are related to program performance. Can't make sense of what I have been discovering either. Cheers! Chris
Hello and welcome! If you would have asked be that question a few weeks ago I would have incorrectly given you an answer. However, I was running into a speed issue recently on the Zoomtown project and found that execution time is not exact in MicroPython. This is certainly an idea for a story to be told though and I will put it on the "to-do" list. Thanks for asking! Chris
Thonny (python) is interpreted and runs slow so you are just letting the execution of the code be your debounce timer. Run it in C and you are likely to see[on off on] from the key bounce. Also there is no difference in triggering on 2 statements to transition high, transition low, vs the statement where you check the or condition. An interrupt will never be simultaneously transition high and transition low at the same exact same time..
Hello Chris! This video is awesome as we said in the 1980 in high school! The example is to keep light on while pushing button. If I wanted to hold light state on by pushing button ounce and not have to keep holding to keep light on. Light would stay on until push button was pushed again to turn light off. How would I have to change code. Thank you so much for your time and great videos.
Hi Joe, Thank you very much for the kind words!!!! I would suggest you see the video on Momentary Switches - I believe I explain how to do that in that video. Cheers! Chris
@@MakingStuffwithChrisDeHut Thank you so much I most sertanly will just got through watching your video on Add a Realtime Clock to your PICO for Enhanced Capability at www.youtube.com/@MakingStuffwithChrisDeHut I know you have that information but maybe someone might not. Cheers and God Bless
First great set of videos Question - Could instead of using the Global Pb_Switch_State why not use the Warning_LED.Value() so the if and elif lines in the code would be : if (Pb_Switch.value() == 1) and (Warning_LED.value() == 0): elif (Pb_Switch.value() == 0) and (Warning_LED.value() == 1): What are your thoughts?
Is it possible for an interrupt function to affect the main loop? I tried using an interrupt to change a variable that was used in the main loop, but unfortunatly the loop would resume in the state that it was before the interrupt was triggered. Is there a work around that?
It sounds like you defined the variable in the "main" are of the program but didn't declare it as public within the interrupt handler. Check for that as it is the only thing I am comming up with. Chris
When you simply turn off the interrupt while executing you may end up with the actual pin state being the opposite before you're done processing the code if the code isn't fast enough. In theory. With C I've usually turned the interrupt off, done the processing and check the actual pin state right before executing the result of the processing... Practically, since a button is a human interface, starting a timer to wait until a 100th of a second before double checking will not be noticeable to the human brain. But it'll eliminate the jitter that a button may perform as well as any static electric discharge triggering the interrupt, putting your statemachine into an inverted state. Edit: you do teach some important lessons about the principles about how to handle interrupts, i just feel that you haven't tried fringe hardware with a lousy bounce going on. It's a common trait amongst theoretical programmers to trust the hardware and environment too much.
Imagine giving a student the task to write an essay about the state of a pin as soon as the state changes. The student detects the change, does research on the current pin state before it starts writing, while ignoring further changes until that task has been finished. The student finishes the work, but in the meantime the state has changed again. Then the next essay is also gonna be about the state rising, but in the meantime everyone reading the essay would have been told that the state is already in a raised state, and believing so, because a CPU is not a democracy. Edit: basically don't trust the very first trigger either, but do wake up on it.
Hi Benjamin, Thanks for posting an add on. Unfortunately to cover every possible scenario with every topic would make the videos extremely long. The average watch duration of a video is 6 minutes and most of my videos are about 3 times that length already. It is a tough balance between providing enough information to give someone a rough idea of what to do and giving them all the information they could possibly need. Cheers! Chris
@@MakingStuffwithChrisDeHut very good point, but I mean, if you anyway do an effort to handle bounce/jitter in a more sophisticated manner than simply using a timer, you may as well make it as reliable as the timer solution 😄 but I know it can also become a rabbit hole to think of all possible scenarios. Your solution isn't a bad one for people to start out with, and you do go to explain why you turn off the interrupt while your handler/callback is at work. Of course, when it's just about flipping a pin when you hit the button it'll almost always work. Imagine if you were performing something slower, like translating the button press to HID over USB or BT, a button that is not in peak condition could indeed bring that statemachine out of sync. But you're right as for a quick-start intro you cover the topic better than those that would simply rely on a timer.
Most likely to simulate other actions that would normally be running in the main loop of a program. This has the effect of slowing down the program as if it were doing other work.
As CPU clock speed increases, debouncing gets harder. Imagine an infinitely fast clock, and this method breaks down. The only way to guarentee the position of a switch is to wait for it to settle down (10 milliseconds or so) or to sample its state multiple times (counting those samples) until you are statistically satisfied.
Good morning davidgari3240, Thanks for sharing that great information! Everyone will do battle with switch bounce and every bit of information helps. Cheers! Chris
Hello henkoegema6390, Thank you for the kind words! Looking at your icon image, I am going to assume that is not you in the photo - very adorable baby though! Cheers! Chris
Many years ago while I was learning to program an Intel 8085 in assembly code, One day, I finally learned how to
create an Interrupt with a timer. It was an Erika moment. It seemed so many jobs back then needed precise timing.
and I was having no fun creating timing loops. Once I could create a 10 mSec timer interrupt, I could time anything
very nicely. That day, I told myself that I could now control anything. And, it turned out true. Learn these timer, interrupt
operations and you will put these pico controllers into a whole new world of control. Thanks Chris for sharing!
Good morning neildodson915,
Thanks for sharing your experiences, it certainly helps others understand the importance of all functions of a microcontroller and how we can control things.
Cheers!
Chris
Hi Chris - often folks complain about LED projects as they are so basic. However, once you get the concept that signals are just merely being passed and the same philosophy can be applied. Understanding the concept instead of this being an isolated solution you can really make some progress in your own code. After watching your video I rewrote my code for my wheel encoders and set both IRQ and Timers to make a more efficient and elegant solution. Many thanks!!
Hi @Steven-jf4cs,
Awesome! I am glad to hear you worked up a more elegant and efficient solution. That is always a rewarding experience in programming.
Cheers!
Chris
I've watched a couple of your videos now and they are excellent.
So many RPi Pico/MicroPython videos are so introductory they never cover poweful features like IQR or component issues like switch bounce.
Thank you very much for the kind words! I try to dig deep whenever I can.
Cheers!
Chris
Hello Chris I have been playing with interrupt driven encoders using interrupt and you have some “features “ in your code. When you initialise the ISR you set up Rising or Falling edges. Note if you don’t specify rising and falling in your code it defaults to this without setting it explicitly. Secondly you probably don’t need to stop the interrupt in the handler given that interrupt in micropython based on a scheduler and are not a true interrupt. I haven’t tested this but I doubt you can enter it multiple times. Finally when you re-initialise the interrupt at the end of the handler you have forgotten to explicitly set if you want rising or falling. In your case you got lucky as not explicitly setting it gave you the functionality required. Note I found all this out trying to detect a rising edge. It worked first time but then defaulted to interrupt on the rising and falling edges. Hopefully this makes sense and comments made in good faith to aid our learning. Best regards Chris
Awesome feedback and thanks for sharing this! Looks like I may have to schedule in a revisit on this when I get some time. Cheers! Chris
@@MakingStuffwithChrisDeHutQuestion. I believe the MP interrupts are hardware based not software based. So there isn't any software scheduler involved. Also, I think some of MPs interrupt handling g has been updated since you last updated this. Any chance you will get making an update in the near future? Would be good to get the info on MPs current interrupt handling functionality. Thanks.
@@christopherlyons7613 I recall looking into that a few months back and the interrupts were still software based. However, I can't tell you what I had for lunch yesterday so I will look into it again when I have a bit of time.
Cheers!
Chris
This is perfect and shows how to elegantly solve common problems with interupts. The program runs right away without any changes on my Pico with exactly the same behaviour as presented in the video. Great learnings in less than 30 minutes. 😀
Thank you very much for the kind words!!!
Cheers!
Chris
Really clear, careful explanation with all the details. Many thanks!
My pleasure Laurence, Thanks for watching!
Cheers!
Chris
Excellent tutorial. IRQs are something of an enigma to most developers outside of embedded systems development and your tutorial explains and demonstrates the subject elegantly. Thank you for taking the time to create such a great resource. More please!
Hello Mark,
Thanks you very much for the kind words!!!!! Currently there are about 100 videos on the Raspberry Pi Pico on my channel and I am adding 1 a week. Even with a very low view count, it is still a lot of fun sharing and the viewers have been super grateful.
Cheers!
Chris
I would be one of those developers lol
I'm just now finding out about interrupts precisely because of the switch bounce and loop polling problems.
In your example you have a 'while True' loop that only has a very short delay of .0001 seconds. This delay is very important due to the way that interrupts work in MicroPython. Under the hood there is a two stage process: when a pin change is detected an internal interrupt handler sets a flag. A scheduler will see this flag and call the users interrupt handler. Without the short delay in the 'while True' loop, a 'busy loop' is created that never gives the scheduler a chance to run and the users handler will not be called. To let the scheduler run, loops should have a call to utime.sleep() or machine.idle(). I discovered this the hard way!
You are correct, it is always a good idea to have some sort of delay in a loop. It appears to be more of a problem in Python that in any other language I have programmed in.
Thanks for sharing your experience.
Cheers!
Chris
Thanks for awesome explanation on dealing with interrupts and key-bounces!
You are welcome!
Cheers!
Chris
in the micropython irq handler you can do ::
state = machine.disable_irq()
global x,y,z ...
other code ... at the end do ::
machine.enable_irq(state)
to stop any interrupt interfering
also in the handler you can find out which situation called the handler, when using IRQ_RISING|IRQ_FALLING combo
print( pin.irq().flags() ) will show if it was Rising or Falling
if you need your code to act differently on each ...
flag returns a number (4/8/12), test it out ( might need to do short press and long press testing )
Thanks for the input Ben! I will look into this later this year when production starts up again.
Thank you, very clear to understand. I am still wondering weather it would be "faster" to avoid as much tests as possible, maybe by defining two specific handlers, one for the OFF transistion, the other for the ON ? I made a few tests, nothing obvious.
Hello @tjeanneret,
I don't know if there is any advantages one way or the other either. Recently I have been discovering little odds and ends in MicroPython that are related to program performance. Can't make sense of what I have been discovering either.
Cheers!
Chris
Great explanation - thanks!
Hello albrody8861,
Happy to hear you found it helpful!
Cheers!
Chris
Thanks Chris! really helpful.
Awesome! Glad you enjoyed the video, thanks for watching!
What would be your thoughts regarding speed on using an object to store the state rather than a global declaration?
Hello and welcome!
If you would have asked be that question a few weeks ago I would have incorrectly given you an answer. However, I was running into a speed issue recently on the Zoomtown project and found that execution time is not exact in MicroPython.
This is certainly an idea for a story to be told though and I will put it on the "to-do" list.
Thanks for asking!
Chris
Thonny (python) is interpreted and runs slow so you are just letting the execution of the code be your debounce timer. Run it in C and you are likely to see[on off on] from the key bounce. Also there is no difference in triggering on 2 statements to transition high, transition low, vs the statement where you check the or condition. An interrupt will never be simultaneously transition high and transition low at the same exact same time..
Thanks for the feedback and sharing your knowledge!
I came here to say the same thing. This absolutely isn't the right way to debounce.
Hello Chris! This video is awesome as we said in the 1980 in high school! The example is to keep light on while pushing button. If I wanted to hold light state on by pushing button ounce and not have to keep holding to keep light on. Light would stay on until push button was pushed again to turn light off. How would I have to change code. Thank you so much for your time and great videos.
Hi Joe,
Thank you very much for the kind words!!!! I would suggest you see the video on Momentary Switches - I believe I explain how to do that in that video.
Cheers!
Chris
@@MakingStuffwithChrisDeHut Thank you so much I most sertanly will just got through watching your video on Add a Realtime Clock to your PICO for Enhanced Capability at www.youtube.com/@MakingStuffwithChrisDeHut
I know you have that information but maybe someone might not. Cheers and God Bless
First great set of videos
Question - Could instead of using the Global Pb_Switch_State why not use the Warning_LED.Value()
so the if and elif lines in the code would be :
if (Pb_Switch.value() == 1) and (Warning_LED.value() == 0):
elif (Pb_Switch.value() == 0) and (Warning_LED.value() == 1):
What are your thoughts?
That is the joy of programming :-) For any single problem there are countless way to solve it.
Cheers!
Chris
very good tutorial, thank you
HI drgeppo, Thank you for taking the time to watch and share, much appreciated.
Cheers!
Chris
thanks a lot, very good tutorial
You are welcome.
Cheers!
Chris
great stuff thanks Chris 👍
Glad you liked it!
Cheers!
Chris
Chris - Any updates using Pico interrupts with the Arduino IDE 2.2.1?
Hi user-zr4hx3el6p ,
Unfortunately no. I just have not had the time or desire to get back into the Arduino environment.
Sorry,
Chris
Is it possible for an interrupt function to affect the main loop? I tried using an interrupt to change a variable that was used in the main loop, but unfortunatly the loop would resume in the state that it was before the interrupt was triggered. Is there a work around that?
It sounds like you defined the variable in the "main" are of the program but didn't declare it as public within the interrupt handler. Check for that as it is the only thing I am comming up with.
Chris
When you simply turn off the interrupt while executing you may end up with the actual pin state being the opposite before you're done processing the code if the code isn't fast enough. In theory.
With C I've usually turned the interrupt off, done the processing and check the actual pin state right before executing the result of the processing...
Practically, since a button is a human interface, starting a timer to wait until a 100th of a second before double checking will not be noticeable to the human brain. But it'll eliminate the jitter that a button may perform as well as any static electric discharge triggering the interrupt, putting your statemachine into an inverted state.
Edit: you do teach some important lessons about the principles about how to handle interrupts, i just feel that you haven't tried fringe hardware with a lousy bounce going on.
It's a common trait amongst theoretical programmers to trust the hardware and environment too much.
Imagine giving a student the task to write an essay about the state of a pin as soon as the state changes.
The student detects the change, does research on the current pin state before it starts writing, while ignoring further changes until that task has been finished.
The student finishes the work, but in the meantime the state has changed again.
Then the next essay is also gonna be about the state rising, but in the meantime everyone reading the essay would have been told that the state is already in a raised state, and believing so, because a CPU is not a democracy.
Edit: basically don't trust the very first trigger either, but do wake up on it.
Hi Benjamin,
Thanks for posting an add on.
Unfortunately to cover every possible scenario with every topic would make the videos extremely long. The average watch duration of a video is 6 minutes and most of my videos are about 3 times that length already. It is a tough balance between providing enough information to give someone a rough idea of what to do and giving them all the information they could possibly need.
Cheers!
Chris
@@MakingStuffwithChrisDeHut very good point, but I mean, if you anyway do an effort to handle bounce/jitter in a more sophisticated manner than simply using a timer, you may as well make it as reliable as the timer solution 😄 but I know it can also become a rabbit hole to think of all possible scenarios.
Your solution isn't a bad one for people to start out with, and you do go to explain why you turn off the interrupt while your handler/callback is at work.
Of course, when it's just about flipping a pin when you hit the button it'll almost always work.
Imagine if you were performing something slower, like translating the button press to HID over USB or BT, a button that is not in peak condition could indeed bring that statemachine out of sync.
But you're right as for a quick-start intro you cover the topic better than those that would simply rely on a timer.
hello! how are you ? ... why do you put that delay in your while loop?
Most likely to simulate other actions that would normally be running in the main loop of a program. This has the effect of slowing down the program as if it were doing other work.
Would you know how to use interrupts in the Arduino IDE, though, rather than using micropython or circuitpython?
Sorry, no. I have not used the arduino IDE/C language with the PICO yet.
As CPU clock speed increases, debouncing gets harder. Imagine an infinitely fast clock, and this method breaks down.
The only way to guarentee the position of a switch is to wait for it to settle down (10 milliseconds or so) or to sample its state multiple times (counting those samples) until you are statistically satisfied.
Good morning davidgari3240,
Thanks for sharing that great information! Everyone will do battle with switch bounce and every bit of information helps.
Cheers!
Chris
Well done. 😀
Hello henkoegema6390,
Thank you for the kind words! Looking at your icon image, I am going to assume that is not you in the photo - very adorable baby though!
Cheers!
Chris
Awesome
Thanks
Hi Shera,
Glad you liked the video!
Cheers
Chris