diff --git a/embassy-stm32/src/fmc.rs b/embassy-stm32/src/fmc.rs
index 873c8a70c..9d731a512 100644
--- a/embassy-stm32/src/fmc.rs
+++ b/embassy-stm32/src/fmc.rs
@@ -36,8 +36,10 @@ where
         // fmc v1 and v2 does not have the fmcen bit
         // fsmc v1, v2 and v3 does not have the fmcen bit
         // This is a "not" because it is expected that all future versions have this bit
-        #[cfg(not(any(fmc_v1x3, fmc_v2x1, fsmc_v1x0, fsmc_v1x3, fsmc_v2x3, fsmc_v3x1)))]
+        #[cfg(not(any(fmc_v1x3, fmc_v2x1, fsmc_v1x0, fsmc_v1x3, fsmc_v2x3, fsmc_v3x1, fmc_v4)))]
         T::REGS.bcr1().modify(|r| r.set_fmcen(true));
+        #[cfg(any(fmc_v4))]
+        T::REGS.nor_psram().bcr1().modify(|r| r.set_fmcen(true));
     }
 
     /// Get the kernel clock currently in use for this FMC instance.
@@ -60,8 +62,10 @@ where
         // fmc v1 and v2 does not have the fmcen bit
         // fsmc v1, v2 and v3 does not have the fmcen bit
         // This is a "not" because it is expected that all future versions have this bit
-        #[cfg(not(any(fmc_v1x3, fmc_v2x1, fsmc_v1x0, fsmc_v1x3, fsmc_v2x3, fsmc_v3x1)))]
+        #[cfg(not(any(fmc_v1x3, fmc_v2x1, fsmc_v1x0, fsmc_v1x3, fsmc_v2x3, fsmc_v3x1, fmc_v4)))]
         T::REGS.bcr1().modify(|r| r.set_fmcen(true));
+        #[cfg(any(fmc_v4))]
+        T::REGS.nor_psram().bcr1().modify(|r| r.set_fmcen(true));
     }
 
     fn source_clock_hz(&self) -> u32 {
diff --git a/embassy-stm32/src/i2s.rs b/embassy-stm32/src/i2s.rs
index e9065dce6..fa9ec0532 100644
--- a/embassy-stm32/src/i2s.rs
+++ b/embassy-stm32/src/i2s.rs
@@ -79,20 +79,20 @@ impl Format {
     #[cfg(any(spi_v1, spi_f1))]
     const fn datlen(&self) -> vals::Datlen {
         match self {
-            Format::Data16Channel16 => vals::Datlen::SIXTEENBIT,
-            Format::Data16Channel32 => vals::Datlen::SIXTEENBIT,
-            Format::Data24Channel32 => vals::Datlen::TWENTYFOURBIT,
-            Format::Data32Channel32 => vals::Datlen::THIRTYTWOBIT,
+            Format::Data16Channel16 => vals::Datlen::BITS16,
+            Format::Data16Channel32 => vals::Datlen::BITS16,
+            Format::Data24Channel32 => vals::Datlen::BITS24,
+            Format::Data32Channel32 => vals::Datlen::BITS32,
         }
     }
 
     #[cfg(any(spi_v1, spi_f1))]
     const fn chlen(&self) -> vals::Chlen {
         match self {
-            Format::Data16Channel16 => vals::Chlen::SIXTEENBIT,
-            Format::Data16Channel32 => vals::Chlen::THIRTYTWOBIT,
-            Format::Data24Channel32 => vals::Chlen::THIRTYTWOBIT,
-            Format::Data32Channel32 => vals::Chlen::THIRTYTWOBIT,
+            Format::Data16Channel16 => vals::Chlen::BITS16,
+            Format::Data16Channel32 => vals::Chlen::BITS32,
+            Format::Data24Channel32 => vals::Chlen::BITS32,
+            Format::Data32Channel32 => vals::Chlen::BITS32,
         }
     }
 }
diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs
index cd1ede0fa..15798e115 100644
--- a/embassy-stm32/src/lib.rs
+++ b/embassy-stm32/src/lib.rs
@@ -216,6 +216,11 @@ pub fn init(config: Config) -> Peripherals {
 
         #[cfg(dbgmcu)]
         crate::pac::DBGMCU.cr().modify(|cr| {
+            #[cfg(any(dbgmcu_h5))]
+            {
+                cr.set_stop(config.enable_debug_during_sleep);
+                cr.set_standby(config.enable_debug_during_sleep);
+            }
             #[cfg(any(dbgmcu_f0, dbgmcu_c0, dbgmcu_g0, dbgmcu_u5, dbgmcu_wba, dbgmcu_l5))]
             {
                 cr.set_dbg_stop(config.enable_debug_during_sleep);
diff --git a/embassy-stm32/src/rcc/f013.rs b/embassy-stm32/src/rcc/f013.rs
index 56bb2a0d9..5046f0a3a 100644
--- a/embassy-stm32/src/rcc/f013.rs
+++ b/embassy-stm32/src/rcc/f013.rs
@@ -379,6 +379,7 @@ pub(crate) unsafe fn init(config: Config) {
         pll1_p: pll,
         #[cfg(stm32f3)]
         pll1_p_mul_2: pll_mul_2,
+        hsi_div_244: hsi.map(|h| h / 244u32),
         sys: Some(sys),
         pclk1: Some(pclk1),
         pclk2: Some(pclk2),
diff --git a/embassy-stm32/src/rcc/f247.rs b/embassy-stm32/src/rcc/f247.rs
index e306d478d..343d075cd 100644
--- a/embassy-stm32/src/rcc/f247.rs
+++ b/embassy-stm32/src/rcc/f247.rs
@@ -288,6 +288,7 @@ pub(crate) unsafe fn init(config: Config) {
 
         clk48: pll.q,
 
+        hsi_div488: hsi.map(|hsi| hsi/488u32),
         hsi_hse: None,
         afif: None,
     );
diff --git a/embassy-stm32/src/rcc/g0.rs b/embassy-stm32/src/rcc/g0.rs
index 0b1f34a20..ae502dd9c 100644
--- a/embassy-stm32/src/rcc/g0.rs
+++ b/embassy-stm32/src/rcc/g0.rs
@@ -365,5 +365,6 @@ pub(crate) unsafe fn init(config: Config) {
         pll1_q: pll1_q_freq,
         pll1_p: pll1_p_freq,
         rtc: rtc,
+        hsi_div_488: None,
     );
 }
diff --git a/embassy-stm32/src/rcc/h.rs b/embassy-stm32/src/rcc/h.rs
index c2a71eaf1..c6da79afb 100644
--- a/embassy-stm32/src/rcc/h.rs
+++ b/embassy-stm32/src/rcc/h.rs
@@ -617,6 +617,7 @@ pub(crate) unsafe fn init(config: Config) {
         hsi: hsi,
         hsi48: hsi48,
         csi: csi,
+        csi_div_122: csi.map(|c| c / 122u32),
         hse: hse,
 
         lse: None,
diff --git a/embassy-stm32/src/rcc/u5.rs b/embassy-stm32/src/rcc/u5.rs
index 43138f05c..c8814ed69 100644
--- a/embassy-stm32/src/rcc/u5.rs
+++ b/embassy-stm32/src/rcc/u5.rs
@@ -290,6 +290,8 @@ pub(crate) unsafe fn init(config: Config) {
         lsi: None,
         msik: None,
         iclk: None,
+        shsi: None,
+        shsi_div_2: None,
     );
 }
 
diff --git a/embassy-stm32/src/sai/mod.rs b/embassy-stm32/src/sai/mod.rs
index b6c3e4028..02f96f8a9 100644
--- a/embassy-stm32/src/sai/mod.rs
+++ b/embassy-stm32/src/sai/mod.rs
@@ -1,5 +1,6 @@
 //! Serial Audio Interface (SAI)
 #![macro_use]
+#![cfg_attr(gpdma, allow(unused))]
 
 use core::marker::PhantomData;
 
@@ -7,6 +8,7 @@ use embassy_hal_internal::{into_ref, PeripheralRef};
 
 use self::sealed::WhichSubBlock;
 pub use crate::dma::word;
+#[cfg(not(gpdma))]
 use crate::dma::{ringbuffer, Channel, ReadableRingBuffer, Request, TransferOptions, WritableRingBuffer};
 use crate::gpio::sealed::{AFType, Pin as _};
 use crate::gpio::AnyPin;
@@ -26,6 +28,7 @@ pub enum Error {
     Overrun,
 }
 
+#[cfg(not(gpdma))]
 impl From<ringbuffer::OverrunError> for Error {
     fn from(_: ringbuffer::OverrunError) -> Self {
         Self::Overrun
@@ -41,7 +44,7 @@ pub enum Mode {
 }
 
 impl Mode {
-    #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))]
+    #[cfg(any(sai_v1, sai_v2, sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))]
     const fn mode(&self, tx_rx: TxRx) -> vals::Mode {
         match tx_rx {
             TxRx::Transmitter => match self {
@@ -76,7 +79,7 @@ pub enum SlotSize {
 }
 
 impl SlotSize {
-    #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))]
+    #[cfg(any(sai_v1, sai_v2, sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))]
     const fn slotsz(&self) -> vals::Slotsz {
         match self {
             SlotSize::DataSize => vals::Slotsz::DATASIZE,
@@ -99,7 +102,7 @@ pub enum DataSize {
 }
 
 impl DataSize {
-    #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))]
+    #[cfg(any(sai_v1, sai_v2, sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))]
     const fn ds(&self) -> vals::Ds {
         match self {
             DataSize::Data8 => vals::Ds::BIT8,
@@ -124,7 +127,7 @@ pub enum FifoThreshold {
 }
 
 impl FifoThreshold {
-    #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))]
+    #[cfg(any(sai_v1, sai_v2, sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))]
     const fn fth(&self) -> vals::Fth {
         match self {
             FifoThreshold::Empty => vals::Fth::EMPTY,
@@ -145,7 +148,7 @@ pub enum MuteValue {
 }
 
 impl MuteValue {
-    #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))]
+    #[cfg(any(sai_v1, sai_v2, sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))]
     const fn muteval(&self) -> vals::Muteval {
         match self {
             MuteValue::Zero => vals::Muteval::SENDZERO,
@@ -164,7 +167,7 @@ pub enum Protocol {
 }
 
 impl Protocol {
-    #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))]
+    #[cfg(any(sai_v1, sai_v2, sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))]
     const fn prtcfg(&self) -> vals::Prtcfg {
         match self {
             Protocol::Free => vals::Prtcfg::FREE,
@@ -183,7 +186,7 @@ pub enum SyncInput {
     /// Syncs with the other A/B sub-block within the SAI unit
     Internal,
     /// Syncs with a sub-block in the other SAI unit
-    #[cfg(sai_v4)]
+    #[cfg(any(sai_v4_2pdm, sai_v4_4pdm))]
     External(SyncInputInstance),
 }
 
@@ -192,14 +195,14 @@ impl SyncInput {
         match self {
             SyncInput::None => vals::Syncen::ASYNCHRONOUS,
             SyncInput::Internal => vals::Syncen::INTERNAL,
-            #[cfg(any(sai_v4))]
+            #[cfg(any(sai_v4_2pdm, sai_v4_4pdm))]
             SyncInput::External(_) => vals::Syncen::EXTERNAL,
         }
     }
 }
 
 /// SAI instance to sync from.
-#[cfg(sai_v4)]
+#[cfg(any(sai_v4_2pdm, sai_v4_4pdm))]
 #[derive(Copy, Clone, PartialEq)]
 #[allow(missing_docs)]
 pub enum SyncInputInstance {
@@ -222,7 +225,7 @@ pub enum StereoMono {
 }
 
 impl StereoMono {
-    #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))]
+    #[cfg(any(sai_v1, sai_v2, sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))]
     const fn mono(&self) -> vals::Mono {
         match self {
             StereoMono::Stereo => vals::Mono::STEREO,
@@ -241,7 +244,7 @@ pub enum BitOrder {
 }
 
 impl BitOrder {
-    #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))]
+    #[cfg(any(sai_v1, sai_v2, sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))]
     const fn lsbfirst(&self) -> vals::Lsbfirst {
         match self {
             BitOrder::LsbFirst => vals::Lsbfirst::LSBFIRST,
@@ -260,7 +263,7 @@ pub enum FrameSyncOffset {
 }
 
 impl FrameSyncOffset {
-    #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))]
+    #[cfg(any(sai_v1, sai_v2, sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))]
     const fn fsoff(&self) -> vals::Fsoff {
         match self {
             FrameSyncOffset::OnFirstBit => vals::Fsoff::ONFIRST,
@@ -279,7 +282,7 @@ pub enum FrameSyncPolarity {
 }
 
 impl FrameSyncPolarity {
-    #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))]
+    #[cfg(any(sai_v1, sai_v2, sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))]
     const fn fspol(&self) -> vals::Fspol {
         match self {
             FrameSyncPolarity::ActiveLow => vals::Fspol::FALLINGEDGE,
@@ -297,7 +300,7 @@ pub enum FrameSyncDefinition {
 }
 
 impl FrameSyncDefinition {
-    #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))]
+    #[cfg(any(sai_v1, sai_v2, sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))]
     const fn fsdef(&self) -> bool {
         match self {
             FrameSyncDefinition::StartOfFrame => false,
@@ -315,7 +318,7 @@ pub enum ClockStrobe {
 }
 
 impl ClockStrobe {
-    #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))]
+    #[cfg(any(sai_v1, sai_v2, sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))]
     const fn ckstr(&self) -> vals::Ckstr {
         match self {
             ClockStrobe::Falling => vals::Ckstr::FALLINGEDGE,
@@ -333,7 +336,7 @@ pub enum ComplementFormat {
 }
 
 impl ComplementFormat {
-    #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))]
+    #[cfg(any(sai_v1, sai_v2, sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))]
     const fn cpl(&self) -> vals::Cpl {
         match self {
             ComplementFormat::OnesComplement => vals::Cpl::ONESCOMPLEMENT,
@@ -352,7 +355,7 @@ pub enum Companding {
 }
 
 impl Companding {
-    #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))]
+    #[cfg(any(sai_v1, sai_v2, sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))]
     const fn comp(&self) -> vals::Comp {
         match self {
             Companding::None => vals::Comp::NOCOMPANDING,
@@ -371,7 +374,7 @@ pub enum OutputDrive {
 }
 
 impl OutputDrive {
-    #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))]
+    #[cfg(any(sai_v1, sai_v2, sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))]
     const fn outdriv(&self) -> vals::Outdriv {
         match self {
             OutputDrive::OnStart => vals::Outdriv::ONSTART,
@@ -404,7 +407,7 @@ pub enum MasterClockDivider {
 }
 
 impl MasterClockDivider {
-    #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))]
+    #[cfg(any(sai_v1, sai_v2, sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))]
     const fn mckdiv(&self) -> u8 {
         match self {
             MasterClockDivider::MasterClockDisabled => 0,
@@ -501,12 +504,12 @@ impl Config {
     }
 }
 
+#[cfg(not(gpdma))]
 enum RingBuffer<'d, W: word::Word> {
     Writable(WritableRingBuffer<'d, W>),
     Readable(ReadableRingBuffer<'d, W>),
 }
 
-#[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))]
 fn dr<W: word::Word>(w: crate::pac::sai::Sai, sub_block: WhichSubBlock) -> *mut W {
     let ch = w.ch(sub_block as usize);
     ch.dr().as_ptr() as _
@@ -528,6 +531,7 @@ fn get_af_types(mode: Mode, tx_rx: TxRx) -> (AFType, AFType) {
     )
 }
 
+#[cfg(not(gpdma))]
 fn get_ring_buffer<'d, T: Instance, W: word::Word>(
     dma: impl Peripheral<P = impl Channel> + 'd,
     dma_buf: &'d mut [W],
@@ -554,12 +558,12 @@ fn update_synchronous_config(config: &mut Config) {
     config.mode = Mode::Slave;
     config.sync_output = false;
 
-    #[cfg(any(sai_v1, sai_v2, sai_v3))]
+    #[cfg(any(sai_v1, sai_v2, sai_v3_2pdm, sai_v3_4pdm))]
     {
         config.sync_input = SyncInput::Internal;
     }
 
-    #[cfg(any(sai_v4))]
+    #[cfg(any(sai_v4_2pdm, sai_v4_4pdm))]
     {
         //this must either be Internal or External
         //The asynchronous sub-block on the same SAI needs to enable sync_output
@@ -599,10 +603,14 @@ pub struct Sai<'d, T: Instance, W: word::Word> {
     fs: Option<PeripheralRef<'d, AnyPin>>,
     sck: Option<PeripheralRef<'d, AnyPin>>,
     mclk: Option<PeripheralRef<'d, AnyPin>>,
+    #[cfg(gpdma)]
+    ring_buffer: PhantomData<W>,
+    #[cfg(not(gpdma))]
     ring_buffer: RingBuffer<'d, W>,
     sub_block: WhichSubBlock,
 }
 
+#[cfg(not(gpdma))]
 impl<'d, T: Instance, W: word::Word> Sai<'d, T, W> {
     /// Create a new SAI driver in asynchronous mode with MCLK.
     ///
@@ -715,13 +723,13 @@ impl<'d, T: Instance, W: word::Word> Sai<'d, T, W> {
         ring_buffer: RingBuffer<'d, W>,
         config: Config,
     ) -> Self {
-        #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))]
+        #[cfg(any(sai_v1, sai_v2, sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))]
         {
             let ch = T::REGS.ch(sub_block as usize);
             ch.cr1().modify(|w| w.set_saien(false));
         }
 
-        #[cfg(any(sai_v4))]
+        #[cfg(any(sai_v4_2pdm, sai_v4_4pdm))]
         {
             if let SyncInput::External(i) = config.sync_input {
                 T::REGS.gcr().modify(|w| {
@@ -740,7 +748,7 @@ impl<'d, T: Instance, W: word::Word> Sai<'d, T, W> {
             }
         }
 
-        #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))]
+        #[cfg(any(sai_v1, sai_v2, sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))]
         {
             let ch = T::REGS.ch(sub_block as usize);
             ch.cr1().modify(|w| {
diff --git a/embassy-stm32/src/spi/mod.rs b/embassy-stm32/src/spi/mod.rs
index 23f027e70..172bc8112 100644
--- a/embassy-stm32/src/spi/mod.rs
+++ b/embassy-stm32/src/spi/mod.rs
@@ -1005,8 +1005,8 @@ mod word_impl {
 
     pub type Config = vals::Dff;
 
-    impl_word!(u8, vals::Dff::EIGHTBIT);
-    impl_word!(u16, vals::Dff::SIXTEENBIT);
+    impl_word!(u8, vals::Dff::BITS8);
+    impl_word!(u16, vals::Dff::BITS16);
 }
 
 #[cfg(spi_v2)]
@@ -1015,19 +1015,19 @@ mod word_impl {
 
     pub type Config = (vals::Ds, vals::Frxth);
 
-    impl_word!(word::U4, (vals::Ds::FOURBIT, vals::Frxth::QUARTER));
-    impl_word!(word::U5, (vals::Ds::FIVEBIT, vals::Frxth::QUARTER));
-    impl_word!(word::U6, (vals::Ds::SIXBIT, vals::Frxth::QUARTER));
-    impl_word!(word::U7, (vals::Ds::SEVENBIT, vals::Frxth::QUARTER));
-    impl_word!(u8, (vals::Ds::EIGHTBIT, vals::Frxth::QUARTER));
-    impl_word!(word::U9, (vals::Ds::NINEBIT, vals::Frxth::HALF));
-    impl_word!(word::U10, (vals::Ds::TENBIT, vals::Frxth::HALF));
-    impl_word!(word::U11, (vals::Ds::ELEVENBIT, vals::Frxth::HALF));
-    impl_word!(word::U12, (vals::Ds::TWELVEBIT, vals::Frxth::HALF));
-    impl_word!(word::U13, (vals::Ds::THIRTEENBIT, vals::Frxth::HALF));
-    impl_word!(word::U14, (vals::Ds::FOURTEENBIT, vals::Frxth::HALF));
-    impl_word!(word::U15, (vals::Ds::FIFTEENBIT, vals::Frxth::HALF));
-    impl_word!(u16, (vals::Ds::SIXTEENBIT, vals::Frxth::HALF));
+    impl_word!(word::U4, (vals::Ds::BITS4, vals::Frxth::QUARTER));
+    impl_word!(word::U5, (vals::Ds::BITS5, vals::Frxth::QUARTER));
+    impl_word!(word::U6, (vals::Ds::BITS6, vals::Frxth::QUARTER));
+    impl_word!(word::U7, (vals::Ds::BITS7, vals::Frxth::QUARTER));
+    impl_word!(u8, (vals::Ds::BITS8, vals::Frxth::QUARTER));
+    impl_word!(word::U9, (vals::Ds::BITS9, vals::Frxth::HALF));
+    impl_word!(word::U10, (vals::Ds::BITS10, vals::Frxth::HALF));
+    impl_word!(word::U11, (vals::Ds::BITS11, vals::Frxth::HALF));
+    impl_word!(word::U12, (vals::Ds::BITS12, vals::Frxth::HALF));
+    impl_word!(word::U13, (vals::Ds::BITS13, vals::Frxth::HALF));
+    impl_word!(word::U14, (vals::Ds::BITS14, vals::Frxth::HALF));
+    impl_word!(word::U15, (vals::Ds::BITS15, vals::Frxth::HALF));
+    impl_word!(u16, (vals::Ds::BITS16, vals::Frxth::HALF));
 }
 
 #[cfg(any(spi_v3, spi_v4, spi_v5))]