From 81bef219e315aca005e50143757c681d5bc122ee Mon Sep 17 00:00:00 2001 From: Gerzain Mata Date: Sun, 27 Jul 2025 16:44:43 -0700 Subject: Working USB_OTG_HS example for STM32WBA --- embassy-stm32/src/lib.rs | 6 +- embassy-stm32/src/usb/mod.rs | 4 +- embassy-stm32/src/usb/otg.rs | 7 -- examples/stm32wba/src/bin/usb_hs_serial.rs | 25 ++---- examples/stm32wba/src/bin/usb_serial.rs | 119 ----------------------------- 5 files changed, 12 insertions(+), 149 deletions(-) delete mode 100644 examples/stm32wba/src/bin/usb_serial.rs diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs index d893f1b54..a676677e1 100644 --- a/embassy-stm32/src/lib.rs +++ b/embassy-stm32/src/lib.rs @@ -546,7 +546,11 @@ fn init_hw(config: Config) -> Peripherals { { use crate::pac::pwr::vals; crate::pac::PWR.svmcr().modify(|w| { - w.set_io2sv(if config.enable_independent_io_supply {vals::Io2sv::B_0X1} else {vals::Io2sv::B_0X0}); + w.set_io2sv(if config.enable_independent_io_supply { + vals::Io2sv::B_0X1 + } else { + vals::Io2sv::B_0X0 + }); }); } #[cfg(stm32u5)] diff --git a/embassy-stm32/src/usb/mod.rs b/embassy-stm32/src/usb/mod.rs index d052934f8..62c751ac8 100644 --- a/embassy-stm32/src/usb/mod.rs +++ b/embassy-stm32/src/usb/mod.rs @@ -111,10 +111,8 @@ fn common_init() { }); crate::pac::PWR.vosr().modify(|w| { w.set_vdd11usbdis(false); - }); - crate::pac::PWR.vosr().modify(|w| { w.set_usbpwren(true); - }) + }); }); // Wait for USB power to stabilize diff --git a/embassy-stm32/src/usb/otg.rs b/embassy-stm32/src/usb/otg.rs index abf54cbad..1c3b99b93 100644 --- a/embassy-stm32/src/usb/otg.rs +++ b/embassy-stm32/src/usb/otg.rs @@ -330,19 +330,12 @@ impl<'d, T: Instance> Bus<'d, T> { #[cfg(all(stm32wba, peri_usb_otg_hs))] { critical_section::with(|_| { - // crate::pac::RCC.apb7enr().modify(|w| { - // w.set_syscfgen(true); - // }); crate::pac::RCC.ahb2enr().modify(|w| { w.set_usb_otg_hsen(true); w.set_usb_otg_hs_phyen(true); }); }); - // pub use crate::pac::rcc::vals::Otghssel; - // // select HSE - // crate::pac::RCC.ccipr2().modify(|w| {w.set_otghssel(Otghssel::HSE);}); - crate::pac::SYSCFG.otghsphytuner2().modify(|w| { w.set_compdistune(0b010); w.set_sqrxtune(0b000); diff --git a/examples/stm32wba/src/bin/usb_hs_serial.rs b/examples/stm32wba/src/bin/usb_hs_serial.rs index 2e17e52d1..20bdeaac3 100644 --- a/examples/stm32wba/src/bin/usb_hs_serial.rs +++ b/examples/stm32wba/src/bin/usb_hs_serial.rs @@ -21,24 +21,16 @@ async fn main(_spawner: Spawner) { let mut config = Config::default(); - { use embassy_stm32::rcc::*; - // External HSE (32 MHz) setup - // config.rcc.hse = Some(Hse { - // prescaler: HsePrescaler::DIV2, - // }); - - // Fine-tune PLL1 dividers/multipliers config.rcc.pll1 = Some(Pll { source: PllSource::HSI, - prediv: PllPreDiv::DIV1, // PLLM = 1 → HSI / 1 = 16 MHz - mul: PllMul::MUL30, // PLLN = 30 → 16 MHz * 30 = 480 MHz VCO - divr: Some(PllDiv::DIV5), // PLLR = 5 → 96 MHz (Sysclk) - divq: Some(PllDiv::DIV10), // PLLQ = 10 → 48 MHz (NOT USED) - // divq: None, - divp: Some(PllDiv::DIV30), // PLLP = 30 → 16 MHz (USBOTG) - frac: Some(0), // Fractional part (enabled) + prediv: PllPreDiv::DIV1, // PLLM = 1 → HSI / 1 = 16 MHz + mul: PllMul::MUL30, // PLLN = 30 → 16 MHz * 30 = 480 MHz VCO + divr: Some(PllDiv::DIV5), // PLLR = 5 → 96 MHz (Sysclk) + divq: Some(PllDiv::DIV10), // PLLQ = 10 → 48 MHz + divp: Some(PllDiv::DIV30), // PLLP = 30 → 16 MHz (USB_OTG_HS) + frac: Some(0), // Fractional part (disabled) }); config.rcc.ahb_pre = AHBPrescaler::DIV1; @@ -54,11 +46,6 @@ async fn main(_spawner: Spawner) { let p = embassy_stm32::init(config); - // TRDT set to 5 - // ASVLD set to 1 - // BSVLD set to 1 - - // Create the driver, from the HAL. let mut ep_out_buffer = [0u8; 256]; let mut config = embassy_stm32::usb::Config::default(); diff --git a/examples/stm32wba/src/bin/usb_serial.rs b/examples/stm32wba/src/bin/usb_serial.rs deleted file mode 100644 index 8d60aed8c..000000000 --- a/examples/stm32wba/src/bin/usb_serial.rs +++ /dev/null @@ -1,119 +0,0 @@ -#![no_std] -#![no_main] - -use defmt::{panic, *}; -use defmt_rtt as _; // global logger -use embassy_executor::Spawner; -use embassy_futures::join::join; -use embassy_stm32::usb::{Driver, Instance}; -use embassy_stm32::{bind_interrupts, peripherals, usb, Config}; -use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; -use embassy_usb::driver::EndpointError; -use embassy_usb::Builder; -use panic_probe as _; - -bind_interrupts!(struct Irqs { - OTG_HS => usb::InterruptHandler; -}); - -#[embassy_executor::main] -async fn main(_spawner: Spawner) { - info!("Hello World!"); - - let mut config = Config::default(); - { - use embassy_stm32::rcc::*; - config.rcc.hsi = true; - config.rcc.pll1 = Some(Pll { - source: PllSource::HSI, // 16 MHz - prediv: PllPreDiv::DIV1, - mul: PllMul::MUL10, - divp: None, - divq: None, - divr: Some(PllDiv::DIV1), // 160 MHz - }); - config.rcc.sys = Sysclk::PLL1_R; - config.rcc.voltage_range = VoltageScale::RANGE1; - config.rcc.hsi48 = Some(Hsi48Config { sync_from_usb: true }); // needed for USB - config.rcc.mux.iclksel = mux::Iclksel::HSI48; // USB uses ICLK - } - - let p = embassy_stm32::init(config); - - // Create the driver, from the HAL. - let mut ep_out_buffer = [0u8; 256]; - let mut config = embassy_stm32::usb::Config::default(); - // Do not enable vbus_detection. This is a safe default that works in all boards. - // However, if your USB device is self-powered (can stay powered on if USB is unplugged), you need - // to enable vbus_detection to comply with the USB spec. If you enable it, the board - // has to support it or USB won't work at all. See docs on `vbus_detection` for details. - config.vbus_detection = false; - let driver = Driver::new_hs(p.USB_OTG_HS, Irqs, p.PD6, p.PD7, &mut ep_out_buffer, config); - - // Create embassy-usb Config - let mut config = embassy_usb::Config::new(0xc0de, 0xcafe); - config.manufacturer = Some("Embassy"); - config.product = Some("USB-serial example"); - config.serial_number = Some("12345678"); - - // Create embassy-usb DeviceBuilder using the driver and config. - // It needs some buffers for building the descriptors. - let mut config_descriptor = [0; 256]; - let mut bos_descriptor = [0; 256]; - let mut control_buf = [0; 64]; - - let mut state = State::new(); - - let mut builder = Builder::new( - driver, - config, - &mut config_descriptor, - &mut bos_descriptor, - &mut [], // no msos descriptors - &mut control_buf, - ); - - // Create classes on the builder. - let mut class = CdcAcmClass::new(&mut builder, &mut state, 64); - - // Build the builder. - let mut usb = builder.build(); - - // Run the USB device. - let usb_fut = usb.run(); - - // Do stuff with the class! - let echo_fut = async { - loop { - class.wait_connection().await; - info!("Connected"); - let _ = echo(&mut class).await; - info!("Disconnected"); - } - }; - - // Run everything concurrently. - // If we had made everything `'static` above instead, we could do this using separate tasks instead. - join(usb_fut, echo_fut).await; -} - -struct Disconnected {} - -impl From for Disconnected { - fn from(val: EndpointError) -> Self { - match val { - EndpointError::BufferOverflow => panic!("Buffer overflow"), - EndpointError::Disabled => Disconnected {}, - } - } -} - -async fn echo<'d, T: Instance + 'd>(class: &mut CdcAcmClass<'d, Driver<'d, T>>) -> Result<(), Disconnected> { - let mut buf = [0; 64]; - loop { - let n = class.read_packet(&mut buf).await?; - let data = &buf[..n]; - info!("data: {:x}", data); - class.write_packet(data).await?; - } -} -- cgit