Rust on embedded – getting the tools

Rust has at least an evens chance of being the future programming language of small embedded systems. If it’s in your future, shouldn’t you at least know about it?

This series of blog posts will take you through the steps needed to install a toolset for embedded development on Cortex-M boards and create a simple application using Rust. But first let’s look at the basic question: why?

Rust and its ecosystem

Rust as a programming language makes claims that are unheard of in our industry. Combining native compiled code with strong claims about memory safety and preventing data races is unique. But that is not enough to make a programming language productive for software development in general and embedded development in particular. To be productive you need a toolset that makes the entire edit-compile-run/debug cycle efficient.

Nowadays that means:

  • a compiler with meaningful error messages,
  • an IDE with syntax-highlighting, completion, re-factoring and integrated debugging,
  • a built tool that knows how to build the mostly used targets by default,
  • support for unit-testing, continuous integration and benchmarking,
  • a dependency manager that makes it easy to integrate existing libraries into your code base
  • and an ecosystem with a huge amount of open source libraries.

Today (November 2017) Rust can check 5 of the 6 bullets points above. For people coming from a background in programming languages like Java and C# the IDE support will still feel like we are living in the early 90s. Today, IDE’s like Visual Studio Code and IntelliJ IDEA (community edition) provide Rust plugins with basic completion, re-factoring and debugging support. The Rust community has recognized that ‘great IDE support’ is necessary for adoption of the language and is tracking its progress on https://areweideyet.com/.

Setting up the tools

This post is going to walk you through the necessary steps to get all the tools up and running. This post assumes a real operating system like Linux or OS X.

Step 1: Getting stuff to compile

In the edit-compile-run/debug cycle we will first focus on ‘compile’.

Rustup

First: the rust toolchain manager, rustup. Go to https://rustup.rs/ and install rustup. This will install a series of tools:

  • rustup, the toolchain manager,
  • the default stable compiler for your platform,
  • the built-tool cargo,
  • the API documentation and
  • the sources for the standard libraries

Check your installation with the rustup show command. My output is:

Default host: x86_64-apple-darwin

stable-x86_64-apple-darwin (default)
rustc 1.22.1 (05e2e1c41 2017-11-22)

The nightly compiler and Rust sources

For embedded development, you currently need features that are not yet stabilised and are therefore not available in the stable compiler. Execute rustup toolchain add nightly to add the nightly compiler and rustup component add rust-src to add the Rust sources. Again, use rustup show to check your installation:

Default host: x86_64-apple-darwin

installed toolchains
 --------------------

stable-x86_64-apple-darwin
nightly-x86_64-apple-darwin

active toolchain
 ----------------

stable-x86_64-apple-darwin (default)
rustc 1.22.1 (05e2e1c41 2017-11-22)

and rustup component list to check the installed components:

>>SNIP<< rust-docs-x86_64-apple-darwin (default) rust-src (installed) >>SNIP<<

Staying up to date

Keeping your compilers up to date is simple: rustup update and wait. You can pick (and pin) specific versions of the compiler using rustup. Example: rustup toolchain add 1.20.

Installing the ARM gcc toolchain

Rust’s compiler will use the platform native linker to link to final binaries. For ARM on embedded that is arm-none-eabi-ld. Head to https://developer.arm.com/open-source/gnu-toolchain/gnu-rm/downloads and install the latest ARM toolchain for your platform. Making the binaries available in your $PATH makes life a lot easier.

Cross-compiling using Xargo

Xargo is a cross-compiling tool for Rust. Xargo is a wrapper around cargo that handles compiling Rust’s core libraries for your target. Installing Xargo is as simple as executing cargo install xargo in your shell.

Step 2: Running your code on the board

Getting your code to run on the board, means getting it on the board first. This post assumes that you are using the BlackMagicProbe/Bluepill to connect to your target board. If that is the case you need to tell the debugger, arm-none-eabi-gdb to use the BlackMagicProbe using the USB-serial connection. That means, entering this at the GDB prompt:

target extended-remote /dev/ENTER_YOUR_DEVICE_HERE

bobbin-cli

There is a tool available that scans your system for available debuggers. It is called bobbin-cli and can simply be installed using Rust’s build tool cargo:
cargo install bobbin-cli. This will download, compile and install bobbin-cli using your default compiler.

Bobbin needs dfu-util to work, so on Linux do sudo apt install dfu-util (or equivalent), on a Mac do: brew install dfu-util or equivalent.  Run bobbin check to see what tools it finds. My output:

 Bobbin 0.8.0
 Rust 1.23.0-nightly (246a6d19c 2017-11-23)
 Cargo 0.24.0-nightly (abd137ad1 2017-11-12)
 Xargo 0.3.8
 GCC 6.3.1 20170215 (release) [ARM/embedded-6-branch revision 245512]
 OpenOCD Not Found
 JLink Not Found
 Bossa Not Found
 Teensy Not Found
 dfu-util 0.9

Finding your board

Now connect your debugger board and execute: bobbin list. On my system this shows:

ID        VID:PID  Vendor / Product                         Serial Number           
2700e45b 1d50:6018 Black Sphere Technologies / Black Magic Probe (Bluepill), (Firmware v1.6-rc0-338-g798d883) C4D6A8F0

bobbin info shows on what device the debugger ports are available:

ID               2700e45bdf2fa10f6dbe1cb90d3894c8679762f2
Vendor ID        1d50
Product ID       6018
Vendor           Black Sphere Technologies
Product          Black Magic Probe (Bluepill), (Firmware v1.6-rc0-338-g798d883)
Serial Number    C4D6A8F0
Type             BlackMagicProbe
Loader Type      blackmagic
Debugger Type    blackmagic
CDC Device       /dev/cu.usbmodemC4D6A8F3
GDB Device       /dev/cu.usbmodemC4D6A8F1

Unsurprisingly, to debug we use the GDB Device.

In the next post we will be creating some example code and running it.

Leave a Reply

Be the First to Comment!

Notify of
avatar
wpDiscuz