From 4ab525c6bbfdf1106de3ad885e4480348f7e2f69 Mon Sep 17 00:00:00 2001 From: Liam Kinne Date: Sat, 31 Aug 2024 05:55:37 +1000 Subject: [PATCH 1/8] impl sealed for GPIO types --- src/gpio.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/gpio.rs b/src/gpio.rs index 72fd617c..64e4b8ba 100644 --- a/src/gpio.rs +++ b/src/gpio.rs @@ -342,6 +342,8 @@ macro_rules! gpio { _mode: PhantomData, } + impl crate::Sealed for $PXi {} + #[allow(clippy::from_over_into)] impl Into<$PXi>> for $PXi { fn into(self) -> $PXi> { From a302df5de55e6363c087529d4ef835b0b346929e Mon Sep 17 00:00:00 2001 From: Liam Kinne Date: Sat, 31 Aug 2024 05:56:13 +1000 Subject: [PATCH 2/8] add USB dependencies --- Cargo.toml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Cargo.toml b/Cargo.toml index 1f0494c8..77b0b297 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,6 +19,8 @@ bitflags = "1.2" vcell = "0.1" static_assertions = "1.1" fugit = "0.3.5" +stm32-usbd = { version = "0.7.0", optional = true } +critical-section = "1.1.2" [dependencies.cortex-m] version = "0.7.7" @@ -71,11 +73,14 @@ cfg-if = "0.1.10" mpu6050 = "0.1.4" bme680 = "0.6.0" embedded-sdmmc = "0.3.0" +usb-device = { version = "0.3.2", features = ["defmt"] } +usbd-serial = "0.2.2" #TODO: Separate feature sets [features] default = ["rt"] rt = ["stm32g4/rt"] +usb = ["dep:stm32-usbd"] stm32g431 = ["stm32g4/stm32g431"] stm32g441 = ["stm32g4/stm32g441"] stm32g471 = ["stm32g4/stm32g471"] From ac4027774af054167e4b1cb507e0cf93d2802312 Mon Sep 17 00:00:00 2001 From: Liam Kinne Date: Sat, 31 Aug 2024 05:56:29 +1000 Subject: [PATCH 3/8] add enable for HSI48 oscillator --- src/rcc/mod.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/rcc/mod.rs b/src/rcc/mod.rs index 1f25ecf1..813ff820 100644 --- a/src/rcc/mod.rs +++ b/src/rcc/mod.rs @@ -440,6 +440,11 @@ impl Rcc { while self.rb.csr.read().lsirdy().bit_is_clear() {} } + pub fn enable_hsi48(&self) { + self.rb.crrcr.modify(|_, w| w.hsi48on().set_bit()); + while self.rb.crrcr.read().hsi48rdy().bit_is_clear() {} + } + pub fn get_reset_reason(&self) -> ResetReason { let csr = self.rb.csr.read(); From e0f537b84a21c47ea9340cd1ab14bdcdbed1e633 Mon Sep 17 00:00:00 2001 From: Liam Kinne Date: Sat, 31 Aug 2024 06:32:02 +1000 Subject: [PATCH 4/8] implement usb peripheral --- examples/usb_serial.rs | 94 ++++++++++++++++++++++++++++++++++++++++++ src/usb.rs | 69 +++++++++++++++++++++++++++++++ 2 files changed, 163 insertions(+) create mode 100644 examples/usb_serial.rs create mode 100644 src/usb.rs diff --git a/examples/usb_serial.rs b/examples/usb_serial.rs new file mode 100644 index 00000000..e2f56b0b --- /dev/null +++ b/examples/usb_serial.rs @@ -0,0 +1,94 @@ +//! CDC-ACM serial port example using polling in a busy loop. +#![deny(warnings)] +#![deny(unsafe_code)] +#![no_std] +#![no_main] + +use cortex_m_rt::entry; +use hal::prelude::*; +use hal::pwr::PwrExt; +use hal::usb::{Peripheral, UsbBus}; +use hal::{rcc, stm32}; +use stm32g4xx_hal as hal; +use stm32g4xx_hal::gpio::Speed; +use stm32g4xx_hal::rcc::{PllConfig, PllMDiv, PllNMul, PllRDiv, PllSrc}; + +use usb_device::prelude::*; +use usbd_serial::{SerialPort, USB_CLASS_CDC}; + +use utils::logger::info; + +use panic_probe as _; + +#[macro_use] +mod utils; + +#[entry] +fn main() -> ! { + utils::logger::init(); + + let dp = stm32::Peripherals::take().expect("cannot take peripherals"); + let pwr = dp.PWR.constrain().freeze(); + let mut rcc = dp.RCC.freeze(rcc::Config::hsi(), pwr); + rcc.enable_hsi48(); + + let gpioa = dp.GPIOA.split(&mut rcc); + + let mut led = gpioa.pa5.into_push_pull_output(); + led.set_low().ok(); + + let usb_dm = gpioa.pa11.into_alternate(); + let usb_dp = gpioa.pa12.into_alternate(); + + let usb = Peripheral { + usb: dp.USB, + pin_dm: usb_dm, + pin_dp: usb_dp, + }; + let usb_bus = UsbBus::new(usb); + + let mut serial = SerialPort::new(&usb_bus); + + let mut usb_dev = UsbDeviceBuilder::new(&usb_bus, UsbVidPid(0x16c0, 0x27dd)) + .strings(&[StringDescriptors::default() + .manufacturer("Fake company") + .product("Serial port") + .serial_number("TEST")]) + .unwrap() + .device_class(USB_CLASS_CDC) + .build(); + + loop { + if !usb_dev.poll(&mut [&mut serial]) { + continue; + } + + let mut buf = [0u8; 64]; + + match serial.read(&mut buf) { + Ok(count) if count > 0 => { + led.set_high().ok(); + + // Echo back in upper case + for c in buf[0..count].iter_mut() { + if 0x61 <= *c && *c <= 0x7a { + *c &= !0x20; + } + } + + let mut write_offset = 0; + while write_offset < count { + match serial.write(&buf[write_offset..count]) { + Ok(len) if len > 0 => { + write_offset += len; + } + _ => {} + } + } + } + _ => {} + } + + led.set_low().ok(); + } +} diff --git a/src/usb.rs b/src/usb.rs new file mode 100644 index 00000000..86c2e68a --- /dev/null +++ b/src/usb.rs @@ -0,0 +1,69 @@ +//! USB peripheral. +//! +//! Provides the required implementation for use of the [`stm32-usbd`] crate. + +pub use stm32_usbd::UsbBus; + +use crate::gpio; +use crate::gpio::gpioa::{PA11, PA12}; +use crate::rcc::{Enable, Reset}; +use crate::stm32::{RCC, USB}; +use core::fmt; +use stm32_usbd::UsbPeripheral; + +/// Trait implemented by all pins that can be the "D-" pin for the USB peripheral +pub trait DmPin: crate::Sealed {} + +/// Trait implemented by all pins that can be the "D+" pin for the USB peripheral +pub trait DpPin: crate::Sealed {} + +impl DmPin for PA11> {} +impl DpPin for PA12> {} + +pub struct Peripheral { + /// USB register block + pub usb: USB, + /// Data negative pin + pub pin_dm: Dm, + /// Data positive pin + pub pin_dp: Dp, +} + +impl fmt::Debug for Peripheral +where + Dm: DmPin + fmt::Debug, + Dp: DpPin + fmt::Debug, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("Peripheral") + .field("usb", &"USB") + .field("pin_dm", &self.pin_dm) + .field("pin_dp", &self.pin_dp) + .finish() + } +} + +// SAFETY: Implementation of Peripheral is thread-safe by using cricitcal sections to ensure +// mutually exclusive access to the USB peripheral +unsafe impl Sync for Peripheral {} + +// SAFETY: The peripheral has the same regiter blockout as the STM32 USBFS +unsafe impl UsbPeripheral for Peripheral { + const REGISTERS: *const () = USB::ptr().cast::<()>(); + const DP_PULL_UP_FEATURE: bool = true; + const EP_MEMORY: *const () = 0x4000_6000 as _; + const EP_MEMORY_SIZE: usize = 1024; + const EP_MEMORY_ACCESS_2X16: bool = true; + + fn enable() { + critical_section::with(|_| unsafe { + let rcc_ptr = &(*RCC::ptr()); + USB::enable(rcc_ptr); + USB::reset(rcc_ptr); + }); + } + + fn startup_delay() { + // not required + } +} From bebfddbc975f5fbe3494331227204d8afbeb46fa Mon Sep 17 00:00:00 2001 From: Liam Kinne Date: Sat, 31 Aug 2024 06:33:44 +1000 Subject: [PATCH 5/8] add module --- src/lib.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index 5441692a..692afdc1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -98,3 +98,5 @@ pub mod time; pub mod timer; // pub mod watchdog; pub mod independent_watchdog; +#[cfg(feature = "usb")] +pub mod usb; From 8c7350a3c1a4bc97b5614bff367b291514d51dc5 Mon Sep 17 00:00:00 2001 From: Liam Kinne Date: Sat, 31 Aug 2024 06:37:33 +1000 Subject: [PATCH 6/8] fix warnings --- examples/usb_serial.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/examples/usb_serial.rs b/examples/usb_serial.rs index e2f56b0b..59e43328 100644 --- a/examples/usb_serial.rs +++ b/examples/usb_serial.rs @@ -10,14 +10,10 @@ use hal::pwr::PwrExt; use hal::usb::{Peripheral, UsbBus}; use hal::{rcc, stm32}; use stm32g4xx_hal as hal; -use stm32g4xx_hal::gpio::Speed; -use stm32g4xx_hal::rcc::{PllConfig, PllMDiv, PllNMul, PllRDiv, PllSrc}; use usb_device::prelude::*; use usbd_serial::{SerialPort, USB_CLASS_CDC}; -use utils::logger::info; - use panic_probe as _; #[macro_use] From 2e8b35b84344b157391ecf046edae2258b9d60b2 Mon Sep 17 00:00:00 2001 From: Liam Kinne Date: Mon, 9 Sep 2024 22:26:16 +1000 Subject: [PATCH 7/8] add required features for example --- Cargo.toml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Cargo.toml b/Cargo.toml index 77b0b297..fff05e33 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -110,3 +110,7 @@ lto = true [[example]] name = "flash_with_rtic" required-features = ["stm32g474"] + +[[example]] +name = "usb_serial" +required-features = ["usb"] From 0ed201ff84cb7f5db491b090c4cc45de4dc4e9b0 Mon Sep 17 00:00:00 2001 From: Liam Kinne Date: Thu, 31 Oct 2024 15:07:02 +1000 Subject: [PATCH 8/8] remove need for critical section dependency --- Cargo.toml | 1 - src/usb.rs | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index b1f34a6e..b78d4e2b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,7 +20,6 @@ vcell = "0.1" static_assertions = "1.1" fugit = "0.3.5" stm32-usbd = { version = "0.7.0", optional = true } -critical-section = "1.1.2" fixed = { version = "1.28.0", optional = true } [dependencies.cortex-m] diff --git a/src/usb.rs b/src/usb.rs index 86c2e68a..0d9181c8 100644 --- a/src/usb.rs +++ b/src/usb.rs @@ -56,7 +56,7 @@ unsafe impl UsbPeripheral for Peripheral