multiple interrupt question

The official pyboard running MicroPython.
This is the reference design and main target board for MicroPython.
You can buy one at the store.
Target audience: Users with a pyboard.
JimTal001
Posts: 176
Joined: Thu Jul 30, 2015 4:59 pm

multiple interrupt question

Post by JimTal001 » Wed Sep 02, 2015 9:53 pm

My data logger uses RTC wakeup intervals to collect data (currently this is all it does). I need to add a few buttons (external to pyboard) which will each be tied to button press interrupts. Additionally I would like to use the accelerometer as an interrupt (if possible) to watch for sensor disturbance (like someone kicks it :( ).

These button interrupts do things like:
1. Start data collection
2. Stop data collection
3. Prepare for data transmit (when I later add bluetooth or wifi)
4. etc...

Are there any pyboard code examples available which demonstrate the handling of multiple interrupts or something similar to my described goal? Also strategy suggestions are greatly appreciated.

BTW: For a button press event, will I need a pullup resistor with the pyboard GPIO? With the raspberry pi I only needed GND and one GPIO pin to monitor for a button press event.

User avatar
dhylands
Posts: 3821
Joined: Mon Jan 06, 2014 6:08 pm
Location: Peachland, BC, Canada
Contact:

Re: multiple interrupt question

Post by dhylands » Thu Sep 03, 2015 1:19 am

With a pushbutton, you always need a pullup/pulldown.

Now the internal pullup/pulldown is often adequate for the task at hand. You also need to be aware that all mechanical switches have bounce, and by this I mean that you may very well get multiple edges per press of the button.

Here's a really good article about switch bounce: http://www.ganssle.com/debouncing.htm

When I use interrupts, then I normally use the following debouncing algorithim:

1 - Setup a falling edge interrupt (assume closing the switch grounds the input)
2 - When the edge occurs, disable the interrupt and start a timer for 20 milliseconds.
3 - When the timer interrupt occurs, check the level of the GPIO line and use that level as the switch value.

You can also do this in a polling fashion and not bother with interrupts at all. This works really well when you have a regular main loop (I often use a main loop which runs on some regular period like 10 msecs. This article describes some background:
http://members.shaw.ca/climber/avrbuttons.html

I created the following C code that I've used before in my robots:
https://github.com/dhylands/projects/bl ... n/Switch.h
https://github.com/dhylands/projects/bl ... n/Switch.c

It works really well when you need to keep track of a bunch of buttons (it's really easy to support up to 32 for example).

Due to the fact that you can't allocate memory from an interrupt, I'd be inclined to just have the interrupt set a flag indicating that the button was pressed. Then your main loop can just do something simple like:

Code: Select all

if start_pressed:
    start_pressed = False
    pyb.delay(20)
    re-enable the ExtInt interrupt
    if start.pin.value():
        # do your start collection process
and have the exti interrupt set start_pressed to True, and disable itself

Another way would be to have an event queue, and have the button presses add an event to the queue and have the main loop dequeue and process events from the event queue.

I'd be happy to code up a more complete example if the above is still too abstract.

JimTal001
Posts: 176
Joined: Thu Jul 30, 2015 4:59 pm

Re: multiple interrupt question

Post by JimTal001 » Thu Sep 03, 2015 1:39 am

Thanks for the input Dave,

But polling would take me out of sleep, correct? I need to maximize sleep as I am on solar power.

User avatar
dhylands
Posts: 3821
Joined: Mon Jan 06, 2014 6:08 pm
Location: Peachland, BC, Canada
Contact:

Re: multiple interrupt question

Post by dhylands » Thu Sep 03, 2015 2:40 am

Well the pyb.sleep() calls will be in sleep, but yes, you're right - polling will consume more power.

Although you're going to be in standby mode most of the time right? So you're really only using the ExtInt as a wakeup.

The main loop could just poll the buttons and the RTC to see what it is it needs to do and then go back into standby mode until the next wakeup.

User avatar
pythoncoder
Posts: 5956
Joined: Fri Jul 18, 2014 8:01 am
Location: UK
Contact:

Re: multiple interrupt question

Post by pythoncoder » Thu Sep 03, 2015 6:25 am

The Pyboard takes over 100mS to come out of standby (http://forum.micropython.org/viewtopic.php?f=6&t=607). By the time it wakes any bounce will be over. Possible options: poll the buttons at the start to determine which caused the wakeup or use callbacks to record the source then check the state of that button. There is a possible issue with callbacks in that their execution will presumably also be delayed while the board comes out of standby: can one be sure they will be executed before the start of the main code?
Peter Hinch
Index to my micropython libraries.

User avatar
dhylands
Posts: 3821
Joined: Mon Jan 06, 2014 6:08 pm
Location: Peachland, BC, Canada
Contact:

Re: multiple interrupt question

Post by dhylands » Thu Sep 03, 2015 4:04 pm

That's a very interesting question and will probably require some experimentation.

What I would expect to happen is that the interrupt will be latched, and when interrupts are enabled, then the interrupt will fire.

My understanding is that standby is kind of like power off, and the pyboard reinitializes everything when that happens? If that's the case then it may very well clear the latched interrupt (and any record of the python callback to be called when the interrupt occurs).

If you use stop mode, then everything should behave as per normal (except for the fact that you may not need to do any debouncing due to the startup delay). I'd still probably poll the GPIO line to verify that it was a real button press rather than noise. If a human is pressing the button, 100msec is still an extremely short amount of time.

JimTal001
Posts: 176
Joined: Thu Jul 30, 2015 4:59 pm

Re: multiple interrupt question

Post by JimTal001 » Thu Sep 03, 2015 4:28 pm

It looks like I need an simple test program which uses the RTC to set the wakeup period and a couple of buttons tied to interrupts with callbacks just to understand the complexity. I would like to stay with python code if possible. Any example like this exist?

Question: In my main loop how can I determine if the wakeup from sleep is due to the RTC?

Code: Select all


rtc = pyb.RTC()
rtc.wakeup(60000) # every 60 sec
...
def mainloop():	
	while True:
		# Is my wakeup from the RTC or an interupt from a button
		readTemp()
		toggleLED()
		pyb.stop() # go to sleep until next wakeup

User avatar
dhylands
Posts: 3821
Joined: Mon Jan 06, 2014 6:08 pm
Location: Peachland, BC, Canada
Contact:

Re: multiple interrupt question

Post by dhylands » Thu Sep 03, 2015 4:57 pm

Here's a simple ExtInt example:

Code: Select all

import pyb

import micropython
micropython.alloc_emergency_exception_buf(100)

led1 = pyb.LED(4) # 4 = Blue
led2 = pyb.LED(3) # 3 = Yellow

pin = pyb.Pin('SW', pyb.Pin.IN, pull=pyb.Pin.PULL_UP)

def callback(line):
    led1.toggle()
    if pin.value(): # 1 = not pressed
        led2.off()
    else:
        led2.on()

ext = pyb.ExtInt(pin, pyb.ExtInt.IRQ_RISING_FALLING, pyb.Pin.PULL_UP, callback)
It toggles the blue LED on rising and falling edges, and sets the yellow LED by polling the pin during the same callback. The USR button on the pyboard is fairly clean, very little debounce required, so when you start out, the blue LED will be on when the button is pushed and will be off when its released. Because the yellow LED is set by querying the pin, it will tend to self correct.

But if you push the button a bunch of times, eventually the blue LED will get out of phase with the button, so the blue LED will be on when the button is not pressed, and pressing the button will turn it off. Keep pressing a bunch more times and it will get back in phase again.

So this shows that there is bounce on the button, and shows one way to use ExtInt.

JimTal001
Posts: 176
Joined: Thu Jul 30, 2015 4:59 pm

Re: multiple interrupt question

Post by JimTal001 » Thu Sep 03, 2015 7:18 pm

Thanks Dave,
I will first try this example. The move to the next step.

One question: I am adding external LEDs and I experienced a case where the pyboard (on power-up) flashes the orange and green light alternatively and boot fails (can't see SD card). What does this mean?

Documents state:
Errors: flashing LEDs

There are currently 2 kinds of errors that you might see:

If the red and green LEDs flash alternatively, then a Python script (eg main.py) has an error. Use the REPL to debug it.
If all 4 LEDs cycle on and off slowly, then there was a hard fault. This cannot be recovered from and you need to do a hard reset.
If I unplug my connection to the breadboard (from Y17 to LED) the pyboard boots correctly on power-up. So, the error is not defined in the documents.

My connection is: Y17 to long LED leg and short LED leg to ground.

If I make the connection from Y17 to LED after bootup everything works fine with the code below.

Code: Select all

import pyb
led = pyb.Pin('X17',pyb.Pin.OUT_PP,pull=pyb.Pin.PULL_UP)

led.low()
led.high()
maybe I need a resistor on the short leg before ground but what size resistor?

User avatar
dhylands
Posts: 3821
Joined: Mon Jan 06, 2014 6:08 pm
Location: Peachland, BC, Canada
Contact:

Re: multiple interrupt question

Post by dhylands » Thu Sep 03, 2015 8:08 pm

Most LEDs need a current limiting resistor (it is possible to buy them with built-in current limiting resistors, but these aren't common).

This article https://www.sparkfun.com/tutorials/219 explains how to calculate an appropriate value.

You can get the forward voltage from the datasheet for the LED.

If you don't know the forward voltage of your LED, then you can measure it using a voltmeter (perhaps using a 470 ohm resistor and a 5V source and measure the voltage drop across the LED). Here's an article with some more details: http://www.instructables.com/id/Determi ... d-Voltage/

The forward voltage is typically somewhere between 1.8v to 3.3v with red LEDs being at the 1.8v end of the spectrum and blue LEDs being at the 3.3v end of the spectrum. Other colors will typically be somewhere in the middle and white will typically be around what blue is.

Did you mean X17? I don't see Y17 on the pyboard.

If you look at: http://micropython.org/resources/pybv10-pinout.jpg you'll see X17 in the bottom left corner with B3 (USR) beside it. X17 is also connected to the USR push button. I'm going to guess that the forward voltage of the LED is low enough that the board thinks that the USR button is pressed, and if the USR button is pressed on startup then it enters into a special Boot Mode selector described here:
http://docs.micropython.org/en/latest/p ... boot-modes

Post Reply