diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml
index 373172760..4b650cc88 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-c551c07bf12513dd8346a9fe0bc70cf79f2ea02f" }
+stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-fbb8f77326dd066aa6c0d66b3b46e76a569dda8b" }
 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-c551c07bf12513dd8346a9fe0bc70cf79f2ea02f", default-features = false, features = ["metadata"]}
+stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-fbb8f77326dd066aa6c0d66b3b46e76a569dda8b", default-features = false, features = ["metadata"]}
 
 
 [features]
diff --git a/embassy-stm32/src/rcc/f4f7.rs b/embassy-stm32/src/rcc/f.rs
similarity index 71%
rename from embassy-stm32/src/rcc/f4f7.rs
rename to embassy-stm32/src/rcc/f.rs
index 718ba9b7c..36d9f178f 100644
--- a/embassy-stm32/src/rcc/f4f7.rs
+++ b/embassy-stm32/src/rcc/f.rs
@@ -1,9 +1,12 @@
-use crate::pac::pwr::vals::Vos;
+use stm32_metapac::flash::vals::Latency;
+
 pub use crate::pac::rcc::vals::{
     Hpre as AHBPrescaler, Pllm as PllPreDiv, Plln as PllMul, Pllp as PllPDiv, Pllq as PllQDiv, Pllr as PllRDiv,
     Pllsrc as PllSource, Ppre as APBPrescaler, Sw as Sysclk,
 };
-use crate::pac::{FLASH, PWR, RCC};
+#[cfg(any(stm32f4, stm32f7))]
+use crate::pac::PWR;
+use crate::pac::{FLASH, RCC};
 use crate::rcc::{set_freqs, Clocks};
 use crate::time::Hertz;
 
@@ -56,6 +59,22 @@ pub struct Pll {
     pub divr: Option<PllRDiv>,
 }
 
+/// Voltage range of the power supply used.
+///
+/// Used to calculate flash waitstates. See
+/// RM0033 - Table 3. Number of wait states according to Cortex®-M3 clock frequency
+#[cfg(stm32f2)]
+pub enum VoltageScale {
+    /// 2.7 to 3.6 V
+    Range0,
+    /// 2.4 to 2.7 V
+    Range1,
+    /// 2.1 to 2.4 V
+    Range2,
+    /// 1.8 to 2.1 V
+    Range3,
+}
+
 /// Configuration of the core clocks
 #[non_exhaustive]
 pub struct Config {
@@ -66,7 +85,7 @@ pub struct Config {
     pub pll_src: PllSource,
 
     pub pll: Option<Pll>,
-    #[cfg(any(all(stm32f4, not(stm32f410)), stm32f7))]
+    #[cfg(any(stm32f2, all(stm32f4, not(stm32f410)), stm32f7))]
     pub plli2s: Option<Pll>,
     #[cfg(any(stm32f446, stm32f427, stm32f437, stm32f4x9, stm32f7))]
     pub pllsai: Option<Pll>,
@@ -76,6 +95,9 @@ pub struct Config {
     pub apb2_pre: APBPrescaler,
 
     pub ls: super::LsConfig,
+
+    #[cfg(stm32f2)]
+    pub voltage: VoltageScale,
 }
 
 impl Default for Config {
@@ -86,7 +108,7 @@ impl Default for Config {
             sys: Sysclk::HSI,
             pll_src: PllSource::HSI,
             pll: None,
-            #[cfg(any(all(stm32f4, not(stm32f410)), stm32f7))]
+            #[cfg(any(stm32f2, all(stm32f4, not(stm32f410)), stm32f7))]
             plli2s: None,
             #[cfg(any(stm32f446, stm32f427, stm32f437, stm32f4x9, stm32f7))]
             pllsai: None,
@@ -96,6 +118,9 @@ impl Default for Config {
             apb2_pre: APBPrescaler::DIV1,
 
             ls: Default::default(),
+
+            #[cfg(stm32f2)]
+            voltage: VoltageScale::Range3,
         }
     }
 }
@@ -103,14 +128,13 @@ impl Default for Config {
 pub(crate) unsafe fn init(config: Config) {
     // set VOS to SCALE1, if use PLL
     // TODO: check real clock speed before set VOS
+    #[cfg(any(stm32f4, stm32f7))]
     if config.pll.is_some() {
-        PWR.cr1().modify(|w| w.set_vos(Vos::SCALE1));
+        PWR.cr1().modify(|w| w.set_vos(crate::pac::pwr::vals::Vos::SCALE1));
     }
 
     // always enable overdrive for now. Make it configurable in the future.
-    #[cfg(not(any(
-        stm32f401, stm32f410, stm32f411, stm32f412, stm32f413, stm32f423, stm32f405, stm32f407, stm32f415, stm32f417
-    )))]
+    #[cfg(any(stm32f446, stm32f4x9, stm32f427, stm32f437, stm32f7))]
     {
         PWR.cr1().modify(|w| w.set_oden(true));
         while !PWR.csr1().read().odrdy() {}
@@ -158,7 +182,7 @@ pub(crate) unsafe fn init(config: Config) {
         source: config.pll_src,
     };
     let pll = init_pll(PllInstance::Pll, config.pll, &pll_input);
-    #[cfg(any(all(stm32f4, not(stm32f410)), stm32f7))]
+    #[cfg(any(stm32f2, all(stm32f4, not(stm32f410)), stm32f7))]
     let _plli2s = init_pll(PllInstance::Plli2s, config.plli2s, &pll_input);
     #[cfg(any(stm32f446, stm32f427, stm32f437, stm32f4x9, stm32f7))]
     let _pllsai = init_pll(PllInstance::Pllsai, config.pllsai, &pll_input);
@@ -182,7 +206,48 @@ pub(crate) unsafe fn init(config: Config) {
 
     let rtc = config.ls.init();
 
-    flash_setup(hclk);
+    #[cfg(stm32f2)]
+    let latency = match (config.voltage, hclk.0) {
+        (VoltageScale::Range3, ..=16_000_000) => Latency::WS0,
+        (VoltageScale::Range3, ..=32_000_000) => Latency::WS1,
+        (VoltageScale::Range3, ..=48_000_000) => Latency::WS2,
+        (VoltageScale::Range3, ..=64_000_000) => Latency::WS3,
+        (VoltageScale::Range3, ..=80_000_000) => Latency::WS4,
+        (VoltageScale::Range3, ..=96_000_000) => Latency::WS5,
+        (VoltageScale::Range3, ..=112_000_000) => Latency::WS6,
+        (VoltageScale::Range3, ..=120_000_000) => Latency::WS7,
+        (VoltageScale::Range2, ..=18_000_000) => Latency::WS0,
+        (VoltageScale::Range2, ..=36_000_000) => Latency::WS1,
+        (VoltageScale::Range2, ..=54_000_000) => Latency::WS2,
+        (VoltageScale::Range2, ..=72_000_000) => Latency::WS3,
+        (VoltageScale::Range2, ..=90_000_000) => Latency::WS4,
+        (VoltageScale::Range2, ..=108_000_000) => Latency::WS5,
+        (VoltageScale::Range2, ..=120_000_000) => Latency::WS6,
+        (VoltageScale::Range1, ..=24_000_000) => Latency::WS0,
+        (VoltageScale::Range1, ..=48_000_000) => Latency::WS1,
+        (VoltageScale::Range1, ..=72_000_000) => Latency::WS2,
+        (VoltageScale::Range1, ..=96_000_000) => Latency::WS3,
+        (VoltageScale::Range1, ..=120_000_000) => Latency::WS4,
+        (VoltageScale::Range0, ..=30_000_000) => Latency::WS0,
+        (VoltageScale::Range0, ..=60_000_000) => Latency::WS1,
+        (VoltageScale::Range0, ..=90_000_000) => Latency::WS2,
+        (VoltageScale::Range0, ..=120_000_000) => Latency::WS3,
+        _ => unreachable!(),
+    };
+
+    #[cfg(any(stm32f4, stm32f7))]
+    let latency = {
+        // Be conservative with voltage ranges
+        const FLASH_LATENCY_STEP: u32 = 30_000_000;
+
+        let latency = (hclk.0 - 1) / FLASH_LATENCY_STEP;
+        debug!("flash: latency={}", latency);
+
+        Latency::from_bits(latency as u8)
+    };
+
+    FLASH.acr().write(|w| w.set_latency(latency));
+    while FLASH.acr().read().latency() != latency {}
 
     RCC.cfgr().modify(|w| {
         w.set_sw(config.sys);
@@ -232,7 +297,7 @@ struct PllOutput {
 #[derive(PartialEq, Eq, Clone, Copy)]
 enum PllInstance {
     Pll,
-    #[cfg(any(all(stm32f4, not(stm32f410)), stm32f7))]
+    #[cfg(any(stm32f2, all(stm32f4, not(stm32f410)), stm32f7))]
     Plli2s,
     #[cfg(any(stm32f446, stm32f427, stm32f437, stm32f4x9, stm32f7))]
     Pllsai,
@@ -244,7 +309,7 @@ fn pll_enable(instance: PllInstance, enabled: bool) {
             RCC.cr().modify(|w| w.set_pllon(enabled));
             while RCC.cr().read().pllrdy() != enabled {}
         }
-        #[cfg(any(all(stm32f4, not(stm32f410)), stm32f7))]
+        #[cfg(any(stm32f2, all(stm32f4, not(stm32f410)), stm32f7))]
         PllInstance::Plli2s => {
             RCC.cr().modify(|w| w.set_plli2son(enabled));
             while RCC.cr().read().plli2srdy() != enabled {}
@@ -275,6 +340,18 @@ fn init_pll(instance: PllInstance, config: Option<Pll>, input: &PllInput) -> Pll
     let vco_freq = in_freq * pll.mul;
     assert!(max::PLL_VCO.contains(&vco_freq));
 
+    // stm32f2 plls are like swiss cheese
+    #[cfg(stm32f2)]
+    match instance {
+        PllInstance::Pll => {
+            assert!(pll.divr.is_none());
+        }
+        PllInstance::Plli2s => {
+            assert!(pll.divp.is_none());
+            assert!(pll.divq.is_none());
+        }
+    }
+
     let p = pll.divp.map(|div| vco_freq / div);
     let q = pll.divq.map(|div| vco_freq / div);
     let r = pll.divr.map(|div| vco_freq / div);
@@ -288,6 +365,7 @@ fn init_pll(instance: PllInstance, config: Option<Pll>, input: &PllInput) -> Pll
             if let Some(divq) = pll.divq {
                 $w.set_pllq(divq);
             }
+            #[cfg(any(stm32f4, stm32f7))]
             if let Some(divr) = pll.divr {
                 $w.set_pllr(divr);
             }
@@ -304,6 +382,12 @@ fn init_pll(instance: PllInstance, config: Option<Pll>, input: &PllInput) -> Pll
         PllInstance::Plli2s => RCC.plli2scfgr().write(|w| {
             write_fields!(w);
         }),
+        #[cfg(stm32f2)]
+        PllInstance::Plli2s => RCC.plli2scfgr().write(|w| {
+            if let Some(divr) = pll.divr {
+                w.set_pllr(divr);
+            }
+        }),
         #[cfg(any(stm32f446, stm32f427, stm32f437, stm32f4x9, stm32f7))]
         PllInstance::Pllsai => RCC.pllsaicfgr().write(|w| {
             write_fields!(w);
@@ -316,22 +400,6 @@ fn init_pll(instance: PllInstance, config: Option<Pll>, input: &PllInput) -> Pll
     PllOutput { p, q, r }
 }
 
-fn flash_setup(clk: Hertz) {
-    use crate::pac::flash::vals::Latency;
-
-    // Be conservative with voltage ranges
-    const FLASH_LATENCY_STEP: u32 = 30_000_000;
-
-    let latency = (clk.0 - 1) / FLASH_LATENCY_STEP;
-    debug!("flash: latency={}", latency);
-
-    let latency = Latency::from_bits(latency as u8);
-    FLASH.acr().write(|w| {
-        w.set_latency(latency);
-    });
-    while FLASH.acr().read().latency() != latency {}
-}
-
 #[cfg(stm32f7)]
 mod max {
     use core::ops::RangeInclusive;
@@ -380,3 +448,22 @@ mod max {
     pub(crate) const PLL_IN: RangeInclusive<Hertz> = Hertz(1_000_000)..=Hertz(2_100_000);
     pub(crate) const PLL_VCO: RangeInclusive<Hertz> = Hertz(100_000_000)..=Hertz(432_000_000);
 }
+
+#[cfg(stm32f2)]
+mod max {
+    use core::ops::RangeInclusive;
+
+    use crate::time::Hertz;
+
+    pub(crate) const HSE_OSC: RangeInclusive<Hertz> = Hertz(4_000_000)..=Hertz(26_000_000);
+    pub(crate) const HSE_BYP: RangeInclusive<Hertz> = Hertz(1_000_000)..=Hertz(26_000_000);
+
+    pub(crate) const SYSCLK: RangeInclusive<Hertz> = Hertz(0)..=Hertz(120_000_000);
+
+    pub(crate) const HCLK: RangeInclusive<Hertz> = Hertz(0)..=Hertz(SYSCLK.end().0);
+    pub(crate) const PCLK1: RangeInclusive<Hertz> = Hertz(0)..=Hertz(SYSCLK.end().0 / 4);
+    pub(crate) const PCLK2: RangeInclusive<Hertz> = Hertz(0)..=Hertz(SYSCLK.end().0 / 2);
+
+    pub(crate) const PLL_IN: RangeInclusive<Hertz> = Hertz(0_950_000)..=Hertz(2_100_000);
+    pub(crate) const PLL_VCO: RangeInclusive<Hertz> = Hertz(192_000_000)..=Hertz(432_000_000);
+}
diff --git a/embassy-stm32/src/rcc/f2.rs b/embassy-stm32/src/rcc/f2.rs
deleted file mode 100644
index 00480222a..000000000
--- a/embassy-stm32/src/rcc/f2.rs
+++ /dev/null
@@ -1,320 +0,0 @@
-use crate::pac::flash::vals::Latency;
-use crate::pac::rcc::vals::Sw;
-pub use crate::pac::rcc::vals::{
-    Hpre as AHBPrescaler, Pllm as PllPreDiv, Plln as PllMul, Pllp as PllPDiv, Pllq as PllQDiv, Pllsrc as PllSource,
-    Ppre as APBPrescaler,
-};
-use crate::pac::{FLASH, RCC};
-use crate::rcc::{set_freqs, Clocks};
-use crate::time::Hertz;
-
-/// HSI speed
-pub const HSI_FREQ: Hertz = Hertz(16_000_000);
-
-#[derive(Clone, Copy)]
-pub struct HSEConfig {
-    pub frequency: Hertz,
-    pub source: HSESrc,
-}
-
-/// System clock mux source
-#[derive(Clone, Copy)]
-pub enum ClockSrc {
-    HSE,
-    HSI,
-    PLL,
-}
-
-/// HSE clock source
-#[derive(Clone, Copy)]
-pub enum HSESrc {
-    /// Crystal/ceramic resonator
-    Crystal,
-    /// External clock source, HSE bypassed
-    Bypass,
-}
-
-#[derive(Clone, Copy)]
-pub struct Pll {
-    pub pre_div: PllPreDiv,
-    pub mul: PllMul,
-    pub divp: PllPDiv,
-    pub divq: PllQDiv,
-}
-
-impl Default for Pll {
-    fn default() -> Self {
-        Pll {
-            pre_div: PllPreDiv::DIV16,
-            mul: PllMul::MUL192,
-            divp: PllPDiv::DIV2,
-            divq: PllQDiv::DIV4,
-        }
-    }
-}
-
-impl Pll {
-    pub fn clocks(&self, src_freq: Hertz) -> PLLClocks {
-        let in_freq = src_freq / self.pre_div;
-        let vco_freq = src_freq / self.pre_div * self.mul;
-        let main_freq = vco_freq / self.divp;
-        let pll48_freq = vco_freq / self.divq;
-        PLLClocks {
-            in_freq,
-            vco_freq,
-            main_freq,
-            pll48_freq,
-        }
-    }
-}
-#[derive(Clone, Copy, PartialEq)]
-pub struct PLLClocks {
-    pub in_freq: Hertz,
-    pub vco_freq: Hertz,
-    pub main_freq: Hertz,
-    pub pll48_freq: Hertz,
-}
-
-/// Voltage range of the power supply used.
-///
-/// Used to calculate flash waitstates. See
-/// RM0033 - Table 3. Number of wait states according to Cortex®-M3 clock frequency
-pub enum VoltageScale {
-    /// 2.7 to 3.6 V
-    Range0,
-    /// 2.4 to 2.7 V
-    Range1,
-    /// 2.1 to 2.4 V
-    Range2,
-    /// 1.8 to 2.1 V
-    Range3,
-}
-
-impl VoltageScale {
-    const fn wait_states(&self, ahb_freq: Hertz) -> Option<Latency> {
-        let ahb_freq = ahb_freq.0;
-        // Reference: RM0033 - Table 3. Number of wait states according to Cortex®-M3 clock
-        // frequency
-        match self {
-            VoltageScale::Range3 => {
-                if ahb_freq <= 16_000_000 {
-                    Some(Latency::WS0)
-                } else if ahb_freq <= 32_000_000 {
-                    Some(Latency::WS1)
-                } else if ahb_freq <= 48_000_000 {
-                    Some(Latency::WS2)
-                } else if ahb_freq <= 64_000_000 {
-                    Some(Latency::WS3)
-                } else if ahb_freq <= 80_000_000 {
-                    Some(Latency::WS4)
-                } else if ahb_freq <= 96_000_000 {
-                    Some(Latency::WS5)
-                } else if ahb_freq <= 112_000_000 {
-                    Some(Latency::WS6)
-                } else if ahb_freq <= 120_000_000 {
-                    Some(Latency::WS7)
-                } else {
-                    None
-                }
-            }
-            VoltageScale::Range2 => {
-                if ahb_freq <= 18_000_000 {
-                    Some(Latency::WS0)
-                } else if ahb_freq <= 36_000_000 {
-                    Some(Latency::WS1)
-                } else if ahb_freq <= 54_000_000 {
-                    Some(Latency::WS2)
-                } else if ahb_freq <= 72_000_000 {
-                    Some(Latency::WS3)
-                } else if ahb_freq <= 90_000_000 {
-                    Some(Latency::WS4)
-                } else if ahb_freq <= 108_000_000 {
-                    Some(Latency::WS5)
-                } else if ahb_freq <= 120_000_000 {
-                    Some(Latency::WS6)
-                } else {
-                    None
-                }
-            }
-            VoltageScale::Range1 => {
-                if ahb_freq <= 24_000_000 {
-                    Some(Latency::WS0)
-                } else if ahb_freq <= 48_000_000 {
-                    Some(Latency::WS1)
-                } else if ahb_freq <= 72_000_000 {
-                    Some(Latency::WS2)
-                } else if ahb_freq <= 96_000_000 {
-                    Some(Latency::WS3)
-                } else if ahb_freq <= 120_000_000 {
-                    Some(Latency::WS4)
-                } else {
-                    None
-                }
-            }
-            VoltageScale::Range0 => {
-                if ahb_freq <= 30_000_000 {
-                    Some(Latency::WS0)
-                } else if ahb_freq <= 60_000_000 {
-                    Some(Latency::WS1)
-                } else if ahb_freq <= 90_000_000 {
-                    Some(Latency::WS2)
-                } else if ahb_freq <= 120_000_000 {
-                    Some(Latency::WS3)
-                } else {
-                    None
-                }
-            }
-        }
-    }
-}
-
-/// Clocks configuration
-pub struct Config {
-    pub hse: Option<HSEConfig>,
-    pub hsi: bool,
-    pub pll_mux: PllSource,
-    pub pll: Pll,
-    pub mux: ClockSrc,
-    pub voltage: VoltageScale,
-    pub ahb_pre: AHBPrescaler,
-    pub apb1_pre: APBPrescaler,
-    pub apb2_pre: APBPrescaler,
-    pub ls: super::LsConfig,
-}
-
-impl Default for Config {
-    #[inline]
-    fn default() -> Config {
-        Config {
-            hse: None,
-            hsi: true,
-            pll_mux: PllSource::HSI,
-            pll: Pll::default(),
-            voltage: VoltageScale::Range3,
-            mux: ClockSrc::HSI,
-            ahb_pre: AHBPrescaler::DIV1,
-            apb1_pre: APBPrescaler::DIV1,
-            apb2_pre: APBPrescaler::DIV1,
-            ls: Default::default(),
-        }
-    }
-}
-
-pub(crate) unsafe fn init(config: Config) {
-    // Make sure HSI is enabled
-    RCC.cr().write(|w| w.set_hsion(true));
-    while !RCC.cr().read().hsirdy() {}
-
-    if let Some(hse_config) = config.hse {
-        RCC.cr().modify(|w| {
-            w.set_hsebyp(match hse_config.source {
-                HSESrc::Bypass => true,
-                HSESrc::Crystal => false,
-            });
-            w.set_hseon(true)
-        });
-        while !RCC.cr().read().hserdy() {}
-    }
-
-    let pll_src_freq = match config.pll_mux {
-        PllSource::HSE => {
-            let hse_config = config
-                .hse
-                .unwrap_or_else(|| panic!("HSE must be configured to be used as PLL input"));
-            hse_config.frequency
-        }
-        PllSource::HSI => HSI_FREQ,
-    };
-
-    // Reference: STM32F215xx/217xx datasheet Table 33. Main PLL characteristics
-    let pll_clocks = config.pll.clocks(pll_src_freq);
-    assert!(Hertz(950_000) <= pll_clocks.in_freq && pll_clocks.in_freq <= Hertz(2_100_000));
-    assert!(Hertz(192_000_000) <= pll_clocks.vco_freq && pll_clocks.vco_freq <= Hertz(432_000_000));
-    assert!(Hertz(24_000_000) <= pll_clocks.main_freq && pll_clocks.main_freq <= Hertz(120_000_000));
-    // USB actually requires == 48 MHz, but other PLL48 peripherals are fine with <= 48MHz
-    assert!(pll_clocks.pll48_freq <= Hertz(48_000_000));
-
-    RCC.pllcfgr().write(|w| {
-        w.set_pllsrc(config.pll_mux);
-        w.set_pllm(config.pll.pre_div);
-        w.set_plln(config.pll.mul);
-        w.set_pllp(config.pll.divp);
-        w.set_pllq(config.pll.divq);
-    });
-
-    let (sys_clk, sw) = match config.mux {
-        ClockSrc::HSI => {
-            assert!(config.hsi, "HSI must be enabled to be used as system clock");
-            (HSI_FREQ, Sw::HSI)
-        }
-        ClockSrc::HSE => {
-            let hse_config = config
-                .hse
-                .unwrap_or_else(|| panic!("HSE must be configured to be used as PLL input"));
-            (hse_config.frequency, Sw::HSE)
-        }
-        ClockSrc::PLL => {
-            RCC.cr().modify(|w| w.set_pllon(true));
-            while !RCC.cr().read().pllrdy() {}
-            (pll_clocks.main_freq, Sw::PLL1_P)
-        }
-    };
-    // RM0033 Figure 9. Clock tree suggests max SYSCLK/HCLK is 168 MHz, but datasheet specifies PLL
-    // max output to be 120 MHz, so there's no way to get higher frequencies
-    assert!(sys_clk <= Hertz(120_000_000));
-
-    let ahb_freq = sys_clk / config.ahb_pre;
-    // Reference: STM32F215xx/217xx datasheet Table 13. General operating conditions
-    assert!(ahb_freq <= Hertz(120_000_000));
-
-    let (apb1_freq, apb1_tim_freq) = match config.apb1_pre {
-        APBPrescaler::DIV1 => (ahb_freq, ahb_freq),
-        pre => {
-            let freq = ahb_freq / pre;
-            (freq, Hertz(freq.0 * 2))
-        }
-    };
-    // Reference: STM32F215xx/217xx datasheet Table 13. General operating conditions
-    assert!(apb1_freq <= Hertz(30_000_000));
-
-    let (apb2_freq, apb2_tim_freq) = match config.apb2_pre {
-        APBPrescaler::DIV1 => (ahb_freq, ahb_freq),
-        pre => {
-            let freq = ahb_freq / pre;
-            (freq, Hertz(freq.0 * 2))
-        }
-    };
-    // Reference: STM32F215xx/217xx datasheet Table 13. General operating conditions
-    assert!(apb2_freq <= Hertz(60_000_000));
-
-    let flash_ws = unwrap!(config.voltage.wait_states(ahb_freq));
-    FLASH.acr().modify(|w| w.set_latency(flash_ws));
-
-    RCC.cfgr().modify(|w| {
-        w.set_sw(sw.into());
-        w.set_hpre(config.ahb_pre);
-        w.set_ppre1(config.apb1_pre);
-        w.set_ppre2(config.apb2_pre);
-    });
-    while RCC.cfgr().read().sws().to_bits() != sw.to_bits() {}
-
-    // Turn off HSI to save power if we don't need it
-    if !config.hsi {
-        RCC.cr().modify(|w| w.set_hsion(false));
-    }
-
-    let rtc = config.ls.init();
-
-    set_freqs(Clocks {
-        sys: sys_clk,
-        hclk1: ahb_freq,
-        hclk2: ahb_freq,
-        hclk3: ahb_freq,
-        pclk1: apb1_freq,
-        pclk1_tim: apb1_tim_freq,
-        pclk2: apb2_freq,
-        pclk2_tim: apb2_tim_freq,
-        pll1_q: Some(pll_clocks.pll48_freq),
-        rtc,
-    });
-}
diff --git a/embassy-stm32/src/rcc/mod.rs b/embassy-stm32/src/rcc/mod.rs
index debd16ca1..2e144dc77 100644
--- a/embassy-stm32/src/rcc/mod.rs
+++ b/embassy-stm32/src/rcc/mod.rs
@@ -15,14 +15,13 @@ mod hsi48;
 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")]
-#[cfg_attr(any(rcc_f3, rcc_f3_v2), path = "f3.rs")]
-#[cfg_attr(any(rcc_f4, rcc_f410, rcc_f7), path = "f4f7.rs")]
+#[cfg_attr(any(stm32f1), path = "f1.rs")]
+#[cfg_attr(any(stm32f3), path = "f3.rs")]
+#[cfg_attr(any(stm32f2, stm32f4, stm32f7), path = "f.rs")]
 #[cfg_attr(rcc_c0, path = "c0.rs")]
 #[cfg_attr(rcc_g0, path = "g0.rs")]
 #[cfg_attr(rcc_g4, path = "g4.rs")]
-#[cfg_attr(any(rcc_h5, rcc_h50, rcc_h7, rcc_h7rm0433, rcc_h7ab), path = "h.rs")]
+#[cfg_attr(any(stm32h5, stm32h7), path = "h.rs")]
 #[cfg_attr(any(stm32l0, stm32l1, stm32l4, stm32l5, stm32wb, stm32wl), path = "l.rs")]
 #[cfg_attr(rcc_u5, path = "u5.rs")]
 #[cfg_attr(rcc_wba, path = "wba.rs")]
diff --git a/examples/stm32f2/src/bin/pll.rs b/examples/stm32f2/src/bin/pll.rs
index feec90016..aae7637dc 100644
--- a/examples/stm32f2/src/bin/pll.rs
+++ b/examples/stm32f2/src/bin/pll.rs
@@ -6,9 +6,6 @@ use core::convert::TryFrom;
 
 use defmt::*;
 use embassy_executor::Spawner;
-use embassy_stm32::rcc::{
-    APBPrescaler, ClockSrc, HSEConfig, HSESrc, Pll, PllMul, PllPDiv, PllPreDiv, PllQDiv, PllSource,
-};
 use embassy_stm32::time::Hertz;
 use embassy_stm32::Config;
 use embassy_time::Timer;
@@ -19,29 +16,35 @@ async fn main(_spawner: Spawner) {
     // Example config for maximum performance on a NUCLEO-F207ZG board
 
     let mut config = Config::default();
-    // By default, HSE on the board comes from a 8 MHz clock signal (not a crystal)
-    config.rcc.hse = Some(HSEConfig {
-        frequency: Hertz(8_000_000),
-        source: HSESrc::Bypass,
-    });
-    // PLL uses HSE as the clock source
-    config.rcc.pll_mux = PllSource::HSE;
-    config.rcc.pll = Pll {
-        // 8 MHz clock source / 8 = 1 MHz PLL input
-        pre_div: unwrap!(PllPreDiv::try_from(8)),
-        // 1 MHz PLL input * 240 = 240 MHz PLL VCO
-        mul: unwrap!(PllMul::try_from(240)),
-        // 240 MHz PLL VCO / 2 = 120 MHz main PLL output
-        divp: PllPDiv::DIV2,
-        // 240 MHz PLL VCO / 5 = 48 MHz PLL48 output
-        divq: PllQDiv::DIV5,
-    };
-    // System clock comes from PLL (= the 120 MHz main PLL output)
-    config.rcc.mux = ClockSrc::PLL;
-    // 120 MHz / 4 = 30 MHz APB1 frequency
-    config.rcc.apb1_pre = APBPrescaler::DIV4;
-    // 120 MHz / 2 = 60 MHz APB2 frequency
-    config.rcc.apb2_pre = APBPrescaler::DIV2;
+
+    {
+        use embassy_stm32::rcc::*;
+
+        // By default, HSE on the board comes from a 8 MHz clock signal (not a crystal)
+        config.rcc.hse = Some(Hse {
+            freq: Hertz(8_000_000),
+            mode: HseMode::Bypass,
+        });
+        // PLL uses HSE as the clock source
+        config.rcc.pll_src = PllSource::HSE;
+        config.rcc.pll = Some(Pll {
+            // 8 MHz clock source / 8 = 1 MHz PLL input
+            prediv: unwrap!(PllPreDiv::try_from(8)),
+            // 1 MHz PLL input * 240 = 240 MHz PLL VCO
+            mul: unwrap!(PllMul::try_from(240)),
+            // 240 MHz PLL VCO / 2 = 120 MHz main PLL output
+            divp: Some(PllPDiv::DIV2),
+            // 240 MHz PLL VCO / 5 = 48 MHz PLL48 output
+            divq: Some(PllQDiv::DIV5),
+            divr: None,
+        });
+        // System clock comes from PLL (= the 120 MHz main PLL output)
+        config.rcc.sys = Sysclk::PLL1_P;
+        // 120 MHz / 4 = 30 MHz APB1 frequency
+        config.rcc.apb1_pre = APBPrescaler::DIV4;
+        // 120 MHz / 2 = 60 MHz APB2 frequency
+        config.rcc.apb2_pre = APBPrescaler::DIV2;
+    }
 
     let _p = embassy_stm32::init(config);
 
diff --git a/tests/stm32/src/common.rs b/tests/stm32/src/common.rs
index fe694cbef..a44e8230f 100644
--- a/tests/stm32/src/common.rs
+++ b/tests/stm32/src/common.rs
@@ -236,24 +236,25 @@ pub fn config() -> Config {
     {
         use embassy_stm32::rcc::*;
         // By default, HSE on the board comes from a 8 MHz clock signal (not a crystal)
-        config.rcc.hse = Some(HSEConfig {
-            frequency: Hertz(8_000_000),
-            source: HSESrc::Bypass,
+        config.rcc.hse = Some(Hse {
+            freq: Hertz(8_000_000),
+            mode: HseMode::Bypass,
         });
         // PLL uses HSE as the clock source
-        config.rcc.pll_mux = PllSource::HSE;
-        config.rcc.pll = Pll {
+        config.rcc.pll_src = PllSource::HSE;
+        config.rcc.pll = Some(Pll {
             // 8 MHz clock source / 8 = 1 MHz PLL input
-            pre_div: unwrap!(PllPreDiv::try_from(8)),
+            prediv: unwrap!(PllPreDiv::try_from(8)),
             // 1 MHz PLL input * 240 = 240 MHz PLL VCO
             mul: unwrap!(PllMul::try_from(240)),
             // 240 MHz PLL VCO / 2 = 120 MHz main PLL output
-            divp: PllPDiv::DIV2,
+            divp: Some(PllPDiv::DIV2),
             // 240 MHz PLL VCO / 5 = 48 MHz PLL48 output
-            divq: PllQDiv::DIV5,
-        };
+            divq: Some(PllQDiv::DIV5),
+            divr: None,
+        });
         // System clock comes from PLL (= the 120 MHz main PLL output)
-        config.rcc.mux = ClockSrc::PLL;
+        config.rcc.sys = Sysclk::PLL1_P;
         // 120 MHz / 4 = 30 MHz APB1 frequency
         config.rcc.apb1_pre = APBPrescaler::DIV4;
         // 120 MHz / 2 = 60 MHz APB2 frequency