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 Rust `sysroot` containing a valid `libcore`
– Used bindgen to wrap the STM32 HAL libraries for use in Rust
– Replaced the core inner loop in `main.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 from [here](https://github.com/brson/multirust) if you haven’t already
– Run `multirust update nightly`

###Make a directory to work in


mkdir embedded_rust_experiment
cd embedded_rust_experiment
multirust 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 -vV
rustc 1.11.0-nightly (ad7fe6521 2016-06-23)
binary: rustc
commit-hash: ad7fe6521b8a59d84102113ad660edb21de2cba6
commit-date: 2016-06-23
host: x86_64-apple-darwin
release: 1.11.0-nightly

And then check out that specific commit:


cd rust
git checkout 8903c21d618fd25dca61d9bb668c5299d21feac9
cd ..

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

###Get ARM gcc

Download ARM gcc from [here](https://launchpad.net/gcc-arm-embedded) 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 from [here](http://www.st.com/content/st_com/en/products/embedded-software/mcus-embedded-software/stm32-embedded-software/stm32cube-embedded-software/stm32cubel1.html#getsoftware-scroll) 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 have Homebrew installed, you can just do this:


brew install openocd

###Run example

Open up `Makefile` in `embedded_rust_experiment ` and make sure the variables: `GCC_ARM_PATH`, `STM32_CUBE_PATH` and `RUST_SRC_PATH` are set to sensible values.

Then to run the example:

– In one console, run openocd.


cd rust-embedded-example
make openocd

– In another console, build and debug.


cd rust-embedded-example
make debug

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

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.