diff --git a/ci.sh b/ci.sh
index 91c7cd3ba..b3429a0a3 100755
--- a/ci.sh
+++ b/ci.sh
@@ -46,10 +46,13 @@ cargo batch  \
     --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f411ce,defmt,exti,time-driver-any,unstable-traits \
     --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f429zi,log,exti,time-driver-any,unstable-traits \
     --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32h755zi-cm7,defmt,exti,time-driver-any,unstable-traits \
+    --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32h7b3ai,defmt,exti,time-driver-any,unstable-traits \
     --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32l476vg,defmt,exti,time-driver-any,unstable-traits \
     --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features nightly,stm32l072cz,defmt,exti,time-driver-any,unstable-traits \
+    --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features nightly,stm32l041f6,defmt,exti,time-driver-any,unstable-traits \
     --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features nightly,stm32l151cb-a,defmt,exti,time-driver-any,unstable-traits \
     --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features nightly,stm32f398ve,defmt,exti,time-driver-any,unstable-traits \
+    --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features nightly,stm32g0c1ve,defmt,exti,time-driver-any,unstable-traits \
     --- build --release --manifest-path docs/modules/ROOT/examples/basic/Cargo.toml --target thumbv7em-none-eabi \
     --- build --release --manifest-path docs/modules/ROOT/examples/layer-by-layer/blinky-pac/Cargo.toml --target thumbv7em-none-eabi \
     --- build --release --manifest-path docs/modules/ROOT/examples/layer-by-layer/blinky-hal/Cargo.toml --target thumbv7em-none-eabi \
diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs
index 2b642db84..1257e0152 100644
--- a/embassy-stm32/build.rs
+++ b/embassy-stm32/build.rs
@@ -49,7 +49,7 @@ fn main() {
                 // We *shouldn't* have singletons for these, but the HAL currently requires
                 // singletons, for using with RccPeripheral to enable/disable clocks to them.
                 "rcc" => {
-                    if r.version == "h7" {
+                    if r.version.starts_with("h7") {
                         singletons.push("MCO1".to_string());
                         singletons.push("MCO2".to_string());
                     }
@@ -436,7 +436,7 @@ fn main() {
                     // MCO is special
                     if pin.signal.starts_with("MCO_") {
                         // Supported in H7 only for now
-                        if regs.version == "h7" {
+                        if regs.version.starts_with("h7") {
                             peri = format_ident!("{}", pin.signal.replace("_", ""));
                         } else {
                             continue;
diff --git a/embassy-stm32/src/adc/v3.rs b/embassy-stm32/src/adc/v3.rs
index 6f36daa23..387b62470 100644
--- a/embassy-stm32/src/adc/v3.rs
+++ b/embassy-stm32/src/adc/v3.rs
@@ -9,11 +9,11 @@ pub const VDDA_CALIB_MV: u32 = 3000;
 /// Sadly we cannot use `RccPeripheral::enable` since devices are quite inconsistent ADC clock
 /// configuration.
 unsafe fn enable() {
-    #[cfg(rcc_h7)]
+    #[cfg(stm32h7)]
     crate::pac::RCC.apb2enr().modify(|w| w.set_adcen(true));
-    #[cfg(rcc_g0)]
+    #[cfg(stm32g0)]
     crate::pac::RCC.apbenr2().modify(|w| w.set_adcen(true));
-    #[cfg(rcc_l4)]
+    #[cfg(stm32l4)]
     crate::pac::RCC.ahb2enr().modify(|w| w.set_adcen(true));
 }
 
@@ -54,9 +54,9 @@ pub struct Vref;
 impl<T: Instance> AdcPin<T> for Vref {}
 impl<T: Instance> super::sealed::AdcPin<T> for Vref {
     fn channel(&self) -> u8 {
-        #[cfg(not(rcc_g0))]
+        #[cfg(not(stm32g0))]
         let val = 0;
-        #[cfg(rcc_g0)]
+        #[cfg(stm32g0)]
         let val = 13;
         val
     }
@@ -66,9 +66,9 @@ pub struct Temperature;
 impl<T: Instance> AdcPin<T> for Temperature {}
 impl<T: Instance> super::sealed::AdcPin<T> for Temperature {
     fn channel(&self) -> u8 {
-        #[cfg(not(rcc_g0))]
+        #[cfg(not(stm32g0))]
         let val = 17;
-        #[cfg(rcc_g0)]
+        #[cfg(stm32g0)]
         let val = 12;
         val
     }
@@ -78,9 +78,9 @@ pub struct Vbat;
 impl<T: Instance> AdcPin<T> for Vbat {}
 impl<T: Instance> super::sealed::AdcPin<T> for Vbat {
     fn channel(&self) -> u8 {
-        #[cfg(not(rcc_g0))]
+        #[cfg(not(stm32g0))]
         let val = 18;
-        #[cfg(rcc_g0)]
+        #[cfg(stm32g0)]
         let val = 14;
         val
     }
@@ -281,7 +281,7 @@ impl<'d, T: Instance> Adc<'d, T> {
     /// Calculates the system VDDA by sampling the internal VREF channel and comparing
     /// the result with the value stored at the factory. If the chip's VDDA is not stable, run
     /// this before each ADC conversion.
-    #[cfg(not(rcc_g0))] // TODO is this supposed to be public?
+    #[cfg(not(stm32g0))] // TODO is this supposed to be public?
     #[allow(unused)] // TODO is this supposed to be public?
     fn calibrate(&mut self, vref: &mut Vref) {
         let vref_cal = unsafe { crate::pac::VREFINTCAL.data().read().value() };
@@ -363,11 +363,11 @@ impl<'d, T: Instance> Adc<'d, T> {
             }
 
             // Configure ADC
-            #[cfg(not(rcc_g0))]
+            #[cfg(not(stm32g0))]
             T::regs()
                 .cfgr()
                 .modify(|reg| reg.set_res(self.resolution.res()));
-            #[cfg(rcc_g0)]
+            #[cfg(stm32g0)]
             T::regs()
                 .cfgr1()
                 .modify(|reg| reg.set_res(self.resolution.res()));
@@ -376,9 +376,9 @@ impl<'d, T: Instance> Adc<'d, T> {
             Self::set_channel_sample_time(pin.channel(), self.sample_time);
 
             // Select channel
-            #[cfg(not(rcc_g0))]
+            #[cfg(not(stm32g0))]
             T::regs().sqr1().write(|reg| reg.set_sq(0, pin.channel()));
-            #[cfg(rcc_g0)]
+            #[cfg(stm32g0)]
             T::regs()
                 .chselr()
                 .write(|reg| reg.set_chsel(pin.channel() as u32));
@@ -400,14 +400,14 @@ impl<'d, T: Instance> Adc<'d, T> {
         }
     }
 
-    #[cfg(rcc_g0)]
+    #[cfg(stm32g0)]
     unsafe fn set_channel_sample_time(_ch: u8, sample_time: SampleTime) {
         T::regs()
             .smpr()
             .modify(|reg| reg.set_smp1(sample_time.sample_time()));
     }
 
-    #[cfg(not(rcc_g0))]
+    #[cfg(not(stm32g0))]
     unsafe fn set_channel_sample_time(ch: u8, sample_time: SampleTime) {
         if ch <= 9 {
             T::regs()
diff --git a/embassy-stm32/src/dac/v2.rs b/embassy-stm32/src/dac/v2.rs
index 751eebf79..9fb01fa94 100644
--- a/embassy-stm32/src/dac/v2.rs
+++ b/embassy-stm32/src/dac/v2.rs
@@ -115,9 +115,11 @@ impl<'d, T: Instance> Dac<'d, T> {
             // configuration.
             #[cfg(rcc_h7)]
             crate::pac::RCC.apb1lenr().modify(|w| w.set_dac12en(true));
-            #[cfg(rcc_g0)]
+            #[cfg(rcc_h7ab)]
+            crate::pac::RCC.apb1lenr().modify(|w| w.set_dac1en(true));
+            #[cfg(stm32g0)]
             crate::pac::RCC.apbenr1().modify(|w| w.set_dac1en(true));
-            #[cfg(rcc_l4)]
+            #[cfg(stm32l4)]
             crate::pac::RCC.apb1enr1().modify(|w| w.set_dac1en(true));
 
             if channels >= 1 {
diff --git a/embassy-stm32/src/dma/bdma.rs b/embassy-stm32/src/dma/bdma.rs
index a37de2d63..2f0715cf6 100644
--- a/embassy-stm32/src/dma/bdma.rs
+++ b/embassy-stm32/src/dma/bdma.rs
@@ -49,6 +49,12 @@ macro_rules! dma_num {
     (BDMA) => {
         0
     };
+    (BDMA1) => {
+        0
+    };
+    (BDMA2) => {
+        1
+    };
 }
 
 pub(crate) unsafe fn on_irq() {
@@ -80,6 +86,9 @@ pub(crate) unsafe fn init() {
 }
 
 pac::dma_channels! {
+    ($channel_peri:ident, BDMA1, bdma, $channel_num:expr, $dmamux:tt) => {
+        // BDMA1 in H7 doesn't use DMAMUX, which breaks
+    };
     ($channel_peri:ident, $dma_peri:ident, bdma, $channel_num:expr, $dmamux:tt) => {
         impl crate::dma::sealed::Channel for crate::peripherals::$channel_peri {
 
diff --git a/embassy-stm32/src/dma/dmamux.rs b/embassy-stm32/src/dma/dmamux.rs
index fd076581b..971695a06 100644
--- a/embassy-stm32/src/dma/dmamux.rs
+++ b/embassy-stm32/src/dma/dmamux.rs
@@ -28,7 +28,7 @@ pub(crate) mod sealed {
 }
 
 pub struct DMAMUX1;
-#[cfg(rcc_h7)]
+#[cfg(stm32h7)]
 pub struct DMAMUX2;
 
 pub trait MuxChannel: sealed::MuxChannel + super::Channel {
diff --git a/embassy-stm32/src/exti.rs b/embassy-stm32/src/exti.rs
index 07d086843..909d0ee88 100644
--- a/embassy-stm32/src/exti.rs
+++ b/embassy-stm32/src/exti.rs
@@ -388,6 +388,6 @@ pub(crate) unsafe fn init() {
 
     #[cfg(not(any(rcc_wb, rcc_wl5, rcc_f1)))]
     <crate::peripherals::SYSCFG as crate::rcc::sealed::RccPeripheral>::enable();
-    #[cfg(rcc_f1)]
+    #[cfg(stm32f1)]
     <crate::peripherals::AFIO as crate::rcc::sealed::RccPeripheral>::enable();
 }
diff --git a/embassy-stm32/src/rcc/l0.rs b/embassy-stm32/src/rcc/l0.rs
index e482dcc21..692791174 100644
--- a/embassy-stm32/src/rcc/l0.rs
+++ b/embassy-stm32/src/rcc/l0.rs
@@ -1,5 +1,7 @@
 use crate::pac::rcc::vals::{Hpre, Msirange, Plldiv, Pllmul, Pllsrc, Ppre, Sw};
-use crate::pac::{CRS, RCC, SYSCFG};
+use crate::pac::RCC;
+#[cfg(crs)]
+use crate::pac::{CRS, SYSCFG};
 use crate::rcc::{set_freqs, Clocks};
 use crate::time::Hertz;
 use crate::time::U32Ext;
@@ -180,6 +182,7 @@ pub struct Config {
     pub ahb_pre: AHBPrescaler,
     pub apb1_pre: APBPrescaler,
     pub apb2_pre: APBPrescaler,
+    #[cfg(crs)]
     pub enable_hsi48: bool,
 }
 
@@ -191,6 +194,7 @@ impl Default for Config {
             ahb_pre: AHBPrescaler::NotDivided,
             apb1_pre: APBPrescaler::NotDivided,
             apb2_pre: APBPrescaler::NotDivided,
+            #[cfg(crs)]
             enable_hsi48: false,
         }
     }
@@ -312,6 +316,7 @@ pub(crate) unsafe fn init(config: Config) {
         }
     };
 
+    #[cfg(crs)]
     if config.enable_hsi48 {
         // Reset SYSCFG peripheral
         RCC.apb2rstr().modify(|w| w.set_syscfgrst(true));
diff --git a/embassy-stm32/src/rcc/mod.rs b/embassy-stm32/src/rcc/mod.rs
index 5c223bc43..01c66f76f 100644
--- a/embassy-stm32/src/rcc/mod.rs
+++ b/embassy-stm32/src/rcc/mod.rs
@@ -33,18 +33,20 @@ pub struct Clocks {
     pub apb2_tim: Hertz,
     #[cfg(any(rcc_wl5, rcc_u5))]
     pub apb3: Hertz,
-    #[cfg(any(rcc_h7))]
+    #[cfg(any(rcc_h7, rcc_h7ab))]
     pub apb4: Hertz,
 
     // AHB
     pub ahb1: Hertz,
     #[cfg(any(
-        rcc_l4, rcc_f4, rcc_f410, rcc_f7, rcc_h7, rcc_g4, rcc_u5, rcc_wb, rcc_wl5
+        rcc_l4, rcc_f4, rcc_f410, rcc_f7, rcc_h7, rcc_h7ab, rcc_g4, rcc_u5, rcc_wb, rcc_wl5
     ))]
     pub ahb2: Hertz,
-    #[cfg(any(rcc_l4, rcc_f4, rcc_f410, rcc_f7, rcc_h7, rcc_u5, rcc_wb, rcc_wl5))]
+    #[cfg(any(
+        rcc_l4, rcc_f4, rcc_f410, rcc_f7, rcc_h7, rcc_h7ab, rcc_u5, rcc_wb, rcc_wl5
+    ))]
     pub ahb3: Hertz,
-    #[cfg(any(rcc_h7))]
+    #[cfg(any(rcc_h7, rcc_h7ab))]
     pub ahb4: Hertz,
 
     #[cfg(any(rcc_f4, rcc_f410, rcc_f7))]
diff --git a/embassy-stm32/src/time_driver.rs b/embassy-stm32/src/time_driver.rs
index 7efe0d3a5..98054e051 100644
--- a/embassy-stm32/src/time_driver.rs
+++ b/embassy-stm32/src/time_driver.rs
@@ -11,12 +11,12 @@ use embassy::time::TICKS_PER_SECOND;
 use stm32_metapac::timer::regs;
 
 use crate::interrupt;
-use crate::interrupt::{CriticalSection, Interrupt};
-use crate::pac::timer::{vals, TimGp16};
+use crate::interrupt::CriticalSection;
+use crate::pac::timer::vals;
 use crate::peripherals;
 use crate::rcc::sealed::RccPeripheral;
-
-use self::sealed::Instance as _;
+use crate::timer::sealed::Basic16bitInstance as BasicInstance;
+use crate::timer::sealed::GeneralPurpose16bitInstance as Instance;
 
 const ALARM_COUNT: usize = 3;
 
@@ -29,25 +29,35 @@ type T = peripherals::TIM4;
 #[cfg(time_driver_tim5)]
 type T = peripherals::TIM5;
 
-#[cfg(time_driver_tim2)]
-#[interrupt]
-fn TIM2() {
-    DRIVER.on_interrupt()
-}
-#[cfg(time_driver_tim3)]
-#[interrupt]
-fn TIM3() {
-    DRIVER.on_interrupt()
-}
-#[cfg(time_driver_tim4)]
-#[interrupt]
-fn TIM4() {
-    DRIVER.on_interrupt()
-}
-#[cfg(time_driver_tim5)]
-#[interrupt]
-fn TIM5() {
-    DRIVER.on_interrupt()
+crate::pac::interrupts! {
+    (TIM2, timer, $block:ident, UP, $irq:ident) => {
+        #[cfg(time_driver_tim2)]
+        #[interrupt]
+        fn $irq() {
+            DRIVER.on_interrupt()
+        }
+    };
+    (TIM3, timer, $block:ident, UP, $irq:ident) => {
+        #[cfg(time_driver_tim3)]
+        #[interrupt]
+        fn $irq() {
+            DRIVER.on_interrupt()
+        }
+    };
+    (TIM4, timer, $block:ident, UP, $irq:ident) => {
+        #[cfg(time_driver_tim4)]
+        #[interrupt]
+        fn $irq() {
+            DRIVER.on_interrupt()
+        }
+    };
+    (TIM5, timer, $block:ident, UP, $irq:ident) => {
+        #[cfg(time_driver_tim5)]
+        #[interrupt]
+        fn $irq() {
+            DRIVER.on_interrupt()
+        }
+    };
 }
 
 // Clock timekeeping works with something we call "periods", which are time intervals
@@ -93,6 +103,7 @@ impl AlarmState {
 }
 
 struct RtcDriver {
+    timer: T,
     /// Number of 2^15 periods elapsed since boot.
     period: AtomicU32,
     alarm_count: AtomicU8,
@@ -103,6 +114,7 @@ struct RtcDriver {
 const ALARM_STATE_NEW: AlarmState = AlarmState::new();
 
 embassy::time_driver_impl!(static DRIVER: RtcDriver = RtcDriver {
+    timer: unsafe { core::mem::transmute(()) }, // steal is not const
     period: AtomicU32::new(0),
     alarm_count: AtomicU8::new(0),
     alarms: Mutex::const_new(CriticalSectionRawMutex::new(), [ALARM_STATE_NEW; ALARM_COUNT]),
@@ -110,10 +122,10 @@ embassy::time_driver_impl!(static DRIVER: RtcDriver = RtcDriver {
 
 impl RtcDriver {
     fn init(&'static self) {
-        let r = T::regs();
+        let r = self.timer.regs_gp16();
 
-        T::enable();
-        T::reset();
+        <T as RccPeripheral>::enable();
+        <T as RccPeripheral>::reset();
 
         let timer_freq = T::frequency();
 
@@ -142,7 +154,7 @@ impl RtcDriver {
             // Enable CC0, disable others
             r.dier().write(|w| w.set_ccie(0, true));
 
-            let irq: <T as sealed::Instance>::Interrupt = core::mem::transmute(());
+            let irq: <T as BasicInstance>::Interrupt = core::mem::transmute(());
             irq.unpend();
             irq.enable();
 
@@ -151,7 +163,7 @@ impl RtcDriver {
     }
 
     fn on_interrupt(&self) {
-        let r = T::regs();
+        let r = self.timer.regs_gp16();
 
         // NOTE(unsafe) Use critical section to access the methods
         // XXX: reduce the size of this critical section ?
@@ -182,7 +194,7 @@ impl RtcDriver {
     }
 
     fn next_period(&self) {
-        let r = T::regs();
+        let r = self.timer.regs_gp16();
 
         let period = self.period.fetch_add(1, Ordering::Relaxed) + 1;
         let t = (period as u64) << 15;
@@ -224,7 +236,7 @@ impl RtcDriver {
 
 impl Driver for RtcDriver {
     fn now(&self) -> u64 {
-        let r = T::regs();
+        let r = self.timer.regs_gp16();
 
         let period = self.period.load(Ordering::Relaxed);
         compiler_fence(Ordering::Acquire);
@@ -261,7 +273,7 @@ impl Driver for RtcDriver {
 
     fn set_alarm(&self, alarm: AlarmHandle, timestamp: u64) {
         critical_section::with(|cs| {
-            let r = T::regs();
+            let r = self.timer.regs_gp16();
 
             let n = alarm.id() as _;
             let alarm = self.get_alarm(cs, alarm);
@@ -291,37 +303,3 @@ impl Driver for RtcDriver {
 pub(crate) fn init() {
     DRIVER.init()
 }
-
-// ------------------------------------------------------
-
-pub(crate) mod sealed {
-    use super::*;
-    pub trait Instance {
-        type Interrupt: Interrupt;
-
-        fn regs() -> TimGp16;
-    }
-}
-
-pub trait Instance: sealed::Instance + Sized + RccPeripheral + 'static {}
-
-macro_rules! impl_timer {
-    ($inst:ident) => {
-        impl sealed::Instance for peripherals::$inst {
-            type Interrupt = crate::interrupt::$inst;
-
-            fn regs() -> TimGp16 {
-                crate::pac::timer::TimGp16(crate::pac::$inst.0)
-            }
-        }
-
-        impl Instance for peripherals::$inst {}
-    };
-}
-
-crate::pac::peripherals!(
-    (timer, TIM2) => { impl_timer!(TIM2); };
-    (timer, TIM3) => { impl_timer!(TIM3); };
-    (timer, TIM4) => { impl_timer!(TIM4); };
-    (timer, TIM5) => { impl_timer!(TIM5); };
-);
diff --git a/stm32-data b/stm32-data
index 608581a89..cb78ac90b 160000
--- a/stm32-data
+++ b/stm32-data
@@ -1 +1 @@
-Subproject commit 608581a8960b95c4d472f59d0b028b47053d5873
+Subproject commit cb78ac90ba8607d6bb38296607c02e28c60391f8