💡 Hint: To show the presentation in Fullscreen press "F".

Lightning
Embedded Development
with Rust





NerdNight19 - OpenLab Augsburg

no std, no main, no cry

featureno_stdstd
heap (dynamic memory)*
collections (Vec, BTreeMap, etc)**
stack overflow protection
runs init code before main
libstd available
libcore available
writing firmware, kernel
or bootloader code
  • Only if you use the alloc crate and use a suitable allocator
    ** Only if you use the collections crate and configure a global default allocator
    ** No HashMap or HashSet due to a lack of a secure random number generator

Rust(Yourself)Up

https://rustup.rs

  • rustc
  • rustfmt
  • clippy
  • cargo
  • rust-analyzer
  • rust-docs
  • rustup target add thumbv6m-none-eabi

Probe-rs

https://probe.rs

  • ”the user-friendly & flexible embedded toolkit”
  • Every ARM or RISC-V target
  • Supports many debug probes
  • Easy debugging (in VSCode) with RTT/GDB

HAL (Hardware Abstraction Layer)

… are sets of routines in software that emulate some platform-specific details, giving programs direct access to hardware resources

… write device-independent, high performance applications by providing standard operating system (OS) calls to hardware

Hot Tipp: svd2rust

Project Overview

myCoolRustProject ├── Cargo.toml ├── Embed.toml ├── README.md ├── rust-toolchain.toml ├── .cargo │ └── config.toml └── src └── bin ├── blinky.rs ├── hello.rs ├── main.rs ├── …

rust-toolchain.toml

[toolchain] channel = “stable” components = [ “rustfmt” ] targets = [ “thumbv6m-none-eabi” ]

  • Version Pinning
  • Simplified Dependency Management
  • Reproducible Builds

Cargo.toml

1 [package] 2 name = “stm32_app” 3 version = “0.1.0” 4 edition = “2021” 5 authors = [“wieerwill”] 6 resolver = “2” 7 8 [dependencies] 9 cortex-m-rt = “0.7.0” 10 defmt = “0.3” 11 defmt-rtt = “0.4” 12 embassy-time = { version = “0.3.1”, features = [ 13 “defmt”, “defmt-timestamp-uptime”, 14 “tick-hz-32_768”, 15 ] } … 16 17 # cargo build/run —release 18 [profile.release] 19 codegen-units = 1 # reduce Code Generation Units 20 debug = false 21 debug-assertions = false 22 incremental = false 23 lto = true # Link Time Optimization 24 opt-level = “z” # Optimize for size “s” or “z” 25 overflow-checks = true 26 strip = “symbols” # or true, removes all output from rtt 27 panic = “abort” # abort immediately rather than unwind 28 location-detail=“none” # Remove Location Details 29 30 [target.stm32l010rb] 31 runner = ‘probe-rs run —chip stm32l010rbtx’

config.toml

1 [target.thumbv6m-none-eabi] 2 runner = ‘probe-rs run —chip STM32L010RBTx’ 3 4 rustflags = [ 5 “-C”, “link-arg=—nmagic”, 6 “-C”, “link-arg=-Tlink.x”, 7 “-C”, “link-arg=-Tdefmt.x”, 8 “-C”, “link-arg=—no-rosegment” 9 ] 10 11 [build] 12 target = “thumbv6m-none-eabi” 13 14 [env] 15 DEFMT_LOG = “trace” 16 17 [alias] 18 main = “embed —release —bin main” 19 rb = “embed —release —bin” 20 s = “size —bin main — -B -x” 21

hello_world.rs

1 #![no_std] 2 #![no_main] 3 4 use {defmt_rtt as _, panic_probe as _}; 5
6 #[embassy_executor::main] 7 async fn main(_spawner: embassy_executor::Spawner) -> ! { 8 let _p = embassy_stm32::init(Default::default()); 9 loop { 10 embassy_time::Timer::after_secs(10).await; 11 defmt::info!(“Hello World”); 12 defmt::error!(“Error”); 13 defmt::warn!(“Warn”); 14 defmt::debug!(“Debug”); 15 defmt::trace!(“Trace”); 16 } 17 }

hello_world_shorter.rs

1 #![no_std] 2 #![no_main] 3 4 use defmt::{info, error, warn, debug, trace}; 5 use embassy_executor::Spawner; 6 use embassy_time::Timer; 7 use {defmt_rtt as _, panic_probe as _}; 8 9 #[embassy_executor::main] 10 async fn main(_spawner: Spawner) -> ! { 11 let _p = embassy_stm32::init(Default::default()); 12 loop { 13 Timer::after_secs(10).await; 14 info!(“Hello World”); 15 error!(“Error”); 16 warn!(“Warn”); 17 debug!(“Debug”); 18 trace!(“Trace”); 19 } 20 }

blinky.rs

8 … 9 #[embassy_executor::main] 10 async fn main(_spawner: Spawner) { 11 let p = embassy_stm32::init(Default::default()); 12 let mut led = Output::new( 13 p.PA9, Level::High, Speed::Low 14 ); 15 16 loop { 17 info!(“high”); 18 led.set_high(); 19 Timer::after_millis(500).await; 20 21 info!(“low”); 22 led.set_low(); 23 Timer::after_millis(500).await; 24 } 25 }

button.rs

8 … 9 #[embassy_executor::main] 10 async fn main(spawner: Spawner) { 11 let p = embassy_stm32::init(Default::default()); 12 let mut button = ExtiInput::new( 13 p.PC2, p.EXTI2, Pull::None); 14 15 loop { 16 button.wait_for_rising_edge().await; 17 info!(“rising edge”); 18 button.wait_for_falling_edge().await; 19 info!(“falling edge”); 20 } 21 }

tick_tack_tasks.rs

8 … 9 #[embassy_executor::task] 10 async fn run() { 11 loop { 12 Timer::after_secs(1).await; 13 info!(“Tick”); 14 } 15 } 16 17 #[embassy_executor::main] 18 async fn main(spawner: Spawner) -> ! { 19 let _p = embassy_stm32::init(Default::default()); 20
21 spawner.spawn(run()).unwrap(); 22 loop { 23 Timer::after_secs(2).await; 24 info!(“Tack”); 25 } 26 }

button_multi.rs

8 … 9 #[embassy_executor::task] 10 async fn alert_button_task(mut button_alert: ExtiInput<‘static>) { 11 loop { 12 button_alert.wait_for_rising_edge().await; 13 Timer::after_millis(10).await; // Debounce 14 info!(“Alert button pressed”); 15 } 16 } 17 18 #[embassy_executor::task] 19 async fn reset_button_task(mut button_reset: ExtiInput<‘static>) { 20 loop { 21 button_reset.wait_for_falling_edge().await; 22 Timer::after_millis(10).await; // Debounce 23 info!(“reset button pressed”); 24 25 button_reset.wait_for_rising_edge().await; 26 Timer::after_millis(10).await; // Debounce 27 info!(“reset button released”); 28 } 29 } 30 31 #[embassy_executor::main] 32 async fn main(spawner: Spawner) { 33 let p = embassy_stm32::init(Default::default()); 34 35 let button_alert = ExtiInput::new( 36 p.PC3, p.EXTI3, Pull::Up 37 ); 38 let button_reset = ExtiInput::new( 39 p.PC4, p.EXTI4, Pull::Up 40 ); 41 42 // Spawn tasks for each button 43 spawner.spawn(alert_button_task(button_alert)).unwrap(); 44 spawner.spawn(reset_button_task(button_reset)).unwrap(); 45 }

pwm.rs

8 … 9 #[embassy_executor::main] 10 async fn main(_spawner: Spawner) -> ! { 11 let p = embassy_stm32::init(Default::default()); 12 13 let buzz_pin = PwmPin::new_ch1(p.PB13, PushPull); 14 let mut pwm = SimplePwm::new( 15 p.TIM21, // Timer 16 Some(buzz_pin), // ch1 17 None, // ch2 18 None, // ch3 19 None, // ch4 20 hz(2000), // default Frequence 21 EdgeAlignedUp, // counting mode 22 ); 23 24 let max_duty = pwm.get_max_duty(); 25 pwm.set_duty(Channel::Ch2, max_duty / 2); //Duty Cycle to 50% 26 27 pwm.enable(Channel::Ch2); 28 29 let mut frequence = 300; 30 loop { 31 info!(“on, freq hz”, frequence); 32 pwm.set_frequency(hz(frequence)); 33 pwm.enable(Channel::Ch2); 34 Timer::after_millis(1000).await; 35 36 info!(“off”); 37 pwm.disable(Channel::Ch2); 38 Timer::after_millis(500).await; 39 frequence += 20; 40 } 41 }

Source of Truth

Zeit für eure Fragen
& Diskussionen

QR code for https://wieerwill.dev/vcard.vcf

WieErWill.dev/vcard.vcf

WieErWill.dev