Getting started with rust on the stm32f411 'black pill' + fibonacci
Jack Everett Fletcher November 22, 2021 [Learning] #rustGuide to setup stm32f411 + fibonacci program
This is just a helpful resource to setup programming your stm32f411 with Rust.
Generate your project
Follow along closely with the README from the knurling app-template here.
After installing the recommended tools and generating your project, you'll have to change some things specific to the stm32f411. You may either do it yourself (it's not too hard) or follow along below. ⬇️
Change .cargo/config.toml
You'll need to set the runner to be runner = "probe-run --chip stm32f411"
.
You also should set the target to take advantage of the capabilities of the board. Set your target such that target = "thumbv7em-none-eabihf"
Your .cargo/config.toml should look like this:
[]
# TODO(2) replace `$CHIP` with your chip's name (see `probe-run --list-chips` output)
= "probe-run --chip stm32f411"
= [
"-C", "linker=flip-link",
"-C", "link-arg=-Tlink.x",
"-C", "link-arg=-Tdefmt.x",
# This is needed if your flash or ram addresses are not aligned to 0x10000 in memory.x
# See https://github.com/rust-embedded/cortex-m-quickstart/pull/95
"-C", "link-arg=--nmagic",
]
[]
# TODO(3) Adjust the compilation target.
# (`thumbv6m-*` is compatible with all ARM Cortex-M chips but using the right
# target improves performance)
#target = "thumbv6m-none-eabi" # Cortex-M0 and Cortex-M0+
# target = "thumbv7m-none-eabi" # Cortex-M3
# target = "thumbv7em-none-eabi" # Cortex-M4 and Cortex-M7 (no FPU)
= "thumbv7em-none-eabihf" # Cortex-M4F and Cortex-M7F (with FPU)
[]
= "run --bin"
= "run --release --bin"
You'll likely have to install the desired toolchain. Run rustup target add thumbv7em-none-eabihf
to get it.
Change Cargo.toml
You'll have to change # some-hal = "1.2.3"
to instead use stm32f4xx-hal
.
🚨NOTE🚨 At the time of writing, the latest published version stm32f4xx-hal = "0.10.1"
does NOT support the latest cortex-m-rt = "0.7.0"
, only 0.6.15
.
Until they publish a new version on crates.io, I recommend you point that dependency to their github, and lock into a specific commit. It'll look something like this:
[]
= "https://github.com/stm32-rs/stm32f4xx-hal"
= "7ac6eff758d7159e53c557db4c24474edfbd42bc"
= ["rt", "stm32f411"]
Your full Cargo.toml will look similar to the following:
[]
# TODO(1) fix `authors` and `name` if you didn't use `cargo-generate`
= ["Your Name <your_name@email.com>"]
= "generated-stm32f411-fun"
= "2018"
= "0.1.0"
[]
= ["testsuite"]
[]
= "0.7.3"
= "0.7.0"
= "0.3.0"
= "0.3.0"
= { = "0.3.0", = ["print-defmt"] }
[]
= "https://github.com/stm32-rs/stm32f4xx-hal"
= "7ac6eff758d7159e53c557db4c24474edfbd42bc"
= ["rt", "stm32f411"]
# cargo build/run
[]
= 1
= 2
= true # <-
= false
= 3 # <-
= true # <-
# cargo test
[]
= 1
= 2
= true # <-
= false
= 3 # <-
= true # <-
# cargo build/run --release
[]
= 1
= 2
= false # <-
= false
= 'fat'
= 3 # <-
= false # <-
# cargo test --release
[]
= 1
= 2
= false # <-
= false
= 'fat'
= 3 # <-
= false # <-
# uncomment this to switch from the crates.io version of defmt to its git version
# check app-template's README for instructions
# [patch.crates-io]
# defmt = { git = "https://github.com/knurling-rs/defmt", rev = "use defmt version reported by `probe-run --version`" }
# defmt-rtt = { git = "https://github.com/knurling-rs/defmt", rev = "use defmt version reported by `probe-run --version`" }
# defmt-test = { git = "https://github.com/knurling-rs/defmt", rev = "use defmt version reported by `probe-run --version`" }
# panic-probe = { git = "https://github.com/knurling-rs/defmt", rev = "use defmt version reported by `probe-run --version`" }
Change src/lib
Your project should use the right hal package. Update use some_hal as _;
to use stm32f4xx_hal as _;
Your src/lib.rs should look like this:
use defmt_rtt as _; // global logger
// TODO(5) adjust HAL import
use stm32f4xx_hal as _; // memory layout
use panic_probe as _;
// same panicking *behavior* as `panic-probe` but doesn't print a panic message
// this prevents the panic message being printed *twice* when `defmt::panic` is invoked
!
/// Terminates the application and makes `probe-run` exit with exit-code = 0
!
Add memory.x
On the stm32f411, your memory.x should be placed at the root of your project. It'll look like this:
MEMORY
{
/* NOTE K = KiBi = 1024 bytes */
FLASH : ORIGIN = 0x08000000, LENGTH = 512K
RAM : ORIGIN = 0x20000000, LENGTH = 128K
}
/* This is where the call stack will be allocated. */
/* The stack is of the full descending type. */
/* NOTE Do NOT modify `_stack_start` unless you know what you are doing */
_stack_start = ORIGIN(RAM) + LENGTH(RAM);
Debugger setup
Both st-link and stm32f411 in one pic:
code 🦀
Below is the full file. Create src/bin/fib_fun.rs
You can run it with cargo run fib_fun
src/bin/fib_fun.rs
!
Interesting note about the below snippet:
.enumerate.for_each;
Why didn't we just skip the .enumerate() call, and write the following?
.for_each;
The index of a slice must absolutely be of type usize
; the program won't compile if it's anything else. You'd get the following error if you tried:
error[E0277]: the type `[u8]` cannot be indexed by `u8`
--> src/bin/fib_fun.rs:17:9
|
17 | nums[elem] = elem;
| ^^^^^^^^^^ slice indices are of type `usize` or ranges of `usize`
|
= help: the trait `SliceIndex<[u8]>` is not implemented for `u8`
= note: required because of the requirements on the impl of `Index<u8>` for `[u8]`