Using Rust in an Embedded Project: A Simple Example

I’ve written a few posts on using Rust for embedded projects:

I think they gave a decent overview of a couple of tricky parts, but as always, the devil is in the details. To help with all the gritty details, I’ve written up a more complete example.

Overview

In order to actually run this example, you’ll need an STM32L1 Discovery Board. I don’t expect many readers to have this exact board, but it should be relatively easy to port to other targets/boards, and I thought a complete example would be useful as a point of comparison. This is basically just STM’s GPIO_IOToggle example but with the core inner loop replaced with some Rust code.

Essentially what I did was:

  • Started with STM’s GPIO_IOToggle example
  • Added a Makefile to build the example
  • Setup the Cargo configuration necessary to target a Cortex-M3 in.cargo/config
  • Added rules to the Makefile to build a Rustsysroot containing a validlibcore
  • Used bindgen to wrap the STM32 HAL libraries for use in Rust
  • Replaced the core inner loop inmain.c of the GPIO_IOToggle example with Rust code
  • Added rules to the Makefile to build the Rust code and link the resulting static library into the final binary

Running My Example

To run my example:

Grab a Rust nightly

  • Install multirust fromhere if you haven’t already
  • Runmultirust update nightly

Make a directory to work in

mkdir embedded_rust_experimentcd embedded_rust_experimentmultirust override nightly

Clone my embedded Rust example

git clone https://github.com/jvranish/rust-embedded-example.git

Clone Rust src into sibling directory

We need to clone the Rust repo:

git clone[email protected]:rust-lang/rust.git

And then we need to check out the commit that matches the version of our compiler. To find the commit for our current compiler you can do this:

$ rustc -vVrustc 1.11.0-nightly (ad7fe6521 2016-06-23)binary: rustccommit-hash: ad7fe6521b8a59d84102113ad660edb21de2cba6commit-date: 2016-06-23host: x86_64-apple-darwinrelease: 1.11.0-nightly

And then check out that specific commit:

cd rustgit checkout 8903c21d618fd25dca61d9bb668c5299d21feac9cd ..

Your commit-hash will almost certainly be different than what I have here. Don’t just copy what I have :)

Download ARM gcc fromhere and put it into a sibling directory. In my case, I put it in../tools/gcc-arm-none-eabi-5_3-2016q1/

Get STM32 Cube for L1 line

Get the Cube HAL fromhere and put it into sibling directory. In my case, I put it in../STM32Cube_FW_L1_V1.5.0/

Install openocd

Install my favorite debugger toolchain. On macOS, if you haveHomebrew installed, you can just do this:

brew install openocd

Run example

Open upMakefile inembedded_rust_experiment and make sure the variables:GCC_ARM_PATH,STM32_CUBE_PATH andRUST_SRC_PATH are set to sensible values.

Then to run the example:

  • In one console, run openocd.
cd rust-embedded-examplemake openocd
  • In another console, build and debug.
cd rust-embedded-examplemake debug

When the gdb prompt shows up, you should be able to pressc and enter. Then you should see blinking lights on your discovery board. That’s it!

Keep up with our latest posts.

We’ll send our latest tips, learnings, and case studies from the Atomic braintrust on a monthly basis.

[mailpoet_form]
Conversation
  • Hi Job,

    Thanks for all your great Rust articles! I’m excited too about what Rust might mean for embedded development.

    I’m trying to build your example here, but I’m having a problem building rust_src with cargo though. I have the the rust source in a sibling directory, and it matches my nightly rustc installation commit. I’m trying to build rust_src via the build-rust make target.

    The sysroot with libcore builds fine, but I’m getting an error when it tries to build rust_src:

    $ make build-rust

    mkdir -p build/sysroot/lib/rustlib/thumbv7m-none-eabi/lib
    rustc –target thumbv7m-none-eabi ../rust/src/libcore/lib.rs –out-dir build/sysroot/lib/rustlib/thumbv7m-none-eabi/lib/

    cargo build –manifest-path rust_src/Cargo.toml –verbose
    Fresh stm32l1hal v0.1.0 (file:///vagrant/rust-embedded-example/stm32l1hal_bindings)
    Compiling rust_src v0.1.0 (file:///vagrant/rust-embedded-example/rust_src)
    Running `rustc rust_src/src/lib.rs –crate-name rust_src –crate-type staticlib -g -C metadata=ecc1d366e0b3e683 –out-dir /vagrant/rust-embedded-example/build/thumbv7m-none-eabi/debug/deps –emit=dep-info,link –target thumbv7m-none-eabi -L dependency=/vagrant/rust-embedded-example/build/thumbv7m-none-eabi/debug/deps –extern stm32l1hal=/vagrant/rust-embedded-example/build/thumbv7m-none-eabi/debug/deps/libstm32l1hal.rlib –sysroot build/sysroot`

    error: failed to link `/vagrant/rust-embedded-example/build/thumbv7m-none-eabi/debug/deps/librust_src.a` to `/vagrant/rust-embedded-example/build/thumbv7m-none-eabi/debug/librust_src.a`

    Caused by:
    Operation not permitted (os error 1)
    make: *** [build-rust] Error 101

    Do you know what’s happening in the this “link” step? The library name is the same, but just in different folders. I am running in a Vagrant instance, which sometimes can have permission problems.

    Matt

  • Comments are closed.