Working USB_OTG_HS example

This commit is contained in:
Gerzain Mata 2025-07-27 13:49:39 -07:00
parent 0545353ec1
commit 1d3c48cf45
5 changed files with 58 additions and 73 deletions

View File

@ -1599,7 +1599,7 @@ fn main() {
for e in rcc_registers.ir.enums {
fn is_rcc_name(e: &str) -> bool {
match e {
"Pllp" | "Pllq" | "Pllr" | "Plldivst" | "Pllm" | "Plln" | "Prediv1" | "Prediv2" => true,
"Pllp" | "Pllq" | "Pllr" | "Plldivst" | "Pllm" | "Plln" | "Prediv1" | "Prediv2" | "Hpre5" => true,
"Timpre" | "Pllrclkpre" => false,
e if e.ends_with("pre") || e.ends_with("pres") || e.ends_with("div") || e.ends_with("mul") => true,
_ => false,

View File

@ -1,43 +1,23 @@
pub use crate::pac::pwr::vals::Vos as VoltageScale;
use crate::pac::rcc::regs::Cfgr1;
use core::ops::Div;
pub use crate::pac::rcc::vals::{
Hpre as AHBPrescaler, Hsepre as HsePrescaler, Ppre as APBPrescaler, Sw as Sysclk, Pllsrc as PllSource,
Plldiv as PllDiv, Pllm as PllPreDiv, Plln as PllMul, Hpre5 as AHB5Prescaler, Hdiv5,
};
#[cfg(all(peri_usb_otg_hs))]
pub use crate::pac::rcc::vals::Otghssel;
use crate::pac::rcc::vals::Pllrge;
pub use crate::pac::rcc::vals::{
Hdiv5, Hpre as AHBPrescaler, Hpre5 as AHB5Prescaler, Hsepre as HsePrescaler, Plldiv as PllDiv, Pllm as PllPreDiv,
Plln as PllMul, Pllsrc as PllSource, Ppre as APBPrescaler, Sw as Sysclk,
};
#[cfg(all(peri_usb_otg_hs))]
pub use crate::pac::{syscfg::vals::Usbrefcksel, SYSCFG};
use crate::pac::{FLASH, RCC};
use crate::rcc::LSI_FREQ;
use crate::time::Hertz;
#[cfg(all(peri_usb_otg_hs))]
pub use crate::pac::rcc::vals::Otghssel;
#[cfg(all(peri_usb_otg_hs))]
pub use crate::pac::{syscfg::vals::Usbrefcksel, SYSCFG};
/// HSI speed
pub const HSI_FREQ: Hertz = Hertz(16_000_000);
// HSE speed
pub const HSE_FREQ: Hertz = Hertz(32_000_000);
// Allow dividing a Hertz value by an AHB5 prescaler directly
impl Div<AHB5Prescaler> for Hertz {
type Output = Hertz;
fn div(self, rhs: AHB5Prescaler) -> Hertz {
// Map the prescaler enum to its integer divisor
let divisor = match rhs {
AHB5Prescaler::DIV1 => 1,
AHB5Prescaler::DIV2 => 2,
AHB5Prescaler::DIV3 => 3,
AHB5Prescaler::DIV4 => 4,
AHB5Prescaler::DIV6 => 6,
_ => unreachable!("Invalid AHB5 prescaler: {:?}", rhs),
};
Hertz(self.0 / divisor)
}
}
#[derive(Clone, Copy, Eq, PartialEq)]
pub struct Hse {
pub prescaler: HsePrescaler,
@ -95,8 +75,7 @@ pub struct Config {
pub apb7_pre: APBPrescaler,
// low speed LSI/LSE/RTC
pub lsi: super::LsConfig,
// pub lsi2: super::LsConfig,
pub ls: super::LsConfig,
pub voltage_scale: VoltageScale,
@ -116,7 +95,7 @@ impl Config {
apb1_pre: APBPrescaler::DIV1,
apb2_pre: APBPrescaler::DIV1,
apb7_pre: APBPrescaler::DIV1,
lsi: crate::rcc::LsConfig::new(),
ls: crate::rcc::LsConfig::new(),
// lsi2: crate::rcc::LsConfig::new(),
voltage_scale: VoltageScale::RANGE2,
mux: super::mux::ClockMux::default(),
@ -151,7 +130,7 @@ pub(crate) unsafe fn init(config: Config) {
crate::pac::PWR.vosr().write(|w| w.set_vos(config.voltage_scale));
while !crate::pac::PWR.vosr().read().vosrdy() {}
let rtc = config.lsi.init();
let rtc = config.ls.init();
let hsi = config.hsi.then(|| {
hsi_enable();
@ -169,7 +148,7 @@ pub(crate) unsafe fn init(config: Config) {
HSE_FREQ
});
let pll_input = PllInput {hse, hsi };
let pll_input = PllInput { hse, hsi };
let pll1 = init_pll(config.pll1, &pll_input, config.voltage_scale);
@ -250,7 +229,6 @@ pub(crate) unsafe fn init(config: Config) {
let hclk5 = sys_clk / config.ahb5_pre;
#[cfg(all(stm32wba, peri_usb_otg_hs))]
let usb_refck = match config.mux.otghssel {
Otghssel::HSE => hse,
@ -276,7 +254,7 @@ pub(crate) unsafe fn init(config: Config) {
w.set_clksel(usb_refck_sel);
});
let lsi = config.lsi.lsi.then_some(LSI_FREQ);
let lsi = config.ls.lsi.then_some(LSI_FREQ);
config.mux.init();
@ -360,7 +338,7 @@ fn init_pll(config: Option<Pll>, input: &PllInput, voltage_range: VoltageScale)
// let vco_freq = ref_freq * pll.mul;
// Calculate VCO frequency including fractional part: FVCO = Fref_ck × (N + FRAC/2^13)
let numerator = (ref_freq.0 as u64) * (((pll.mul as u64) + 1 << 13) + pll.frac.unwrap_or(0) as u64);
let vco_hz = (numerator >> 13) as u32;
let vco_hz = (numerator >> 13) as u32;
let vco_freq = Hertz(vco_hz);
assert!(vco_freq >= vco_min && vco_freq <= vco_max);
@ -381,7 +359,9 @@ fn init_pll(config: Option<Pll>, input: &PllInput, voltage_range: VoltageScale)
w.set_pllq(pll.divq.unwrap_or(PllDiv::DIV1));
w.set_pllr(pll.divr.unwrap_or(PllDiv::DIV1));
});
RCC.pll1fracr().write(|w| {w.set_pllfracn(pll.frac.unwrap_or(0));});
RCC.pll1fracr().write(|w| {
w.set_pllfracn(pll.frac.unwrap_or(0));
});
let input_range = match ref_freq.0 {
..=8_000_000 => Pllrge::FREQ_4TO8MHZ,
@ -400,10 +380,12 @@ fn init_pll(config: Option<Pll>, input: &PllInput, voltage_range: VoltageScale)
};
}
RCC.pll1cfgr().write(|w| {write_fields!(w);});
RCC.pll1cfgr().write(|w| {
write_fields!(w);
});
// Enable PLL
pll_enable(true);
PllOutput{ p, q, r }
}
PllOutput { p, q, r }
}

View File

@ -110,7 +110,7 @@ fn common_init<T: Instance>() {
w.set_usv(crate::pac::pwr::vals::Usv::B_0X1);
});
crate::pac::PWR.vosr().modify(|w| {
w.set_vdd11usbdis(true);
w.set_vdd11usbdis(false);
});
crate::pac::PWR.vosr().modify(|w| {
w.set_usbpwren(true);

View File

@ -9,7 +9,6 @@ embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = [
embassy-sync = { version = "0.7.0", path = "../../embassy-sync", features = ["defmt"] }
embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] }
embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
embassy-net = { version = "0.7.0", path = "../../embassy-net", features = ["defmt", "udp", "proto-ipv6", "medium-ieee802154", ], optional = true }
embassy-usb = { version = "0.5.0", path = "../../embassy-usb", features = ["defmt"] }
embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
@ -18,7 +17,7 @@ defmt-rtt = "1.0.0"
cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
cortex-m-rt = "0.7.0"
embedded-hal = "1.0.0"
embedded-hal = "0.2.6"
panic-probe = { version = "1.0.0", features = ["print-defmt"] }
heapless = { version = "0.8", default-features = false }
static_cell = "2"

View File

@ -2,17 +2,14 @@
#![no_main]
use defmt::{panic, *};
use defmt_rtt as _; // global logger
use embassy_executor::Spawner;
use embassy_futures::join::join;
use embassy_stm32::rcc::{mux, AHB5Prescaler, AHBPrescaler, APBPrescaler, Hse, HsePrescaler, Sysclk, VoltageScale};
use embassy_stm32::rcc::{PllDiv, PllMul, PllPreDiv, PllSource};
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 _;
use {defmt_rtt as _, panic_probe as _};
bind_interrupts!(struct Irqs {
USB_OTG_HS => usb::InterruptHandler<peripherals::USB_OTG_HS>;
@ -24,37 +21,44 @@ async fn main(_spawner: Spawner) {
let mut config = Config::default();
// External HSE (32 MHz) setup
// config.rcc.hse = Some(Hse {
// prescaler: HsePrescaler::DIV2,
// });
// Fine-tune PLL1 dividers/multipliers
config.rcc.pll1 = Some(embassy_stm32::rcc::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)
});
{
use embassy_stm32::rcc::*;
// External HSE (32 MHz) setup
// config.rcc.hse = Some(Hse {
// prescaler: HsePrescaler::DIV2,
// });
config.rcc.ahb_pre = AHBPrescaler::DIV1;
config.rcc.apb1_pre = APBPrescaler::DIV1;
config.rcc.apb2_pre = APBPrescaler::DIV1;
config.rcc.apb7_pre = APBPrescaler::DIV1;
config.rcc.ahb5_pre = AHB5Prescaler::DIV4;
// 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)
});
// voltage scale for max performance
config.rcc.voltage_scale = VoltageScale::RANGE1;
// route PLL1_P into the USBOTGHS block
config.rcc.mux.otghssel = mux::Otghssel::PLL1_P;
config.rcc.sys = Sysclk::PLL1_R;
config.rcc.ahb_pre = AHBPrescaler::DIV1;
config.rcc.apb1_pre = APBPrescaler::DIV1;
config.rcc.apb2_pre = APBPrescaler::DIV1;
config.rcc.apb7_pre = APBPrescaler::DIV1;
config.rcc.ahb5_pre = AHB5Prescaler::DIV4;
config.rcc.voltage_scale = VoltageScale::RANGE1;
config.rcc.mux.otghssel = mux::Otghssel::PLL1_P;
config.rcc.sys = Sysclk::PLL1_R;
}
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();