I am developing a secure, cloud-connected home monitoring system using the B-U585I-IOT02A development board, which contains an STM32U585 Arm Cortex-M33 microcontroller. The firmware is divided into a C bootloader and a Rust application. The bootloader occupies the first 256 KiB of internal flash and launches the Rust application from 0x08040000.
The Rust application will handle onboard sensor acquisition and later Wi-Fi, MQTT over TLS and AWS IoT Core communication. The bootloader-to-application handover has been verified on the hardware, and the current work is establishing peripheral access and UART output from Rust. Further details are available in my previous post about the secure STM32 home monitoring project with Rust.
This is a short post to get you familiar with some of the fundamental terminology that you will come across in a typical Rust project. By no means is this comprehensive, but it is enough to get you going.
The Rust application uses Cargo as its build and dependency-management system.
Installing Rust and Cargo on Ubuntu
Cargo is installed with the Rust toolchain through rustup. On Ubuntu, install curl if it is not already available:
sudo apt updatesudo apt install curl
Install Rust, Cargo and rustup using the official installer:
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
The command can be broken down as follows:
curldownloads content from a URL.--proto '=https'permits only HTTPS.--tlsv1.2requires TLS 1.2 or later.-shides the normal download progress.-Sdisplays an error if the download fails.-fmakes the command fail for HTTP server errors.https://sh.rustup.rsprovides the officialrustupinstaller script.| shsends the downloaded script directly to the shell for execution.
The script installs the Rust toolchain for the current user, normally under:
~/.rustup/~/.cargo/
The installation includes:
It also configures ~/.cargo/bin for inclusion in the shell’s PATH. It does not normally require sudo or install Rust system-wide. This is the installation command provided by the official Rust documentation.
If you prefer to inspect the script before executing it:
curl --proto '=https' --tlsv1.2 -sSf \ https://sh.rustup.rs \ -o rustup-install.shless rustup-install.shsh rustup-install.sh
Follow the on-screen instructions and select the default installation.
Load the Cargo environment and verify the installation
source "$HOME/.cargo/env"rustc --versioncargo --version
Install the Arm Cortex-M33 compilation target
For this STM32U5 application, install the Arm Cortex-M33 compilation target:
rustup target add thumbv8m.main-none-eabihf
Project manifest file Cargo.toml
Rust projects use Cargo.toml as the manifest for package information, dependencies and build configuration. For this project, Cargo.toml looks like this:
[package]name = "stm32u5_application"version = "0.1.0"edition = "2024"[dependencies]cortex-m = "0.7.9"cortex-m-rt = "0.7.6"panic-halt = "1.0.0"stm32u5 = { version = "0.16.0", default-features = false, features = ["stm32u585"] }
Packages
The [package] section identifies the name of the firmware application, its current version and the Rust edition used by the source code.
Dependencies
The [dependencies] section lists the crates required by the firmware:
cortex-mis a Rust library that provides Cortex-M processor support.cortex-m-rtprovides the embedded runtime, startup code and reset-handler entry point.panic-haltprovides a panic handler that halts execution when a Rust panic occurs.stm32u5provides register-level access to STM32U5 peripherals.
Crate
A crate is a Rust compilation unit. It can be a reusable library or an executable program. The crates listed under [dependencies] are external libraries that Cargo downloads, compiles and makes available to the application.
The stm32u585 feature selects support for the STM32U585 device used by the B-U585I-IOT02A board. Setting default-features to false prevents the crate’s default feature set from being enabled, while the required device feature is selected explicitly.
Cargo configuration file .cargo/config.toml
Cargo.toml describes the package and its dependencies. It does not describe how the package is built for a particular board. That is the role of .cargo/config.toml, which sits in a .cargo directory inside the application directory:
~/stm32u5_iot_project/application/├── .cargo/│ └── config.toml├── Cargo.toml└── src/
Cargo searches for this file in the current directory and each parent directory, so placing it alongside Cargo.toml applies it to every build run from the application directory. For this project it contains:
[build]target = "thumbv8m.main-none-eabihf"[target.thumbv8m.main-none-eabihf]rustflags = [ "-C", "link-arg=-Tlink.x",]
The [build] section sets the default compilation target, so cargo build produces an Arm Cortex-M33 binary without --target being given on the command line. Without it, Cargo would build for the host machine.
The [target.thumbv8m.main-none-eabihf] section passes an argument to the linker for that target only. -T link.x selects the linker script supplied by cortex-m-rt, which places the vector table and sections in the correct order and reads the memory layout from the project’s memory.x file. The memory.x file is where the application’s flash origin of 0x08040000 and its length are declared.
The .cargo directory begins with a dot, so it is hidden by default. Use ls -a to confirm it is present.
Cargo Build
The application is built from the application directory:
cd ~/stm32u5_iot_project/applicationcargo build
Cargo reads the manifest and uses the dependency versions recorded in Cargo.lock. The embedded target configuration selects thumbv8m.main-none-eabihf for the Arm Cortex-M33 processor, while the linker uses the project’s application memory map.
The development build produces the following Arm ELF executable:
target/thumbv8m.main-none-eabihf/debug/stm32u5_application
In C or C++ terms, Cargo.toml is broadly comparable to a CMakeLists.txt file combined with a dependency manifest. Cargo manages dependency resolution, compiler invocation and creation of the STM32 application executable.
Part of the series
Secure STM32 home monitoring with Rust

Discover more from Tech For Talk
Subscribe to get the latest posts sent to your email.

1 Comment