diff --git a/embassy-stm32/src/adc/mod.rs b/embassy-stm32/src/adc/mod.rs
index 56ecd63ca..94a8538bf 100644
--- a/embassy-stm32/src/adc/mod.rs
+++ b/embassy-stm32/src/adc/mod.rs
@@ -1,5 +1,6 @@
 #![macro_use]
 
+#[cfg(not(adc_f3))]
 #[cfg_attr(adc_f1, path = "f1.rs")]
 #[cfg_attr(adc_v1, path = "v1.rs")]
 #[cfg_attr(adc_v2, path = "v2.rs")]
@@ -7,14 +8,16 @@
 #[cfg_attr(adc_v4, path = "v4.rs")]
 mod _version;
 
-#[cfg(not(adc_f1))]
+#[cfg(not(any(adc_f1, adc_f3)))]
 mod resolution;
 mod sample_time;
 
+#[cfg(not(adc_f3))]
 #[allow(unused)]
 pub use _version::*;
-#[cfg(not(adc_f1))]
+#[cfg(not(any(adc_f1, adc_f3)))]
 pub use resolution::Resolution;
+#[cfg(not(adc_f3))]
 pub use sample_time::SampleTime;
 
 use crate::peripherals;
@@ -22,13 +25,14 @@ use crate::peripherals;
 pub struct Adc<'d, T: Instance> {
     #[allow(unused)]
     adc: crate::PeripheralRef<'d, T>,
+    #[cfg(not(adc_f3))]
     sample_time: SampleTime,
 }
 
 pub(crate) mod sealed {
     pub trait Instance {
         fn regs() -> crate::pac::adc::Adc;
-        #[cfg(all(not(adc_f1), not(adc_v1)))]
+        #[cfg(not(any(adc_f1, adc_v1, adc_f3)))]
         fn common_regs() -> crate::pac::adccommon::AdcCommon;
     }
 
@@ -56,7 +60,7 @@ foreach_peripheral!(
             fn regs() -> crate::pac::adc::Adc {
                 crate::pac::$inst
             }
-            #[cfg(all(not(adc_f1), not(adc_v1)))]
+            #[cfg(not(any(adc_f1, adc_v1, adc_f3)))]
             fn common_regs() -> crate::pac::adccommon::AdcCommon {
                 foreach_peripheral!{
                     (adccommon, $common_inst:ident) => {
diff --git a/embassy-stm32/src/adc/sample_time.rs b/embassy-stm32/src/adc/sample_time.rs
index 0faa1e3c0..df0525560 100644
--- a/embassy-stm32/src/adc/sample_time.rs
+++ b/embassy-stm32/src/adc/sample_time.rs
@@ -1,3 +1,4 @@
+#[cfg(not(adc_f3))]
 macro_rules! impl_sample_time {
     ($default_doc:expr, $default:ident, ($(($doc:expr, $variant:ident, $pac_variant:ident)),*)) => {
         #[doc = concat!("ADC sample time\n\nThe default setting is ", $default_doc, " ADC clock cycles.")]
diff --git a/embassy-stm32/src/can/fdcan.rs b/embassy-stm32/src/can/fdcan.rs
new file mode 100644
index 000000000..c31a7fc63
--- /dev/null
+++ b/embassy-stm32/src/can/fdcan.rs
@@ -0,0 +1,66 @@
+pub use bxcan;
+use embassy_hal_common::PeripheralRef;
+
+use crate::peripherals;
+
+pub(crate) mod sealed {
+    use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
+    use embassy_sync::channel::Channel;
+    use embassy_sync::waitqueue::AtomicWaker;
+
+    pub struct State {
+        pub tx_waker: AtomicWaker,
+        pub err_waker: AtomicWaker,
+        pub rx_queue: Channel<CriticalSectionRawMutex, (u16, bxcan::Frame), 32>,
+    }
+
+    impl State {
+        pub const fn new() -> Self {
+            Self {
+                tx_waker: AtomicWaker::new(),
+                err_waker: AtomicWaker::new(),
+                rx_queue: Channel::new(),
+            }
+        }
+    }
+
+    pub trait Instance {
+        const REGISTERS: *mut bxcan::RegisterBlock;
+
+        fn regs() -> &'static crate::pac::can::Fdcan;
+        fn state() -> &'static State;
+    }
+}
+
+pub trait InterruptableInstance {}
+pub trait Instance: sealed::Instance + InterruptableInstance + 'static {}
+
+pub struct BxcanInstance<'a, T>(PeripheralRef<'a, T>);
+
+unsafe impl<'d, T: Instance> bxcan::Instance for BxcanInstance<'d, T> {
+    const REGISTERS: *mut bxcan::RegisterBlock = T::REGISTERS;
+}
+
+foreach_peripheral!(
+    (can, $inst:ident) => {
+        impl sealed::Instance for peripherals::$inst {
+            const REGISTERS: *mut bxcan::RegisterBlock = crate::pac::$inst.as_ptr() as *mut _;
+
+            fn regs() -> &'static crate::pac::can::Fdcan {
+                &crate::pac::$inst
+            }
+
+            fn state() -> &'static sealed::State {
+                static STATE: sealed::State = sealed::State::new();
+                &STATE
+            }
+        }
+
+        impl Instance for peripherals::$inst {}
+
+        impl InterruptableInstance for peripherals::$inst {}
+    };
+);
+
+pin_trait!(RxPin, Instance);
+pin_trait!(TxPin, Instance);
diff --git a/embassy-stm32/src/can/mod.rs b/embassy-stm32/src/can/mod.rs
index c7e2e620a..4ff5aa0de 100644
--- a/embassy-stm32/src/can/mod.rs
+++ b/embassy-stm32/src/can/mod.rs
@@ -1,5 +1,6 @@
 #![macro_use]
 
 #[cfg_attr(can_bxcan, path = "bxcan.rs")]
+#[cfg_attr(can_fdcan, path = "fdcan.rs")]
 mod _version;
 pub use _version::*;
diff --git a/embassy-stm32/src/dac/mod.rs b/embassy-stm32/src/dac/mod.rs
index 6712585cf..bf15eaac5 100644
--- a/embassy-stm32/src/dac/mod.rs
+++ b/embassy-stm32/src/dac/mod.rs
@@ -41,7 +41,7 @@ pub enum Ch1Trigger {
     #[cfg(dac_v3)]
     Tim1,
     Tim2,
-    #[cfg(not(dac_v2))]
+    #[cfg(not(dac_v3))]
     Tim3,
     #[cfg(dac_v3)]
     Tim4,
@@ -72,7 +72,7 @@ impl Ch1Trigger {
             #[cfg(dac_v3)]
             Ch1Trigger::Tim1 => dac::vals::Tsel1::TIM1_TRGO,
             Ch1Trigger::Tim2 => dac::vals::Tsel1::TIM2_TRGO,
-            #[cfg(dac_v2)]
+            #[cfg(not(dac_v3))]
             Ch1Trigger::Tim3 => dac::vals::Tsel1::TIM3_TRGO,
             #[cfg(dac_v3)]
             Ch1Trigger::Tim4 => dac::vals::Tsel1::TIM4_TRGO,