diff --git a/.vscode/launch.json b/.vscode/launch.json index c899c7449f658dc64f51100d0332cff06772c77d..6ed0aed685496ee27d4ee0e64903870ff1554c08 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -88,6 +88,56 @@ "cwd": "${workspaceRoot}" }, // Launch configuration for `examples` + // - debug + // - semihosting + // - ITM/SWO tracing to file/fifo `/tmp/itm.fifo` + // - run to main + { + "type": "cortex-debug", + "request": "launch", + "servertype": "openocd", + "name": "itm fifo (debug) stm32f4", + "preLaunchTask": "cargo build --example --features stm32f4", + "executable": "./target/thumbv7em-none-eabihf/debug/examples/${fileBasenameNoExtension}", + "configFiles": [ + "interface/stlink.cfg", + // "interface/stlink-v2-1.cfg", // deprecated setup script + "target/stm32f4x.cfg" + ], + "postLaunchCommands": [ + "monitor arm semihosting enable", + "monitor tpiu config internal /tmp/itm.fifo uart off 16000000", + "monitor itm port 0 on" + ], + "runToMain": true, + "cwd": "${workspaceRoot}" + }, + // Launch configuration for `examples` + // - debug + // - semihosting + // - ITM/SWO tracing to file/fifo `/tmp/itm.fifo` + // - run to main + { + "type": "cortex-debug", + "request": "launch", + "servertype": "openocd", + "name": "itm fifo (debug) rtfm", + "preLaunchTask": "cargo build --example --features rtfm", + "executable": "./target/thumbv7em-none-eabihf/debug/examples/${fileBasenameNoExtension}", + "configFiles": [ + "interface/stlink.cfg", + // "interface/stlink-v2-1.cfg", // deprecated setup script + "target/stm32f4x.cfg" + ], + "postLaunchCommands": [ + "monitor arm semihosting enable", + "monitor tpiu config internal /tmp/itm.fifo uart off 16000000", + "monitor itm port 0 on" + ], + "runToMain": true, + "cwd": "${workspaceRoot}" + }, + // Launch configuration for `examples` // - release // - semihosting // - ITM/SWO tracing to file/fifo `/tmp/itm.fifo` @@ -121,8 +171,8 @@ "type": "cortex-debug", "request": "launch", "servertype": "openocd", - "name": "itm fifo 64MHz (release)", - "preLaunchTask": "cargo build --example --release", + "name": "itm fifo 64MHz (release) stm32f4", + "preLaunchTask": "cargo build --example --release --features stm32f4", "executable": "./target/thumbv7em-none-eabihf/release/examples/${fileBasenameNoExtension}", "configFiles": [ "interface/stlink.cfg", diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 13860c24cd509bafc8fd02512f1a0a64170df201..c5dc1cfeb28edfcc0b42b4a4b44f2d993738d597 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -41,8 +41,32 @@ }, { "type": "shell", - "label": "cargo build --example --release", - "command": "cargo build --example ${fileBasenameNoExtension} --release", + "label": "cargo build --example --features stm32f4", + "command": "cargo build --example ${fileBasenameNoExtension} --features stm32f4", + "group": { + "kind": "build", + "isDefault": true + }, + "problemMatcher": [ + "$rustc" + ] + }, + { + "type": "shell", + "label": "cargo build --example --features rtfm", + "command": "cargo build --example ${fileBasenameNoExtension} --features rtfm", + "group": { + "kind": "build", + "isDefault": true + }, + "problemMatcher": [ + "$rustc" + ] + }, + { + "type": "shell", + "label": "cargo build --example --release --features stm32f4", + "command": "cargo build --example ${fileBasenameNoExtension} --release --features stm32f4", "group": { "kind": "build", "isDefault": true diff --git a/Cargo.toml b/Cargo.toml index ff1c334328f6f767010efae2f71327de145f1633..774fd51bf12ca13cb290995d006e321df8401860 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -53,6 +53,10 @@ bench = false name = "device" required-features = ["stm32f4"] +[[example]] +name = "bare6" +required-features = ["stm32f4"] + [[example]] name = "serial" required-features = ["stm32f4xx-hal"] @@ -85,9 +89,14 @@ required-features = ["rtfm"] name = "rtfm_blinky_msg3" required-features = ["rtfm"] +[[example]] +name = "rtfm_blinky_sw_reset" +required-features = ["rtfm"] + +# for more info see, https://doc.rust-lang.org/rustc/codegen-options/index.html [profile.dev] -opt-level = 1 -codegen-units = 16 +# opt-level = 1 # better optimization (may optimize out symbols) +# codegen-units = 16 debug = true lto = false diff --git a/examples/bare5.rs b/examples/bare5.rs index 90ce2066c5f374b5277ea923bcc474927c1ce524..138c7ee46881c9fb933de665b8d78a65eb6cc0fc 100644 --- a/examples/bare5.rs +++ b/examples/bare5.rs @@ -189,17 +189,19 @@ fn idle(rcc: &mut RCC, gpioa: &mut GPIOA) { loop { // set PA5 high gpioa.BSRRH.write(1 << 5); // set bit, output hight (turn on led) - // alternatively to set the bit high we can - // read the value, or with PA5 (bit 5) and write back - // gpioa.ODR.write(gpioa.ODR.read() | (1 << 5)); + + // alternatively to set the bit high we can + // read the value, or with PA5 (bit 5) and write back + // gpioa.ODR.write(gpioa.ODR.read() | (1 << 5)); wait(10_000); // set PA5 low gpioa.BSRRL.write(1 << 5); // clear bit, output low (turn off led) - // alternatively to clear the bit we can - // read the value, mask out PA5 (bit 5) and write back - // gpioa.ODR.write(gpioa.ODR.read() & !(1 << 5)); + + // alternatively to clear the bit we can + // read the value, mask out PA5 (bit 5) and write back + // gpioa.ODR.write(gpioa.ODR.read() & !(1 << 5)); wait(10_000); } } diff --git a/examples/bare6.rs b/examples/bare6.rs new file mode 100644 index 0000000000000000000000000000000000000000..fe91a1398a516097a29b3c7727ef156b5752fe43 --- /dev/null +++ b/examples/bare6.rs @@ -0,0 +1,212 @@ +//! bare6.rs +//! +//! Clocking +//! +//! What it covers: +//! - using svd2rust generated API +//! - setting the clock via script (again) +//! - routing the clock to a PIN for monitoring by an oscilloscope + +#![no_main] +#![no_std] + +extern crate panic_halt; + +use cortex_m::{iprintln, peripheral::itm::Stim}; +use cortex_m_rt::entry; + +use stm32f4::stm32f401::{self, DWT, GPIOA, GPIOC, RCC}; + +#[entry] +fn main() -> ! { + let p = stm32f401::Peripherals::take().unwrap(); + let mut c = stm32f401::CorePeripherals::take().unwrap(); + + let stim = &mut c.ITM.stim[0]; + iprintln!(stim, "bare6"); + + c.DWT.enable_cycle_counter(); + unsafe { + c.DWT.cyccnt.write(0); + } + let t = DWT::get_cycle_count(); + iprintln!(stim, "{}", t); + + clock_out(&p.RCC, &p.GPIOC); + idle(stim, p.RCC, p.GPIOA); +} + +// user application +fn idle(stim: &mut Stim, rcc: RCC, gpioa: GPIOA) -> ! { + iprintln!(stim, "idle"); + + // power on GPIOA, RM0368 6.3.11 + rcc.ahb1enr.modify(|_, w| w.gpioaen().set_bit()); + + // configure PA5 as output, RM0368 8.4.1 + gpioa.moder.modify(|_, w| w.moder5().bits(1)); + + // at 16 Mhz, 8_000_000 cycles = period 0.5s + // at 64 Mhz, 4*8_000_000 cycles = period 0.5s + // let cycles = 8_000_000; + let cycles = 4 * 8_000_000; + + loop { + iprintln!(stim, "on {}", DWT::get_cycle_count()); + // set PA5 high, RM0368 8.4.7 + gpioa.bsrr.write(|w| w.bs5().set_bit()); + wait_cycles(cycles); + + iprintln!(stim, "off {}", DWT::get_cycle_count()); + // set PA5 low, RM0368 8.4.7 + gpioa.bsrr.write(|w| w.br5().set_bit()); + wait_cycles(cycles); + } +} + +// uses the DWT.CYCNT +// doc: ARM trm_100166_0001_00_en.pdf, chapter 9.2 +// we use the `cortex-m` abstraction, as re-exported by the stm32f40x +fn wait_cycles(nr_cycles: u32) { + let t = DWT::get_cycle_count().wrapping_add(nr_cycles); + while (DWT::get_cycle_count().wrapping_sub(t) as i32) < 0 {} +} + +// see the Reference Manual RM0368 (www.st.com/resource/en/reference_manual/dm00096844.pdf) +// rcc, chapter 6 +// gpio, chapter 8 +fn clock_out(rcc: &RCC, gpioc: &GPIOC) { + // output MCO2 to pin PC9 + + // mco2 : SYSCLK = 0b00 + // mcopre : divide by 4 = 0b110 + rcc.cfgr + .modify(|_, w| unsafe { w.mco2().bits(0b00).mco2pre().bits(0b110) }); + + // power on GPIOC, RM0368 6.3.11 + rcc.ahb1enr.modify(|_, w| w.gpiocen().set_bit()); + + // MCO_2 alternate function AF0, STM32F401xD STM32F401xE data sheet + // table 9 + // AF0, gpioc reset value = AF0 + + // configure PC9 as alternate function 0b10, RM0368 6.2.10 + gpioc.moder.modify(|_, w| w.moder9().bits(0b10)); + + // otyper reset state push/pull, in reset state (don't need to change) + + // ospeedr 0b11 = very high speed + gpioc.ospeedr.modify(|_, w| w.ospeedr9().bits(0b11)); +} + +// Optional assignment +// 0. Compile and run the example, in 16Mhz +// +// > cargo build --example bare6 --features "stm32f4" +// (or use the vscode build task) +// +// The "stm32f4" feature enables the optional dependency "stm32f4", with the "stm32f401" feature set +// +// Cargo.toml: +// +// [dependencies.stm32f4] +// version = "0.9.0" +// features = ["stm32f401", "rt"] +// optional = true +// (this will provide the "stm32f401" interrupt vector through the "rt" feature) +// +// [[example]] +// name = "bare6" +// required-features = ["stm32f4"] +// (this will require/force you to use the stm32f4 feature) +// +// 1. The processor SYSCLK defaults to HCI 16Mhz +// (this is what you get after a `monitor reset halt`). +// +// Confirm that your ITM dump traces the init, idle and led on/off. +// Make sure your TPIU is set to a system clock at 16Mhz +// +// What is the frequency of blinking? +// +// ** your answer here ** +// +// commit your answers (bare6_1) +// +// 2. Now connect an oscilloscope to PC9, which is set to +// output the MCO2. +// +// What is the frequency of MCO2 read by the oscilloscope? +// +// ** your answer here ** +// +// Compute the value of SYSCLK based on the oscilloscope reading +// +// ** your answer here ** +// +// What is the peak to peak reading of the signal? +// +// ** your answer here ** +// +// Make a folder called "pictures" in your git project. +// Make a screen dump or photo of the oscilloscope output. +// Save the the picture as "bare_6_16mhz_high_speed". +// +// Commit your answers (bare6_2) +// +// 3. Now run the example in 64Mz +// You can do that by issuing a `monitor reset init` +// which reprograms SYSCLK to 4*HCI. +// +// +// Confirm that your ITM dump traces the init, idle and led on/off +// (make sure your TPIU is set to a system clock at 64Mhz) +// +// Uncommnet: `let cycles = 4 * 8_000_000; +//` +// What is the frequency of blinking? +// +// ** your answer here ** +// +// Commit your answers (bare6_3) +// +// 4. Repeat experiment 2 +// +// What is the frequency of MCO2 read by the oscilloscope? +// +// ** your answer here ** +// +// Compute the value of SYSCLK based on the oscilloscope reading. +// +// ** your answer here ** +// +// What is the peak to peak reading of the signal? +// +// ** your answer here ** +// +// Make a screen dump or photo of the oscilloscope output. +// Save the the picture as "bare_6_64mhz_high_speed". +// +// Commit your answers (bare6_4) +// +// 5. In the `clock_out` function, the setup of registers is done through +// setting bit-pattens manually, e.g. +// rcc.cfgr +// .modify(|_, w| unsafe { w.mco2().bits(0b00).mco2pre().bits(0b110) }); +// +// However based on the vendor SVD file the svd2rust API provides +// a better abstraction, based on pattern enums and functions. +// +// To view the API you can generate documentation for your crate: +// +// > cargo doc --features "stm32f4" --open +// +// By searching for `mco2` you find the enumerations and functions. +// So here +// `w.mco2().bits{0b00}` is equivalent to +// `w.mco2().sysclk()` and improves readability. +// +// Replace all bit-patterns used by the function name equivalents. +// +// Test that the application still runs as before. +// +// Commit your code (bare6_4) \ No newline at end of file diff --git a/examples/rtfm_blinky_sw_reset.rs b/examples/rtfm_blinky_sw_reset.rs new file mode 100644 index 0000000000000000000000000000000000000000..bf8367568a1420cbb0f02a1e8dbdfc622fdd8aad --- /dev/null +++ b/examples/rtfm_blinky_sw_reset.rs @@ -0,0 +1,73 @@ +#![deny(unsafe_code)] +// #![deny(warnings)] +#![no_main] +#![no_std] + +use cortex_m; +use cortex_m::peripheral::DWT; +use panic_halt as _; +use rtfm::cyccnt::U32Ext; +use stm32f4xx_hal::stm32; + +#[rtfm::app(device = stm32f4xx_hal::stm32, monotonic = rtfm::cyccnt::CYCCNT, peripherals = true)] +const APP: () = { + #[init(schedule = [toggle])] + fn init(cx: init::Context) { + let mut core = cx.core; + let device = cx.device; + + // Initialize (enable) the monotonic timer (CYCCNT) + core.DCB.enable_trace(); + // required on Cortex-M7 devices that software lock the DWT (e.g. STM32F7) + DWT::unlock(); + core.DWT.enable_cycle_counter(); + + // semantically, the monotonic timer is frozen at time "zero" during `init` + // NOTE do *not* call `Instant::now` in this context; it will return a nonsense value + let now = cx.start; // the start time of the system + + // power on GPIOA, RM0368 6.3.11 + device.RCC.ahb1enr.modify(|_, w| w.gpioaen().set_bit()); + // configure PA5 as output, RM0368 8.4.1 + device.GPIOA.moder.modify(|_, w| w.moder5().bits(1)); + + cx.schedule + .toggle(now + 8_000_000.cycles(), true, device.GPIOA, core.SCB, 1) + .ok(); + } + + #[task(schedule= [toggle])] + fn toggle( + cx: toggle::Context, + toggle: bool, + gpioa: stm32::GPIOA, + mut scb: stm32::SCB, + mut state: u8, + ) { + if toggle { + gpioa.bsrr.write(|w| w.bs5().set_bit()); + } else { + gpioa.bsrr.write(|w| w.br5().set_bit()); + } + + state += 1; + if state == 10 { + //state = 0; + // scb.system_reset(); + cortex_m::peripheral::SCB::sys_reset(); + }; + cx.schedule + .toggle( + cx.scheduled + (state as u32 * 400_000).cycles(), + !toggle, + gpioa, + scb, + state, + ) + .ok(); + } + + extern "C" { + fn EXTI0(); + } +};