Article summary
I’ve written a few posts on using Rust for embedded projects:
- Rust Sysroots for Easier Embedded Projects
- Using Rust 1.8 Stable for Building Embedded Firmware
- Generating Rust Bindings for Embedded Libraries
- Embedded Rust Right Now!
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 validlibcore
- 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 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 :)
Download ARM gcc from here 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 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!
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