From 0272deb158c4cc821e8f587283817a0fe5f82cf8 Mon Sep 17 00:00:00 2001
From: Dario Nieuwenhuis <dirbaio@dirbaio.net>
Date: Sun, 5 Nov 2023 23:35:01 +0100
Subject: [PATCH] stm32/rcc: add shared code for hsi48 with crs support.

---
 embassy-stm32/Cargo.toml                      |  4 +-
 embassy-stm32/src/rcc/g4.rs                   | 50 ++-------------
 embassy-stm32/src/rcc/h.rs                    | 16 +----
 embassy-stm32/src/rcc/hsi48.rs                | 62 +++++++++++++++++++
 embassy-stm32/src/rcc/l0l1.rs                 | 38 ++----------
 embassy-stm32/src/rcc/l4l5.rs                 | 26 ++++----
 embassy-stm32/src/rcc/mod.rs                  |  5 ++
 embassy-stm32/src/rcc/u5.rs                   |  9 +--
 examples/stm32g4/src/bin/usb_serial.rs        |  6 +-
 examples/stm32h5/src/bin/eth.rs               |  2 +-
 examples/stm32h5/src/bin/usb_serial.rs        | 46 +++++++-------
 examples/stm32h7/src/bin/eth.rs               |  2 +-
 examples/stm32h7/src/bin/eth_client.rs        |  2 +-
 .../stm32h7/src/bin/low_level_timer_api.rs    |  1 -
 examples/stm32h7/src/bin/rng.rs               |  2 +-
 examples/stm32h7/src/bin/usb_serial.rs        |  2 +-
 examples/stm32l0/src/bin/button_exti.rs       |  3 +-
 examples/stm32l0/src/bin/lora_cad.rs          |  2 +-
 examples/stm32l0/src/bin/lora_lorawan.rs      |  2 +-
 examples/stm32l0/src/bin/lora_p2p_receive.rs  |  2 +-
 examples/stm32l0/src/bin/lora_p2p_send.rs     |  2 +-
 .../src/bin/spe_adin1110_http_server.rs       |  2 +-
 examples/stm32l4/src/bin/usb_serial.rs        |  2 +-
 examples/stm32u5/src/bin/usb_serial.rs        |  3 +-
 tests/stm32/src/common.rs                     |  6 +-
 25 files changed, 136 insertions(+), 161 deletions(-)
 create mode 100644 embassy-stm32/src/rcc/hsi48.rs

diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml
index 2a2df5c56..7e11e2631 100644
--- a/embassy-stm32/Cargo.toml
+++ b/embassy-stm32/Cargo.toml
@@ -58,7 +58,7 @@ rand_core = "0.6.3"
 sdio-host = "0.5.0"
 embedded-sdmmc = { git = "https://github.com/embassy-rs/embedded-sdmmc-rs", rev = "a4f293d3a6f72158385f79c98634cb8a14d0d2fc", optional = true }
 critical-section = "1.1"
-stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-73b8c37ae74fc28b247188c989fd99400611bd6b" }
+stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-8381654ade324de3945c3c755d359686e957e99b" }
 vcell = "0.1.3"
 bxcan = "0.7.0"
 nb = "1.0.0"
@@ -76,7 +76,7 @@ critical-section = { version = "1.1", features = ["std"] }
 [build-dependencies]
 proc-macro2 = "1.0.36"
 quote = "1.0.15"
-stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-73b8c37ae74fc28b247188c989fd99400611bd6b", default-features = false, features = ["metadata"]}
+stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-8381654ade324de3945c3c755d359686e957e99b", default-features = false, features = ["metadata"]}
 
 
 [features]
diff --git a/embassy-stm32/src/rcc/g4.rs b/embassy-stm32/src/rcc/g4.rs
index b14a61973..13eb0c48d 100644
--- a/embassy-stm32/src/rcc/g4.rs
+++ b/embassy-stm32/src/rcc/g4.rs
@@ -7,7 +7,6 @@ pub use crate::pac::rcc::vals::{
     Pllr as PllR, Ppre as APBPrescaler,
 };
 use crate::pac::{PWR, RCC};
-use crate::rcc::sealed::RccPeripheral;
 use crate::rcc::{set_freqs, Clocks};
 use crate::time::Hertz;
 
@@ -67,23 +66,13 @@ pub struct Pll {
 pub enum Clock48MhzSrc {
     /// Use the High Speed Internal Oscillator. For USB usage, the CRS must be used to calibrate the
     /// oscillator to comply with the USB specification for oscillator tolerance.
-    Hsi48(Option<CrsConfig>),
+    Hsi48(super::Hsi48Config),
     /// Use the PLLQ output. The PLL must be configured to output a 48MHz clock. For USB usage the
     /// PLL needs to be using the HSE source to comply with the USB specification for oscillator
     /// tolerance.
     PllQ,
 }
 
-/// Sets the sync source for the Clock Recovery System (CRS).
-pub enum CrsSyncSource {
-    /// Use an external GPIO to sync the CRS.
-    Gpio,
-    /// Use the Low Speed External oscillator to sync the CRS.
-    Lse,
-    /// Use the USB SOF to sync the CRS.
-    Usb,
-}
-
 /// Clocks configutation
 pub struct Config {
     pub mux: ClockSrc,
@@ -102,12 +91,6 @@ pub struct Config {
     pub ls: super::LsConfig,
 }
 
-/// Configuration for the Clock Recovery System (CRS) used to trim the HSI48 oscillator.
-pub struct CrsConfig {
-    /// Sync source for the CRS.
-    pub sync_src: CrsSyncSource,
-}
-
 impl Default for Config {
     #[inline]
     fn default() -> Config {
@@ -118,7 +101,7 @@ impl Default for Config {
             apb2_pre: APBPrescaler::DIV1,
             low_power_run: false,
             pll: None,
-            clock_48mhz_src: Some(Clock48MhzSrc::Hsi48(None)),
+            clock_48mhz_src: Some(Clock48MhzSrc::Hsi48(Default::default())),
             adc12_clock_source: Adcsel::DISABLE,
             adc345_clock_source: Adcsel::DISABLE,
             ls: Default::default(),
@@ -288,33 +271,8 @@ pub(crate) unsafe fn init(config: Config) {
 
                 crate::pac::rcc::vals::Clk48sel::PLL1_Q
             }
-            Clock48MhzSrc::Hsi48(crs_config) => {
-                // Enable HSI48
-                RCC.crrcr().modify(|w| w.set_hsi48on(true));
-                // Wait for HSI48 to turn on
-                while RCC.crrcr().read().hsi48rdy() == false {}
-
-                // Enable and setup CRS if needed
-                if let Some(crs_config) = crs_config {
-                    crate::peripherals::CRS::enable_and_reset();
-
-                    let sync_src = match crs_config.sync_src {
-                        CrsSyncSource::Gpio => crate::pac::crs::vals::Syncsrc::GPIO,
-                        CrsSyncSource::Lse => crate::pac::crs::vals::Syncsrc::LSE,
-                        CrsSyncSource::Usb => crate::pac::crs::vals::Syncsrc::USB,
-                    };
-
-                    crate::pac::CRS.cfgr().modify(|w| {
-                        w.set_syncsrc(sync_src);
-                    });
-
-                    // These are the correct settings for standard USB operation. If other settings
-                    // are needed there will need to be additional config options for the CRS.
-                    crate::pac::CRS.cr().modify(|w| {
-                        w.set_autotrimen(true);
-                        w.set_cen(true);
-                    });
-                }
+            Clock48MhzSrc::Hsi48(config) => {
+                super::init_hsi48(config);
                 crate::pac::rcc::vals::Clk48sel::HSI48
             }
         };
diff --git a/embassy-stm32/src/rcc/h.rs b/embassy-stm32/src/rcc/h.rs
index 7e924f0ac..4407d9e93 100644
--- a/embassy-stm32/src/rcc/h.rs
+++ b/embassy-stm32/src/rcc/h.rs
@@ -21,9 +21,6 @@ pub const HSI_FREQ: Hertz = Hertz(64_000_000);
 /// CSI speed
 pub const CSI_FREQ: Hertz = Hertz(4_000_000);
 
-/// HSI48 speed
-pub const HSI48_FREQ: Hertz = Hertz(48_000_000);
-
 const VCO_RANGE: RangeInclusive<Hertz> = Hertz(150_000_000)..=Hertz(420_000_000);
 #[cfg(any(stm32h5, pwr_h7rm0455))]
 const VCO_WIDE_RANGE: RangeInclusive<Hertz> = Hertz(128_000_000)..=Hertz(560_000_000);
@@ -126,7 +123,7 @@ pub struct Config {
     pub hsi: Option<HSIPrescaler>,
     pub hse: Option<Hse>,
     pub csi: bool,
-    pub hsi48: bool,
+    pub hsi48: Option<super::Hsi48Config>,
     pub sys: Sysclk,
 
     pub pll1: Option<Pll>,
@@ -155,7 +152,7 @@ impl Default for Config {
             hsi: Some(HSIPrescaler::DIV1),
             hse: None,
             csi: false,
-            hsi48: false,
+            hsi48: Some(Default::default()),
             sys: Sysclk::HSI,
             pll1: None,
             pll2: None,
@@ -301,14 +298,7 @@ pub(crate) unsafe fn init(config: Config) {
     };
 
     // Configure HSI48.
-    RCC.cr().modify(|w| w.set_hsi48on(config.hsi48));
-    let _hsi48 = match config.hsi48 {
-        false => None,
-        true => {
-            while !RCC.cr().read().hsi48rdy() {}
-            Some(CSI_FREQ)
-        }
-    };
+    let _hsi48 = config.hsi48.map(super::init_hsi48);
 
     // Configure CSI.
     RCC.cr().modify(|w| w.set_csion(config.csi));
diff --git a/embassy-stm32/src/rcc/hsi48.rs b/embassy-stm32/src/rcc/hsi48.rs
new file mode 100644
index 000000000..19a8c8cb9
--- /dev/null
+++ b/embassy-stm32/src/rcc/hsi48.rs
@@ -0,0 +1,62 @@
+#![allow(unused)]
+
+use crate::pac::crs::vals::Syncsrc;
+use crate::pac::{CRS, RCC};
+use crate::rcc::sealed::RccPeripheral;
+use crate::time::Hertz;
+
+/// HSI48 speed
+pub const HSI48_FREQ: Hertz = Hertz(48_000_000);
+
+/// Configuration for the HSI48 clock
+#[derive(Clone, Copy, Debug)]
+pub struct Hsi48Config {
+    /// Enable CRS Sync from USB Start Of Frame (SOF) events.
+    /// Required if HSI48 is going to be used as USB clock.
+    ///
+    /// Other use cases of CRS are not supported yet.
+    pub sync_from_usb: bool,
+}
+
+impl Default for Hsi48Config {
+    fn default() -> Self {
+        Self { sync_from_usb: false }
+    }
+}
+
+pub(crate) fn init_hsi48(config: Hsi48Config) -> Hertz {
+    // Enable VREFINT reference for HSI48 oscillator
+    #[cfg(stm32l0)]
+    crate::pac::SYSCFG.cfgr3().modify(|w| {
+        w.set_enref_hsi48(true);
+        w.set_en_vrefint(true);
+    });
+
+    // Enable HSI48
+    #[cfg(not(any(stm32u5, stm32g0, stm32h5, stm32h7, stm32u5, stm32wba, stm32f0)))]
+    let r = RCC.crrcr();
+    #[cfg(any(stm32u5, stm32g0, stm32h5, stm32h7, stm32u5, stm32wba))]
+    let r = RCC.cr();
+    #[cfg(any(stm32f0))]
+    let r = RCC.cr2();
+
+    r.modify(|w| w.set_hsi48on(true));
+    while r.read().hsi48rdy() == false {}
+
+    if config.sync_from_usb {
+        crate::peripherals::CRS::enable_and_reset();
+
+        CRS.cfgr().modify(|w| {
+            w.set_syncsrc(Syncsrc::USB);
+        });
+
+        // These are the correct settings for standard USB operation. If other settings
+        // are needed there will need to be additional config options for the CRS.
+        crate::pac::CRS.cr().modify(|w| {
+            w.set_autotrimen(true);
+            w.set_cen(true);
+        });
+    }
+
+    HSI48_FREQ
+}
diff --git a/embassy-stm32/src/rcc/l0l1.rs b/embassy-stm32/src/rcc/l0l1.rs
index 3af279595..25a7762a3 100644
--- a/embassy-stm32/src/rcc/l0l1.rs
+++ b/embassy-stm32/src/rcc/l0l1.rs
@@ -3,8 +3,6 @@ pub use crate::pac::rcc::vals::{
     Hpre as AHBPrescaler, Msirange as MSIRange, Plldiv as PLLDiv, Plldiv as PllDiv, Pllmul as PLLMul, Pllmul as PllMul,
     Pllsrc as PLLSource, Ppre as APBPrescaler, Sw as ClockSrc,
 };
-#[cfg(crs)]
-use crate::pac::{crs, CRS, SYSCFG};
 use crate::pac::{FLASH, PWR, RCC};
 use crate::rcc::{set_freqs, Clocks};
 use crate::time::Hertz;
@@ -47,7 +45,7 @@ pub struct Config {
     pub hsi: bool,
     pub hse: Option<Hse>,
     #[cfg(crs)]
-    pub hsi48: bool,
+    pub hsi48: Option<super::Hsi48Config>,
 
     pub pll: Option<Pll>,
 
@@ -68,7 +66,7 @@ impl Default for Config {
             hse: None,
             hsi: false,
             #[cfg(crs)]
-            hsi48: false,
+            hsi48: Some(Default::default()),
 
             pll: None,
 
@@ -174,37 +172,11 @@ pub(crate) unsafe fn init(config: Config) {
     let (pclk2, pclk2_tim) = super::util::calc_pclk(hclk1, config.apb2_pre);
 
     #[cfg(crs)]
-    if config.hsi48 {
-        // Reset CRS peripheral
-        RCC.apb1rstr().modify(|w| w.set_crsrst(true));
-        RCC.apb1rstr().modify(|w| w.set_crsrst(false));
-
-        // Enable CRS peripheral
-        RCC.apb1enr().modify(|w| w.set_crsen(true));
-
-        // Initialize CRS
-        CRS.cfgr().write(|w|
-
-        // Select LSE as synchronization source
-        w.set_syncsrc(crs::vals::Syncsrc::LSE));
-        CRS.cr().modify(|w| {
-            w.set_autotrimen(true);
-            w.set_cen(true);
-        });
-
-        // Enable VREFINT reference for HSI48 oscillator
-        SYSCFG.cfgr3().modify(|w| {
-            w.set_enref_hsi48(true);
-            w.set_en_vrefint(true);
-        });
-
+    let _hsi48 = config.hsi48.map(|config| {
         // Select HSI48 as USB clock
         RCC.ccipr().modify(|w| w.set_hsi48msel(true));
-
-        // Enable dedicated USB clock
-        RCC.crrcr().modify(|w| w.set_hsi48on(true));
-        while !RCC.crrcr().read().hsi48rdy() {}
-    }
+        super::init_hsi48(config)
+    });
 
     set_freqs(Clocks {
         sys: sys_clk,
diff --git a/embassy-stm32/src/rcc/l4l5.rs b/embassy-stm32/src/rcc/l4l5.rs
index 44748620c..c44839104 100644
--- a/embassy-stm32/src/rcc/l4l5.rs
+++ b/embassy-stm32/src/rcc/l4l5.rs
@@ -58,8 +58,8 @@ pub struct Config {
     pub msi: Option<MSIRange>,
     pub hsi: bool,
     pub hse: Option<Hse>,
-    #[cfg(any(all(stm32l4, not(any(stm32l47x, stm32l48x))), stm32l5, stm32wb))]
-    pub hsi48: bool,
+    #[cfg(crs)]
+    pub hsi48: Option<super::Hsi48Config>,
 
     // pll
     pub pll: Option<Pll>,
@@ -108,8 +108,8 @@ impl Default for Config {
             pllsai1: None,
             #[cfg(any(stm32l47x, stm32l48x, stm32l49x, stm32l4ax, rcc_l4plus, stm32l5))]
             pllsai2: None,
-            #[cfg(any(all(stm32l4, not(any(stm32l47x, stm32l48x))), stm32l5, stm32wb))]
-            hsi48: true,
+            #[cfg(crs)]
+            hsi48: Some(Default::default()),
             #[cfg(any(stm32l4, stm32l5, stm32wb))]
             clk48_src: Clk48Src::HSI48,
             ls: Default::default(),
@@ -126,7 +126,8 @@ pub const WPAN_DEFAULT: Config = Config {
         prescaler: HsePrescaler::DIV1,
     }),
     mux: ClockSrc::PLL1_R,
-    hsi48: true,
+    #[cfg(crs)]
+    hsi48: Some(super::Hsi48Config { sync_from_usb: false }),
     msi: None,
     hsi: false,
     clk48_src: Clk48Src::PLL1_Q,
@@ -216,15 +217,10 @@ pub(crate) unsafe fn init(config: Config) {
         hse.freq
     });
 
-    #[cfg(any(all(stm32l4, not(any(stm32l47x, stm32l48x))), stm32l5, stm32wb))]
-    let hsi48 = config.hsi48.then(|| {
-        RCC.crrcr().modify(|w| w.set_hsi48on(true));
-        while !RCC.crrcr().read().hsi48rdy() {}
-
-        Hertz(48_000_000)
-    });
-    #[cfg(any(stm32l47x, stm32l48x))]
-    let hsi48 = None;
+    #[cfg(crs)]
+    let _hsi48 = config.hsi48.map(super::init_hsi48);
+    #[cfg(not(crs))]
+    let _hsi48: Option<Hertz> = None;
 
     let _plls = [
         &config.pll,
@@ -275,7 +271,7 @@ pub(crate) unsafe fn init(config: Config) {
     RCC.ccipr1().modify(|w| w.set_clk48sel(config.clk48_src));
     #[cfg(any(stm32l4, stm32l5, stm32wb))]
     let _clk48 = match config.clk48_src {
-        Clk48Src::HSI48 => hsi48,
+        Clk48Src::HSI48 => _hsi48,
         Clk48Src::MSI => msi,
         Clk48Src::PLLSAI1_Q => pllsai1.q,
         Clk48Src::PLL1_Q => pll.q,
diff --git a/embassy-stm32/src/rcc/mod.rs b/embassy-stm32/src/rcc/mod.rs
index c11a9cc6b..e15f4fe41 100644
--- a/embassy-stm32/src/rcc/mod.rs
+++ b/embassy-stm32/src/rcc/mod.rs
@@ -9,6 +9,11 @@ mod mco;
 pub use bd::*;
 pub use mco::*;
 
+#[cfg(crs)]
+mod hsi48;
+#[cfg(crs)]
+pub use hsi48::*;
+
 #[cfg_attr(rcc_f0, path = "f0.rs")]
 #[cfg_attr(any(rcc_f1, rcc_f100, rcc_f1cl), path = "f1.rs")]
 #[cfg_attr(rcc_f2, path = "f2.rs")]
diff --git a/embassy-stm32/src/rcc/u5.rs b/embassy-stm32/src/rcc/u5.rs
index 2bbacbbdc..c111362bf 100644
--- a/embassy-stm32/src/rcc/u5.rs
+++ b/embassy-stm32/src/rcc/u5.rs
@@ -115,7 +115,7 @@ pub struct Config {
     pub apb1_pre: APBPrescaler,
     pub apb2_pre: APBPrescaler,
     pub apb3_pre: APBPrescaler,
-    pub hsi48: bool,
+    pub hsi48: Option<super::Hsi48Config>,
     /// The voltage range influences the maximum clock frequencies for different parts of the
     /// device. In particular, system clocks exceeding 110 MHz require `RANGE1`, and system clocks
     /// exceeding 55 MHz require at least `RANGE2`.
@@ -189,7 +189,7 @@ impl Default for Config {
             apb1_pre: APBPrescaler::DIV1,
             apb2_pre: APBPrescaler::DIV1,
             apb3_pre: APBPrescaler::DIV1,
-            hsi48: true,
+            hsi48: Some(Default::default()),
             voltage_range: VoltageScale::RANGE3,
             ls: Default::default(),
         }
@@ -322,10 +322,7 @@ pub(crate) unsafe fn init(config: Config) {
         }
     };
 
-    if config.hsi48 {
-        RCC.cr().modify(|w| w.set_hsi48on(true));
-        while !RCC.cr().read().hsi48rdy() {}
-    }
+    let _hsi48 = config.hsi48.map(super::init_hsi48);
 
     // The clock source is ready
     // Calculate and set the flash wait states
diff --git a/examples/stm32g4/src/bin/usb_serial.rs b/examples/stm32g4/src/bin/usb_serial.rs
index 9099b609a..188988b14 100644
--- a/examples/stm32g4/src/bin/usb_serial.rs
+++ b/examples/stm32g4/src/bin/usb_serial.rs
@@ -4,7 +4,7 @@
 
 use defmt::{panic, *};
 use embassy_executor::Spawner;
-use embassy_stm32::rcc::{Clock48MhzSrc, ClockSrc, CrsConfig, CrsSyncSource, Pll, PllM, PllN, PllQ, PllR, PllSrc};
+use embassy_stm32::rcc::{Clock48MhzSrc, ClockSrc, Hsi48Config, Pll, PllM, PllN, PllQ, PllR, PllSrc};
 use embassy_stm32::time::Hertz;
 use embassy_stm32::usb::{self, Driver, Instance};
 use embassy_stm32::{bind_interrupts, peripherals, Config};
@@ -41,9 +41,7 @@ async fn main(_spawner: Spawner) {
 
     if USE_HSI48 {
         // Sets up the Clock Recovery System (CRS) to use the USB SOF to trim the HSI48 oscillator.
-        config.rcc.clock_48mhz_src = Some(Clock48MhzSrc::Hsi48(Some(CrsConfig {
-            sync_src: CrsSyncSource::Usb,
-        })));
+        config.rcc.clock_48mhz_src = Some(Clock48MhzSrc::Hsi48(Hsi48Config { sync_from_usb: true }));
     } else {
         config.rcc.clock_48mhz_src = Some(Clock48MhzSrc::PllQ);
     }
diff --git a/examples/stm32h5/src/bin/eth.rs b/examples/stm32h5/src/bin/eth.rs
index 5bec9d447..b2758cba0 100644
--- a/examples/stm32h5/src/bin/eth.rs
+++ b/examples/stm32h5/src/bin/eth.rs
@@ -37,7 +37,7 @@ async fn net_task(stack: &'static Stack<Device>) -> ! {
 async fn main(spawner: Spawner) -> ! {
     let mut config = Config::default();
     config.rcc.hsi = None;
-    config.rcc.hsi48 = true; // needed for rng
+    config.rcc.hsi48 = Some(Default::default()); // needed for RNG
     config.rcc.hse = Some(Hse {
         freq: Hertz(8_000_000),
         mode: HseMode::BypassDigital,
diff --git a/examples/stm32h5/src/bin/usb_serial.rs b/examples/stm32h5/src/bin/usb_serial.rs
index 735826a69..13b218d00 100644
--- a/examples/stm32h5/src/bin/usb_serial.rs
+++ b/examples/stm32h5/src/bin/usb_serial.rs
@@ -4,9 +4,6 @@
 
 use defmt::{panic, *};
 use embassy_executor::Spawner;
-use embassy_stm32::rcc::{
-    AHBPrescaler, APBPrescaler, Hse, HseMode, Pll, PllDiv, PllMul, PllPreDiv, PllSource, Sysclk, VoltageScale,
-};
 use embassy_stm32::time::Hertz;
 use embassy_stm32::usb::{Driver, Instance};
 use embassy_stm32::{bind_interrupts, pac, peripherals, usb, Config};
@@ -23,26 +20,29 @@ bind_interrupts!(struct Irqs {
 #[embassy_executor::main]
 async fn main(_spawner: Spawner) {
     let mut config = Config::default();
-    config.rcc.hsi = None;
-    config.rcc.hsi48 = true; // needed for usb
-    config.rcc.hse = Some(Hse {
-        freq: Hertz(8_000_000),
-        mode: HseMode::BypassDigital,
-    });
-    config.rcc.pll1 = Some(Pll {
-        source: PllSource::HSE,
-        prediv: PllPreDiv::DIV2,
-        mul: PllMul::MUL125,
-        divp: Some(PllDiv::DIV2), // 250mhz
-        divq: None,
-        divr: None,
-    });
-    config.rcc.ahb_pre = AHBPrescaler::DIV2;
-    config.rcc.apb1_pre = APBPrescaler::DIV4;
-    config.rcc.apb2_pre = APBPrescaler::DIV2;
-    config.rcc.apb3_pre = APBPrescaler::DIV4;
-    config.rcc.sys = Sysclk::PLL1_P;
-    config.rcc.voltage_scale = VoltageScale::Scale0;
+    {
+        use embassy_stm32::rcc::*;
+        config.rcc.hsi = None;
+        config.rcc.hsi48 = Some(Hsi48Config { sync_from_usb: true }); // needed for USB
+        config.rcc.hse = Some(Hse {
+            freq: Hertz(8_000_000),
+            mode: HseMode::BypassDigital,
+        });
+        config.rcc.pll1 = Some(Pll {
+            source: PllSource::HSE,
+            prediv: PllPreDiv::DIV2,
+            mul: PllMul::MUL125,
+            divp: Some(PllDiv::DIV2), // 250mhz
+            divq: None,
+            divr: None,
+        });
+        config.rcc.ahb_pre = AHBPrescaler::DIV2;
+        config.rcc.apb1_pre = APBPrescaler::DIV4;
+        config.rcc.apb2_pre = APBPrescaler::DIV2;
+        config.rcc.apb3_pre = APBPrescaler::DIV4;
+        config.rcc.sys = Sysclk::PLL1_P;
+        config.rcc.voltage_scale = VoltageScale::Scale0;
+    }
     let p = embassy_stm32::init(config);
 
     info!("Hello World!");
diff --git a/examples/stm32h7/src/bin/eth.rs b/examples/stm32h7/src/bin/eth.rs
index e37d8797b..b7a077374 100644
--- a/examples/stm32h7/src/bin/eth.rs
+++ b/examples/stm32h7/src/bin/eth.rs
@@ -36,7 +36,7 @@ async fn main(spawner: Spawner) -> ! {
         use embassy_stm32::rcc::*;
         config.rcc.hsi = Some(HSIPrescaler::DIV1);
         config.rcc.csi = true;
-        config.rcc.hsi48 = true; // needed for RNG
+        config.rcc.hsi48 = Some(Default::default()); // needed for RNG
         config.rcc.pll1 = Some(Pll {
             source: PllSource::HSI,
             prediv: PllPreDiv::DIV4,
diff --git a/examples/stm32h7/src/bin/eth_client.rs b/examples/stm32h7/src/bin/eth_client.rs
index 88df53f01..f0f28ec9c 100644
--- a/examples/stm32h7/src/bin/eth_client.rs
+++ b/examples/stm32h7/src/bin/eth_client.rs
@@ -37,7 +37,7 @@ async fn main(spawner: Spawner) -> ! {
         use embassy_stm32::rcc::*;
         config.rcc.hsi = Some(HSIPrescaler::DIV1);
         config.rcc.csi = true;
-        config.rcc.hsi48 = true; // needed for RNG
+        config.rcc.hsi48 = Some(Default::default()); // needed for RNG
         config.rcc.pll1 = Some(Pll {
             source: PllSource::HSI,
             prediv: PllPreDiv::DIV4,
diff --git a/examples/stm32h7/src/bin/low_level_timer_api.rs b/examples/stm32h7/src/bin/low_level_timer_api.rs
index e4bac8a5a..e0be495d1 100644
--- a/examples/stm32h7/src/bin/low_level_timer_api.rs
+++ b/examples/stm32h7/src/bin/low_level_timer_api.rs
@@ -19,7 +19,6 @@ async fn main(_spawner: Spawner) {
         use embassy_stm32::rcc::*;
         config.rcc.hsi = Some(HSIPrescaler::DIV1);
         config.rcc.csi = true;
-        config.rcc.hsi48 = true; // needed for RNG
         config.rcc.pll1 = Some(Pll {
             source: PllSource::HSI,
             prediv: PllPreDiv::DIV4,
diff --git a/examples/stm32h7/src/bin/rng.rs b/examples/stm32h7/src/bin/rng.rs
index af1d6ebb8..1fb4cfec0 100644
--- a/examples/stm32h7/src/bin/rng.rs
+++ b/examples/stm32h7/src/bin/rng.rs
@@ -15,7 +15,7 @@ bind_interrupts!(struct Irqs {
 #[embassy_executor::main]
 async fn main(_spawner: Spawner) {
     let mut config = Config::default();
-    config.rcc.hsi48 = true; // needed for RNG.
+    config.rcc.hsi48 = Some(Default::default()); // needed for RNG
     let p = embassy_stm32::init(config);
     info!("Hello World!");
 
diff --git a/examples/stm32h7/src/bin/usb_serial.rs b/examples/stm32h7/src/bin/usb_serial.rs
index 19d77183b..648ff6eea 100644
--- a/examples/stm32h7/src/bin/usb_serial.rs
+++ b/examples/stm32h7/src/bin/usb_serial.rs
@@ -25,7 +25,7 @@ async fn main(_spawner: Spawner) {
         use embassy_stm32::rcc::*;
         config.rcc.hsi = Some(HSIPrescaler::DIV1);
         config.rcc.csi = true;
-        config.rcc.hsi48 = true; // needed for USB
+        config.rcc.hsi48 = Some(Hsi48Config { sync_from_usb: true }); // needed for USB
         config.rcc.pll1 = Some(Pll {
             source: PllSource::HSI,
             prediv: PllPreDiv::DIV4,
diff --git a/examples/stm32l0/src/bin/button_exti.rs b/examples/stm32l0/src/bin/button_exti.rs
index 441b00c6d..ffede253e 100644
--- a/examples/stm32l0/src/bin/button_exti.rs
+++ b/examples/stm32l0/src/bin/button_exti.rs
@@ -11,8 +11,7 @@ use {defmt_rtt as _, panic_probe as _};
 
 #[embassy_executor::main]
 async fn main(_spawner: Spawner) {
-    let mut config = Config::default();
-    config.rcc.hsi48 = true;
+    let config = Config::default();
     let p = embassy_stm32::init(config);
 
     let button = Input::new(p.PB2, Pull::Up);
diff --git a/examples/stm32l0/src/bin/lora_cad.rs b/examples/stm32l0/src/bin/lora_cad.rs
index 61024ef79..8ca9e8b22 100644
--- a/examples/stm32l0/src/bin/lora_cad.rs
+++ b/examples/stm32l0/src/bin/lora_cad.rs
@@ -23,8 +23,8 @@ const LORA_FREQUENCY_IN_HZ: u32 = 903_900_000; // warning: set this appropriatel
 #[embassy_executor::main]
 async fn main(_spawner: Spawner) {
     let mut config = embassy_stm32::Config::default();
+    config.rcc.hsi = true;
     config.rcc.mux = embassy_stm32::rcc::ClockSrc::HSI;
-    config.rcc.hsi48 = true;
     let p = embassy_stm32::init(config);
 
     let mut spi_config = spi::Config::default();
diff --git a/examples/stm32l0/src/bin/lora_lorawan.rs b/examples/stm32l0/src/bin/lora_lorawan.rs
index 9c4f32916..4365c4cf6 100644
--- a/examples/stm32l0/src/bin/lora_lorawan.rs
+++ b/examples/stm32l0/src/bin/lora_lorawan.rs
@@ -33,8 +33,8 @@ const LORAWAN_REGION: region::Region = region::Region::EU868; // warning: set th
 #[embassy_executor::main]
 async fn main(_spawner: Spawner) {
     let mut config = embassy_stm32::Config::default();
+    config.rcc.hsi = true;
     config.rcc.mux = embassy_stm32::rcc::ClockSrc::HSI;
-    config.rcc.hsi48 = true;
     let p = embassy_stm32::init(config);
 
     let mut spi_config = spi::Config::default();
diff --git a/examples/stm32l0/src/bin/lora_p2p_receive.rs b/examples/stm32l0/src/bin/lora_p2p_receive.rs
index 4a50182c2..0627ac087 100644
--- a/examples/stm32l0/src/bin/lora_p2p_receive.rs
+++ b/examples/stm32l0/src/bin/lora_p2p_receive.rs
@@ -23,8 +23,8 @@ const LORA_FREQUENCY_IN_HZ: u32 = 903_900_000; // warning: set this appropriatel
 #[embassy_executor::main]
 async fn main(_spawner: Spawner) {
     let mut config = embassy_stm32::Config::default();
+    config.rcc.hsi = true;
     config.rcc.mux = embassy_stm32::rcc::ClockSrc::HSI;
-    config.rcc.hsi48 = true;
     let p = embassy_stm32::init(config);
 
     let mut spi_config = spi::Config::default();
diff --git a/examples/stm32l0/src/bin/lora_p2p_send.rs b/examples/stm32l0/src/bin/lora_p2p_send.rs
index f6de6a5cd..4f12cadc8 100644
--- a/examples/stm32l0/src/bin/lora_p2p_send.rs
+++ b/examples/stm32l0/src/bin/lora_p2p_send.rs
@@ -23,8 +23,8 @@ const LORA_FREQUENCY_IN_HZ: u32 = 903_900_000; // warning: set this appropriatel
 #[embassy_executor::main]
 async fn main(_spawner: Spawner) {
     let mut config = embassy_stm32::Config::default();
+    config.rcc.hsi = true;
     config.rcc.mux = embassy_stm32::rcc::ClockSrc::HSI;
-    config.rcc.hsi48 = true;
     let p = embassy_stm32::init(config);
 
     let mut spi_config = spi::Config::default();
diff --git a/examples/stm32l4/src/bin/spe_adin1110_http_server.rs b/examples/stm32l4/src/bin/spe_adin1110_http_server.rs
index f76b504a7..62caeea55 100644
--- a/examples/stm32l4/src/bin/spe_adin1110_http_server.rs
+++ b/examples/stm32l4/src/bin/spe_adin1110_http_server.rs
@@ -90,7 +90,7 @@ async fn main(spawner: Spawner) {
             divq: None,
             divr: Some(PllRDiv::DIV2), // sysclk 80Mhz clock (8 / 1 * 20 / 2)
         });
-        config.rcc.hsi48 = true; // needed for rng
+        config.rcc.hsi48 = Some(Default::default()); // needed for RNG
     }
 
     let dp = embassy_stm32::init(config);
diff --git a/examples/stm32l4/src/bin/usb_serial.rs b/examples/stm32l4/src/bin/usb_serial.rs
index 15c6f1982..d459245d5 100644
--- a/examples/stm32l4/src/bin/usb_serial.rs
+++ b/examples/stm32l4/src/bin/usb_serial.rs
@@ -23,7 +23,7 @@ async fn main(_spawner: Spawner) {
     info!("Hello World!");
 
     let mut config = Config::default();
-    config.rcc.hsi48 = true;
+    config.rcc.hsi48 = Some(Hsi48Config { sync_from_usb: true }); // needed for USB
     config.rcc.mux = ClockSrc::PLL1_R;
     config.rcc.hsi = true;
     config.rcc.pll = Some(Pll {
diff --git a/examples/stm32u5/src/bin/usb_serial.rs b/examples/stm32u5/src/bin/usb_serial.rs
index f59f623b3..eaa1c2912 100644
--- a/examples/stm32u5/src/bin/usb_serial.rs
+++ b/examples/stm32u5/src/bin/usb_serial.rs
@@ -29,8 +29,7 @@ async fn main(_spawner: Spawner) {
         n: Plln::MUL10,
         r: Plldiv::DIV1,
     });
-    //config.rcc.mux = ClockSrc::MSI(MSIRange::Range48mhz);
-    config.rcc.hsi48 = true;
+    config.rcc.hsi48 = Some(Hsi48Config { sync_from_usb: true }); // needed for USB
 
     let p = embassy_stm32::init(config);
 
diff --git a/tests/stm32/src/common.rs b/tests/stm32/src/common.rs
index 54e23e436..3668e18ce 100644
--- a/tests/stm32/src/common.rs
+++ b/tests/stm32/src/common.rs
@@ -306,7 +306,7 @@ pub fn config() -> Config {
     {
         use embassy_stm32::rcc::*;
         config.rcc.hsi = None;
-        config.rcc.hsi48 = true; // needed for rng
+        config.rcc.hsi48 = Some(Default::default()); // needed for RNG
         config.rcc.hse = Some(Hse {
             freq: Hertz(8_000_000),
             mode: HseMode::BypassDigital,
@@ -332,7 +332,7 @@ pub fn config() -> Config {
         use embassy_stm32::rcc::*;
         config.rcc.hsi = Some(HSIPrescaler::DIV1);
         config.rcc.csi = true;
-        config.rcc.hsi48 = true; // needed for RNG
+        config.rcc.hsi48 = Some(Default::default()); // needed for RNG
         config.rcc.pll1 = Some(Pll {
             source: PllSource::HSI,
             prediv: PllPreDiv::DIV4,
@@ -364,7 +364,7 @@ pub fn config() -> Config {
         use embassy_stm32::rcc::*;
         config.rcc.hsi = Some(HSIPrescaler::DIV1);
         config.rcc.csi = true;
-        config.rcc.hsi48 = true; // needed for RNG
+        config.rcc.hsi48 = Some(Default::default()); // needed for RNG
         config.rcc.pll1 = Some(Pll {
             source: PllSource::HSI,
             prediv: PllPreDiv::DIV4,