From 4c83d66bc3721acf835b22f3645cf2b4e8fdae23 Mon Sep 17 00:00:00 2001 From: Jonas Jacobsson <01joja@gamil.com> Date: Fri, 12 Mar 2021 23:28:57 +0100 Subject: [PATCH] Got one led to work --- examples/all_combinations_of_colurs.rs | 293 +++++++++++++++++++++++++ examples/green_to_blink2.rs | 195 ++++++++++++++++ examples/rtic_bare6.rs | 2 +- examples/rtic_bare7.rs | 36 ++- examples/rtic_bare8.rs | 30 ++- examples/rtic_bare9.rs | 46 +++- src/main.rs | 119 +++++++++- 7 files changed, 682 insertions(+), 39 deletions(-) create mode 100644 examples/all_combinations_of_colurs.rs create mode 100644 examples/green_to_blink2.rs diff --git a/examples/all_combinations_of_colurs.rs b/examples/all_combinations_of_colurs.rs new file mode 100644 index 0000000..c969b8b --- /dev/null +++ b/examples/all_combinations_of_colurs.rs @@ -0,0 +1,293 @@ +//! rtic_bare7.rs +//! +//! HAL OutputPin abstractions +//! +//! What it covers: +//! - using embedded hal, and the OutputPin abstraction + +#![no_main] +#![no_std] + + +use panic_rtt_target as _; +use rtic::cyccnt::{Instant, U32Ext as _}; +use rtt_target::{rprintln, rtt_init_print}; +use stm32f4xx_hal::stm32; + +use stm32f4xx_hal::{ + gpio::{gpioa::PA1, gpioa::PA2, gpioa::PA3, Output, PushPull}, + prelude::*, +}; + +use embedded_hal::digital::v2::{OutputPin, ToggleableOutputPin}; + +const OFFSET: u32 = 50_000_000; + +#[rtic::app(device = stm32f4xx_hal::stm32, monotonic = rtic::cyccnt::CYCCNT, peripherals = true)] +const APP: () = { + struct Resources { + // late resources + //GPIOA: stm32::GPIOA, + led_red: PA3<Output<PushPull>>, + led_green: PA2<Output<PushPull>>, + led_blue: PA1<Output<PushPull>>, + } + #[init(schedule = [toggle])] + fn init(cx: init::Context) -> init::LateResources { + rtt_init_print!(); + rprintln!("init"); + + + let mut core = cx.core; + let device = cx.device; + + + // Initialize (enable) the monotonic timer (CYCCNT) + core.DCB.enable_trace(); + 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 + + // Schedule `toggle` to run 8e6 cycles (clock cycles) in the future + let number_of_toggles = 0; + cx.schedule.toggle(now + OFFSET.cycles(),number_of_toggles).unwrap(); + + // power on GPIOA, RM0368 6.3.11 + device.RCC.ahb1enr.modify(|_, w| w.gpioaen().set_bit()); + // configure PA3 as output, RM0368 8.4.1 + device.GPIOA.moder.modify(|_, w| w.moder3().bits(1)); + device.GPIOA.moder.modify(|_, w| w.moder2().bits(1)); + device.GPIOA.moder.modify(|_, w| w.moder1().bits(1)); + + + let gpioa = device.GPIOA.split(); + + // pass on late resources + init::LateResources { + //GPIOA: device.GPIOA, + led_red: gpioa.pa3.into_push_pull_output(), + led_green: gpioa.pa2.into_push_pull_output(), + led_blue: gpioa.pa1.into_push_pull_output(), + } + } + + #[idle] + fn idle(_cx: idle::Context) -> ! { + rprintln!("idle"); + loop { + continue; + } + } + + #[task(resources = [led_green,led_blue,led_red], schedule = [toggle])] + fn toggle(cx: toggle::Context, mut no_toggled: i32) { + static mut TOGGLE: bool = false; + //rprintln!("toggle @ {:?}", Instant::now()); + //rprintln!("times I have toggled {:?}", no_toggled); + no_toggled +=1; + + if no_toggled % 8 == 0{ + rprintln!("White"); + cx.resources.led_red.set_high().ok(); + cx.resources.led_green.set_high().ok(); + cx.resources.led_blue.set_high().ok(); + } else if no_toggled % 8 == 1{ + rprintln!("Green-yellow"); //Needs more oomph to be real yellow. + cx.resources.led_red.set_high().ok(); + cx.resources.led_green.set_high().ok(); + cx.resources.led_blue.set_low().ok(); + } else if no_toggled % 8 == 2{ + rprintln!("Purple"); + cx.resources.led_red.set_high().ok(); + cx.resources.led_green.set_low().ok(); + cx.resources.led_blue.set_high().ok(); + } else if no_toggled % 8 == 3{ + rprintln!("Light blue"); + cx.resources.led_red.set_low().ok(); + cx.resources.led_green.set_high().ok(); + cx.resources.led_blue.set_high().ok(); + } else if no_toggled % 8 == 4{ + rprintln!("Red"); + cx.resources.led_red.set_high().ok(); + cx.resources.led_green.set_low().ok(); + cx.resources.led_blue.set_low().ok(); + } else if no_toggled % 8 == 5{ + rprintln!("Green"); + cx.resources.led_red.set_low().ok(); + cx.resources.led_green.set_high().ok(); + cx.resources.led_blue.set_low().ok(); + } else if no_toggled % 8 == 6{ + rprintln!("Blue"); + cx.resources.led_red.set_low().ok(); + cx.resources.led_green.set_low().ok(); + cx.resources.led_blue.set_high().ok(); + } else { + rprintln!("Off"); + cx.resources.led_red.set_low().ok(); + cx.resources.led_green.set_low().ok(); + cx.resources.led_blue.set_low().ok(); + } + + //*TOGGLE = !*TOGGLE; + cx.schedule.toggle(cx.scheduled + OFFSET.cycles(),no_toggled).unwrap(); + } + + extern "C" { + fn EXTI0(); + } +}; + +fn _toggle_generic<E>(led: &mut dyn OutputPin<Error = E>, toggle: &mut bool) { + if *toggle { + led.set_high().ok(); + } else { + led.set_low().ok(); + } + + *toggle = !*toggle; +} + +fn _toggleable_generic<E>(led: &mut dyn ToggleableOutputPin<Error = E>) { + led.toggle().ok(); +} + +// 1. In this example you will use RTT. +// +// > cargo run --example rtic_bare7 +// +// Look in the generated documentation for `set_high`/`set_low`. +// (You created documentation for your dependencies in previous exercise +// so you can just search (press `S`) for `OutputPin`). +// You will find that these methods are implemented for `Output` pins. +// +// Now change your code to use these functions instead of the low-level GPIO API. +// +// HINTS: +// - A GPIOx peripheral can be `split` into individual PINs Px0..Px15). +// - A Pxy, can be turned into an `Output` by `into_push_pull_output`. +// - You may optionally set other pin properties as well (such as `speed`). +// - An `Output` pin provides `set_low`/`set_high` +// - Instead of passing `GPIO` resource to the `toggle` task pass the +// `led: PA5<Output<PushPull>>` resource instead. +// +// Comment your code to explain the steps taken. +// +// Confirm that your implementation correctly toggles the LED as in +// previous exercise. +// +// Commit your code (bare7_1) +// +// 2. Further generalizations: +// +// Now look at the documentation for `embedded_hal::digital::v2::OutputPin`. +// +// You see that the OutputPin trait defines `set_low`/`set_high` functions. +// Your task is to alter the code to use the `set_low`/`set_high` API. +// +// The function `_toggle_generic` is generic to any object that +// implements the `OutputPin<Error = E>` trait. +// +// Digging deeper we find the type parameter `E`, which in this case +// is left generic (unbound). +// +// It will be instantiated with a concrete type argument when called. +// +// Our `PA5<Output<PushPull>>` implements `OutputPin` trait, thus +// we can pass the `led` resource to `_toggle_generic`. +// +// The error type is given by the stm32f4xx-hal implementation: +// where `core::convert::Infallible` is used to indicate +// there are no errors to be expected (hence infallible). +// +// Additionally, `_toggle_generic` takes a mutable reference +// `toggle: &mut bool`, so you need to pass your `TOGGLE` variable. +// +// As you see, `TOGGLE` holds the "state", switching between +// `true` and `false` (to make your led blink). +// +// Change your code into using the `_toggle_generic` function. +// (You may rename it to `toggle_generic` if wished.) +// +// Confirm that your implementation correctly toggles the LED as in +// previous exercise. +// +// Commit your code (bare7_2) +// +// 3. What about the state? +// +// In your code `TOGGLE` holds the "state". However, the underlying +// hardware ALSO holds the state (if the corresponding bit is set/cleared). +// +// What if we can leverage that, and guess what we can!!!! +// +// Look at the documentation for `embedded_hal::digital::v2::ToggleableOutputPin`, +// and the implementation of: +// +// fn _toggleable_generic(led: &mut dyn ToggleableOutputPin<Error = Infallible>) { +// led.toggle().ok(); +// } +// +// The latter does not take any state variable, instead it directly `toggle()` +// the `ToggleableOutputPin`. +// +// Now alter your code to leverage on the `_toggleable_generic` function. +// (You should be able to remove the `TOGGLE` state variable altogether.) +// +// Confirm that your implementation correctly toggles the LED as in +// previous exercise. +// +// Commit your code (bare7_3) +// +// 4. Discussion: +// +// In this exercise you have gone from a very hardware specific implementation, +// to leveraging abstractions (batteries included). +// +// Your final code amounts to "configuration" rather than "coding". +// +// This reduces the risk of errors (as you let the libraries do the heavy lifting). +// +// This also improves code-re use. E.g., if you were to do something less +// trivial then merely toggling you can do that in a generic manner, +// breaking out functionality into "components" re-usable in other applications. +// +// Of course the example is trivial, you don't gain much here, but the principle +// is the same behind drivers for USART communication, USB, PMW3389 etc. +// +// 5. More details: +// +// Looking closer at the implementation: +// `led: &mut dyn OutputPin<Error = E>` +// +// You may ask what kind of mumbo jumbo is at play here. +// +// This is the way to express that we expect a mutable reference to a trait object +// that implements the `OutputPin`. Since we will change the underlying object +// (in this case an GPIOA pin 5) the reference needs to be mutable. +// +// Trait objects are further explained in the Rust book. +// The `dyn` keyword indicates dynamic dispatch (through a VTABLE). +// https://doc.rust-lang.org/std/keyword.dyn.html +// +// Notice: the Rust compiler (rustc + LLVM) is really smart. In many cases +// it can analyse the call chain, and conclude the exact trait object type at hand. +// In such cases the dynamic dispatch is turned into a static dispatch +// and the VTABLE is gone, and we have a zero-cost abstraction. +// +// If the trait object is stored for e.g., in an array along with other +// trait objects (of different concrete type), there is usually no telling +// the concrete type of each element, and we will have dynamic dispatch. +// Arguably, this is also a zero-cost abstraction, as there is no (obvious) +// way to implement it more efficiently. Remember, zero-cost is not without cost +// just that it is as good as it possibly gets (you can't make it better by hand). +// +// You can also force the compiler to deduce the type at compile time, by using +// `impl` instead of `dyn`, if you are sure you don't want the compiler to +// "fallback" to dynamic dispatch. +// +// You might find Rust to have long compile times. Yes you are right, +// and this type of deep analysis done in release mode is part of the story. +// On the other hand, the aggressive optimization allows us to code +// in a generic high level fashion and still have excellent performing binaries. \ No newline at end of file diff --git a/examples/green_to_blink2.rs b/examples/green_to_blink2.rs new file mode 100644 index 0000000..040bfb1 --- /dev/null +++ b/examples/green_to_blink2.rs @@ -0,0 +1,195 @@ +//! bare8.rs +//! +//! Serial +//! +//! What it covers: +//! - serial communication +//! - bad design + +#![no_main] +#![no_std] + +use panic_rtt_target as _; + + +use stm32f4xx_hal::{ + gpio::{gpioa::PA, Output, PushPull}, + prelude::*, + serial::{config::Config, Rx, Serial, Tx}, + stm32::USART2, + nb::block, +}; + +use rtic::app; +use rtt_target::{rprintln, rtt_init_print}; + +#[app(device = stm32f4xx_hal::stm32, peripherals = true)] +const APP: () = { + struct Resources { + // Late resources + TX: Tx<USART2>, + RX: Rx<USART2>, + } + + // init runs in an interrupt free section + #[init] + fn init(cx: init::Context) -> init::LateResources { + rtt_init_print!(); + rprintln!("init"); + + let device = cx.device; + + let rcc = device.RCC.constrain(); + + // 16 MHz (default, all clocks) + let clocks = rcc.cfgr.freeze(); + + let gpioa = device.GPIOA.split(); + + let tx = gpioa.pa2.into_alternate_af7(); + let rx = gpioa.pa3.into_alternate_af7(); + + let serial = Serial::usart2( + device.USART2, + (tx, rx), + Config::default().baudrate(115_200.bps()), + clocks, + ) + .unwrap(); + + // Separate out the sender and receiver of the serial port + let (tx, rx) = serial.split(); + + // Late resources + init::LateResources { TX: tx, RX: rx } + } + + // idle may be interrupted by other interrupts/tasks in the system + #[idle(resources = [RX, TX])] + fn idle(cx: idle::Context) -> ! { + let rx = cx.resources.RX; + let tx = cx.resources.TX; + let mut received = 0; + let mut errors = 0; + + loop { + match block!(rx.read()) { + Ok(byte) => { + rprintln!("Ok {:?}", byte); + tx.write(byte).unwrap(); + received +=1; + } + Err(err) => { + rprintln!("Error {:?}", err); + let test:u8 = 13; + tx.write(test).unwrap(); + errors +=1; + } + } + rprintln!("Numbers of received: {:?}", received); + rprintln!("Numbers of errors: {:?}", errors); + } + } +}; + +// 0. Background +// +// The Nucleo st-link programmer provides a Virtual Com Port (VCP). +// It is connected to the PA2(TX)/PA3(RX) pins of the stm32f401/411. +// On the host, the VCP is presented under `/dev/ttyACMx`, where +// `x` is an enumerated number (ff 0 is busy it will pick 1, etc.) +// +// 1. In this example we use RTT. +// +// > cargo run --example rtic_bare8 +// +// Start a terminal program, e.g., `moserial`. +// Connect to the port +// +// Device /dev/ttyACM0 +// Baude Rate 115200 +// Data Bits 8 +// Stop Bits 1 +// Parity None +// +// This setting is typically abbreviated as 115200 8N1. +// +// Send a single character (byte), (set the option `No end` in `moserial`). +// Verify that sent bytes are echoed back, and that RTT tracing is working. +// +// Try sending "a", don't send the quotation marks, just a. +// +// What do you receive in `moserial`? +// +// I can't run moserial (Windows). But PuTTY seems to get a. +// +// What do you receive in the RTT terminal? +// +// OK 97 +// +// Try sending: "abcd" as a single sequence, don't send the quotation marks, just abcd. +// +// What did you receive in `moserial`? +// +// ad (Running PuTTY. Not moserial) +// +// What do you receive in the RTT terminal? +// +// Ok 97 +// Error Overrun +// Ok 100 +// +// What do you believe to be the problem? +// +// Hint: Look at the code in `idle` what does it do? +// +// The buffer have not been read from and has not been cleared. +// +// Experiment a bit, what is the max length sequence you can receive without errors? +// +// 8 bits or 1 byte. +// +// Commit your answers (bare8_1) +// +// 2. Add a local variable `received` that counts the number of bytes received. +// Add a local variable `errors` that counts the number of errors. +// +// Adjust the RTT trace to print the added information inside the loop. +// +// Compile/run reconnect, and verify that it works as intended. +// +// Commit your development (bare8_2) +// +// 3. Experiment a bit, what is the max length sequence you can receive without errors? +// +// 1 +// +// How did the added tracing/instrumentation affect the behavior? +// +// I now only receive a back. +// +// Commit your answer (bare8_3) +// +// 4. Now try compile and run the same experiment 3 but in --release mode. +// +// > cargo run --example rtic_bare8 --release +// +// Reconnect your `moserial` terminal. +// +// Experiment a bit, what is the max length sequence you can receive without errors? +// +// Now I receive "ad" again +// +// Commit your answer (bare8_4) +// +// 5. Discussion +// +// (If you ever used Arduino, you might feel at home with the `loop` and poll design.) +// +// Typically, this is what you can expect from a polling approach, if you +// are not very careful what you are doing. This exemplifies a bad design. +// +// Loss of data might be Ok for some applications but this typically NOT what we want. +// +// (With that said, Arduino gets away with some simple examples as their drivers do +// internal magic - buffering data etc.) diff --git a/examples/rtic_bare6.rs b/examples/rtic_bare6.rs index 255ff36..4faa076 100644 --- a/examples/rtic_bare6.rs +++ b/examples/rtic_bare6.rs @@ -98,7 +98,7 @@ const APP: () = { rprintln!("toggle @ {:?}", Instant::now()); if *TOGGLE { - cx.resources.GPIOA.bsrr.write(|w| w.bs5().set_bit()); + cx.resources.GPIOA.bsrr.write(|w| w.bs5z().set_bit()); } else { cx.resources.GPIOA.bsrr.write(|w| w.br5().set_bit()); } diff --git a/examples/rtic_bare7.rs b/examples/rtic_bare7.rs index 0f2dea1..50b167a 100644 --- a/examples/rtic_bare7.rs +++ b/examples/rtic_bare7.rs @@ -8,6 +8,7 @@ #![no_main] #![no_std] + use panic_rtt_target as _; use rtic::cyccnt::{Instant, U32Ext as _}; use rtt_target::{rprintln, rtt_init_print}; @@ -17,7 +18,7 @@ use stm32f4xx_hal::{ gpio::{gpioa::PA5, Output, PushPull}, prelude::*, }; -; + use embedded_hal::digital::v2::{OutputPin, ToggleableOutputPin}; const OFFSET: u32 = 8_000_000; @@ -26,17 +27,19 @@ const OFFSET: u32 = 8_000_000; const APP: () = { struct Resources { // late resources - GPIOA: stm32::GPIOA, - // led: PA5<Output<PushPull>>, + //GPIOA: stm32::GPIOA, + led: PA5<Output<PushPull>>, } #[init(schedule = [toggle])] fn init(cx: init::Context) -> init::LateResources { rtt_init_print!(); rprintln!("init"); + let mut core = cx.core; let device = cx.device; + // Initialize (enable) the monotonic timer (CYCCNT) core.DCB.enable_trace(); core.DWT.enable_cycle_counter(); @@ -46,16 +49,21 @@ const APP: () = { let now = cx.start; // the start time of the system // Schedule `toggle` to run 8e6 cycles (clock cycles) in the future - cx.schedule.toggle(now + OFFSET.cycles()).unwrap(); + let number_of_toggles = 0; + cx.schedule.toggle(now + OFFSET.cycles(),number_of_toggles).unwrap(); // 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)); + + let gpioa = device.GPIOA.split(); + // pass on late resources init::LateResources { - GPIOA: device.GPIOA, + //GPIOA: device.GPIOA, + led: gpioa.pa5.into_push_pull_output(), } } @@ -67,19 +75,25 @@ const APP: () = { } } - #[task(resources = [GPIOA], schedule = [toggle])] - fn toggle(cx: toggle::Context) { + #[task(resources = [led], schedule = [toggle])] + fn toggle(cx: toggle::Context, mut no_toggled: i32) { static mut TOGGLE: bool = false; rprintln!("toggle @ {:?}", Instant::now()); + rprintln!("times I have toggled {:?}", no_toggled); + no_toggled +=1; + /* if *TOGGLE { - cx.resources.GPIOA.bsrr.write(|w| w.bs5().set_bit()); + cx.resources.led.set_high(); } else { - cx.resources.GPIOA.bsrr.write(|w| w.br5().set_bit()); + cx.resources.led.set_low(); } + */ + + _toggleable_generic(cx.resources.led); - *TOGGLE = !*TOGGLE; - cx.schedule.toggle(cx.scheduled + OFFSET.cycles()).unwrap(); + //*TOGGLE = !*TOGGLE; + cx.schedule.toggle(cx.scheduled + OFFSET.cycles(),no_toggled).unwrap(); } extern "C" { diff --git a/examples/rtic_bare8.rs b/examples/rtic_bare8.rs index b4b18ee..040bfb1 100644 --- a/examples/rtic_bare8.rs +++ b/examples/rtic_bare8.rs @@ -11,13 +11,13 @@ use panic_rtt_target as _; -use nb::block; use stm32f4xx_hal::{ gpio::{gpioa::PA, Output, PushPull}, prelude::*, serial::{config::Config, Rx, Serial, Tx}, stm32::USART2, + nb::block, }; use rtic::app; @@ -69,17 +69,25 @@ const APP: () = { fn idle(cx: idle::Context) -> ! { let rx = cx.resources.RX; let tx = cx.resources.TX; + let mut received = 0; + let mut errors = 0; loop { match block!(rx.read()) { Ok(byte) => { rprintln!("Ok {:?}", byte); tx.write(byte).unwrap(); + received +=1; } Err(err) => { rprintln!("Error {:?}", err); + let test:u8 = 13; + tx.write(test).unwrap(); + errors +=1; } } + rprintln!("Numbers of received: {:?}", received); + rprintln!("Numbers of errors: {:?}", errors); } } }; @@ -113,31 +121,33 @@ const APP: () = { // // What do you receive in `moserial`? // -// ** your answer here ** +// I can't run moserial (Windows). But PuTTY seems to get a. // // What do you receive in the RTT terminal? // -// ** your answer here ** +// OK 97 // // Try sending: "abcd" as a single sequence, don't send the quotation marks, just abcd. // // What did you receive in `moserial`? // -// ** your answer here ** +// ad (Running PuTTY. Not moserial) // // What do you receive in the RTT terminal? // -// ** your answer here ** +// Ok 97 +// Error Overrun +// Ok 100 // // What do you believe to be the problem? // // Hint: Look at the code in `idle` what does it do? // -// ** your answer here ** +// The buffer have not been read from and has not been cleared. // // Experiment a bit, what is the max length sequence you can receive without errors? // -// ** your answer here ** +// 8 bits or 1 byte. // // Commit your answers (bare8_1) // @@ -152,11 +162,11 @@ const APP: () = { // // 3. Experiment a bit, what is the max length sequence you can receive without errors? // -// ** your answer here ** +// 1 // // How did the added tracing/instrumentation affect the behavior? // -// ** your answer here ** +// I now only receive a back. // // Commit your answer (bare8_3) // @@ -168,7 +178,7 @@ const APP: () = { // // Experiment a bit, what is the max length sequence you can receive without errors? // -// ** your answer here ** +// Now I receive "ad" again // // Commit your answer (bare8_4) // diff --git a/examples/rtic_bare9.rs b/examples/rtic_bare9.rs index a1fc61c..6c3d4bb 100644 --- a/examples/rtic_bare9.rs +++ b/examples/rtic_bare9.rs @@ -13,17 +13,23 @@ use stm32f4xx_hal::{ prelude::*, serial::{config::Config, Event, Rx, Serial, Tx}, stm32::USART2, + nb::block, }; use rtic::app; use rtt_target::{rprintln, rtt_init_print}; + #[app(device = stm32f4xx_hal::stm32, peripherals = true)] const APP: () = { struct Resources { // Late resources TX: Tx<USART2>, RX: Rx<USART2>, + #[init(0)] + fel: u32, + #[init(0)] + corr: u32, } // init runs in an interrupt free section @@ -59,7 +65,7 @@ const APP: () = { let (tx, rx) = serial.split(); // Late resources - init::LateResources { TX: tx, RX: rx } + init::LateResources { TX: tx, RX: rx} } // idle may be interrupted by other interrupts/tasks in the system @@ -71,23 +77,51 @@ const APP: () = { } // capacity sets the size of the input buffer (# outstanding messages) - #[task(resources = [TX], priority = 1, capacity = 128)] - fn rx(cx: rx::Context, data: u8) { + #[task(resources = [TX], priority = 2, capacity = 128)] + fn rx(cx: rx::Context,data:u8) { let tx = cx.resources.TX; tx.write(data).unwrap(); + } + + #[task(priority = 1,resources = [fel,corr])] + fn trace(cx: trace::Context, worked: bool,data:u8,){ + match worked{ + true => { + *cx.resources.corr +=1; + rprintln!("Ok {:?}", data); + } + false =>{ + *cx.resources.fel +=1; + rprintln!("some error"); + } + } + rprintln!("correct {}", cx.resources.corr); + rprintln!("errors {}", cx.resources.fel); rprintln!("data {}", data); } // Task bound to the USART2 interrupt. - #[task(binds = USART2, priority = 2, resources = [RX], spawn = [rx])] + #[task(binds = USART2, priority = 3, resources = [RX], spawn = [rx,trace])] fn usart2(cx: usart2::Context) { let rx = cx.resources.RX; - let data = rx.read().unwrap(); + let data; + match (rx.read()) { + Ok(byte) => { + data = byte; + let result = cx.spawn.trace(true,byte); + } + Err(err) => { + data = 0; + rprintln!("Error {:?}", err); + cx.spawn.trace(false,data).unwrap(); + } + } cx.spawn.rx(data).unwrap(); } extern "C" { fn EXTI0(); + fn USART1(); } }; @@ -148,7 +182,7 @@ const APP: () = { // // Were you able to crash it? // -// ** your answer here ** +// Yes // // Notice, the input tracing in `moserial` seems broken, and may loose data. // So don't be alarmed if data is missing, its a GUI tool after all. diff --git a/src/main.rs b/src/main.rs index 7922596..04dfbf9 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,20 +1,117 @@ +#![deny(unsafe_code)] +#![deny(warnings)] #![no_std] #![no_main] -// pick a panicking behavior -use panic_halt as _; // you can put a breakpoint on `rust_begin_unwind` to catch panics -// use panic_abort as _; // requires nightly +// pick a panicking behavior// use panic_abort as _; // requires nightly // use panic_itm as _; // logs messages over ITM; requires ITM support // use panic_semihosting as _; // logs messages to the host stderr; requires a debugger -use cortex_m::asm; -use cortex_m_rt::entry; -#[entry] -fn main() -> ! { - asm::nop(); // To not have main optimize to abort in release mode, remove when you add code +use panic_halt as _; // you can put a breakpoint on `rust_begin_unwind` to catch panics +use rtt_target::{rprintln, rtt_init_print}; + + +use cortex_m::peripheral::DWT; +use stm32f4xx_hal::stm32; + +//use cortex_m::asm; +//use cortex_m_rt::entry; + +use rtic::cyccnt::{Instant, U32Ext as _}; + + +#[rtic::app(device = stm32f4xx_hal::stm32, monotonic = rtic::cyccnt::CYCCNT, peripherals = true)] +const APP: () = { + struct Resources { + // late resources + GPIOA: stm32::GPIOA, + GPIOC: stm32::GPIOC, + //button: <stm32::GPIOC as int>::PC13, + } + + #[init(schedule = [toggle])] + fn init(cx: init::Context) -> init::LateResources { + rtt_init_print!(); + rprintln!("init"); + + for i in 0..11 { + rprintln!("RTIC Says Hello, world {}!!", i); + } + + 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(); - loop { - // your code goes here + // 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 + + // Schedule `toggle` to run 8e6 cycles (clock cycles) in the future + cx.schedule.toggle(now + 8_000_000.cycles()).unwrap(); + + // 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)); + + // Test button thingy. Think I put PC13 to input + device.GPIOC.moder.modify(|_, w| w.moder13().bits(0)); + // device.GPIOC.pupdr.modify(|_, w| w.pupdr13().bits(0)); + + // pass on late resources + init::LateResources { + GPIOA: device.GPIOA, + GPIOC: device.GPIOC, + //button: device.button, + } } -} + + + #[idle] + fn idle(_cx: idle::Context) -> ! { + rprintln!("lets get lazy"); + loop { + continue; + } + } + + + + #[task(resources = [GPIOA,GPIOC], schedule = [toggle])] + fn toggle(cx: toggle::Context) { + static mut TOGGLE: bool = false; + rprintln!("toggle @ {:?}", Instant::now()); + + if *TOGGLE { + cx.resources.GPIOA.bsrr.write(|w| w.bs5().set_bit()); + } else { + cx.resources.GPIOA.bsrr.write(|w| w.br5().set_bit()); + } + +<<<<<<< HEAD +======= + //cx.resources.GPIOC.PullDown; + +>>>>>>> 3104a68743e72194c1e8649cdee76a82240fc05e + *TOGGLE = !*TOGGLE; + cx.schedule + .toggle(cx.scheduled + 16_000_000.cycles()) + .unwrap(); +<<<<<<< HEAD +======= + +>>>>>>> 3104a68743e72194c1e8649cdee76a82240fc05e + } + + extern "C" { + fn EXTI0(); + } +}; + -- GitLab