From c391ea71f7cd5271612bea42a19a529d2c042a4e Mon Sep 17 00:00:00 2001 From: Per Lindgren <per.lindgren@ltu.se> Date: Sun, 7 Mar 2021 15:44:02 +0100 Subject: [PATCH] updated rtic_bare7 --- examples/rtic_bare7.rs | 111 +++++++++++++++++++++++++++++++++-------- 1 file changed, 90 insertions(+), 21 deletions(-) diff --git a/examples/rtic_bare7.rs b/examples/rtic_bare7.rs index 6813067..fc08f00 100644 --- a/examples/rtic_bare7.rs +++ b/examples/rtic_bare7.rs @@ -1,15 +1,26 @@ //! rtic_bare7.rs //! -//! Clocking +//! 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::PA5, Output, PushPull}, + prelude::*, +}; + +use core::convert::Infallible; +use embedded_hal::digital::v2::{OutputPin, ToggleableOutputPin}; + const OFFSET: u32 = 8_000_000; #[rtic::app(device = stm32f4xx_hal::stm32, monotonic = rtic::cyccnt::CYCCNT, peripherals = true)] @@ -17,6 +28,7 @@ const APP: () = { struct Resources { // late resources GPIOA: stm32::GPIOA, + // led: PA5<Output<PushPull>>, } #[init(schedule = [toggle])] fn init(cx: init::Context) -> init::LateResources { @@ -76,23 +88,38 @@ const APP: () = { } }; +fn _toggle_generic(led: &mut dyn OutputPin<Error = Infallible>, toggle: &mut bool) { + if *toggle { + led.set_high().ok(); + } else { + led.set_low().ok(); + } + + *toggle = !*toggle; +} + +fn _toggleable_generic(led: &mut dyn ToggleableOutputPin<Error = Infallible>) { + led.toggle().ok(); +} + // 1. In this example you will use RTT. // // > cargo run --example rtic_bare7 // -// Now look at the documentation for `embedded_hal::digital::v2::OutputPin`. +// 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. // -// 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. +// 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` -// (and implements the `OutputPin` trait in embedded-hal). +// - 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. // @@ -101,29 +128,71 @@ const APP: () = { // // Commit your code (bare7_1) // -// 2. Optional +// 2. Further generalizations: // -// Use the `toggle` function instead to further simply your code. +// 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. // -// Notice: -// The `ToggleableOutputPin` abstraction requires `embedded-hal` -// to compiled with the `unproven` feature. +// The function `_toggle_generic` is generic to any object that +// implements the `OutputPin<Error = Infallible>` trait. // -// The `embedded-hal` traits is mostly used to write drivers -// that is hardware agnostic (and thus cross platform). +// The type parameter `Error = Infallible` indicates that +// there are no errors to be expected (hence infallible). // -// However: -// In our case we can use `toggle` directly as implemented by the `stm32f4xx-hal`. +// Our `PA5<Output<PushPull>>` (led) is such an implementor. +// Additionally, `_toggle_generic` takes a mutable reference +// `toggle: &mut bool`, so you need to pass your `TOGGLE` variable. // -// Confirm that your implementation correctly toggles the LED. +// As you see, `TOGGLE` holds the "state", switching between +// `true` and `false` (to make your led blink). // -// Which one do you prefer and why (what problem does it solve)? +// 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. // -// ** your answer here ** +// Commit your code (bare7_3) // -// Commit your answer (bare7_2) +// 4. Discussion: +// +// In this exercise you have gone from a very hardware specific implementation, +// to leveraging abstractions (batteries included). // -// 3. Discussion +// Your final code amounts to "configuration" rather than "coding". // -// In this exercise you have learned more on navigating the generated documentation -// and to use abstractions to simplify and generalize your code. +// 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. -- GitLab