From 8af2da37f6e13daabdc275f19ffe434430c64fa5 Mon Sep 17 00:00:00 2001 From: Gabriel Dobato Date: Tue, 18 Jun 2024 20:57:43 +0200 Subject: [PATCH] Prepare async infrastructure --- .cargo/config.toml | 19 +-- Cargo.toml | 1 + README.md | 16 +-- examples/{blinky.rs => rtic_blinky.rs} | 7 +- examples/{usb_echo.rs => rtic_usb_echo.rs} | 5 +- .../{usb_led_ctrl.rs => rtic_usb_led_ctrl.rs} | 9 +- src/board/async_impl.rs | 1 + src/board/mod.rs | 135 +----------------- src/board/non_async_impl.rs | 130 +++++++++++++++++ 9 files changed, 170 insertions(+), 153 deletions(-) rename examples/{blinky.rs => rtic_blinky.rs} (92%) rename examples/{usb_echo.rs => rtic_usb_echo.rs} (98%) rename examples/{usb_led_ctrl.rs => rtic_usb_led_ctrl.rs} (98%) create mode 100644 src/board/async_impl.rs create mode 100644 src/board/non_async_impl.rs diff --git a/.cargo/config.toml b/.cargo/config.toml index a677387..c3fddde 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -5,17 +5,18 @@ ee = "embed --example" oe = "objcopy --example" # Aliases -blinky = "be blinky" -blinky-probe = "ee blinky" -blinky-bin = "oe blinky --release -- -O binary target/thumbv7em-none-eabihf/release/examples/blinky.bin" +# TODO: Automate all this +rtic_blinky = "be rtic_blinky" +rtic_blinky-probe = "ee rtic_blinky" +rtic_blinky-bin = "oe rtic_blinky --release -- -O binary target/thumbv7em-none-eabihf/release/examples/rtic_blinky.bin" -usb_echo = "be usb_echo" -usb_echo-probe = "ee usb_echo" -usb_echo-bin = "oe usb_echo --release -- -O binary target/thumbv7em-none-eabihf/release/examples/usb_echo.bin" +rtic_usb_echo = "be rtic_usb_echo" +rtic_usb_echo-probe = "ee rtic_usb_echo" +rtic_usb_echo-bin = "oe rtic_usb_echo --release -- -O binary target/thumbv7em-none-eabihf/release/examples/rtic_usb_echo.bin" -usb_led_ctrl = "be usb_led_ctrl" -usb_led_ctrl-probe = "ee usb_led_ctrl" -usb_led_ctrl-bin = "oe usb_led_ctrl --release -- -O binary target/thumbv7em-none-eabihf/release/examples/usb_led_ctrl.bin" +rtic_usb_led_ctrl = "be rtic_usb_led_ctrl" +rtic_usb_led_ctrl-probe = "ee rtic_usb_led_ctrl" +rtic_usb_led_ctrl-bin = "oe rtic_usb_led_ctrl --release -- -O binary target/thumbv7em-none-eabihf/release/examples/rtic_usb_led_ctrl.bin" [build] target = "thumbv7em-none-eabihf" # Cortex-M4F and Cortex-M7F (with FPU) diff --git a/Cargo.toml b/Cargo.toml index ec33e93..bce7062 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,6 +18,7 @@ embedded-hal-v1 = { version = "1.0.0", package = "embedded-hal" } embedded-hal-v0 = { version = "0.2.6", package = "embedded-hal", features = ["unproven"] } embedded-hal-async = "1.0.0" rtic-sync = "1.3.0" +fugit = "0.3.7" [dev-dependencies] rtic = { version = "2.1.1", features = ["thumbv7-backend"] } diff --git a/README.md b/README.md index 43dd7ce..1c4b3ff 100644 --- a/README.md +++ b/README.md @@ -43,9 +43,9 @@ To build an example, run the following command: ``` cargo [--release] ``` -For instance, to build `blinky`: +For instance, to build `rtic_blinky`: ``` -cargo blinky +cargo rtic_blinky ``` ## Flash with DFU (USB) 1. If not already, install [dfu-utils](https://dfu-util.sourceforge.net/) on your system. @@ -55,17 +55,17 @@ cargo blinky ``` cargo -bin ``` - For example, to generate the target binary for `blinky`, run the following command: + For example, to generate the target binary for `rtic_blinky`, run the following command: ``` - cargo blinky-bin + cargo rtic_blinky-bin ``` 4. Flash the binary to the target by running the following command: ``` dfu-util -a 0 -d 2341:035b --dfuse-address=0x08040000:leave -D ``` - For example, to flash `blinky`, run the following command: + For example, to flash `rtic_blinky`, run the following command: ``` - dfu-util -a 0 -d 2341:035b --dfuse-address=0x08040000:leave -D target/thumbv7em-none-eabihf/release/examples/blinky.bin + dfu-util -a 0 -d 2341:035b --dfuse-address=0x08040000:leave -D target/thumbv7em-none-eabihf/release/examples/rtic_blinky.bin ``` ## Flash with debug probe (JLink, ST-Link) 1. Connect the probe to the JTAG port of the breakout board. @@ -73,8 +73,8 @@ cargo blinky ``` cargo -probe [--release] ``` - For example, to flash `blinky`, run the following command: + For example, to flash `rtic_blinky`, run the following command: ``` - cargo blinky-probe + cargo rtic_blinky-probe ``` \ No newline at end of file diff --git a/examples/blinky.rs b/examples/rtic_blinky.rs similarity index 92% rename from examples/blinky.rs rename to examples/rtic_blinky.rs index 2c4f477..11018e4 100644 --- a/examples/blinky.rs +++ b/examples/rtic_blinky.rs @@ -1,4 +1,4 @@ -//! Example Blinky +//! Example of blinky //! //! Toggles the 3 user LEDs with a different frequency //! @@ -7,7 +7,10 @@ #![no_main] use defmt::info; -use portenta_h7::board::{self, Board, LedBlue, LedGreen, LedRed}; +use portenta_h7::board::{ + self, + non_async_impl::{Board, LedBlue, LedGreen, LedRed}, +}; use rtic::app; use rtic_monotonics::systick::prelude::*; diff --git a/examples/usb_echo.rs b/examples/rtic_usb_echo.rs similarity index 98% rename from examples/usb_echo.rs rename to examples/rtic_usb_echo.rs index f9751e7..fc5a511 100644 --- a/examples/usb_echo.rs +++ b/examples/rtic_usb_echo.rs @@ -9,7 +9,10 @@ #![no_main] use defmt::{error, info}; -use portenta_h7::board::{self, Board, LedGreen, LedRed, UsbBusImpl}; +use portenta_h7::board::{ + self, + non_async_impl::{Board, LedGreen, LedRed, UsbBusImpl}, +}; use rtic::app; use rtic_monotonics::systick::prelude::*; use rtic_sync::{channel::*, make_channel}; diff --git a/examples/usb_led_ctrl.rs b/examples/rtic_usb_led_ctrl.rs similarity index 98% rename from examples/usb_led_ctrl.rs rename to examples/rtic_usb_led_ctrl.rs index 39c93d0..6774367 100644 --- a/examples/usb_led_ctrl.rs +++ b/examples/rtic_usb_led_ctrl.rs @@ -1,19 +1,20 @@ //! Example USB LED Control //! //! Controls LEDs over USB using the USB Device Class (CDC) for communication. -//! //! The `Led` enum represents the different LEDs that can be controlled: Red (`0xAA`), Green (`0xBB`), and Blue (`0xCC`). -//! //! The `Action` enum represents the actions that can be performed on an LED: turning it on (`0x01`) or off (`0x02`). -//! //! To control an LED, send the hexadecimal value of the LED followed by the hexadecimal value of the action. For example, to turn the red LED on, send `0xAA 0x01`. +//! #![no_std] #![no_main] use core::mem::size_of; use defmt::{debug, error, info}; -use portenta_h7::board::{self, Board, LedBlue, LedGreen, LedRed, UsbBusImpl}; +use portenta_h7::board::{ + self, + non_async_impl::{Board, LedBlue, LedGreen, LedRed, UsbBusImpl}, +}; use rtic::app; use rtic_monotonics::systick::prelude::*; use rtic_sync::{channel::*, make_channel}; diff --git a/src/board/async_impl.rs b/src/board/async_impl.rs new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/src/board/async_impl.rs @@ -0,0 +1 @@ + diff --git a/src/board/mod.rs b/src/board/mod.rs index 2b5fbd3..fdb3f6b 100644 --- a/src/board/mod.rs +++ b/src/board/mod.rs @@ -1,131 +1,8 @@ -//! board +#[cfg(feature = "async")] +pub mod async_impl; -use crate::{ - drivers::{led, pmic}, - hal, sys, -}; -use core::sync::atomic::{AtomicBool, Ordering}; -use defmt::debug; -use hal::{ - gpio::{Output, Pin, PinState, PushPull}, - pac, - prelude::*, - rcc, - time::Hertz, - usb_hs::{UsbBus, USB1_ULPI}, -}; +#[cfg(not(feature = "async"))] +pub mod non_async_impl; -type DigitalOutputPin = Pin>; -pub type LedRed = led::Led>; -pub type LedGreen = led::Led>; -pub type LedBlue = led::Led>; -pub type UsbPer = USB1_ULPI; -pub type UsbBusImpl = UsbBus; -pub const CORE_FREQUENCY: Hertz = Hertz::from_raw(480_000_000); - -pub struct Board { - pub led_red: LedRed, - pub led_green: LedGreen, - pub led_blue: LedBlue, - pub usb: UsbPer, -} - -impl Board { - pub fn take() -> Self { - static TAKEN: AtomicBool = AtomicBool::new(false); - debug_assert!(!TAKEN.swap(true, Ordering::SeqCst)); - Self::setup() - } - - fn setup() -> Self { - // Reset previous configuration and enable external oscillator as HSE source (25 MHz) - sys::Clk::new().reset().enable_ext_clock(); - let dp = pac::Peripherals::take().unwrap(); - - // Configure power domains and clock tree - let pwrcfg = dp.PWR.constrain().vos0(&dp.SYSCFG).freeze(); - let ccdr = dp - .RCC - .constrain() - .use_hse(25.MHz()) - .bypass_hse() - .sys_ck(CORE_FREQUENCY) - .hclk(240.MHz()) - .pll1_strategy(rcc::PllConfigStrategy::Iterative) - .freeze(pwrcfg, &dp.SYSCFG); - - debug_assert_eq!(sys::Clk::get_source(), Some(sys::ClkSource::Pll1)); - debug_assert_eq!(sys::Clk::get_pll_source(), sys::PllSourceVariant::Hse); - - // GPIOs - let (gpioa, gpiob, gpioc, gpioh, gpioi, gpioj) = { - ( - dp.GPIOA.split(ccdr.peripheral.GPIOA), - dp.GPIOB.split(ccdr.peripheral.GPIOB), - dp.GPIOC.split(ccdr.peripheral.GPIOC), - dp.GPIOH.split_without_reset(ccdr.peripheral.GPIOH), // Do not do a reset since external oscillator is enabled by GPIOH1 - dp.GPIOI.split(ccdr.peripheral.GPIOI), - dp.GPIOJ.split(ccdr.peripheral.GPIOJ), - ) - }; - // Enable ULPI transceiver (GPIOJ4) - let mut ulpi_reset = gpioj.pj4.into_push_pull_output(); - ulpi_reset.set_high(); - - let usb = USB1_ULPI::new( - dp.OTG1_HS_GLOBAL, - dp.OTG1_HS_DEVICE, - dp.OTG1_HS_PWRCLK, - gpioa.pa5.into_alternate(), - gpioi.pi11.into_alternate(), - gpioh.ph4.into_alternate(), - gpioc.pc0.into_alternate(), - gpioa.pa3.into_alternate(), - gpiob.pb0.into_alternate(), - gpiob.pb1.into_alternate(), - gpiob.pb10.into_alternate(), - gpiob.pb11.into_alternate(), - gpiob.pb12.into_alternate(), - gpiob.pb13.into_alternate(), - gpiob.pb5.into_alternate(), - ccdr.peripheral.USB1OTG, - &ccdr.clocks, - ); - - // User LEDs - let gpiok = dp.GPIOK.split(ccdr.peripheral.GPIOK); - let (output_k5, output_k6, output_k7) = ( - gpiok.pk5.into_push_pull_output_in_state(PinState::High), - gpiok.pk6.into_push_pull_output_in_state(PinState::High), - gpiok.pk7.into_push_pull_output_in_state(PinState::High), - ); - - let led_red = led::Led::new(output_k5); - let led_green = led::Led::new(output_k6); - let led_blue = led::Led::new(output_k7); - - // PMIC - let (i2c1_scl, i2c1_sda) = ( - gpiob.pb6.into_alternate_open_drain(), - gpiob.pb7.into_alternate_open_drain(), - ); - let i2c1 = dp.I2C1.i2c( - (i2c1_scl, i2c1_sda), - 400.kHz(), - ccdr.peripheral.I2C1, - &ccdr.clocks, - ); - let mut pmic = pmic::Pmic::new(i2c1); - match pmic.device_id() { - Ok(id) => debug!("PMIC device ID: {:X}", id), - Err(_) => debug!("PMIC device ID read error"), - } - - Board { - led_red, - led_green, - led_blue, - usb, - } - } -} +pub use fugit::HertzU32; +pub const CORE_FREQUENCY: HertzU32 = HertzU32::from_raw(480_000_000); diff --git a/src/board/non_async_impl.rs b/src/board/non_async_impl.rs new file mode 100644 index 0000000..4c0eda9 --- /dev/null +++ b/src/board/non_async_impl.rs @@ -0,0 +1,130 @@ +//! board + +use crate::board::CORE_FREQUENCY; +use crate::{ + drivers::{led, pmic}, + hal, sys, +}; +use core::sync::atomic::{AtomicBool, Ordering}; +use defmt::debug; +use hal::{ + gpio::{Output, Pin, PinState, PushPull}, + pac, + prelude::*, + rcc, + usb_hs::{UsbBus, USB1_ULPI}, +}; + +type DigitalOutputPin = Pin>; +pub type LedRed = led::Led>; +pub type LedGreen = led::Led>; +pub type LedBlue = led::Led>; +pub type UsbPer = USB1_ULPI; +pub type UsbBusImpl = UsbBus; + +pub struct Board { + pub led_red: LedRed, + pub led_green: LedGreen, + pub led_blue: LedBlue, + pub usb: UsbPer, +} + +impl Board { + pub fn take() -> Self { + static TAKEN: AtomicBool = AtomicBool::new(false); + debug_assert!(!TAKEN.swap(true, Ordering::SeqCst)); + Self::setup() + } + + fn setup() -> Self { + // Reset previous configuration and enable external oscillator as HSE source (25 MHz) + sys::Clk::new().reset().enable_ext_clock(); + let dp = pac::Peripherals::take().unwrap(); + + // Configure power domains and clock tree + let pwrcfg = dp.PWR.constrain().vos0(&dp.SYSCFG).freeze(); + let ccdr = dp + .RCC + .constrain() + .use_hse(25.MHz()) + .bypass_hse() + .sys_ck(CORE_FREQUENCY) + .hclk(240.MHz()) + .pll1_strategy(rcc::PllConfigStrategy::Iterative) + .freeze(pwrcfg, &dp.SYSCFG); + + debug_assert_eq!(sys::Clk::get_source(), Some(sys::ClkSource::Pll1)); + debug_assert_eq!(sys::Clk::get_pll_source(), sys::PllSourceVariant::Hse); + + // GPIOs + let (gpioa, gpiob, gpioc, gpioh, gpioi, gpioj) = { + ( + dp.GPIOA.split(ccdr.peripheral.GPIOA), + dp.GPIOB.split(ccdr.peripheral.GPIOB), + dp.GPIOC.split(ccdr.peripheral.GPIOC), + dp.GPIOH.split_without_reset(ccdr.peripheral.GPIOH), // Do not do a reset since external oscillator is enabled by GPIOH1 + dp.GPIOI.split(ccdr.peripheral.GPIOI), + dp.GPIOJ.split(ccdr.peripheral.GPIOJ), + ) + }; + // Enable ULPI transceiver (GPIOJ4) + let mut ulpi_reset = gpioj.pj4.into_push_pull_output(); + ulpi_reset.set_high(); + + let usb = USB1_ULPI::new( + dp.OTG1_HS_GLOBAL, + dp.OTG1_HS_DEVICE, + dp.OTG1_HS_PWRCLK, + gpioa.pa5.into_alternate(), + gpioi.pi11.into_alternate(), + gpioh.ph4.into_alternate(), + gpioc.pc0.into_alternate(), + gpioa.pa3.into_alternate(), + gpiob.pb0.into_alternate(), + gpiob.pb1.into_alternate(), + gpiob.pb10.into_alternate(), + gpiob.pb11.into_alternate(), + gpiob.pb12.into_alternate(), + gpiob.pb13.into_alternate(), + gpiob.pb5.into_alternate(), + ccdr.peripheral.USB1OTG, + &ccdr.clocks, + ); + + // User LEDs + let gpiok = dp.GPIOK.split(ccdr.peripheral.GPIOK); + let (output_k5, output_k6, output_k7) = ( + gpiok.pk5.into_push_pull_output_in_state(PinState::High), + gpiok.pk6.into_push_pull_output_in_state(PinState::High), + gpiok.pk7.into_push_pull_output_in_state(PinState::High), + ); + + let led_red = led::Led::new(output_k5); + let led_green = led::Led::new(output_k6); + let led_blue = led::Led::new(output_k7); + + // PMIC + let (i2c1_scl, i2c1_sda) = ( + gpiob.pb6.into_alternate_open_drain(), + gpiob.pb7.into_alternate_open_drain(), + ); + let i2c1 = dp.I2C1.i2c( + (i2c1_scl, i2c1_sda), + 400.kHz(), + ccdr.peripheral.I2C1, + &ccdr.clocks, + ); + let mut pmic = pmic::Pmic::new(i2c1); + match pmic.device_id() { + Ok(id) => debug!("PMIC device ID: {:X}", id), + Err(_) => debug!("PMIC device ID read error"), + } + + Board { + led_red, + led_green, + led_blue, + usb, + } + } +}