refactor for streamlining

This commit is contained in:
2026-03-11 13:59:56 +01:00
parent a48ba2963d
commit 3112d15eec
91 changed files with 207 additions and 845 deletions

View File

@@ -1,31 +0,0 @@
# Hardware Baseline (Bluepill + ST-Link)
## Board and Probe
- MCU board: STM32F103C8T6 Bluepill
- Debug probe: ST-Link (SWD)
## SWD Wiring
1. ST-Link `SWDIO` -> Bluepill `PA13`
2. ST-Link `SWCLK` -> Bluepill `PA14`
3. ST-Link `GND` -> Bluepill `GND`
4. ST-Link `3V3` -> Bluepill `3V3` (falls notwendig)
5. Optional: ST-Link `NRST` -> Bluepill `NRST`
## Workshop I/O Wiring
1. LED:
- Onboard LED an `PC13` (active-low)
2. Button:
- Externer Taster von `PA0` nach `GND`
- Interner Pull-up wird im Code aktiviert
3. Analog:
- Poti/Sensor-Ausgang an `PA1`
- Sensorversorgung über `3V3` + `GND`
## Sanity Checks
1. `probe-rs list` zeigt ST-Link an.
2. `probe-rs chip list | grep STM32F103C8` findet Target.
3. Beim Flashen keine "No probe found"-Meldung.

View File

@@ -6,28 +6,84 @@ Ideal für RoboCup-Interessierte aus der außerschulischen bzw. beruflichen Bild
## Workshop Layout
Dieses Repository ist als "Rust by Example"-ähnlicher Lernpfad aufgebaut:
Jede Übung hat ihren eigenen Ordner. Der Lernpfad ist nummeriert.
Jede Übung hat Aufgabe mit TODOs zum Lösen.
- `tutorial/00-setup-live` bis `tutorial/08-final-combined`
- Jeder Schritt hat:
- `task/` (Aufgabe mit TODOs)
- `solution/` (Referenzlösung)
- Teilnehmer arbeiten nur in `task/`.
## Ablauf
## Quick Start
0. Install Rust
1. Rust Basics - Hello World
2. Rust Basics - Typen
3. Rust Basics - Ownership/Borrow
4. kleines Desktop Programm
5. Embedded - no std
6. Embedded - LED Blinky
7. Embedded - Button Input
8. Embedded - Analog Readout
9. Embedded - EmbassyRS
1. Host vorbereiten:
- `bash scripts/setup-live.sh`
2. Host prüfen:
- `bash scripts/verify-host.sh`
3. Probe prüfen:
- `bash scripts/verify-probe.sh`
4. Schritt ausführen:
- `bash scripts/run-step.sh 01 task`
# Hardware
## Core Files
- MCU board: STM32F103C8T6 Bluepill
- Debug probe: ST-Link (SWD)
- [WORKSHOP.md](/home/wieerwill/Dokumente/GitHub/didkata-rust-on-robots/WORKSHOP.md)
- [HARDWARE.md](/home/wieerwill/Dokumente/GitHub/didkata-rust-on-robots/HARDWARE.md)
- [TROUBLESHOOTING.md](/home/wieerwill/Dokumente/GitHub/didkata-rust-on-robots/TROUBLESHOOTING.md)
- [references/source-map.md](/home/wieerwill/Dokumente/GitHub/didkata-rust-on-robots/references/source-map.md)
## SWD Wiring
1. ST-Link `SWDIO` -> Bluepill `PA13`
2. ST-Link `SWCLK` -> Bluepill `PA14`
3. ST-Link `GND` -> Bluepill `GND`
4. ST-Link `3V3` -> Bluepill `3V3`
5. Optional: ST-Link `NRST` -> Bluepill `NRST`
## Workshop I/O Wiring
1. LED:
- Onboard LED an `PC13` (active-low)
2. Button:
- Externer Taster von `PA0` nach `GND`
- Interner Pull-up wird im Code aktiviert
3. Analog (optional):
- Poti/Sensor-Ausgang an `PA1`
- Sensorversorgung über `3V3` + `GND`
# Troubleshooting
## Host Setup
1. `rustup: command not found`
- Rust via rustup installieren.
2. `probe-rs: command not found`
- `cargo install probe-rs-tools`
3. Target fehlt
- `rustup target add thumbv7m-none-eabi`
## Probe / Flashing
1. `No probe found`
- USB-Kabel/Port prüfen
- ST-Link Treiber/udev prüfen
- `probe-rs list` erneut ausführen
2. `chip not found`
- Runner-String prüfen: `STM32F103C8`
3. `Permission denied` (Linux)
- udev-Regeln für ST-Link setzen und neu laden
## Runtime Behavior
1. LED blinkt nicht
- PC13 active-low beachten
- Versorgung prüfen
2. Button reagiert nicht
- Taster nach GND verdrahten
- `PA0` korrekt belegt?
3. Analogwerte ändern sich nicht
- Sensor/Poti wirklich an `PA1`
- Gemeinsame Masse sicherstellen
## Fallback in Session
Wenn eine Station nicht stabil läuft:
1. Mit funktionierender Nachbarn pairen.
2. `solution/` ausführen.
3. Später wieder auf `task/` zurückwechseln.

View File

@@ -1,41 +0,0 @@
# Troubleshooting
## Host Setup
1. `rustup: command not found`
- Rust via rustup installieren.
2. `probe-rs: command not found`
- `cargo install probe-rs-tools`
3. Target fehlt
- `rustup target add thumbv7m-none-eabi`
## Probe / Flashing
1. `No probe found`
- USB-Kabel/Port prüfen
- ST-Link Treiber/udev prüfen
- `probe-rs list` erneut ausführen
2. `chip not found`
- Runner-String prüfen: `STM32F103C8`
3. `Permission denied` (Linux)
- udev-Regeln für ST-Link setzen und neu laden
## Runtime Behavior
1. LED blinkt nicht
- PC13 active-low beachten
- Versorgung prüfen
2. Button reagiert nicht
- Taster nach GND verdrahten
- `PA0` korrekt belegt?
3. Analogwerte ändern sich nicht
- Sensor/Poti wirklich an `PA1`
- Gemeinsame Masse sicherstellen
## Fallback in Session
Wenn eine Station nicht stabil läuft:
1. Mit funktionierender Nachbarn pairen.
2. `solution/` ausführen.
3. Später wieder auf `task/` zurückwechseln.

View File

@@ -1,71 +0,0 @@
# Workshop Plan (60 Minutes)
## Goal
Von Rust-Basics zu echter Hardware auf STM32F103C8 Bluepill:
- LED blinken
- Button einlesen
- Analogwert einlesen
- Ausgabe live über `probe-rs` / RTT sehen
## Timing
1. 00:00-00:10: Setup + Probe Smoke Test (`00`)
2. 00:10-00:28: Rust Basics (`01`-`03`)
3. 00:28-00:36: Erstes `no_std` Firmware-Projekt (`04`)
4. 00:36-00:44: LED Blinky (`05`)
5. 00:44-00:50: Button Input (`06`)
6. 00:50-00:56: Analog Readout (`07`)
7. 00:56-01:00: Integration (`08`)
## Rules During Workshop
1. Bearbeite nur `task/`.
2. Nutze `solution/` nur als Hilfe bei Blockern.
3. Falls >3 Minuten blockiert: Diff vergleichen, minimalen Fix übernehmen, weiter.
4. Bei Embedded-Schritten: Board vor jedem `cargo run` korrekt verkabeln.
## Repo Management During Workshop
1. `main` enthält Aufgaben und Referenzlösungen.
2. Instructor kann Wiederherstellungspunkte als Tags setzen:
- `step-00-start` ... `step-08-solution`
3. Teilnehmer arbeiten auf lokalem Branch:
- `participant/<name>`
4. Wenn eine Aufgabe nicht weitergeht:
- minimalen Diff aus `solution/` übernehmen und fortfahren.
## Step Contract
Jeder Schritt enthält:
- `README.md` mit Ziel, Ablauf, Done-Check
- `task/` (Aufgabe)
- `solution/` (Referenz)
## Script Contract
- `scripts/setup-live.sh`
- `scripts/verify-host.sh`
- `scripts/verify-probe.sh`
- `scripts/run-step.sh <step-id> <task|solution>`
- `scripts/check-step.sh <step-id>`
## Target Contract (Embedded Steps 04-08)
- Target: `thumbv7m-none-eabi`
- Runner: `probe-rs run --chip STM32F103C8`
- Logging: `defmt-rtt` + `panic-probe`
## Acceptance Scenarios
1. Steps `01`-`03`: `cargo run` funktioniert für `task/` und `solution/`.
2. Steps `04`-`08`: `cargo build --release` funktioniert für `task/` und `solution/`.
3. Probe-Verbindung:
- `probe-rs list` erkennt ST-Link.
4. Behavior:
- `05`: LED blinkt
- `06`: Press/Release Logs
- `07`: ADC-Wert reagiert auf Eingang
- `08`: integriertes Verhalten läuft stabil

48
shell.nix Normal file
View File

@@ -0,0 +1,48 @@
{ pkgs ? import <nixpkgs> {} }:
let
overrides = (builtins.fromTOML (builtins.readFile ./rust-embassy-stm32/rust-toolchain.toml));
libPath = with pkgs; lib.makeLibraryPath [
# load external libraries that you need in your rust project here
];
in
pkgs.mkShell rec {
nativeBuildInputs = [ pkgs.pkg-config ];
buildInputs = with pkgs; [
clang
# Replace llvmPackages with llvmPackages_X, where X is the latest LLVM version (at the time of writing, 16)
llvmPackages.bintools
rustup
];
RUSTC_VERSION = overrides.toolchain.channel;
# https://github.com/rust-lang/rust-bindgen#environment-variables
LIBCLANG_PATH = pkgs.lib.makeLibraryPath [ pkgs.llvmPackages_latest.libclang.lib ];
shellHook = ''
export PATH=$PATH:''${CARGO_HOME:-~/.cargo}/bin
export PATH=$PATH:''${RUSTUP_HOME:-~/.rustup}/toolchains/$RUSTC_VERSION-x86_64-unknown-linux-gnu/bin/
'';
# Add precompiled library to rustc search path
RUSTFLAGS = (builtins.map (a: ''-L ${a}/lib'') [
# add libraries here (e.g. pkgs.libvmi)
]);
LD_LIBRARY_PATH = libPath;
# Add glibc, clang, glib, and other headers to bindgen search path
BINDGEN_EXTRA_CLANG_ARGS =
# Includes normal include path
(builtins.map (a: ''-I"${a}/include"'') [
# add dev libraries here (e.g. pkgs.libvmi.dev)
pkgs.glibc.dev
])
# Includes with special directory paths
++ [
''-I"${pkgs.llvmPackages_latest.libclang.lib}/lib/clang/${pkgs.llvmPackages_latest.libclang.version}/include"''
''-I"${pkgs.glib.dev}/include/glib-2.0"''
''-I${pkgs.glib.out}/lib/glib-2.0/include/''
];
}

View File

@@ -1,39 +0,0 @@
# Source Map
Dieses Mapping dokumentiert, welche gesammelten Quellen in welche Workshop-Bausteine eingeflossen sind.
## Rust Basics (`01`-`03`)
1. `sources/rust-by-example/*`
- Schrittweiser Lernstil mit kleinen, lauffähigen Beispielen
2. `sources/Introduction - A Gentle Introduction to Rust.md`
- sanfter Einstieg in Ownership/Borrowing
3. `sources/Learn Rust - Rust Programming Language.md`
- Orientierung an offiziellen Lernpfaden
## Embedded Foundations (`04`)
1. `sources/Intro to Rust on Embedded Your First no_std Project with Code Examples Hubble Network Community.md`
- `no_std`, PAC/HAL/BSP, Einstiegspfad
2. `sources/rust-embedded-book/src/intro/no-std.md`
- saubere no_std-Grundlagen
3. `sources/rust-embedded-book/src/peripherals/singletons.md`
- Ownership auf Hardware-Peripherie übertragen
## Tooling and Workflow (`00`, scripts)
1. `sources/Embedded Rust Toolchains Albert Skog.md`
- Probe-rs/probe-run Workflow-Einordnung
2. `sources/Embassy Book.md`
- praktischer Cargo + probe-rs Runner-Ansatz
## STM32 Practical Steps (`05`-`08`)
1. `sources/rust-embassy-stm32/src/bin/{blinky.rs,button.rs,adc.rs}`
- konkrete Zielübungen (LED/Button/ADC + Logs)
2. `sources/STM32F4 Embedded Rust at the HAL *.md`
- didaktische Sequenz: GPIO -> Input -> ADC -> Integration
3. `sources/AnyLeaf articles Writing embedded firmware using Rust.md`
- Register/HAL-Abstraktionslevel, Embedded-Rust Argumentation
4. `sources/Brave new IO Embedded in Rust.md`
- Ownership/Typisierung für sichere Hardwarezugriffe

View File

@@ -1,4 +1,4 @@
# Task Checklist
# 00 - install rust
- [ ] Rust toolchain installiert (`rustup`, `cargo`, `rustc`)
- [ ] Target `thumbv7m-none-eabi` installiert

View File

@@ -28,9 +28,14 @@ if ! command -v probe-rs >/dev/null 2>&1; then
cargo install probe-rs-tools
sudo groupadd --system plugdev
sudo usermod -a -G plugdev $USER
probe-rs complete install
else
echo "[setup] probe-rs already installed"
probe-rs --version
fi
probe-rs list
probe-rs info
probe-rs chip list | grep STM32F103C8
echo "[setup] done"

View File

@@ -1,17 +0,0 @@
# 00 - Setup Live (10 min)
## Goal
Jede Station kann Rust-Code bauen und eine Bluepill über ST-Link erkennen.
## Steps
1. install rustup
2. add target
3. add probe-rs
## Done when
1. `rustc`, `cargo`, `probe-rs` verfügbar.
2. `thumbv7m-none-eabi` installiert.
3. `probe-rs list` zeigt die Probe.

7
tutorial/01-rust-hello/Cargo.lock generated Normal file
View File

@@ -0,0 +1,7 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4
[[package]]
name = "rust_hello_task"
version = "0.1.0"

View File

@@ -1,4 +1,4 @@
[package]
name = "step01_rust_hello_task"
name = "rust_hello_task"
version = "0.1.0"
edition = "2021"

View File

@@ -1,20 +1,15 @@
# 01 - Rust Hello (5 min)
## Goal
# 01 - Rust Hello
Erstes lauffähiges Rust-Programm, das Daten über `println!` ausgibt.
## Run
- `bash scripts/run-step.sh 01 task`
```bash
cd src/
rustc main.c
./main.c
```
## Tasks
1. Öffne `task/src/main.rs`.
2. Ersetze die TODO-Werte.
3. Starte erneut mit `cargo run`.
## Done when
1. Das Programm kompiliert.
2. Die Ausgabe enthält euren Namen und Workshop-Titel.
```bash
cargo run
```

BIN
tutorial/01-rust-hello/src/main Executable file

Binary file not shown.

View File

@@ -3,7 +3,8 @@ fn main() {
let participant_name = "Your Name";
let workshop_title = "Rust on Embedded @ Didacta";
println!("Hello, {participant_name}!");
println!("Welcome to: {workshop_title}");
// TODO: Insert the strings in the output
println!("Hello, TODO !");
println!("Welcome to: TODO");
println!("Next step: types, control flow, and ownership.");
}

Binary file not shown.

View File

@@ -0,0 +1,7 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4
[[package]]
name = "rust_types_control_task"
version = "0.1.0"

View File

@@ -1,4 +1,4 @@
[package]
name = "step01_rust_hello_solution"
name = "rust_types_control_task"
version = "0.1.0"
edition = "2021"

View File

@@ -1,20 +1,3 @@
# 02 - Types and Control Flow (6 min)
## Goal
Mit Typen, `if`, und `match` kleine Entscheidungen ausdrücken.
## Run
- `bash scripts/run-step.sh 02 task`
## Tasks
1. Passe die Schwellwerte in `classify_adc` an.
2. Teste mit mehreren ADC-Werten.
3. Beobachte die Ausgabe von `pressed/released` und `low/medium/high`.
## Done when
1. Das Programm kompiliert.
2. Für unterschiedliche Werte entstehen unterschiedliche Klassifizierungen.

View File

@@ -1,4 +0,0 @@
[package]
name = "step02_rust_types_control_solution"
version = "0.1.0"
edition = "2021"

View File

@@ -16,14 +16,17 @@ fn classify_adc(raw: u16) -> &'static str {
}
fn main() {
// TODO: fill in some values into the arrays
let button_samples = [false, true, true, false];
let adc_samples: [u16; 5] = [120, 900, 1500, 2600, 3900];
for pressed in button_samples {
println!("button: {}", classify_button(pressed));
// call and print the function for the button
println!("button: {}");
}
for raw in adc_samples {
println!("adc raw={raw:4} => {}", classify_adc(raw));
// call and print the function for the button
println!("adc raw={raw:4} => {}");
}
}

View File

@@ -1,4 +1,4 @@
[package]
name = "step02_rust_types_control_task"
name = "rust_ownership_borrow_task"
version = "0.1.0"
edition = "2021"

View File

@@ -1,20 +1,3 @@
# 03 - Ownership and Borrowing (7 min)
## Goal
# 03 - Ownership and Borrowing
Ownership und Borrowing an einem kleinen Robot-State praktisch verstehen.
## Run
- `bash scripts/run-step.sh 03 task`
## Tasks
1. Lies die Funktionen mit `&RobotState` und `&mut RobotState`.
2. Ergänze die TODOs in der Task-Datei.
3. Achte auf Compiler-Fehler, wenn mutable/immutable borrows kollidieren.
## Done when
1. Das Programm kompiliert.
2. LED-State, Button-Count und ADC-Wert werden korrekt aktualisiert.

View File

@@ -1,4 +0,0 @@
[package]
name = "step03_rust_ownership_borrow_solution"
version = "0.1.0"
edition = "2021"

View File

@@ -6,27 +6,31 @@ struct RobotState {
}
fn print_state(state: &RobotState) {
// TODO: print the different elements of RobotState
println!(
"state => led_on={}, button_count={}, last_adc={}",
state.led_on, state.button_count, state.last_adc
???
);
}
fn toggle_led(state: &mut RobotState) {
state.led_on = !state.led_on;
// TODO: change the LED state to the inverse of itself
state.led_on = ??
}
fn record_button_press(state: &mut RobotState) {
state.button_count += 1;
// TODO: increase the button counter on press
state.button_count = ??
}
fn update_adc(state: &mut RobotState, raw: u16) {
// TODO: keep this function as the single writer for ADC state.
state.last_adc = raw;
// TODO: update the adc value with the given one
state.last_adc = ??
}
fn main() {
let mut state = RobotState {
// TODO: change the RobotState so we can edit its values
let state = RobotState {
led_on: false,
button_count: 0,
last_adc: 0,

View File

@@ -1,4 +1,4 @@
[package]
name = "step03_rust_ownership_borrow_task"
name = "rust_desktop_programm"
version = "0.1.0"
edition = "2021"

View File

@@ -0,0 +1,3 @@
# 04 Desktop Programm
kleines CLI Tool um Fertigkeiten auszuprobieren

View File

View File

@@ -1,20 +0,0 @@
# 04 - Embedded no_std Hello (8 min)
## Goal
Erstes Bare-Metal-Programm mit `#![no_std]`, `#![no_main]` und RTT Logs.
## Run
- `bash scripts/run-step.sh 04 task`
## Tasks
1. Lies die Top-Level-Attribute in `task/src/main.rs`.
2. Passe die Log-Ausgaben an.
3. Flashe mit `cargo run --release`.
## Done when
1. Firmware läuft auf Bluepill.
2. RTT zeigt zyklisch eine "alive"-Meldung.

View File

@@ -1,22 +0,0 @@
[package]
name = "step04_embedded_no_std_hello_solution"
version = "0.1.0"
edition = "2021"
[dependencies]
cortex-m = "0.7.7"
cortex-m-rt = "0.7.5"
defmt = "0.3.10"
defmt-rtt = "0.4.2"
panic-probe = { version = "0.3.2", features = ["print-defmt"] }
nb = "1.1.0"
[dependencies.stm32f1xx-hal]
version = "0.11.0"
features = ["rt", "stm32f103", "medium"]
[profile.release]
codegen-units = 1
debug = 2
lto = true
opt-level = "z"

View File

@@ -1,22 +0,0 @@
[package]
name = "step04_embedded_no_std_hello_task"
version = "0.1.0"
edition = "2021"
[dependencies]
cortex-m = "0.7.7"
cortex-m-rt = "0.7.5"
defmt = "0.3.10"
defmt-rtt = "0.4.2"
panic-probe = { version = "0.3.2", features = ["print-defmt"] }
nb = "1.1.0"
[dependencies.stm32f1xx-hal]
version = "0.11.0"
features = ["rt", "stm32f103", "medium"]
[profile.release]
codegen-units = 1
debug = 2
lto = true
opt-level = "z"

View File

@@ -1,20 +0,0 @@
# 05 - LED Blink (8 min)
## Goal
Onboard-LED (PC13, active-low) per Timer toggeln.
## Run
- `bash scripts/run-step.sh 05 task`
## Tasks
1. Prüfe in `task/src/main.rs`, welche Pegel "LED an/aus" bedeuten.
2. Passe Blinkfrequenz an.
3. Verifiziere LED und Logs.
## Done when
1. LED blinkt sichtbar.
2. Logs zeigen den Schaltzustand.

View File

@@ -1,5 +1,5 @@
[package]
name = "step05_led_blink_task"
name = "embedded_no_std"
version = "0.1.0"
edition = "2021"

View File

@@ -0,0 +1,3 @@
# 05 - Embedded no_std
Erstes Bare-Metal-Programm mit `#![no_std]`, `#![no_main]` und RTT Logs.

View File

@@ -8,11 +8,9 @@ use {defmt_rtt as _, panic_probe as _};
#[entry]
fn main() -> ! {
// TODO: personalize these log lines.
info!("step04: no_std hello on stm32f103c8");
info!("stm: no_std hello on stm32f103c8");
loop {
// TODO: we want this as a loop
asm::delay(8_000_000);
info!("step04: alive");
}
info!("stm: alive");
}

View File

@@ -8,10 +8,10 @@ use {defmt_rtt as _, panic_probe as _};
#[entry]
fn main() -> ! {
info!("step04: boot ok");
info!("boot ok");
loop {
asm::delay(8_000_000);
info!("step04: alive");
info!("alive");
}
}

View File

@@ -1,20 +0,0 @@
# 06 - Button Input (6 min)
## Goal
Button an PA0 (Pull-up) lesen und Press/Release als Log ausgeben.
## Run
- `bash scripts/run-step.sh 06 task`
## Tasks
1. Verdrahtung prüfen: PA0 -> Button -> GND.
2. Starte `task` und beobachte Logs.
3. Passe Polling-Intervall an.
## Done when
1. Pressed/Released wird korrekt erkannt.
2. Keine Flut von Wiederhol-Logs bei gehaltenem Taster.

View File

@@ -1,12 +0,0 @@
[target.thumbv7m-none-eabi]
runner = "probe-rs run --chip STM32F103C8"
rustflags = [
"-C", "link-arg=-Tlink.x",
"-C", "link-arg=-Tdefmt.x",
]
[build]
target = "thumbv7m-none-eabi"
[env]
DEFMT_LOG = "info"

View File

@@ -1,22 +0,0 @@
[package]
name = "step06_button_input_solution"
version = "0.1.0"
edition = "2021"
[dependencies]
cortex-m = "0.7.7"
cortex-m-rt = "0.7.5"
defmt = "0.3.10"
defmt-rtt = "0.4.2"
panic-probe = { version = "0.3.2", features = ["print-defmt"] }
nb = "1.1.0"
[dependencies.stm32f1xx-hal]
version = "0.11.0"
features = ["rt", "stm32f103", "medium"]
[profile.release]
codegen-units = 1
debug = 2
lto = true
opt-level = "z"

View File

@@ -1,5 +0,0 @@
MEMORY
{
FLASH : ORIGIN = 0x08000000, LENGTH = 64K
RAM : ORIGIN = 0x20000000, LENGTH = 20K
}

View File

@@ -1,4 +0,0 @@
[toolchain]
channel = "stable"
components = ["rustfmt"]
targets = ["thumbv7m-none-eabi"]

View File

@@ -1,12 +0,0 @@
[target.thumbv7m-none-eabi]
runner = "probe-rs run --chip STM32F103C8"
rustflags = [
"-C", "link-arg=-Tlink.x",
"-C", "link-arg=-Tdefmt.x",
]
[build]
target = "thumbv7m-none-eabi"
[env]
DEFMT_LOG = "info"

View File

@@ -1,5 +0,0 @@
MEMORY
{
FLASH : ORIGIN = 0x08000000, LENGTH = 64K
RAM : ORIGIN = 0x20000000, LENGTH = 20K
}

View File

@@ -1,4 +0,0 @@
[toolchain]
channel = "stable"
components = ["rustfmt"]
targets = ["thumbv7m-none-eabi"]

View File

@@ -1,5 +1,5 @@
[package]
name = "step06_button_input_task"
name = "led_blink_task"
version = "0.1.0"
edition = "2021"

View File

@@ -0,0 +1,3 @@
# 06 - LED Blink
Onboard-LED (PC13, active-low) per Timer toggeln.

View File

@@ -16,7 +16,7 @@ fn main() -> ! {
let mut gpioc = dp.GPIOC.split(&mut rcc);
// Bluepill onboard LED on PC13 is active-low.
let mut led = gpioc.pc13.into_push_pull_output(&mut gpioc.crh);
// TODO: create LED Pin Input
let mut timer = Timer::syst(cp.SYST, &rcc.clocks).counter_hz();
timer.start(2.Hz()).unwrap();

View File

@@ -1,20 +0,0 @@
# 07 - Analog Readout (6 min)
## Goal
ADC auf PA1 lesen und Werte über RTT streamen.
## Run
- `bash scripts/run-step.sh 07 task`
## Tasks
1. Verdrahtung prüfen: Analogsignal an PA1.
2. Werte ausgeben und in drei Bereiche klassifizieren.
3. Potentiometer/Sensor bewegen und Änderung beobachten.
## Done when
1. Rohwert ändert sich mit Eingangsspannung.
2. Klassifizierung (`low/medium/high`) reagiert sinnvoll.

View File

@@ -1,12 +0,0 @@
[target.thumbv7m-none-eabi]
runner = "probe-rs run --chip STM32F103C8"
rustflags = [
"-C", "link-arg=-Tlink.x",
"-C", "link-arg=-Tdefmt.x",
]
[build]
target = "thumbv7m-none-eabi"
[env]
DEFMT_LOG = "info"

View File

@@ -1,22 +0,0 @@
[package]
name = "step07_analog_readout_solution"
version = "0.1.0"
edition = "2021"
[dependencies]
cortex-m = "0.7.7"
cortex-m-rt = "0.7.5"
defmt = "0.3.10"
defmt-rtt = "0.4.2"
panic-probe = { version = "0.3.2", features = ["print-defmt"] }
nb = "1.1.0"
[dependencies.stm32f1xx-hal]
version = "0.11.0"
features = ["rt", "stm32f103", "medium"]
[profile.release]
codegen-units = 1
debug = 2
lto = true
opt-level = "z"

View File

@@ -1,5 +0,0 @@
MEMORY
{
FLASH : ORIGIN = 0x08000000, LENGTH = 64K
RAM : ORIGIN = 0x20000000, LENGTH = 20K
}

View File

@@ -1,4 +0,0 @@
[toolchain]
channel = "stable"
components = ["rustfmt"]
targets = ["thumbv7m-none-eabi"]

View File

@@ -1,12 +0,0 @@
[target.thumbv7m-none-eabi]
runner = "probe-rs run --chip STM32F103C8"
rustflags = [
"-C", "link-arg=-Tlink.x",
"-C", "link-arg=-Tdefmt.x",
]
[build]
target = "thumbv7m-none-eabi"
[env]
DEFMT_LOG = "info"

View File

@@ -1,5 +0,0 @@
MEMORY
{
FLASH : ORIGIN = 0x08000000, LENGTH = 64K
RAM : ORIGIN = 0x20000000, LENGTH = 20K
}

View File

@@ -1,4 +0,0 @@
[toolchain]
channel = "stable"
components = ["rustfmt"]
targets = ["thumbv7m-none-eabi"]

View File

@@ -1,5 +1,5 @@
[package]
name = "step05_led_blink_solution"
name = "button_input_task"
version = "0.1.0"
edition = "2021"

View File

@@ -0,0 +1,3 @@
# 07 - Button Input
Button an PA0 (Pull-up) lesen und Press/Release als Log ausgeben.

View File

@@ -15,8 +15,7 @@ fn main() -> ! {
let mut rcc = dp.RCC.constrain();
let mut gpioa = dp.GPIOA.split(&mut rcc);
// Button wiring: PA0 -> button -> GND
let button = gpioa.pa0.into_pull_up_input(&mut gpioa.crl);
// TODO: Button wiring: PA0 -> button -> GND
let mut timer = Timer::syst(cp.SYST, &rcc.clocks).counter_hz();
timer.start(40.Hz()).unwrap();
@@ -24,15 +23,9 @@ fn main() -> ! {
let mut last_pressed = false;
loop {
let pressed = button.is_low();
if pressed != last_pressed {
if pressed {
info!("button: pressed");
} else {
info!("button: released");
}
last_pressed = pressed;
}
// TODO: get the current button status
// TODO: print a message when the button is pressed and released
// Poll at 25ms to avoid too much log spam.
block!(timer.wait()).unwrap();

View File

@@ -1,5 +1,5 @@
[package]
name = "step07_analog_readout_task"
name = "analog_readout_task"
version = "0.1.0"
edition = "2021"

View File

@@ -0,0 +1,3 @@
# 08 - Analog Readout
ADC auf PA1 lesen und Werte über RTT streamen.

View File

@@ -24,8 +24,7 @@ fn main() -> ! {
let mut rcc = dp.RCC.constrain();
let mut gpioa = dp.GPIOA.split(&mut rcc);
let mut adc = Adc::new(dp.ADC1, &mut rcc);
let mut analog_pin = gpioa.pa1.into_analog(&mut gpioa.crl);
// TODO: set up ADC and ADC Pin and read
let mut timer = Timer::syst(cp.SYST, &rcc.clocks).counter_hz();
timer.start(10.Hz()).unwrap();

View File

@@ -1,22 +0,0 @@
# 08 - Final Combined (4 min)
## Goal
Blink + Button + ADC in einem Programm kombinieren.
## Behavior
1. ADC steuert Blink-Intervall.
2. Button toggelt Betriebsmodus:
- `Mode::Blinking`
- `Mode::ForcedOff`
## Run
- `bash scripts/run-step.sh 08 task`
## Done when
1. LED-Verhalten ändert sich per Button.
2. ADC beeinflusst Blinkgeschwindigkeit im Blink-Modus.
3. Logs zeigen Mode, ADC und Delay.

View File

@@ -1,12 +0,0 @@
[target.thumbv7m-none-eabi]
runner = "probe-rs run --chip STM32F103C8"
rustflags = [
"-C", "link-arg=-Tlink.x",
"-C", "link-arg=-Tdefmt.x",
]
[build]
target = "thumbv7m-none-eabi"
[env]
DEFMT_LOG = "info"

View File

@@ -1,22 +0,0 @@
[package]
name = "step08_final_combined_solution"
version = "0.1.0"
edition = "2021"
[dependencies]
cortex-m = "0.7.7"
cortex-m-rt = "0.7.5"
defmt = "0.3.10"
defmt-rtt = "0.4.2"
panic-probe = { version = "0.3.2", features = ["print-defmt"] }
nb = "1.1.0"
[dependencies.stm32f1xx-hal]
version = "0.11.0"
features = ["rt", "stm32f103", "medium"]
[profile.release]
codegen-units = 1
debug = 2
lto = true
opt-level = "z"

View File

@@ -1,5 +0,0 @@
MEMORY
{
FLASH : ORIGIN = 0x08000000, LENGTH = 64K
RAM : ORIGIN = 0x20000000, LENGTH = 20K
}

View File

@@ -1,4 +0,0 @@
[toolchain]
channel = "stable"
components = ["rustfmt"]
targets = ["thumbv7m-none-eabi"]

View File

@@ -1,83 +0,0 @@
#![no_std]
#![no_main]
use cortex_m_rt::entry;
use defmt::info;
use nb::block;
use stm32f1xx_hal::{adc::Adc, pac, prelude::*, timer::Timer};
use {defmt_rtt as _, panic_probe as _};
#[derive(Clone, Copy, PartialEq, Eq)]
enum Mode {
Blinking,
ForcedOff,
}
fn interval_from_adc(raw: u16) -> u32 {
100 + (u32::from(raw) * 800 / 4095)
}
#[entry]
fn main() -> ! {
let cp = cortex_m::Peripherals::take().unwrap();
let dp = pac::Peripherals::take().unwrap();
let mut rcc = dp.RCC.constrain();
let mut gpioa = dp.GPIOA.split(&mut rcc);
let mut gpioc = dp.GPIOC.split(&mut rcc);
let mut led = gpioc.pc13.into_push_pull_output(&mut gpioc.crh);
let button = gpioa.pa0.into_pull_up_input(&mut gpioa.crl);
let mut adc = Adc::new(dp.ADC1, &mut rcc);
let mut analog_pin = gpioa.pa1.into_analog(&mut gpioa.crl);
let mut tick = Timer::syst(cp.SYST, &rcc.clocks).counter_hz();
tick.start(100.Hz()).unwrap();
let mut mode = Mode::Blinking;
let mut last_pressed = false;
let mut led_on = false;
let mut elapsed_ms: u32 = 0;
loop {
let pressed = button.is_low();
if pressed && !last_pressed {
mode = if mode == Mode::Blinking {
info!("mode -> ForcedOff");
Mode::ForcedOff
} else {
info!("mode -> Blinking");
Mode::Blinking
};
}
last_pressed = pressed;
let raw: u16 = adc.read(&mut analog_pin).unwrap();
let interval_ms = interval_from_adc(raw);
match mode {
Mode::Blinking => {
elapsed_ms += 10;
if elapsed_ms >= interval_ms {
elapsed_ms = 0;
led_on = !led_on;
if led_on {
led.set_low();
} else {
led.set_high();
}
info!("mode=Blinking adc={} interval_ms={} led_on={}", raw, interval_ms, led_on);
}
}
Mode::ForcedOff => {
led_on = false;
led.set_high();
elapsed_ms = 0;
info!("mode=ForcedOff adc={} interval_ms={}", raw, interval_ms);
}
}
block!(tick.wait()).unwrap();
}
}

View File

@@ -1,12 +0,0 @@
[target.thumbv7m-none-eabi]
runner = "probe-rs run --chip STM32F103C8"
rustflags = [
"-C", "link-arg=-Tlink.x",
"-C", "link-arg=-Tdefmt.x",
]
[build]
target = "thumbv7m-none-eabi"
[env]
DEFMT_LOG = "info"

View File

@@ -1,22 +0,0 @@
[package]
name = "step08_final_combined_task"
version = "0.1.0"
edition = "2021"
[dependencies]
cortex-m = "0.7.7"
cortex-m-rt = "0.7.5"
defmt = "0.3.10"
defmt-rtt = "0.4.2"
panic-probe = { version = "0.3.2", features = ["print-defmt"] }
nb = "1.1.0"
[dependencies.stm32f1xx-hal]
version = "0.11.0"
features = ["rt", "stm32f103", "medium"]
[profile.release]
codegen-units = 1
debug = 2
lto = true
opt-level = "z"

View File

@@ -1,5 +0,0 @@
MEMORY
{
FLASH : ORIGIN = 0x08000000, LENGTH = 64K
RAM : ORIGIN = 0x20000000, LENGTH = 20K
}

View File

@@ -1,4 +0,0 @@
[toolchain]
channel = "stable"
components = ["rustfmt"]
targets = ["thumbv7m-none-eabi"]

View File

@@ -1,85 +0,0 @@
#![no_std]
#![no_main]
use cortex_m_rt::entry;
use defmt::info;
use nb::block;
use stm32f1xx_hal::{adc::Adc, pac, prelude::*, timer::Timer};
use {defmt_rtt as _, panic_probe as _};
#[derive(Clone, Copy, PartialEq, Eq)]
enum Mode {
Blinking,
ForcedOff,
}
fn interval_from_adc(raw: u16) -> u32 {
// Map 0..4095 -> 100..900 ms
100 + (u32::from(raw) * 800 / 4095)
}
#[entry]
fn main() -> ! {
let cp = cortex_m::Peripherals::take().unwrap();
let dp = pac::Peripherals::take().unwrap();
let mut rcc = dp.RCC.constrain();
let mut gpioa = dp.GPIOA.split(&mut rcc);
let mut gpioc = dp.GPIOC.split(&mut rcc);
let mut led = gpioc.pc13.into_push_pull_output(&mut gpioc.crh);
let button = gpioa.pa0.into_pull_up_input(&mut gpioa.crl);
let mut adc = Adc::new(dp.ADC1, &mut rcc);
let mut analog_pin = gpioa.pa1.into_analog(&mut gpioa.crl);
// Fast base tick: all app timing derives from this.
let mut tick = Timer::syst(cp.SYST, &rcc.clocks).counter_hz();
tick.start(100.Hz()).unwrap(); // 10 ms
let mut mode = Mode::Blinking;
let mut last_pressed = false;
let mut led_on = false;
let mut elapsed_ms: u32 = 0;
loop {
let pressed = button.is_low();
if pressed && !last_pressed {
mode = if mode == Mode::Blinking {
info!("mode -> ForcedOff");
Mode::ForcedOff
} else {
info!("mode -> Blinking");
Mode::Blinking
};
}
last_pressed = pressed;
let raw: u16 = adc.read(&mut analog_pin).unwrap();
let interval_ms = interval_from_adc(raw);
match mode {
Mode::Blinking => {
elapsed_ms += 10;
if elapsed_ms >= interval_ms {
elapsed_ms = 0;
led_on = !led_on;
if led_on {
led.set_low(); // active-low
} else {
led.set_high();
}
info!("mode=Blinking adc={} interval_ms={} led_on={}", raw, interval_ms, led_on);
}
}
Mode::ForcedOff => {
led_on = false;
led.set_high();
elapsed_ms = 0;
info!("mode=ForcedOff adc={} interval_ms={}", raw, interval_ms);
}
}
block!(tick.wait()).unwrap();
}
}