My notes from implementing Job Vranish's excellent guide.
Follow along with the guide above, getting rustc from rustup or similar:
rustc 1.0.0-nightly (dcaeb6aa2 2015-01-18 11:28:53 +0000)
binary: rustc
commit-hash: dcaeb6aa23ecba2dc2af870668a9239136d20fa3
commit-date: 2015-01-18 11:28:53 +0000
host: x86_64-unknown-linux-gnu
release: 1.0.0-nightly
(I have a nightly just around alpha2).
Then we want a target spec. The two linked examples work but for hard float support (which my C tends to get built with) we need to swap the llvm-target to thumbv7em-none-eabihf
, as in thumbv7em-none-eabihf in this gist.
Create a folder to work in, grab Rust, build libcore:
$ mkdir embedded-rust
$ cd embedded-rust
$ git clone [email protected]:rust-lang/rust.git
$ cd rust
$ git checkout dcaeb6aa23ecba2dc2af870668a9239136d20fa3
$ cd ..
$ vi thumbv7em-none-eabihf # Get thumbv7-none-eabihf from this gist
$ mkdir libcore-thumbv7em-none-eabihf
$ rustc -C opt-level=2 -Z no-landing-pads --target thumbv7em-none-eabihf -g rust/src/libcore/lib.rs --out-dir libcore-thumbv7em-none-eabihf
Now create a new STM32 project. Here I'll use libopencm3.
$ mkdir example
$ cd example
$ git clone https://github.com/libopencm3/libopencm3.git
$ cd libopencm3
$ make -j8
$ cd ..
Finally we write some C code (with our main function, though main could just as happily go in the Rust code), a sample Rust file with a single function we'll call from the C, and a Makefile (from the libopencm3 project). The Makefile is modified slightly to support rust code compilation (see Makefile-notable). Then we build it and try it out!
$ vi example.c # From this gist
$ vi test_rust.rs # From this gist
$ vi Makefile # From this gist
$ cp ../thumbv7em-none-eabihf . # There's probably a better way to reference this
$ make
$ make debug
(gdb) break main
Breakpoint 1 at 0x80001ae: file example.c, line 9.
(gdb) run
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /home/adam/Projects/embedded-rust/example/example.elf
Note: automatically using hardware breakpoints for read-only addresses.
Breakpoint 1, main () at example.c:9
9 volatile uint32_t a = 5;
(gdb) s
10 volatile uint32_t b = 6;
(gdb)
11 volatile uint32_t c = test_add(a, b);
(gdb)
test_rust::test_add (a=5, b=6) at test_rust.rs:36
36 return a + b;
(gdb)
37 }
(gdb)
main () at example.c:12
12 (void)c;
(gdb) p c
$1 = 11