Rust on Embedded

Didacta Workshop

STM32F103C8 Bluepill + ST-Link + Rust

Workshop Goal

  • Understand core Rust basics
  • Build and flash no_std firmware
  • Blink LED, read button, read analog input
  • See output with probe-rs RTT logs

Flow (60 min)

  • 00 setup, 01-03 Rust basics
  • 04 first embedded app
  • 05 LED blink
  • 06 button input
  • 07 analog readout
  • 08 final combined app

How We Work

  • Edit only task/ folders
  • Use solution/ only when stuck
  • One step at a time, linear slides

Step 00 Task: Setup Live

Next task: Prepare host + probe tools.

Learn: Embedded Rust toolchain basics.

bash scripts/setup-live.sh
bash scripts/verify-host.sh
bash scripts/verify-probe.sh

Step 00 Solution

  • rustup, cargo, probe-rs available
  • Target thumbv7m-none-eabi installed
  • probe-rs list sees ST-Link
  • probe-rs chip list contains STM32F103C8

Step 01 Task: Rust Hello

Next task: Edit the TODO values and run.

Learn: fn main, variables, println!.

bash scripts/run-step.sh 01 task

Step 01 Solution

  • Program compiles and runs with cargo run
  • Console output shows your name and workshop title
  • You can navigate the task/solution structure

Step 02 Task: Types + Control Flow

Next task: Tune threshold logic in classify_adc.

Learn: explicit types, if, match.

bash scripts/run-step.sh 02 task

Step 02 Solution

  • ADC values map to low/medium/high
  • Button states map to pressed/released
  • Program output changes correctly with input values

Step 03 Task: Ownership + Borrowing

Next task: Complete/update state mutation functions.

Learn: &T vs &mut T, safe mutation design.

bash scripts/run-step.sh 03 task

Step 03 Solution

  • State is read via immutable reference
  • State changes happen through mutable references
  • Compiler enforces safe access patterns

Step 04 Task: Embedded no_std Hello

Next task: Flash first no_std firmware and watch RTT logs.

Learn: #![no_std], #![no_main], #[entry].

bash scripts/run-step.sh 04 task

Step 04 Solution

  • Firmware flashes to Bluepill
  • RTT shows boot + alive messages
  • You now have a working embedded Rust baseline

Step 05 Task: LED Blink

Next task: Toggle PC13 in a timed loop.

Learn: HAL GPIO output + active-low LED behavior.

bash scripts/run-step.sh 05 task

Step 05 Solution

  • PC13 low = LED on, PC13 high = LED off
  • Timer loop controls blink frequency
  • RTT logs match LED state changes

Step 06 Task: Button Input

Next task: Read PA0 with pull-up and detect transitions.

Learn: digital input polling + simple edge detection.

bash scripts/run-step.sh 06 task

Step 06 Solution

  • Pressed/released events are logged correctly
  • No repeated spam while button is held
  • Wiring pattern: PA0 -> button -> GND

Step 07 Task: Analog Readout

Next task: Read ADC on PA1 and print values.

Learn: one-shot ADC + value classification.

bash scripts/run-step.sh 07 task

Step 07 Solution

  • ADC raw value changes with analog input
  • Classification low/medium/high works
  • Periodic readout appears in RTT console

Step 08 Task: Final Combined

Next task: Integrate LED + button + ADC behavior.

Learn: small embedded state machine.

bash scripts/run-step.sh 08 task

Step 08 Solution

  • Button toggles mode: Blinking / ForcedOff
  • ADC value controls blink interval in Blinking mode
  • Integrated firmware runs stable with logs

Workshop Wrap-up

  • You moved from Rust basics to real MCU firmware
  • You used no_std, HAL GPIO, button input, and ADC
  • Next: extend with UART, interrupts, or Embassy async