Blinking an STM32 with Rust from MacOS
Tags:
Bottom Line: I blinked an LED in Rust. I’ve been increasingly enthusiastic about Mozilla’s new open source programming language Rust over the last year or so. There is lots to read about the reasons that different people like rust, so I’ll spare you the details, but I think it’s exciting that even an amateur like myself can enjoy such a powerful, fast, and safe language.
One of the many promising things about Rust is its potential for safer and more ergonomic low-level programming in the embedded world; I’ve been keeping a casual eye on progress here as a tinkerer that really don’t know much C++ (and so my Arduino and ATMEGA328p adventures tend to be pretty tame).
Recently, a quick glance through a thread on r/rust (which has been one of several examples of Rust’s unusually welcoming community) suggested that the STM32 boards were a good way for a beginner to get started in embedded rust, so I picked one up.
I found a really great “hello world” walkthrough that took me most of
the way. Much of it has been copied verbatim below, though a few steps are
slightly different, and linked post has much more information about the steps
being taken, so I highly recomend you read through it. I’ve also put a basic
framework up as a git repo at
github.com/n8henrie/rust-stm32; it
already has the memory file, .cargo/config
, and Cargo.toml
as well as the
basic main.rs
; once dependencies are installed, if you clone it you should be
able to cargo build
get a binary you can use. The step below essentially walk
you through making your own identical repo, (like the author of the linked
blog post has also done here).
Requirements:
- STM32 bluepill
- FTDI for programming it (which seems to work fine instead of an ST-Link)
- Working rust setup (including
rustup
andcargo
, I’m on rust 1.34.1)
Step by step:
cargo install cargo-binutils
andrustup component add llvm-tools-preview
to get thecargo objcopy
commands cargo-binutils reporustup target add thumbv7m-none-eabi
(note this is7m
and not7em
, which may be a typo in the how-to post linked above)- make a new crate:
cargo new rust-stm32 && cd rust-stm32
- edit
Cargo.toml
to match this example - make
memory.x
as instructed here:$ cat > memory.x <<EOF /* Linker script for the STM32F103C8T6 */ MEMORY { FLASH : ORIGIN = 0x08000000, LENGTH = 64K RAM : ORIGIN = 0x20000000, LENGTH = 20K } EOF
- Add to
./.cargo/config
:[build] # Instruction set of Cortex-M3 (used in BluePill) target = "thumbv7m-none-eabi" rustflags = [ # use the Tlink.x script from the cortex-m-rt crate "-C", "link-arg=-Tlink.x", ]
- make
src/main.rs
:- Example: https://github.com/n8henrie/rust-stm32/blob/master/src/main.rs
- My STM was already blinking a few times per second by default, so consider changing the delay by an order of magnitude to make sure your code is being executed
cargo build --release
cargo objcopy -- -O binary target/thumbv7m-none-eabi/release/rust-stm32 rust-stm32.bin
- Build
stm32loader
to flash the code to the STM32 from MacOS:- Clone repo:
git clone https://github.com/florisla/stm32loader.git
cd stm32loader
- Make venv:
python3 -m venv .venv
- Source venv:
source ./.venv/bin/activate
- Update pip to >= 19.1.1
pip install --upgrade pip
- Install in editable mode:
pip install -e .
- Clone repo:
-
Connect the (unplugged) FTDI to the STM32 (as a mnemonic, remember “Tx to Ten”, and also make sure your FTDI is set to 3.3v)
FTDI STM32 TX A10 RX A9 3V 3V GND GND - Move the jumper for BOOT0 (the one closer to edge of board) from 0 to 1 (3.3v)
- Flash the program:
stm32loader -p /dev/tty.usb1 -e -w -v /path/to/rust-stm32.bin
, where flags are for port, erase, write, and verify - If it looks like it flashed correctly, disconnect it, move BOOT0 back to 0 / off, reconnect power, and see if you have a blinking light!
Links: