Microcontroller programming with BBC micro:bit

Pocket-Size Programming

© Lead Image © Burmakin Andrey, 123rf.com

© Lead Image © Burmakin Andrey, 123rf.com

Author(s):

Designed for students, the BBC micro:bit, in conjunction with MicroPython and the Mu editor, can help you get started with microcontroller programming.

The idea of developing a microcontroller for schools dates back to 2012. In 2016, in cooperation with the University of Lancaster and several dozen industry partners, the British Broadcasting Corporation (BBC) delivered on this concept with the BBC micro:bit [1]. Although developed for seventh grade students, the BBC micro:bit offers an introduction to microcontroller programing for users of any age.

You can purchase the micro:bit individually for $14.95 or as the micro:bit Go Bundle (which includes batteries, a battery holder, and USB cable) for $17.50 from Adafruit [2].

The microcontroller and its components fit on a 5x4cm board (Figure 1). The 32-bit processor, an ARM Cortex-M0, runs at a clock speed of 16MHz. The micro:bit offers 16KB of RAM and a 256KB flash memory. In principle, a Bluetooth Low Energy (BLE) radio is also available. See Table 1 for more specifications.

Table 1

micro:bit Specifications

25 individually programmable LEDs (5x5 matrix)

Three-axis accelerometer

Three-axis magnetometer

Light and temperature sensors

Two programmable buttons

Micro USB socket for power supply and data transfer

Plug contact for external 3V power supply

Five contacts for crocodile clips (ground, 3V, and three I/O)

Further inputs and outputs via special connectors

Figure 1: The micro:bit with connecting cables, a breadboard, and components.

If you connect a micro:bit to a Raspberry Pi via a micro-USB cable, the Raspberry Pi will identify the micro:bit as a USB stick with a size of 64MB. Using the lsusb command will reveal that the micro:bit's USB interface component is an LPC1768 chip from NXP. Listing 1 reveals that the micro:bit has a device name of ttyACM3.

Listing 1

micro:bit Device Name

$ lsusb
[...]
Bus 002 Device 019: ID 0d28:0204 NXP LPC1768
[...]
$ dmesg | grep tty
[...]
[17860.723466] cdc_acm 2-1.2.1:1.1: ttyACM3: USB ACM device

The micro:bit can be powered via USB or battery, using the battery holder (shown in Figure 1 on the left) with two AAA zinc or alkaline batteries plugged into the top connector. Optionally, you can use the 3V pad at the bottom, but do so with caution. The micro:bit's voltage range is 1.8-3.6V.

The memory-hungry Bluetooth module cannot be addressed as a standard BLE in MicroPython, but a radio connection between modules should at least work.

MicroPython

While the micro:bit understands various programming languages, this article focuses on MicroPython, the version of Python optimized for running on microprocessors.

If you want to program microcontrollers on register level, you won't get far with MicroPython, but then neither is the micro:bit the tool for this task. Instead, an Arduino [3] would be the better choice, which, unlike the micro:bit, offers circuit diagrams and board layouts.

The micro:bit's operating system constantly monitors the USB memory. If it detects a hex file in USB memory, the system transfers it to the internal memory as a byte sequence and executes it.

MicroPython comes with a very simple filesystem that allows programs to write files to the microcontroller and read them from there. However, even attaching data to existing files is too much for the system. The size limit is 30KB. Since the files are stored in internal memory, they can only be addressed by the running program, but not via the USB interface.

Mu

To program the micro:bit, you use the Mu editor [4], a simple Python editor. Mu recognizes the micro:bit at startup if it is connected to a computer via a USB cable. Mu will prompt you to select the BBC micro:bit mode.

Due to the integrated libraries, the resulting programs are only executable on the micro:bit. This means that run-time errors can only be analyzed and output on the micro:bit. As soon as you press the Check button, the Mu editor searches for syntax errors. For example, in Listing 2, the word hello in the second line is syntactically incorrect. The solution would be to comment out the line or quote the string (Figure 2).

Listing 2

Syntax Error

import microbit
print(hello)
print(1/0)
Figure 2: A MicroPython program with a run-time error message in the Mu editor.

Pressing the Flash button converts the program to hex code and transfers it to the micro:bit where it is executed immediately. You can restart the program via the reset button, which is just like switching on the micro:bit again by applying the supply voltage.

The code from Listing 2 terminates with a run-time error message in the Mu editor:

division by zero

The micro:bit outputs the error code as a ticker on its 5x5 LED matrix. You can look up the error code in the Mu editor by pressing the REPL (which stands for Read-Evaluate-Print-Loop) button (Figure 2).

A Simple Project

Listing 3 shows the code for a prank that delivers a high-pitched squeak when it's dark; if you turn on the light to find the sound source, the system remains silent.

Listing 3

Squeak in the Dark

01 import microbit
02 import music
03 import random
04
05 BrightTrig = 50
06
07 while True:
08   br = microbit.display.read_light_level()
09   if br < BrightTrig:
10     microbit.sleep(800 * (1+random.randrange(10)))
11     music.pitch(900, 80 * (1+random.randrange(5)))

Lines 1-3 import the required Python libraries. The micro:bit not only makes its LEDs light up, it can also use them like photodiodes. Depending on the brightness, the microbit.display.read_light_level() command returns a value between   and 255. At a value of 50, it is already quite dark (line 5).

The continuous loop introduced by while True stores the measured brightness in the variable br. If it is greater than the threshold value BrightTrig, nothing happens. Otherwise, the program calls microbit.sleep (a wait command) that lasts at least 800 milliseconds, depending on the random number random.randrange(10).

The command music.pitch generates a square wave signal of 900Hz at output  . Here too, a random generator controls the duration.

By connecting a small loudspeaker to the micro:bit contacts 0 and GND, the prank begins. Crocodile clips connect a jack plug to an amplifier's line-in input (Figure 3). The micro:bit's power is just enough to connect a ceramic speaker (the small black cylinder shown in Figure 1). You can also use a buzzer (i.e., a ceramic loudspeaker with a built-in tone generator). Then you just need to switch the output on and off again instead of modulating it at 900Hz.

Figure 3: Crocodile clips can be used to connect a jack plug to the BBC micro:bit.

MicroPython Commands

Table 2 lists the most important MicroPython commands for communicating with the micro:bit's sensors. There are commands for the matrix display (Figure 4), the buttons, and the digital input and output.

Table 2

micro:bit Commands

Function

Effect

microbit.display.show(Image.HAPPY)

Displays a smiley face on the LED matrix

microbit.display.show(Image.SAD)

Displays a frowning face on the LED matrix

microbit.display.set_pixel(1, 2, 9)

Switches the LED at position (1,2) to maximum brightness

microbit.button_a.is_pressed()

Checks whether button a is pressed

microbit.button_a.was_pressed()

Checks whether the button was pressed after switching on, or the last request

microbit.button_a.get_presses()

Counts how many times the button was pressed after the last request

microbit.accelerometer.get_x()

Reads the x-coordinates of the position sensor

microbit.pin0.read_digital()

Reads the digital input at pin 0

microbit.pin0.write_digital(1)

Sets the digital input at pin 0

music.play(music.RINGTONE)

Plays a tune if a speaker is connected to pin 0

The command is always preceded by the name of the matching MicroPython library.

Figure 4: The LEDs in the micro:bit's matrix display can be actuated at different brightness levels.

The acceleration sensor also serves as a position sensor when the module is at rest. In order not to have to deal with the orientation angles of its three axes, there is the microbit.accelerometer.current_gesture() command. It understands the orientations up, down, left, right, face up, face down, and shake.

A magnetometer with three axes is also available. In theory, it is sensitive enough to detect the direction of the Earth's magnetic field – in practice, it is difficult to do so. The temperature sensor is similar: It also measures the processor temperature. However, under no circumstances should you heat up the board with a hair dryer – be content with measuring the ambient temperature.

The microbin.pin0.is_touched() command connects the digital input via a 10m ohm pull-up resistor. The micro:bit uses this to detect if there is too high of a resistance to ground. Typically, one finger is sufficient for this, while another finger simultaneously touches the micro:bit's ground cable (GND, the large contact at bottom right on the board).

Interface

Once flashed, the microcontroller no longer accepts commands. Instead, it switches to communication and outputs its information serially via the USB connection. In Figure 5, the connected micro:bit passes the brightness value to Mu's REPL command window via the print() command. If you close the program, you get direct access to the data.

Figure 5: Outputting the brightness in the Mu REPL command window.

You already know the device name for the serial interface, in our case ttyACM3, as shown in Listing 1. The commands in Listing 4 redirect the micro:bit's output to the terminal window. The cat command returns the brightness value as a decimal number; od -x returns it as a hexadecimal number (Figure 6).

Listing 4

Redirecting Output to the Terminal

$ cat /dev/ttyACM3
$ od -x < /dev/ttyACM3
Figure 6: Data output produced by the micro:bit in a terminal window.

Hex Files

The Mu editor converts the program code into a hex file. If you disconnect the micro:bit before flashing, the Mu editor enables access to the file and asks where to store it.

The hex file consists of an 8KB MicroPython interpreter. MicroPython is a reduced Python instruction set, which feels like real Python in its basic functions. Additionally, the file contains the program's byte sequence, which the MicroPython interpreter then executes. Finally, the hex file contains a compressed version of the actual program text including comments.

Contrary to what the name might suggest, the hex file is initially a text file: The address and bytes are written out as text (Listing 5). The file therefore shrinks as soon as the system converts the ASCII text into binary numbers. This explains why a hex file of more than 500KB fits into the micro:bit's memory, which has a capacity of 256KB – including the Micropython interpreter. In the end there are about 8KB of physical memory for your own python scripts.

Listing 5

Sample Hex File

:020000040000FA
:1000000000400020218E01005D8E01005F8E010006
:1000100000000000000000000000000000000000E0
[...]

Flashing the micro:bit via a connected computer is a more elegant solution. The micro:bit logs on to the computer's filesystem as a USB stick, so you just need to copy the hex file to it. If the micro:bit recognizes the format, it converts the content into a byte sequence and immediately writes it to its flash memory. Otherwise, the file remains in USB memory, just like on a normal memory stick.

Although flashing always overwrites the old data, the data is retained when the power supply is disconnected. The micro:bit executes the program once it has been loaded, as soon as you resupply power.

Outlook

While the micro:bit's MicroPython software is documented in detail [5], the hardware is not. The outputs are probably short-circuit proof; they possibly also limit the current to 10 or 90mA. However, there are no reliable statements about this. For this reason, you should only connect light emitting diodes via a protective resistor.

The microcontroller has a wide range of internal interfaces; it can handle I2C, SPI, LIN, and UART, as well as USB and USB OTG. Many of the 23 inputs/outputs are also routed to the outside, but only as simple PCB plug contacts, which can only be used with a special connector.

Calliope Mini [6], a project managed by Germany's Calliope gGmbH, describes itself as a further development of the micro:bit. Calliope Mini circuit diagrams and software are freely available as open hardware or open source, and there are also several manuals as open educational resources.

Calliope Mini's circuit board has additional sensors like a microphone and loudspeaker, as well as four I/O contacts for crocodile clips (instead of the micro:bit's three I/O contacts). The two modules do not differ in terms of memory size. The Calliope developers route all other interface contacts to the outside via an easily accessible pin headers. This might be a more reliable solution than the extension board required for the micro:bit. On the other hand, the community and its comments on the Internet are much more for micro:bit than for ohter MicroPython-based educational boards.

Conclusions

The BBC micro:bit offers an introduction to microcontroller programming and teaches how to use modern high-level languages like Python.

However, the MicroPython interpreter eats up memory and impacts speed. If you are looking to push a microcontroller to its limits, Arduino and its programming environment are a better option.