Skip to content

benjaminschlegel87/lets-blink

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Intro

This repository contains my own version of the classic embedded Hello World! — the blink an LED example. There is a blog post accompanying this example.

Motivation

Most examples I found when I first started learning Rust relied on ready-made abstractions such as a HAL (Hardware Abstraction Layer) or a BSP (Board Support Package). That’s a great way to get started: install the necessary tools, copy the example, and just like that you have a blinking LED.

My goal, however, was to go a bit deeper.

When it comes to hardware-related low-level programming, I find it difficult to accept seemingly magical abstractions without first understanding how to access the hardware directly if needed.

Approach

I believe there is real value in exploring different layers of abstraction, especially when you’re new to the language. This project is my best effort to make an LED blink — but by working through various levels of abstraction rather than relying solely on prebuilt layers.

Requirements

  • STM32F3 Discovery Board + Mini USB Cable
  • Rust Compiler with "thumb7em-none-eabihf" Target installed
  • probe-rs installed
  • ST-Link Driver installed

Installation

This is not a complete step-by-step guide! It shows the rough steps, but more may be necessary in detail.

  1. Installing rustup (Tool to install and update the rust compiler)

https://www.rust-lang.org/learn/get-started

Download and execute Rustup-init.exe 64 Bit (you may need to install “Visual Studio C++ Build tools” as described) 2) Add MCU Target

Run the following command:

rustup target add thumbv7em-none-eabihf 

Allows for cross-compilation for the MCU

thumbv7em-none-eabihf => Triplet for Cortex-M4 processor with FPU

Fun Fact regarding naming of the triplet: thumbv7em => Defines the used instruction set. In this case it is the reduced arm instruction set which is called thumb. It is a smaller instruction set and therefore a thumb is smaller than an arm.

  1. Install probe-rs

Run the following command:

cargo install probe-rs-tools --locked

Installs probe-rs which is a tool to directly flash/debug the MCU via STLink/JLink probes

Example

After everything has been installed, the following command can be executed in the root of the repo:

Raw Memory access

This is as basic as it can get. Blinking an LED by accessing the specific memory locations via raw pointers.

cargo run --bin minimal

Register Level Abstraction

PAC = Peripheral Access crate This crate is automatically generated from the SVD file of the MCU with the SVD2Rust tool. Gives you rudimentary access functions for the registers. It is no longer necessary to work with addresses, pointers or masks. Still this register level manipulation should feel familiar to low-level C-programmers.

cargo run --bin pac

Peripheral Level Abstraction

A HAL crate provides typical peripheral functions directly without having to deal with registers. A HAL crate typically implements the traits of the crate embedded-hal.

cargo run --bin hal

Board Level Abstraction

A Board Support Package is based on the HAL and defines functions that are provided by the specific board. Here we use the STM32F3Discovery Board and an LED component.

cargo run --bin bsp

Adding a minimal async executor

Rust is an extremely good choice for using asynchronous programming in embedded applications. Async is very powerful in modeling I/O bound systems and Rust makes it possible with very simple executors suitable even for small MCUs.

This examples shows a minimalistic spinning loop async executor that runs two LED tasks in parallel.

cargo run --bin async

All commands can be built with the addition --release as a maximum optimized variant (especially interesting for the minimum example)

All examples should flash the orange LED on the connected board with approx. 1Hz (surprise depending on --release included)

Binutils

For a deeper dive into the memory footprint of a rust program cargo-binutils is an execellent tool.

cargo-binutils is:

Cargo subcommands to invoke the LLVM tools shipped with the Rust toolchain

Installation via this cmd:

cargo install cargo-binutils

This adds alot of options to cargo to get information of the binary. One example is:

cargo size --bin minimal

For an release build:

cargo size --bin minimal --release

About

My take on an embedded "Hello World!"

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages