From 801a36c7b4e476388e55c842dec09d7ef2607a5a Mon Sep 17 00:00:00 2001 From: Derek Hageman <hageman@inthat.cloud> Date: Thu, 4 Jan 2024 07:52:53 -0700 Subject: [PATCH] stm32: Add G0 USB RCC Add configuration for STM32G0 USB clock. --- embassy-stm32/src/rcc/g0.rs | 51 ++++++++++++++++++++++++++++++++++++- 1 file changed, 50 insertions(+), 1 deletion(-) diff --git a/embassy-stm32/src/rcc/g0.rs b/embassy-stm32/src/rcc/g0.rs index aedc95bf3..b38fe1dcc 100644 --- a/embassy-stm32/src/rcc/g0.rs +++ b/embassy-stm32/src/rcc/g0.rs @@ -72,6 +72,22 @@ pub enum PllSource { HSE(Hertz, HseMode), } +/// Sets the source for the 48MHz clock to the USB peripheral. +#[cfg(any(stm32g0b1, stm32g0c1, stm32g0b0))] +pub enum UsbSrc { + /// Use the High Speed Internal Oscillator. The CRS must be used to calibrate the + /// oscillator to comply with the USB specification for oscillator tolerance. + #[cfg(any(stm32g0b1, stm32g0c1))] + Hsi48(super::Hsi48Config), + /// Use the PLLQ output. The PLL must be configured to output a 48MHz clock. The + /// PLL needs to be using the HSE source to comply with the USB specification for oscillator + /// tolerance. + PllQ, + /// Use the HSE source directly. The HSE must be a 48MHz source. The HSE source must comply + /// with the USB specification for oscillator tolerance. + HSE, +} + /// Clocks configutation pub struct Config { pub mux: ClockSrc, @@ -79,6 +95,8 @@ pub struct Config { pub apb_pre: APBPrescaler, pub low_power_run: bool, pub ls: super::LsConfig, + #[cfg(any(stm32g0b1, stm32g0c1, stm32g0b0))] + pub usb_src: Option<UsbSrc>, } impl Default for Config { @@ -90,6 +108,8 @@ impl Default for Config { apb_pre: APBPrescaler::DIV1, low_power_run: false, ls: Default::default(), + #[cfg(any(stm32g0b1, stm32g0c1, stm32g0b0))] + usb_src: None, } } } @@ -303,13 +323,42 @@ pub(crate) unsafe fn init(config: Config) { let lsi_freq = (sw == Sw::LSI).then_some(super::LSI_FREQ); let hse_freq = (sw == Sw::HSE).then_some(sys_clk); + #[cfg(any(stm32g0b1, stm32g0c1, stm32g0b0))] + let hsi48_freq = config.usb_src.and_then(|config| { + match config { + UsbSrc::PllQ => { + // Make sure the PLLQ is enabled and running at 48Mhz + assert!(pll1_q_freq.is_some() && pll1_q_freq.unwrap().0 == 48_000_000); + RCC.ccipr2() + .modify(|w| w.set_usbsel(crate::pac::rcc::vals::Usbsel::PLL1_Q)); + None + } + UsbSrc::HSE => { + // Make sure the HSE is enabled and running at 48Mhz + assert!(hse_freq.is_some() && hse_freq.unwrap().0 == 48_000_000); + RCC.ccipr2() + .modify(|w| w.set_usbsel(crate::pac::rcc::vals::Usbsel::HSE)); + None + } + #[cfg(any(stm32g0b1, stm32g0c1))] + UsbSrc::Hsi48(config) => { + let freq = super::init_hsi48(config); + RCC.ccipr2() + .modify(|w| w.set_usbsel(crate::pac::rcc::vals::Usbsel::HSI48)); + Some(freq) + } + } + }); + #[cfg(not(any(stm32g0b1, stm32g0c1, stm32g0b0)))] + let hsi48_freq: Option<Hertz> = None; + set_freqs(Clocks { sys: sys_clk, hclk1: ahb_freq, pclk1: apb_freq, pclk1_tim: apb_tim_freq, hsi: hsi_freq, - hsi48: None, + hsi48: hsi48_freq, hsi_div_8: hsi_div_8_freq, hse: hse_freq, lse: lse_freq,