diff --git a/Cargo.toml b/Cargo.toml index 5566427d541becf7805eb85b9fee5795675370b6..80141736d21cfdb6d8cbf6fafca12f3b25029317 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,11 +12,11 @@ cortex-m-rtic = "0.5.5" # tracing cortex-m-semihosting = "0.3.5" -rtt-target = { version = "0.2.2", features = ["cortex-m"] } +rtt-target = { version = "0.3.0", features = ["cortex-m"] } # panic handlers panic-halt = "0.2.0" -panic-semihosting = "0.5.4" +panic-semihosting = "0.5.6" panic-rtt-target = { version = "0.1.1", features = ["cortex-m"] } [dependencies.stm32f4] diff --git a/README.md b/README.md index bc0b0e712cbe7673aac8b76a0cdca9bb7b936522..cc1de83be63db0f07d1b16e72506e1ce45eec16d 100644 --- a/README.md +++ b/README.md @@ -23,11 +23,32 @@ Linux tooling: - `openocd` - `arm-none-eabi-gdb`, or -- `gdb-multiarch` +- `gdb-multiarch` ## Editor You may use any editor of choice. `vscode` supports Rust using the `rust-analyzer` plugin. +--- +## Exercises +- `src/main.rs` + + Developing embedded applications in Rust is made simle by the RTIC framework. In this exercise you will familiarize yourself with the basics `init` and `idle`, and see how you can trace the output to a terminal using `cargo-run`. + + You will also learn about `panic`s and how they can be traced. + +- `examples/rtt_timing.rs` + + Here you will learn about cycle accurate timing measurements. + + - Using instrumentation code (which introduces bloat and overhead). + + - Non intrusive measurements using the on-chip debug unit and `gdb`. + + - Code generation optimization + + - Code inspection, `objdump`, debugging and interactive `disassemble`. + + - Code trimming, RTIC is "A Zero-Cost Abstraction for Memory Safe Concurrency". diff --git a/examples/rtt_simple.rs b/examples/rtt_simple.rs deleted file mode 100644 index c9005a436f1a189eb86647fa8a53f8e3e6b07ba0..0000000000000000000000000000000000000000 --- a/examples/rtt_simple.rs +++ /dev/null @@ -1,43 +0,0 @@ -//! examples/rtt_simple.rs - -#![deny(unsafe_code)] -#![deny(warnings)] -#![no_main] -#![no_std] - -use panic_rtt_target as _; -use rtt_target::{rprintln, rtt_init_print}; -use stm32f4; - -#[rtic::app(device = stm32f4)] -const APP: () = { - #[init] - fn init(_cx: init::Context) { - rtt_init_print!(); - rprintln!("init"); - } - - #[idle] - fn idle(_cx: idle::Context) -> ! { - rprintln!("idle"); - loop { - continue; - } - } -}; - -// > cargo run rtt_simple -// Compiling app v0.1.0 (/home/pln/courses/e7020e/app) -// Finished dev [unoptimized + debuginfo] target(s) in 0.15s -// Running `probe-run --chip STM32F411RETx target/thumbv7em-none-eabi/debug/examples/rtt_simple` -// flashing program .. -// DONE -// resetting device -// init -// idle -// -// > [Ctrl-C] -// stack backtrace: -// 0: 0x0800031a - rtt_simple::idle -// 1: 0x0800036c - main -// 2: 0x080001da - Reset diff --git a/examples/rtt_timing.rs b/examples/rtt_timing.rs index e589698619d1c4730bfd78a73a59f5219fba96dd..4ee67756ac0d8fceb17692d8701abfa5df55fba9 100644 --- a/examples/rtt_timing.rs +++ b/examples/rtt_timing.rs @@ -69,6 +69,10 @@ fn timed_loop() -> (u32, u32) { // // [Your answer here] // +// A.3) Why do we need a wrapping subtraction? +// +// [Your answer here] +// // ------------------------------------------------------------------------ // Now try a release (optimized build, see `Cargo.toml` for build options). // B.1) What is the cycle count for the loop? @@ -99,14 +103,14 @@ fn timed_loop() -> (u32, u32) { // info: using existing install for 'nightly-x86_64-unknown-linux-gnu' // info: override toolchain for '/home/pln/courses/e7020e/app' set to 'nightly-x86_64-unknown-linux-gnu' // -// nightly-x86_64-unknown-linux-gnu unchanged - rustc 1.49.0-nightly (cf9cf7c92 2020-11-10) +// nightly-x86_64-unknown-linux-gnu unchanged - rustc 1.49.0-nightly (cf9cf7c92 2020-11-10) // // > rustup target add thumbv7em-none-eabi // (only needed first time) // // Now try a release (optimized build, see `Cargo.toml` for build options). // C.1) What is the cycle count for the loop? -// > cargo run --example rtt_timing --release +// > cargo run --example rtt_timing --release --features nightly // // [Your answer here] // @@ -121,7 +125,7 @@ fn timed_loop() -> (u32, u32) { // ------------------------------------------------------------------------ // D) Now lets have a closer look at the generated assembly. // -// > cargo objdump --example rtt_timing --release --features nightly -- --disassemble > rtt_timing.objdump +// > cargo objdump --example rtt_timing --release --features nightly -- --disassemble --no-show-raw-insn > rtt_timing.objdump // // Open the file in you editor and search for the `timed_loop`. // diff --git a/src/main.rs b/src/main.rs index bc85ce18358c7480181753a839d9eb6a9d7862d5..885c4d75da0780a0baec617f7860895b39d2965b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,33 +1,91 @@ -//! examples/init.rs +//! main.rs #![deny(unsafe_code)] -// #![deny(warnings)] +#![deny(warnings)] #![no_main] #![no_std] -use cortex_m; // use panic_halt as _; use panic_rtt_target as _; use rtt_target::{rprintln, rtt_init_print}; use stm32f4; -// #[rtic::app(device = lm3s6965, peripherals = true)] #[rtic::app(device = stm32f4)] const APP: () = { #[init] fn init(_cx: init::Context) { - rtt_init_print!(); rprintln!("init"); } #[idle] fn idle(_cx: idle::Context) -> ! { - rprintln!("idle"); - panic!("panic"); + // panic!("panic"); loop { continue; } } }; + +// A) A Simple Trace +// > cargo run +// cargo run +// Compiling app v0.1.0 (/home/pln/courses/d7020e/rtic_f4xx_nucleo) +// Finished dev [unoptimized + debuginfo] target(s) in 0.18s +// Running `probe-run --chip STM32F411RETx target/thumbv7em-none-eabi/debug/app` +// (HOST) INFO flashing program (15.06 KiB) +// (HOST) INFO success! +// ──────────────────────────────────────────────────────────────────────────────── +// init +// idle +// +// B) Breaking +// Now press Ctrl-C +// ^Cstack backtrace: +// 0: app::idle +// at src/main.rs:25 +// 1: main +// at src/main.rs:13 +// 2: Reset +// at /home/pln/.cargo/registry/src/github.com-1ecc6299db9ec823/cortex-m-rt-0.6.13/src/lib.rs:526 +// +// Make sure you got the expected output +// +// C) Panic tracing +// Rust is designed for reliability, with the aim to deliver memory safety +// and defined behavior at all times. +// Recoverable errors (in libraries and user code) should use the `Result<T,E>` type, +// while unrecoverable errors should `panic`. +// +// Let's introduce a `panic` (uncomment line 24). +// > cargo run +// +// What is the output? +// +// [Your answer here] +// +// D) Panic halt +// Tracing is nice during development, but requires a debugger attached +// and a host listening. For a deployed product, other `panic` behavior +// should be adopted (e.g. storing to flash, for later post-mortem debugging) +// or just reset:ing the device. In this example we chose just to `halt` +// +// Enable `panic_halt` (line 8). +// > cargo run +// +// What is the output? +// +// [Your answer here] +// +// Now press Ctrl-C +// +// What is the output? +// +// [Your answer here] +// +// E) Find the source +// Figure out how to find the source of `panic_halt`, and look at the implementation. +// +// - `cargo doc --open` (you need to disable the rtt-panic handler in `Cargo.toml`). +// - `crates.io`