diff --git a/.vscode/launch.json b/.vscode/launch.json index df1f5da4233c32f202ce0528ab3bf8d004983751..1a6ca56aecc5e6c5d8e435d3a34cdada0b1a691d 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -202,7 +202,7 @@ "request": "launch", "servertype": "openocd", "name": "bare1 (release)", - "preLaunchTask": "cargo build --example bare1", + "preLaunchTask": "cargo build --example bare1 --release", "executable": "./target/thumbv7em-none-eabihf/release/examples/bare1", "postLaunchCommands": [ "monitor arm semihosting enable" @@ -260,7 +260,7 @@ "request": "launch", "servertype": "openocd", "name": "bare2 (release)", - "preLaunchTask": "cargo build --example bare2", + "preLaunchTask": "cargo build --example bare2 --release", "executable": "./target/thumbv7em-none-eabihf/release/examples/bare2", "postLaunchCommands": [ "monitor arm semihosting enable" @@ -284,6 +284,22 @@ ], "cwd": "${workspaceRoot}" }, + { + "type": "cortex-debug", + "request": "launch", + "servertype": "openocd", + "name": "bare3 (dubug)", + "preLaunchTask": "cargo build --example bare3", + "executable": "./target/thumbv7em-none-eabihf/debug/examples/bare3", + "postLaunchCommands": [ + "monitor arm semihosting enable" + ], + "configFiles": [ + "interface/stlink.cfg", + "target/stm32f4x.cfg" + ], + "cwd": "${workspaceRoot}" + }, { "type": "cortex-debug", "request": "launch", diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 6bd84bc5bb4d224239ac82f575acfb899227221e..8e04b2f671f910dbaa33113910dfc00ef646c760 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -134,6 +134,18 @@ "kind": "build", "isDefault": true } - } + }, + { + "type": "shell", + "label": "cargo build --example bare3", + "command": "cargo build --example bare3", + "problemMatcher": [ + "$rustc" + ], + "group": { + "kind": "build", + "isDefault": true + } + }, ] } \ No newline at end of file diff --git a/examples/bare1.rs b/examples/bare1.rs index 4a10eced59853290b20228d905f2793f1ee0bbcd..3b5de813553fc4e8a0833216010a27a1f335d0ff 100644 --- a/examples/bare1.rs +++ b/examples/bare1.rs @@ -1,6 +1,6 @@ //! bare1.rs //! -//! Tracing and assembly code +//! Inspecting the generated assembly //! //! What it covers //! - tracing over semihosting and ITM @@ -13,33 +13,35 @@ extern crate panic_halt; -use cortex_m::{iprintln, Peripherals}; use cortex_m_rt::entry; -use cortex_m_semihosting::hprintln; #[entry] +#[inline(never)] fn main() -> ! { - let mut p = Peripherals::take().unwrap(); - let stim = &mut p.ITM.stim[0]; + // Prepend by `x` by _ to avoid warning (never used). + // The compiler is smart enough to figure out that + // `x` is not used in any menaningful way. - let mut x = 27; - iprintln!(stim, "x = {:?}", x); - hprintln!("x = {:?}", x).unwrap(); + let mut _x = 0; loop { - x += 1; + _x += 1; cortex_m::asm::nop(); cortex_m::asm::bkpt(); - x -= 1; + _x -= 1; } } // 0. Setup // For this example we will use the `nightly` compiler -// to get true inline assembly. +// to get inline assembly. +// (Inline assembly is currently not stabelized.) // // > rustup override set nightly // -// You may need/want to install addititonal components also), +// In the `Corgo.toml` file, uncomment +// # features = ["inline-asm"] # <- currently requires nightly compiler +// +// You may need/want to install addititonal components also, // to that end look at the install section in the README.md. // If you change toolchain, exit and re-start `vscode`. // @@ -93,7 +95,7 @@ fn main() -> ! { // // commit your answers (bare1_5) // -// Tips: The optimized build should have some 8 instructions +// Tips: The optimized build should have 3 instructions // while the debug (dev) build should have > 20 instructions // (both counting the inner loop only). The debug build // should have additional code that call panic if the additon @@ -119,7 +121,7 @@ fn main() -> ! { // You can enable this flag (uncomment the corresponding flag in // the `.cargo/config` file.) // -// What is now the disassembly of the loop: +// What is now the disassembly of the loop (in debug mode): // // ** your answer here ** // @@ -159,3 +161,21 @@ fn main() -> ! { // If you write a library depending on wrapping arithmetics // do NOT rely on a compiler flag. (The end user might compile // it without this flag enabled, and thus get erronous results.) +// +// NOTICE: +// ------ +// You are now on a `nightly` release of the compiler for good and bad. +// You can chose to switch back to the stable channel. If so you must +// restore the `Cargo.toml` (comment out the `features = ["inline-asm"]`) +// +// Pros and cons of nightly: +// + Acccess to new Rust features (such as inline assembly) +// - No guarantee these features will work, they might change semantics, +// or even be revoked. +// +// The compiler itself is the same, the stable release is just a snapchot +// of the nightly (released each 6 week). It is the latest nightly +// that passed some additional regression test, not a different compiler. +// And of course, the stable has the experimental features disabled. +// +// So its up to you to decide if you want to use the stable or nightly. diff --git a/examples/bare2.rs b/examples/bare2.rs new file mode 100644 index 0000000000000000000000000000000000000000..d68edd2e155eca87e19a5dae2127c85aefab56e7 --- /dev/null +++ b/examples/bare2.rs @@ -0,0 +1,87 @@ +//! bare2.rs +//! +//! Measuring execution time +//! +//! What it covers +//! - generating documentation +//! - using core peripherals +//! - measuring time using the DWT +//! + +#![no_main] +#![no_std] + +extern crate panic_halt; + +use cortex_m::{iprintln, peripheral::DWT, Peripherals}; +use cortex_m_rt::entry; + +// burns CPU cycles by just looping `i` times +fn wait(i: u32) { + for _ in 0..i { + // no operation (ensured not optimized out) + cortex_m::asm::nop(); + } +} + +#[entry] +fn main() -> ! { + let mut p = Peripherals::take().unwrap(); + let stim = &mut p.ITM.stim[0]; + let mut dwt = p.DWT; + + iprintln!(stim, "Measure Me!"); + + dwt.enable_cycle_counter(); + + // Reading the cycle counter can be done without `owning` access + // the DWT (since it has no side effetc). + // + // Look in the docs: + // pub fn enable_cycle_counter(&mut self) + // pub fn get_cycle_count() -> u32 + // + // Notice the difference in the function signature! + + let start = DWT::get_cycle_count(); + wait(1_000_000); + let end = DWT::get_cycle_count(); + + // notice all printing outside of the section to measure! + iprintln!(stim, "Start {:?}", start); + iprintln!(stim, "End {:?}", end); + + loop {} +} + +// 0. Setup +// > cargo doc --open +// This will document your crate, and open the docs in your browser. +// If it does not auto-open, the copy paste the path in your browser. +// +// In the docs, seach (`S`) for DWT, and click `cortex_m::peripheral::DWT`. +// Read the API docs. +// +// 1. Build and run the application (debug build). +// What is the output in the ITM console? +// +// ** your answer here ** + +// Rebuild and run in release mode +// +// ** your answer here ** +// +// Compute the ratio between debug/release optimized code +// (the speedup). +// +// ** your answer here ** +// +// commit your answers (bare2_1) +// +// 3. *Optional +// Inspect the generated binaries, and try stepping through the code +// for both debug and release binaries. How do they differ? +// +// ** your answer here ** +// +// commit your answers (bare2_2) diff --git a/examples/bare3.rs b/examples/bare3.rs new file mode 100644 index 0000000000000000000000000000000000000000..2d23861ebc7e27673c8d4ccca090d12660bdc572 --- /dev/null +++ b/examples/bare3.rs @@ -0,0 +1,98 @@ +//! bare3.rs +//! +//! String types in Rust +//! +//! What it covers: +//! - types, str, arrays ([u8;uszie]), slices (&[u8]) +//! - iteration, copy +//! + +#![no_main] +#![no_std] + +extern crate panic_halt; + +use cortex_m_rt::entry; +use cortex_m_semihosting::{hprint, hprintln}; + +#[entry] +fn main() -> ! { + let s = "ABCD"; + let bs = s.as_bytes(); + + hprintln!("s = {}", s).unwrap(); + hprintln!("bs = {:?}", bs).unwrap(); + + hprintln!("iterate over slice").unwrap(); + for c in bs { + hprint!("{},", c).unwrap(); + } + + hprintln!("iterate iterate using (raw) indexing").unwrap(); + for i in 0..s.len() { + hprintln!("{},", bs[i]).unwrap(); + } + + hprintln!("").unwrap(); + + let a = [65u8; 4]; + //let mut a = [0u8; 4]; + + hprintln!("").unwrap(); + hprintln!("a = {}", core::str::from_utf8(&a).unwrap()).unwrap(); + + loop {} +} + +// 1. Build and run the application (debug build) +// +// What is the output in the `openocd` (Adapter Output) console +// +// ** your answer here ** +// +// What is the type of `s`? +// +// ** your answer here ** +// +// What is the type of `bs`? +// +// ** your answer here ** +// +// What is the type of `c`? +// +// ** your answer here ** +// +// What is the type of `a`? +// +// ** your answer here ** +// +// What is the type of `i`? +// +// ** your answer here ** +// +// commit your answers (bare3_1) +// +// 2. Make types of `s`, `bs`, `c`, `a`, `i` explicit +// +// commit your answers (bare3_2) +// +// 3. Uncomment line `let mut a = [0u8; 4]; +//` +// Run the program, what happens and why? +// +// ** your answer here ** +// +// commit your answers (bare3_3) +// +// 4. Alter the program so that the data from `bs` is copied byte by byte into `a`. +// +// Test that it works as intended. +// +// commit your answers (bare3_4) +// +// 5. Look for a way to make this copy done without a loop. +// https://doc.rust-lang.org/beta/std/primitive.slice.html +// +// Implement and test your solution +// +// commit your answers (bare3_5)