All about the 'wait flag' and a complete list of the functions that can use it. Am looking for info.

Questions and discussion about running MicroPython on a micro:bit board.
Target audience: MicroPython users with a micro:bit.
Post Reply
PixelShady
Posts: 9
Joined: Mon Sep 02, 2019 4:36 pm

All about the 'wait flag' and a complete list of the functions that can use it. Am looking for info.

Post by PixelShady » Tue Nov 19, 2019 11:54 pm

Like a lot of people who've been playing around with their microbit for a while, I've started wanting my device to perform more than one task at a time.

I've come across this old (2016) github post by Nicholas Tollervey (link below) which gives a very brief list of built-in functions that can run in the background; namely: display.scroll, display.show, and music.play.

Link to post - https://github.com/bbcmicrobit/micropyt ... -250978354

My Questions:
  • Are these still the only three functions that can use a wait-flag set to false and run in the background, or has the list gotten longer since 2016?
  • What are the reasons why more, if not all, functions can't make use of this wait-flag?
  • Also, can someone create their own function which makes use of a wait-flag, or is this some kind of hidden feature?
  • Is it something to do with hardware limitations, and if so then what are they?
Thanks

User avatar
jimmo
Posts: 1681
Joined: Tue Aug 08, 2017 1:57 am
Location: Sydney, Australia
Contact:

Re: All about the 'wait flag' and a complete list of the functions that can use it. Am looking for info.

Post by jimmo » Wed Nov 20, 2019 12:36 am

PixelShady wrote:
Tue Nov 19, 2019 11:54 pm
Are these still the only three functions that can use a wait-flag set to false and run in the background, or has the list gotten longer since 2016?
Also music.pitch and audio.play, but yes that's basically it.
PixelShady wrote:
Tue Nov 19, 2019 11:54 pm
What are the reasons why more, if not all, functions can't make use of this wait-flag?
Mostly because they were the ones that needed it most (i.e. they take time to run, so you want this "non-blocking" way of using them).

Can you give an example of another built-in function that would benefit from it? Sorry it's been a while since I did a lot of micro:bit stuff and nothing is jumping into my head.

Or are you saying you'd like to be able to do this for your own functions? (See next part)
PixelShady wrote:
Tue Nov 19, 2019 11:54 pm
Also, can someone create their own function which makes use of a wait-flag, or is this some kind of hidden feature?
Not from Python... it's a hidden feature in that it's part of the implementation of how the display and music modules work, but also it relies on the fact that they operate on a timer running independently of the MicroPython virtual machine. Sort of like a thread...but not quite.

But you can kind of achieve the same result if you write your code a bit differently... I've written a bit about this in other posts (e.g. viewtopic.php?f=17&t=7150&p=40706 , also see the linked blog post).

This still doesn't really help you if you want to do some long piece of computation, but if you instead want to schedule a bunch of independent tasks, then re-structuring your program around running_time() can allow for much more sophisticated programs. There are kind of two ways to achieve this:
- Schedule tasks for a given time (i.e. each thing that happens can have its own "when should i next run" time, then when running_time() reaches that time, do the thing)
- Round-robin between tasks and have them independently figure out what to do.

(Where "task" is just a loose term for a piece of code that you can run)

Code: Select all

task_a_run_at = None
task_b_run_at = None
while True:
  if task_a_run_at is not None and running_time() > task_a_run_at:
    # code for task a goes here
    task_b_run_at = running_time() + 5000 # schedule task b in 5 seconds time
    task_a_run_at = None
  
  if task_b_run_at is not None and running_time() > task_b_run_at:
    # code for task b goes here
    task_b_run_at = None
You can get much more sophisticated and do things like have a queue of function callbacks with attached "run at" times, but for a lot of programs (especially that will work on the micro:bit) the above approach gets you pretty far. The basic rule is just to never use the "sleep()" function.
PixelShady wrote:
Tue Nov 19, 2019 11:54 pm
Is it something to do with hardware limitations, and if so then what are they?
Sort of. The micro:bit is one of the smallest devices that MicroPython can run on, so a lot of features are missing. On "bigger" devices, MicroPython allows things like interrupts and it also has a way to schedule functions to run interleaved in the current function. And on some devices, it supports proper threading, so you can just have tasks running truly concurrently.

My personal preference is to use asyncio, which is a Python feature for writting concurrent code without threads, and MicroPython support for it is continuously improving (e.g. https://github.com/micropython/micropython/pull/5332 ). Unfortunately I don't know if it is feasible to run on the micro:bit.

For some more technical background, the way the micro:bit port works is that it runs the MicroPython VM, which runs your code. But in the background there's a timer that calls some internal functions every (from memory I think it's) 6 milliseconds (which is called a "tick"). So for example, the display can only turn on a third of the LEDs at any time. So every tick, the display moves onto a different set of LEDs. (And this happens fast enough that your eye doesn't see it). Also it checks whether there's an animation in progress (e.g. a scroll) and whether it should update the display. Or move onto the next note in the current song, etc.

The actual display.scroll function (for example), just sits there sleeping waiting for this background process of ticks to finally finish scrolling the display, then finally returns back to your Python code. When you use wait=False, it just skips that last bit and returns back to your Python code immediately, letting the background ticks do their work.

(There's actually a faster timer used for dimming the LEDs, and music is more complicated, but you get the idea...)

Post Reply