Rust on the micro:bit 101 part 1

About this tutorial/guide

Motivation

In this issue on my github repository for the Micro:bit Rust board support crate I’ve been asked to provide a tutorial or howto about how to get started with using the crate and starting to program the BBC Micro:bit (which is a rather cool and cheap fully equipped micro controller board meant for teaching computer science to kids in school). Since there’re not really a tutorial covering everything from 0 to a working application, this is my attempt on providing that based on an available and affordable kit.

Similar work

The Rust embedded working group started work on a new, more comprehensive book about embedded programming with Rust. Parts of this book will take over content from Jorge Aparicios’ Discovery Book which is a bit outdated and also on a bit more advanced level than what I would like to present here. His blog is also a nice ressource of extended information in this domain.

Structure

I’m planning to cover everything from the pre-requisites to programming full programs using built-in peripherals as well as on-board and external components over a series of posts, explaining all important aspects along the way.

This first part will cover the installation of the toolchain and show you how to exercise and test your setup. There will be follow-ups explaining the Rust embedded ecosystem, additional tools, the structure of an application, how to use peripherals, common pitfalls and more…

So let’s dive right in.

The toolchain

Rust has the nice property that there are tools available providing an easy way to bootstrap the compiler and set up an environment without any hassles. The main tool that will get you started is called rustup. Unfortunately I can only cover the installation on Unixish OSes here, if you’re on Windows, please follow the instruction on this page.

Please note that although big steps have been achieved towards being able to use a stable rust version, this is not quite reality and also requires jumping through some annoying hoops so I’ll still use nightly for now.

Rustc

So to get going (I’m using a Linux Mint 18.3 system here) you simply start the interactive rustup installation tool like this:

$ curl https://sh.rustup.rs -sSf | sh -s -- --default-toolchain nightly
info: downloading installer

Welcome to Rust!

This will download and install the official compiler for the Rust programming
language, and its package manager, Cargo.

It will add the cargo, rustc, rustup and other commands to Cargo's bin
directory, located at:

  /home/egger/.cargo/bin

This path will then be added to your PATH environment variable by modifying the
profile file located at:

  /home/egger/.profile

You can uninstall at any time with rustup self uninstall and these changes will
be reverted.

Current installation options:

   default host triple: x86_64-unknown-linux-gnu
     default toolchain: nightly
  modify PATH variable: yes

1) Proceed with installation (default)
2) Customize installation
3) Cancel installation
1

info: syncing channel updates for 'nightly-x86_64-unknown-linux-gnu'
info: latest update on 2018-05-31, rust version 1.28.0-nightly (5d0631a64 2018-05-30)
info: downloading component 'rustc'
 68.2 MiB /  68.2 MiB (100 %)  11.2 MiB/s ETA:   0 s
info: downloading component 'rust-std'
 51.4 MiB /  51.4 MiB (100 %)  11.9 MiB/s ETA:   0 s
info: downloading component 'cargo'
info: downloading component 'rust-docs'
info: installing component 'rustc'
info: installing component 'rust-std'
info: installing component 'cargo'
info: installing component 'rust-docs'
info: default toolchain set to 'nightly'

  nightly installed - rustc 1.28.0-nightly (5d0631a64 2018-05-30)


Rust is installed now. Great!

To get started you need Cargo's bin directory ($HOME/.cargo/bin) in your PATH
environment variable. Next time you log in this will be done automatically.

To configure your current shell run source $HOME/.cargo/env

Rust MCU support

The Micro:bit runs with a microcontroller of the ARM Cortex-M0 kind. To add support for this architecture to rust you’ll need to add a component:

$ rustup target install thumbv6m-none-eabi
info: downloading component 'rust-std' for 'thumbv6m-none-eabi'
info: installing component 'rust-std' for 'thumbv6m-none-eabi'

GNU dependencies

At the moment it is also still necessary to install various GNU utilities for efficient work. This will hopefully become superfluous in the nearer future but for now the workarounds are still a bit awkward so let’s install them. For Debian(-ish) OSes you can simply install the packages using apt-get like:

$ sudo apt-get install binutils-arm-none-eabi gcc-arm-none-eabi
Reading package lists... Done
Building dependency tree
Reading state information... Done
The following NEW packages will be installed:
  binutils-arm-none-eabi gcc-arm-none-eabi
0 upgraded, 2 newly installed, 0 to remove and 34 not upgraded.
Need to get 19.4 MB of archives.
After this operation, 145 MB of additional disk space will be used.
Get:1 http://ftp.uni-stuttgart.de/ubuntu xenial/universe amd64 binutils-arm-none-eabi amd64 2.26-4ubuntu1+8 [2,083 kB]
Get:2 http://ftp.uni-stuttgart.de/ubuntu xenial/universe amd64 gcc-arm-none-eabi amd64 15:4.9.3+svn231177-1 [17.3 MB]
Fetched 19.4 MB in 2s (8,386 kB/s)
Selecting previously unselected package binutils-arm-none-eabi.
(Reading database ... 276397 files and directories currently installed.)
Preparing to unpack .../binutils-arm-none-eabi_2.26-4ubuntu1+8_amd64.deb ...
Unpacking binutils-arm-none-eabi (2.26-4ubuntu1+8) ...
Selecting previously unselected package gcc-arm-none-eabi.
Preparing to unpack .../gcc-arm-none-eabi_15%3a4.9.3+svn231177-1_amd64.deb ...
Unpacking gcc-arm-none-eabi (15:4.9.3+svn231177-1) ...
Processing triggers for man-db (2.7.5-1) ...
Processing triggers for libc-bin (2.23-0ubuntu10) ...
Setting up binutils-arm-none-eabi (2.26-4ubuntu1+8) ...
Setting up gcc-arm-none-eabi (15:4.9.3+svn231177-1) ...
Processing triggers for libc-bin (2.23-0ubuntu10) ...

For other operating systems there might also be packages available to be installed with the resident package management. If not, please refer to ARMs website to download and install a pre-packaged generic GCC and binutils toolchain.

microbit crate

In order to test the installation we’re going to clone my microbit crate so we have something to compile and play with:

$ git clone https://github.com/therealprof/microbit
Cloning into 'microbit'...
remote: Counting objects: 202, done.
remote: Compressing objects: 100% (16/16), done.
remote: Total 202 (delta 8), reused 8 (delta 4), pack-reused 182
Receiving objects: 100% (202/202), 41.34 KiB | 244.00 KiB/s, done.
Resolving deltas: 100% (119/119), done.

Test the setup

So with everything important downloaded and installed we should be able to test the compilation.

To do so, change to the downloaded microbit clone and let’s compile the included examples:

$ cargo build --release --examples
    Updating registry `https://github.com/rust-lang/crates.io-index`
  Installing microbit v0.5.0
 Downloading vcell v0.1.0
 Downloading numtoa v0.0.7
 Downloading cortex-m v0.5.2
 Downloading nb v0.1.1
 Downloading nrf51-hal v0.5.0
 Downloading static-ref v0.2.1
 Downloading rand v0.4.2
 Downloading cortex-m-rt v0.5.1
 Downloading volatile-register v0.2.0
 Downloading mag3110 v0.1.2
 Downloading panic-abort v0.1.1
 Downloading aligned v0.2.0
 Downloading bare-metal v0.2.0
 Downloading cc v1.0.17
 Downloading embedded-hal v0.2.1
 Downloading cast v0.2.2
 Downloading void v1.0.2
 Downloading nrf51 v0.5.0
 Downloading r0 v0.2.2
 Downloading embedded-hal v0.1.3
   Compiling cc v1.0.17
   Compiling vcell v0.1.0
   Compiling r0 v0.2.2
   Compiling nrf51 v0.5.0
   Compiling nb v0.1.1
   Compiling aligned v0.2.0
   Compiling bare-metal v0.2.0
   Compiling void v1.0.2
   Compiling cast v0.2.2
   Compiling static-ref v0.2.1
   Compiling panic-abort v0.1.1
   Compiling numtoa v0.0.7
   Compiling rand v0.4.2
   Compiling volatile-register v0.2.0
   Compiling embedded-hal v0.2.1
   Compiling embedded-hal v0.1.3
   Compiling mag3110 v0.1.2
   Compiling cortex-m v0.5.2
   Compiling cortex-m-rt v0.5.1
   Compiling nrf51-hal v0.5.0
   Compiling microbit v0.5.0 (file:///home/egger/microbit)
    Finished release [optimized + debuginfo] target(s) in 26.96s

If your build looks like this: Concratulations, you now have a number of executables for your Micro:bit in target/thumbv6m-none-eabi/release/examples/

$ ls -l target/thumbv6m-none-eabi/release/examples/
-rwxr-xr-x 2 egger egger 158056 May 31 19:06 gpio_direct_blinky
-rwxr-xr-x 2 egger egger 174340 May 31 19:06 gpio_hal_blinky
-rwxr-xr-x 2 egger egger 171964 May 31 19:06 gpio_hal_ledbutton
-rwxr-xr-x 2 egger egger 273276 May 31 19:06 gpio_hal_printbuttons
-rwxr-xr-x 2 egger egger 349300 May 31 19:06 gpio_hal_receivedcf77
-rwxr-xr-x 2 egger egger 269184 May 31 19:06 i2c_direct_printmagserial
-rwxr-xr-x 2 egger egger 303892 May 31 19:06 i2c_haldriver_printmagserial
-rwxr-xr-x 2 egger egger 297640 May 31 19:06 i2c_hal_printmagserial
-rwxr-xr-x 2 egger egger 253400 May 31 19:06 rng_direct_printrngserial
-rwxr-xr-x 2 egger egger 303120 May 31 19:06 rng_hal_printrandserial
-rwxr-xr-x 2 egger egger 166284 May 31 19:06 serial_direct_echo
-rwxr-xr-x 2 egger egger 163648 May 31 19:06 serial_direct_helloworld
-rwxr-xr-x 2 egger egger 186016 May 31 19:06 serial_hal_blocking_echo

For now you can flash those to your Micro:bit by dragging and dropping them onto the virtual disk created by the Micro:bit. And don’t worry about the size for now; those files include debugging symbols which we’ll use later. Oh, and if the flasher comes back after a while with a time out error: Don’t worry, the built-in flasher is not the brightest kid around the block.

And that’s it for this part. If you have any suggestions what to cover in the next part, feel free to contact me; the same applies if you find any errors in the text. Also feel free to open issues on github or send me pull requests.