Automating loading micropython code to the BBC micro:bit in Linux


When I edit micropython for a microbit project, I want the code to automagically load onto the microbit each time that I save the code. Then I want to see any messages from the microbit displayed. I worked out a toolchain that does this under Linux.

I summarise the toolchain in the next section, then go through each step in more detail.

For the examples in this post, I am editing a file called ''.


Use your favourite editor for creating your code with. The toolchain to load the code to the microbit kicks off when you save the file.

There are four tools needed to automate the process.

  • A script to locate and mount the microbit. I wrote a blog post about this script here.
  • The uflash utility to write the micropython file to the microbit.
  • screen terminal to display messages from the microbit
  • inotifywait command to monitor the micropython file being edited


Use pip to install this. Details are in the link given earlier in this post. To load to an attached microbit, simply type:


Using virtual environments makes my life easier, so I use one for my microbit programming. There are plenty of blog posts detailing how to set up and use these.

script to attach a microbit

I wrote a blog post on how to create a script that automatically locates and mounts a microbit here. This script is aliased to mm and md in my .bashrc file to mount a microbit and dismount a microbit.


screen is built in to most Linux distros, so I use it here. This connects to the port that is in use by the microbit and displays any output from the microbit.

You need to know what port your microbit is attached to though. On my laptop this is often /dev/ttyACM3, which I use in the example below.

I present a script in the next section to automatically find the port that the microbit is connected to and fire up a screen connection using this.

To fire up the connection manually, if you know the port (in this example /dev/ttyACM3) use:

screen /dev/ttyACM3 115200

Remember to kill screen without leaving it running in the background by using:

control-a k

One potential problem with screen, is that it is easy to 'detach' from screen instead of ending the process, which leaves an instance of screen running invisibly which is attached to the same port as the microbit. When you come to try and run screen or connect to the microbit again, you will see an error like the one below:

can't open device "/dev/ttyACM3" 

To find and kill the errant screen instance:

lsof | grep /dev/ttyACM3

If you get something like:

screen  8610  elm    5u   CHR  166,3      0t0 5599015 /dev/ttyACM3

You still have a screen instance attached to the port. The PID is the second value in the list, in this case 8610. Kill it using e.g.

kill 8610

One way to prevent this potential problem is to replace screen with another terminal display tool such as gtkterm.

script to automate finding and connecting to the microbit

The python3 script below automates finding a connected microbit. The script starts a screen session on the port that the microbit is connected to.

Find pyboard or microbit and open a terminal.
Created on 4 Nov 2015.
Usage: find_device [device]
Calls screen on "device". If device is not given, looks for /dev/ttyACM* devices
then /dev/tty.usbmodem* devices (for MacOS).
import sys
import os
import fnmatch

BAUD = 115200

def main():
    if len(sys.argv) > 1:
        ttymodems = [sys.argv[1]]
        ttymodems = fnmatch.filter(os.listdir('/dev'), 'ttyACM*')
        if len(ttymodems) == 0:
            ttymodems = fnmatch.filter(os.listdir('/dev'), 'tty.usbmodem*')
        if len(ttymodems) == 0:
            print('Error: no pyboard found.')
        ttymodems[0] = '/dev/' + ttymodems[0]
        print('connection at: {}'.format(ttymodems[0]))
    os.system('screen '+ttymodems[0] + ' {}'.format(BAUD))

if __name__ == "__main__":


inotifywait is a command line tool that can be configured to watch a file for a change, then trigger an action. Here we use it to watch for a change in the micropython file being edited. When this file is saved, inotifywait mounts the microbit and flashes the file to it.

If infotifywait is not already installed, then you need to install inotify-tools.

The command to watch a file called for a change, then run the alias mm (to mount the microbit) and to flash the file to the microbit is:

while inotifywait -e modify ; do mm && uflash ; done

I would have formatted the above line as the other code in this post but found that the syntax highlighter plug-in refuses to show the ampersand symbol correctly.


Some editors have the 'feature' of 'kind of' saving the file you are editing while you are editing it. This creates a new timestamp for the file and activates inotifywait without your saving the file. mu is one of these editors. In this case, I do not use inotify and run the following command from the command line each time I want to flash the updated file. In this example the updated file is called

mm && uflash

but why not use a Makefile

Makefiles are typically used to build programming projects, detailing the dependencies of each component. The file is run when 'make' is typed on the command line.

The one-liner command using inotifywait is fine for this simple example where we are editing a single file. Which is most of what I do with the microbit and micropython. Makefile comes into its own for more complex builds involving multiple files. It allows for extra run-time options to be added, e.g. to clean files created by earlier builds.

For completeness, I present a simple Makefile below for this project. Makefile is a useful tool that is worth learning to use for when we have larger projects to build.


I created a Makefile containing commands to mount the microbit to the Linux filesystem, then flash a micropython file to the attached microbit.

An example Makefile is below. Note: Use tabs to create the indents after the line 'run:'. Or the World Ends. The supporting file is in the same directory as to keep it simple.

	./ mount

In this example, is the script to attach a microbit, detailed above.

uflash is the tool used to write the .py file to the microbit. This is detailed above.

To automate the Makefile being run each time that we save new code, we can use the inotifywait command below:

while inotifywait -e close_write ; do make; done

Powering the BBC micro:bit with a 5V power bank

I had an interesting question to a blog post I made about running a DC motor from a microbit. The blog post is here. I am pleased that anybody reads my blogs.

Doesn't applying 5V to the microbit board exceed the voltage spec?

When we connect the board to our laptops or PCs, we apply 5V to the board through the USB connector. Sometimes I run the board from a USB power bank. This supplies 5V to the microbit. The advantage of using the power bank over AAA batteries is that I can use the power bank to also run e.g. a DC motor. So far I have not cooked off a microbit doing this.

But I still only measure 3.2V on the pads on the board edge connector.

Why is this?

Let's look at the board circuit schematics. Please find a screengrab showing the USB connector on the left and the microcontroller on the microbit on the right.

BBC micro:bit schematic fragment, showing USB connector and the microcontroller.

Let's zoom in on the connector:

Schematic showing the USB connector.

The 5V input voltage on the USB connector is given the net label VBUS_IF. This label reappears next to the little number 5 - which means this is where the track connects to on the PCB. The zener diode to the left of the number 5 and the 10 Ohm resistor R31 to the right combine to protect the board in the case of reverse polarity - if somehow the voltage is applied to the USB connector backwards, the current flows to ground, not into the microcontroller.

The capacitor C31 and C33 are there to act as little charge stores for the microcontroller for when it needs a sudden 'oomph' of charge that the USB power supply cannot supply quickly enough. These are called decoupling capacitors.

The +5V signal is renamed VBUS_IF_2 to the right of R31. Lets look at where this goes into the microcontroller. I labelled the net VBUS_IF_2:

So our +5V USB voltage connects to the microcontroller on a dedicated pin VREGIN. This is the input to a regulator inside of the microcontroller. The output of this regulator is a DC voltage called +3.3V_IF. This output supplies the +3.3V seen elsewhere in the board and on the board edge connector pads.

Now, if the input to VREGIN is below 3.3V, we are not going to see 3.3V on the output pads. In fact, I see 3.2V with an input of 5V, so there is a 0.1V drop somewhere on the board.

So, in summary, we can apply 5V through the USB connector.

One last schematic fragment. This shows the battery connector and where this supply connects with the voltage generated by the internal regulator on the microcontroller:

Microbit schematic showing the battery connector and how it connects to the board voltage tracks.

The battery voltage goes through a low drop BAT60A schottky diode labelled D2. This then connects to V_TGT. This is the main voltage rail for powering most of the board components, such as the magnetometer and accelerometer. This is also the rail that connects to the board edge connector on the pad labelled '3V'.

Both the output from the microcontroller regulator, labelled 3.3V_IF and the voltage from the battery labelled VBAT connect to this rail through BAT60A schottky diodes. The diodes mean that the battery voltage and the regulator output voltages are isolated from each other, but either can produce V_TGT.

What if both a battery and a USB connector are connected? Whichever is the higher of VBAT or 3.3V_IF, minus a small voltage drop created by the BAT60A diode, will produce V_TGT. The voltage drop across the diode is around 0.1-0.2V according to the datasheet for the BAT60A.

It would be dangerous to the board to apply 5V to the battery connector. I am not about to try this. The battery connector bypasses the regulator in the microcontroller, so applying a high voltage to this connector applies the same high voltage to the components on the microbit board, minus a small drop across the BAT60A diode. Many of these are not rated to work at 5V.

The board is designed to take 5V only through the USB connector.

Configuring a Python virtualenv in Debian

Python virtual environments are a good idea. Naturally, I had a few problems getting mine to work properly. I found that my globally installed libraries were visible the activated venv. The whole point of a venv is to isolate libraries. The globally installed libraries that are not also explicitly installed in the venv should not be usable.

I use Debian and the bash shell.

So how did I fix what I found is a common problem?


# blank the PYTHONPATH environment variable
virtualenv my_venv
# use python3, not python as a REPL or the interpreter in e.g. VSCode
# use pip install, not python -m pip install

I have this line in my .bashrc file:


This means that when I create my venv, this path gets added to the PYTHONPATH environment variable in the venv. This allows the venv to see the packages in ~/.local/lib/python3.7/site-packages/. Which we do not want.

To prevent this, blank the PYTHONPATH before creating the venv by typing:


We can check on what the PYTHONPATH environment variable is by entering:


This should now be blank.

Go ahead and create a new venv by typing e.g.

virtualenv my_venv

This is where things continued to be a little.... non-standard. I should be able to use:

python -m pip freeze

To see only the packages that I install in the venv. But I see all the global packages.

Using only:


shows me what I should see. I would like to know why.

Similarly, I should get a REPL with access to only the packages installed in the venv using:


but typing this starts a REPL that allows me to import globally installed packages.

To get around this, use:


Now things behave as they should. I cannot import a package that is globally installed but not installed in the venv. Which is the correct behaviour for a venv. I use the path to the python3 executable in the my_venv/bin directory as the interpreter in e.g. VSCode when I want to use a venv.

I found I had several installations of pip in various locations. I deleted all of them except for the one in /usr/bin.

If you want to learn more about virtual environments, I recommend this series of short videos:

The videos recommend using the command:

python -m pip

in the venv, which I found to be unreliable.

Instead I just use:


Check that this is pointing to the correct executable by typing:

which pip

Running handShake in administrator mode to operate Grid 3

Sensory Software's Grid 3 is a popular communication software package, running in Windows. Naturally, I would like handShake to be able to operate this software through the software keystrokes that handShake generates.  To get Grid 3 to respond to a software keystroke, I have to 'elevate' the script which runs on the communication device to run as an Administrator.

There is a second solution. I can use a Freetronics Leostick USB dongle as a pretend keyboard and have this generate keystrokes that appear as coming from a physical keyboard. I did this for a while, but this adds a layer of complexity and expense to the project. The simplest solution is to run handShake as an Administrator when using Grid 3, or other software that requires software keystrokes to come from an elevated source.

I tested out adding the functionality for handShake to detect when Grid3 was running, then automatically try to elevate the script to run in Administrator mode. I got this running. Then removed the functionality. Why? Security. Software running as Administrator can damage your system if incorrectly or maliciously written.

Now handShake detects if Grid 3 is running and advises that this requires the software to be restarted as an Administrator, but does not try to automate this restart. The decision is left to the user.

The Grid 3 software is detected using the code shown below. The code looks through the titles of the windows for any that match the ones in the list called ADMIN_SOFTWARE. At the moment there is only one title to check for - 'grid'. This is the title for a window running Grid3. As I find other packages that demand that my script runs as Administrator to have the ability to interact with it, then I will add their titles to the ADMIN_SOFTWARE list.


def target_admin_sware(software=ADMIN_SOFTWARE):
    ''' Check if target software requires this script to run as Administrator. '''
    toplist, winlist = [], []'Looking for software that requires elevation to Aministrator: {}'
    def _enum_cb(hwnd, results):
        winlist.append((hwnd, win32gui.GetWindowText(hwnd)))
    win32gui.EnumWindows(_enum_cb, toplist)
    for sware in software:
        # winlist is a list of tuples (window_id, window title)
        for hwnd, title in winlist:
            if sware in title.lower():
      'found software requiring Administrator mode {}'
                return True
    return False

Running handShake as Administrator is a choice that the user makes and implements if he or she deems necessary.  As all of the code is on the project GitHub site, the code can be reviewed to check that it is safe to run as an Administrator.

One of the advantages of open source projects is that they are open to this kind of scrutiny to find security flaws.

For interest, I detail the code I added and then removed from the script to enable it to detect if it is running as an administrator and if not, request to be restarted as an Administrator.

I added the option to run the script as an Administrator from the command line using the click library.


@click.option('-a', '--admin', default=False, 
    help='Run as administrator. Required for Grid 3.')

@click.option('-k', '--keystroke', default='F1',
     help='Keystroke to send. Default is F1.')

def main(admin, keystroke):'software keystroke is {}'.format(keystroke))
    logging.debug('admin flag is {}'.format(admin))
    if is_admin():'running as administrator')
    else:'not running as administrator')
        if admin:
  "restarting as administrator")

To test if the script is running as an administrator I added this method:

def is_admin():
    ''' Is the script running as an Administrator? '''
        return windll.shell32.IsUserAnAdmin()
        return False

Give Me a Minute idea in use in commercial AAC software

To understand this post, please read the first couple of paragraphs of my give-me-a-minute project page.

The idea presented in give-me-a-minute looks to be making it into commerical AAC products. I don't pretend that my project influenced this development. Be nice to think it did though... I'll come back to reality now.

One implementation is as 'partner windows' where the text being composed on an AAC display is mirrored to a second screen that faces away from the person composing the test. A pattern that indicates that text is being composed can be displayed instead. This can be easily seen by somebody facing the composer. The partner windows are incorporated in some of the I-series AAC devices made by Tobii Dynavox.

When I presented Give Me a Minue at Communication Matters in 2019, the father of somebody who uses AAC approached me with a concern over the idea. His son sometimes wants to compose private text and not to have anybody else know that he is doing this. Having the text replicated completely removes this privacy. Having a pattern indicating that the device is in use, but not giving away the content, is a step to preserving privacy. Give Me a Minute displays a pattern. The I-series has an option to display a pattern of bouncing dots instead of text. In both cases some privacy is maintained until the final text is delivered as speech. However, even having this pattern on the display gives away some privacy. The father of the AAC user who talked to me indicated that he would want to be able to turn the feature on and off easily.

As I have no access to the AAC software, I don't have the ability to add this extra feature to Give Me a Minute. The instructions for the partner window software on the I-series is here. It looks like the only way to turn the indicator window on or off is to go through the settings menu.

The Twitter feed where I learned of these developments is here: My contributions are under the name 'Oppy'.

Therapy Box plan to incorporate their idea in the next release of their predictable AAC software.

Connecting the BBC micro:bit to Windows and adding code to it

This page details how to connect the BBC micro:bit to Windows then install a pre-written program to it. This guide was written to support some of my 'how-to' guides for assistive technology devices I made using the BBC micro:bit.

Author: Matthew Oppenheim


GitHub site:


Connect the microbit using a micro USB cable from the microbit to the Windows device. You do not need a battery pack for the microbit. The microbit is powered from the USB connection.

  • Install the driver for the microbit if you are not using Windows 10.
  • Connect the microbit using a USB cable to the device with the communication software on it.

To install software, drag and drop the file, which ends with .hex, into the MICROBIT folder.

Connecting a microbit to a Windows machine

Connect your microbit to your Windows machine using a USB cable.

BBC microbit board connected using a micro USB cable to the Windows device. A battery pack is not needed.

Windows 10 should automatically detect the microbit. If you are using an earlier version of Windows, you will need to install the driver for the microbit.

If File Explorer shows that the microbit is attached, you are done. Success. The screenshot of File Explorer below shows that the microbit is connected as a drive called 'MICROBIT'. A new microbit has a demo program installed which will scroll all kinds of things across the LEDs.

If the microbit does not automatically connect, download and run the microbit driver installer.

microbit showing as successfully connected in File Explorer.

How to install the microbit driver if the microbit is not detected

Windows 10 should recognise the microbit, but in testing, this was not found to always be the case. The driver can be manually installed using the instructions in this section.

I found that Windows 7 would find and download the driver for the microbit on its own when left for about 5 minutes. The microbit needs to be connected with the USB cable first.

If for any reason the driver is not found and installed by Windows automatically, then the driver can be downloaded and installed manually.

The name of the driver installation file is:


A newer version may be available.

Get this file by clicking on the 'Download current driver' link on this page:

The microbit needs to be plugged in before the serial driver installer is run.

Follow the instructions on the webpage to install the driver. Once installed, the microbit should show up as a connected drive, as shown in the screenshot above.

Installing code on to the micro:bit

The micro:bit is programmed by placing .hex files onto it. This can be done by dragging and dropping these files onto the MICROBIT folder from File Explorer. For instance, if you are trying to install a file called ubit_flash.hex, the file called ubit_flash.hex needs to be dragged and dropped into the MICROBIT folder as shown in the screenshot below.

Drag and drop the file ubit_flash.hex to the MICROBIT folder.

Wait about 10 seconds for the microbit to start to program. The light on the back of the microbit will then flash for about 10 seconds as it loads the new program.

The code will remain stored on the microbit and run whenever it is powered. The microbit can be left unpowered and the code will stay on the device for when you next connect it to the Windows device.

As the microbits are being distributed to all 11-12 year-olds in the UK, if you get stuck installing code on to the microbit and live in the UK, find a friendly 11-12 year-old to help you out.


Microbit is connected, but the software tells you that no microbit is found

If a microbit is plugged in and you still get the message that there is no microbit connected, then the microbit driver is not installed. Look at 'Installing the microbit driver'.

3D printing face shields on a Creality CR10-Mini

Like a lot of folk right now (mid Covid-19 lockdown), I'm using a 3D printer to produce face shields. I started from scratch and with little experience of using a 3D printer. This post will detail some of the issues I had and my solutions, in the off chance that this information could help somebody else.

Please see my HSE manager testing one of the completed face shields in the picture below so you know what I am talking about. These face shields are requested by front line workers as there is a scarcity of off-the-shelf personal protective equipment (PPE) . I print the yellow clip at the top. The face shield is an A4 clear plastic sheet bought from an online stationery store. The holes are punched using a four hole A4 punch. The design comes from the national 3D printing society.

Careful testing of the final product.

I work through a couple in Ulverston who set the scheme up at They received some funding through donations and kindly sent me some filament and the pre-punched sheets. Requests for the face shields go straight to this couple. I try to fulfill some of the orders that they receive.

I bought a Creality CR10-Mini 3D printer the same day I read of their project. Why this printer? There's quote "There are two types of fool, one says 'This is old and therefore good'. The second says 'This is new and therefore better' ". I went for the 'old and therefore good' option. The CR10-Mini is a printer that came out a few years ago, so there are many videos on YouTube to show me how to set up the printer and trouble-shoot inevitable problems. The CR10-Mini gets good reviews for the beginner, which I most definitely am. Maybe a more recent printer would give me more for my money, but I needed to get into production as soon as possible. Some of the reviews of more recently produced or cheaper machines showed that simple bodges were necessary to get them running. I can't nip down the local hardware store to get some washers or a spring at the moment. This YouTube video , comparing the Creality CR10-Mini with the Creality Ender 3, convinced me to spend the extra to get a printer that lookes easier to get into production than a cheaper model that may take some extra time and experience to set up. However, if you don't have the extra money, the Ender 3 looks to be a good printer.

The CR10-Mini was straight forwards to set up. Most of the online reviews are made by people who have substantial experience of 3D printers and may have forgotten what it is like to know almost nothing about them. Even so, bolting the printer together while following this YouTube video was not difficult. An experienced 3D printer guy would laugh, shake the parts a little and have a machine ready. I didn't find the manual too helpful, so stuck with the video guide.


Watch this video on levelling the printer, download and edit the G code as suggested by the presenter. Then run the code to check your levelling and nozzle clearance. I check this levelling about once a day now.

Problems encountered and solutions

Prints not sticking to the glass plate

Check the plate levelling and the clearance between the extruder nozzle and the plate. Get a good tight clearance as suggested in the video linked in the Tips section.

Use decent filament - not the sample that came with the printer.

Decreased first layer print speed to 20 mm/s. This gives the plastic more time to melt and stick to the glass plate.

Increased glass plate temperature from the suggested 60C to 70C. This worked well. I stepped the temperature back down to 60C as my experience and confidence increased. A higher bed temperature increases the chance of the plastic melting and bonding to the plate against using a lower temperature. The higher bed temperature increases the start up time, as the bed has to get to the higher temperature and uses more electricity.

Smeared the glass with a film of UHU glue stick. I was shown this trick by a friend some years ago when having an induction on the lab 3D printer, which I then did not touch again.

After about 100 prints, I was getting the hang of things. So I cleaned off all the UHU glue stick from the plate and found that the prints stick straight to the glass. I guess that I got my nozzle clearance good and tight so that the base layer of plastic squishes down and sticks. Maybe smearing the glue on for a while then cleaning all of this off removed any residual grease on the plate. I will never know.

Knocking sound and a decrease in print quality.

This happened after about 100 hours of printing. Please see the photo below. The layers of filament are not as tight as they should be on the part shown on the top of the photo. The part on the bottom of the photo was printed after I fixed the problem. Note that the prints were both made at low resolution and high speed. The machine is capable of a smoother finish if you give it the time.

Poor quality print (top) from slipping filament. Better quality print below.

I found that that the little gear wheel-shaped filament feeder was slipping on the filament. So less filament was fed to the extruder than intended, leading to material missing on the final print.

I fixed this by cleaning the teeth on the wheel. Please see the photo below where I indicate the component that needed cleaning. In the photo it is shiny and clean though.

CR10-Mini filament feeding mechanism showing the component that needed cleaning to prevent filament slippage.

The feeder wheel is toothed and metal, so inevitably the teeth gum up with bits of plastic from the filament, allowing the filament to slip. I should also look at how my filament reel is mounted, in case there is excess drag on the filament entering the printer, leading to it slipping in the feed mechanism.

To clean the wheel, I first preheated the nozzle to PLA temp, then pulled out the filament. I unbolted the plastic feed tube. I cut a short length of filament and fed it through the feed mechanism. Then I pulled this filament rod back and forwards while holding a toothbrush against the gear wheel teeth.

I reassembled the printer and tried again. Instant fix! A video showing how to do this in detail can be found on this YouTube video.

Printer not levelling correctly

One of the wires connecting the printer to the control unit snagged above the contact switch on the Z-axis controller. This switch is used to help the machine reset its home position. When the printer was resetting, this wire pressed onto the contact, triggering a false home position. The incorrect wire position is shown in the photo below.

Wire on top of contact switch, causing incorrect print bed levelling.


I print two nested head-pieces at a time as shown below. I tried some stacked prints, but they didn't come out as well as the single-layer prints. My lack of experience and the need to maintain production stop me from trying more. A year from now I'll laugh at my not printing stacks, but right now, I'm running with what I know works. As always 'Experience is something you get after you needed it'.

Creality CR-10 Mini printing two face shield clips in a tasteful shade of yellow.

I printed off about 145 clips for local care home and hospice orders and sent a batch of prints to the NHS scheme, for a grand total of 200 prints. Then I was asked to return to my paid work offshore, so my PPE manufacturing came to an end. Until the next pandemic...

micro:bit C toolchain explained, part 1. ninja & cmake.

December 2020: I wrote this post when only v1 of the micro:bit existed. I haven't yet checked to see if the contents are still valid for the toolchain used to program v2 of the micro:bit.

I use the offline build tools from Lancaster University for compiling and building C-code for the BBC Micro:bit board. I used the toolset without really understanding what was going on under the hood. I spent some happy time fixing this. Understanding our tools gives us a better chance of fixing things when they fail. I hope to pass on what I learned here.

So you have written some C code to go onto your micro:bit. Great. Now how does your beautiful prose get converted into the executable (often called a binary) file that can be copied onto the micro:bit?

The components of the toolchain that are unleashed upon your unsuspecting C code are shown below. Let's start at the bottom.

Offline tool chain for building an executable from C code for the micro:bit

The 'file to go to micro:bit' is the end product of the chain of build tools and the Gnu C compiler (called gcc) shown above. This is the file that you copy to your micro:bit and is automatically executed when you power up the micro:bit. Let's talk about gcc.


gcc stands for the Gnu C Compiler. If we write a simple 'hello world' C program contained in a single file to run on your workstation, telling your C compiler (in our case gcc) how to build the executable can be done in a single command. For example, the command gcc -o hello hello_world.c creates an executable file called 'hello' from a C program in a single file called hello_world.c, using gcc to do the compiling and linking. It gets more complicated when there are multiple files in the project. As we are using the micro:bit, there will be multiple files as many C files need to be brought into your project to enable the code to be built to run on the micro:bit hardware.

gcc is used to do the compiling and linking of your C code and the supporting libraries that are needed to enable the code to run on the micro:bit. gcc comes as standard with most distributions of Linux. But something has to tell gcc what files how to assemble the general mish-mash of interdependent files and libraries. This is what ninja does. ninja is a 'build tool'. Let's discuss what build tools are.

build tools

To understand the rest of the blocks in the toolchain, we need to have a little chat about build tools. A build tool looks for instructions in a text file, which is often called a build file on how to build 'something'. That something could be how to use a compiler to compile and link files written in C, or for indeed another language. That something could also be how to build the instruction text file for a different build tool. This , which will then go on to do 'something else'.

The build file contains a list of rules, such as the flags and controls to run the compiler with. It also contains a list of build statements which say how to build each of the files necessary to produce the output.

There are many different build tools. The micro:bit toolchain uses several. ninja, cmake, yotta and make are all build tools. Each of these tools looks for a text file specific to that tool. Here's a little table for each build tool command and the corresponding build file that it works with.

build toolbuild file

A build tool can often be used for building more than one type of language or thing. Let's make build tools clearer by looking at how we use the ninja build tool to build a simple C project.


In the micro:bit toolchain, the ninja build tool uses a build file called to instruct gcc on how to compile and link all of the project's C files. Entering 'ninja' at the command line causes the contents of this file to be processed by the ninja build system. The file contains details of the interdependencies of the files that are used to create the binary that we want to load onto the micro:bit.

Let's look at how ninja could be used with a simple three file C project outside of the micro:bit system. Consider a simple example project, split across three files. The three files are called array.c, display.c and display.h. This example runs on your workstation, not on the micro:bit. I'm trying to keep it simple to show what ninja does and what a simple file looks like. We will use this example to help explain some of the other build tools as well.


#include <stdio.h>
#include "display.h"

int main() {
    int v[5] = {1,2,3,4,5};
    display_arr(v, 5);
    return 0;


#ifndef DISPLAY_H
#define DISPLAY_H

void display_arr(int *arr, int len);



#include <stdio.h>
#include "display.h"

void display_arr(int *arr, int len) {
    for (int count=0; count<len; count++) {
        printf("arr[%i] = %i\n", count, arr[count]);

We can see that the files depend on each other. To build these three files into a single executable we need to tell gcc how each file depends on other files. An example file that will compile and link the three example files to create an executable called 'array' is shown below.

cc  = gcc
cflags = -Wall -g
rule compile
    command = $cc $cflags -c $in -o $out

rule link
    command = $cc $in -o $out

build array.o: compile array.c
build display.o: compile display.c
build array: link array.o display.o

default array

Putting all of these files into the same directory and typing ninja will create the following output:

[3/3] gcc array.o display.o -o array

You will find a new file called 'array' in the same folder. This is an executable file. Typing array at the command line gives this unexciting output:

arr[0] = 1
arr[1] = 2
arr[2] = 3
arr[3] = 4
arr[4] = 5

ninja is a relatively recent build tool. Traditionally the make build tool is used to build C programs. I will cover this tool in part 2 and show how this tool can be used to automate loading your code onto the micro:bit. However, with the micro:bit, ninja is used here. I've read that ninja offers about a 10x increase in speed of building the executable for large projects compared with make.

In our example above, I wrote the file by hand. But how do we create this file for our project? As I mentioned, building an executable for the micro:bit requires a bunch of C files and libraries to be compiled and linked with the source code that we write.

At the top of the ninja website, it states that ninja 'is designed to have its input files generated by a higher-level build system'. In our case, this is done using the CMake build tool. So CMake produces the file. Let's have a look at CMake.


CMake is used to create the file. That's right - we are using one build tool to create the build file for another build tool to do something. There is a lot of this going on in the micro:bit build system. CMake can generate the build instruction files for a variety of build tools. Type cmake --help and look at the list of generators at the bottom. CMake uses the Ninja generator to generate the file.

Let's use CMake to create a file for our previous example C code. In the directory with the C files, create a file called CMakeLists.txt with the content below.


add_executable(array array.c display.c)

Two lines only! Create a directory called build_ninja and cd into this. Then type CMake .. -G "Ninja". The ".." part will look for the CMakeLists.txt file in the directory above where you are now, then use the contents to create the file. You will see a lot of new files are created including a file.

The file I wrote by hand earlier contains 10 non-blank lines. The new file created by CMake contains 95 non-blank lines! Granted, a lot of them are comments, but still.... One of the first lines in the new file is include This file contains an extra 44 non-blank lines. So we have moved from 10 lines to a total of 95 + 44 = 139 lines. I included as a build file in the diagram at the top of this page as this file becomes part of the file.

The next obvious question is 'how is the CMakeLists.txt file created for the micro:bit build system'. This is done by yotta.

End dribble

Right, this is enough for one post.

In part 2 we will discuss yotta and the directory structure of the micro:bit C projects.

Additional reading

One good website that helped me figure out the programming toolchain, about 2/3 of the way down the article is

Using Vim to change character hexadecimal values beyond standard ASCII values

I needed to insert the character with hexadecimal value 0xFF into a text file. Problem was, every time I did this using vim and xxd, it didn't 'stick'. Turned out I needed to open the file for editing using the '-b' flag:

vim -b 

Longer story and example.

vim test.txt

Text in the file:


Press <escape> and type the following to see the hexadecimal values:


This is what you will see, the line number on the left, the hexadecimal values of each character (two numbers per character) and on the right the text. The final '.' indicates an end of line and is represented by the final 0x0a value.

00000000: 3132 330a                                123.

Fair enough. ASCII ox31 is indeed 1, 0x32 is 2, 0x33 is 3. Now I change the '1' to be character 0xFF using the text editor. I now have:

00000000: FF32 330a                                123.

Convert back to text using:

:%!xxd -r

I see:


Success! Tea and cakes. The funky ÿ symbol surely means character 0xFF? But, but, but, when I reverted to hexadecimal using :%!xxd , the 'FF' had not stuck:

00000000: c3bf 3233 0a                             ..23.

What is this crazy 0xc3bf now in my file instead of a lovely 0xff? Turns out that this will happen when I try to insert any hexadecimal value over the magic decimal 127 = 0x7F, which is the last value of the standard ASCII table.

The solution is, as already mentioned, to open the file in binary mode using:

 vim -b test.txt

Editing the hexadecimal values again using <escape> followed by:


Now I adjust the text to be:

00000000: ff32 330a                                .23.

Back to text view using <escape> followed by:

:%!xxd -r

This time I see:


The <ff> acts as a single character - I can't delete a part of it, all or nothing. Which is as it should be - it represents a single character, so behaves as one

Save the file and display it using 'more test.txt' or 'less test.txt' or 'cat test.txt'. We don't judge which is your preferred method of displaying files. Now I get:


The funky � symbol seems to mean 'This is not a standard ASCII character'. I get the same symbol for different hexadecimal values over 0x7f.

Why am I doing this? I needed to test that a C program was correctly reading the end of file (EOF) character. For whatever reason, a common EOF character is -1 which in two's complement wraps around to be 0xFF. I was directed to check that the C-code would not confuse character 0xFF with the EOF character.

Communication Matters Conference 2019

I attended the 2019 Communication Matters Conference in Leeds on Monday. I presented a poster on three of my assistive technology projects using the BBC micro:bit and gave a 'lightning talk' - 15 slides, auto advancing every 25 seconds. I wrote the PowerPoint presentation using Libreoffice on my Linux distro. Just before giving the talk I realised I had not tested it in Windows, which the conference PC was running with. Of course. Why use Linux for free when you can pay for Windows? Fortunately the slides displayed and auto-advanced correctly. This was my first time presenting at a conference, so I was a little nervous. I think it all went well. I didn't notice anybody asleep and nothing was thrown.

A number of people showed interest in the poster. I presented my handshake, give-me-a-minute and hand-wave projects. Hopefully this interest will carry over to implementing these projects to help people access communication devices.

If any of these projects are of use for you or somebody you know, please get in touch. Contact details are on my home page.

Standing by my poster with the sunlight glinting gently off my baldy head.
My Mighty Poster. The original is A1.

People laugh when I tell them that I mostly failed over the years that I prodded at these projects. I went down the proverbial rabbit hole trying to implement camera based virtual switches before moving to repurposing simpler off the shelf technology, such as the BBC micro:bit.

I finally realised that trying to implement vision based controllers in the Real World was too much for Little Matty working on my time off from my paid work offshore. I managed to demonstrate the idea of using depth cameras to create virtual controls using head tracking: before moving on.

I was gratified to see a presentation from a Japanese team that succeeded with depth camera based controllers: The Japanese team have been working on this project for 5 years and have 9 people working on the team, according to the team member I talked with at the conference. So even simple sounding ideas using off the shelf technology can take significant resources and software development to implement in the Real World.