diff --git a/embassy-stm32/src/can/bx/mod.rs b/embassy-stm32/src/can/bx/mod.rs
deleted file mode 100644
index cd82148ba..000000000
--- a/embassy-stm32/src/can/bx/mod.rs
+++ /dev/null
@@ -1,1010 +0,0 @@
-//! Driver for the STM32 bxCAN peripheral.
-//!
-//! This crate provides a reusable driver for the bxCAN peripheral found in many low- to middle-end
-//! STM32 microcontrollers. HALs for compatible chips can reexport this crate and implement its
-//! traits to easily expose a featureful CAN driver.
-//!
-//! # Features
-//!
-//! - Supports both single- and dual-peripheral configurations (where one bxCAN instance manages the
-//!   filters of a secondary instance).
-//! - Handles standard and extended frames, and data and remote frames.
-//! - Support for interrupts emitted by the bxCAN peripheral.
-//! - Transmission respects CAN IDs and protects against priority inversion (a lower-priority frame
-//!   may be dequeued when enqueueing a higher-priority one).
-//! - Implements the [`embedded-hal`] traits for interoperability.
-//! - Support for both RX FIFOs (as [`Rx0`] and [`Rx1`]).
-//!
-//! # Limitations
-//!
-//! - Support for querying error states and handling error interrupts is incomplete.
-//!
-
-// Deny a few warnings in doctests, since rustdoc `allow`s many warnings by default
-#![allow(clippy::unnecessary_operation)] // lint is bugged
-
-//mod embedded_hal;
-pub mod filter;
-
-#[allow(clippy::all)] // generated code
-use core::cmp::{Ord, Ordering};
-use core::convert::Infallible;
-use core::marker::PhantomData;
-use core::mem;
-
-pub use embedded_can::{ExtendedId, Id, StandardId};
-
-/// CAN Header: includes ID and length
-pub type Header = crate::can::frame::Header;
-
-/// Data for a CAN Frame
-pub type Data = crate::can::frame::ClassicData;
-
-use crate::can::_version::Envelope;
-use crate::can::bx::filter::MasterFilters;
-use crate::can::enums::BusError;
-/// CAN Frame
-pub use crate::can::frame::Frame;
-use crate::pac::can::vals::Lec;
-
-#[derive(Debug, Copy, Clone, Eq, PartialEq)]
-pub(crate) enum RxFifo {
-    Fifo0,
-    Fifo1,
-}
-
-trait IntoBusError {
-    fn into_bus_err(self) -> Option<BusError>;
-}
-
-impl IntoBusError for Lec {
-    fn into_bus_err(self) -> Option<BusError> {
-        match self {
-            Lec::STUFF => Some(BusError::Stuff),
-            Lec::FORM => Some(BusError::Form),
-            Lec::ACK => Some(BusError::Acknowledge),
-            Lec::BITRECESSIVE => Some(BusError::BitRecessive),
-            Lec::BITDOMINANT => Some(BusError::BitDominant),
-            Lec::CRC => Some(BusError::Crc),
-            Lec::CUSTOM => Some(BusError::Software),
-            _ => None,
-        }
-    }
-}
-
-/// A bxCAN peripheral instance.
-///
-/// This trait is meant to be implemented for a HAL-specific type that represent ownership of
-/// the CAN peripheral (and any pins required by it, although that is entirely up to the HAL).
-///
-/// # Safety
-///
-/// It is only safe to implement this trait, when:
-///
-/// * The implementing type has ownership of the peripheral, preventing any other accesses to the
-///   register block.
-/// * `REGISTERS` is a pointer to that peripheral's register block and can be safely accessed for as
-///   long as ownership or a borrow of the implementing type is present.
-pub unsafe trait Instance {}
-
-/// A bxCAN instance that owns filter banks.
-///
-/// In master-slave-instance setups, only the master instance owns the filter banks, and needs to
-/// split some of them off for use by the slave instance. In that case, the master instance should
-/// implement [`FilterOwner`] and [`MasterInstance`], while the slave instance should only implement
-/// [`Instance`].
-///
-/// In single-instance configurations, the instance owns all filter banks and they can not be split
-/// off. In that case, the instance should implement [`Instance`] and [`FilterOwner`].
-///
-/// # Safety
-///
-/// This trait must only be implemented if the instance does, in fact, own its associated filter
-/// banks, and `NUM_FILTER_BANKS` must be correct.
-pub unsafe trait FilterOwner: Instance {
-    /// The total number of filter banks available to the instance.
-    ///
-    /// This is usually either 14 or 28, and should be specified in the chip's reference manual or datasheet.
-    const NUM_FILTER_BANKS: u8;
-}
-
-/// A bxCAN master instance that shares filter banks with a slave instance.
-///
-/// In master-slave-instance setups, this trait should be implemented for the master instance.
-///
-/// # Safety
-///
-/// This trait must only be implemented when there is actually an associated slave instance.
-pub unsafe trait MasterInstance: FilterOwner {}
-
-// TODO: what to do with these?
-/*
-#[derive(Debug, Copy, Clone, Eq, PartialEq, Format)]
-pub enum Error {
-    Stuff,
-    Form,
-    Acknowledgement,
-    BitRecessive,
-    BitDominant,
-    Crc,
-    Software,
-}*/
-
-/// Error that indicates that an incoming message has been lost due to buffer overrun.
-#[derive(Debug, Clone, Copy, PartialEq, Eq)]
-#[cfg_attr(feature = "defmt", derive(defmt::Format))]
-pub struct OverrunError {
-    _priv: (),
-}
-
-/// Identifier of a CAN message.
-///
-/// Can be either a standard identifier (11bit, Range: 0..0x3FF) or a
-/// extendended identifier (29bit , Range: 0..0x1FFFFFFF).
-///
-/// The `Ord` trait can be used to determine the frame’s priority this ID
-/// belongs to.
-/// Lower identifier values have a higher priority. Additionally standard frames
-/// have a higher priority than extended frames and data frames have a higher
-/// priority than remote frames.
-#[derive(Clone, Copy, Debug, PartialEq, Eq)]
-#[cfg_attr(feature = "defmt", derive(defmt::Format))]
-pub(crate) struct IdReg(u32);
-
-impl IdReg {
-    const STANDARD_SHIFT: u32 = 21;
-
-    const EXTENDED_SHIFT: u32 = 3;
-
-    const IDE_MASK: u32 = 0x0000_0004;
-
-    const RTR_MASK: u32 = 0x0000_0002;
-
-    /// Creates a new standard identifier (11bit, Range: 0..0x7FF)
-    ///
-    /// Panics for IDs outside the allowed range.
-    fn new_standard(id: StandardId) -> Self {
-        Self(u32::from(id.as_raw()) << Self::STANDARD_SHIFT)
-    }
-
-    /// Creates a new extendended identifier (29bit , Range: 0..0x1FFFFFFF).
-    ///
-    /// Panics for IDs outside the allowed range.
-    fn new_extended(id: ExtendedId) -> IdReg {
-        Self(id.as_raw() << Self::EXTENDED_SHIFT | Self::IDE_MASK)
-    }
-
-    fn from_register(reg: u32) -> IdReg {
-        Self(reg & 0xFFFF_FFFE)
-    }
-
-    /// Returns the identifier.
-    fn to_id(self) -> Id {
-        if self.is_extended() {
-            Id::Extended(unsafe { ExtendedId::new_unchecked(self.0 >> Self::EXTENDED_SHIFT) })
-        } else {
-            Id::Standard(unsafe { StandardId::new_unchecked((self.0 >> Self::STANDARD_SHIFT) as u16) })
-        }
-    }
-
-    /// Returns the identifier.
-    fn id(self) -> embedded_can::Id {
-        if self.is_extended() {
-            embedded_can::ExtendedId::new(self.0 >> Self::EXTENDED_SHIFT)
-                .unwrap()
-                .into()
-        } else {
-            embedded_can::StandardId::new((self.0 >> Self::STANDARD_SHIFT) as u16)
-                .unwrap()
-                .into()
-        }
-    }
-
-    /// Returns `true` if the identifier is an extended identifier.
-    fn is_extended(self) -> bool {
-        self.0 & Self::IDE_MASK != 0
-    }
-
-    /// Returns `true` if the identifer is part of a remote frame (RTR bit set).
-    fn rtr(self) -> bool {
-        self.0 & Self::RTR_MASK != 0
-    }
-}
-
-impl From<&embedded_can::Id> for IdReg {
-    fn from(eid: &embedded_can::Id) -> Self {
-        match eid {
-            embedded_can::Id::Standard(id) => IdReg::new_standard(StandardId::new(id.as_raw()).unwrap()),
-            embedded_can::Id::Extended(id) => IdReg::new_extended(ExtendedId::new(id.as_raw()).unwrap()),
-        }
-    }
-}
-
-impl From<IdReg> for embedded_can::Id {
-    fn from(idr: IdReg) -> Self {
-        idr.id()
-    }
-}
-
-/// `IdReg` is ordered by priority.
-impl Ord for IdReg {
-    fn cmp(&self, other: &Self) -> Ordering {
-        // When the IDs match, data frames have priority over remote frames.
-        let rtr = self.rtr().cmp(&other.rtr()).reverse();
-
-        let id_a = self.to_id();
-        let id_b = other.to_id();
-        match (id_a, id_b) {
-            (Id::Standard(a), Id::Standard(b)) => {
-                // Lower IDs have priority over higher IDs.
-                a.as_raw().cmp(&b.as_raw()).reverse().then(rtr)
-            }
-            (Id::Extended(a), Id::Extended(b)) => a.as_raw().cmp(&b.as_raw()).reverse().then(rtr),
-            (Id::Standard(a), Id::Extended(b)) => {
-                // Standard frames have priority over extended frames if their Base IDs match.
-                a.as_raw()
-                    .cmp(&b.standard_id().as_raw())
-                    .reverse()
-                    .then(Ordering::Greater)
-            }
-            (Id::Extended(a), Id::Standard(b)) => {
-                a.standard_id().as_raw().cmp(&b.as_raw()).reverse().then(Ordering::Less)
-            }
-        }
-    }
-}
-
-impl PartialOrd for IdReg {
-    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
-        Some(self.cmp(other))
-    }
-}
-
-pub(crate) struct Registers {
-    pub canregs: crate::pac::can::Can,
-}
-
-impl Registers {
-    fn enter_init_mode(&mut self) {
-        self.canregs.mcr().modify(|reg| {
-            reg.set_sleep(false);
-            reg.set_inrq(true);
-        });
-        loop {
-            let msr = self.canregs.msr().read();
-            if !msr.slak() && msr.inak() {
-                break;
-            }
-        }
-    }
-
-    // Leaves initialization mode, enters sleep mode.
-    fn leave_init_mode(&mut self) {
-        self.canregs.mcr().modify(|reg| {
-            reg.set_sleep(true);
-            reg.set_inrq(false);
-        });
-        loop {
-            let msr = self.canregs.msr().read();
-            if msr.slak() && !msr.inak() {
-                break;
-            }
-        }
-    }
-
-    fn set_bit_timing(&mut self, bt: crate::can::util::NominalBitTiming) {
-        let prescaler = u16::from(bt.prescaler) & 0x1FF;
-        let seg1 = u8::from(bt.seg1);
-        let seg2 = u8::from(bt.seg2) & 0x7F;
-        let sync_jump_width = u8::from(bt.sync_jump_width) & 0x7F;
-        self.canregs.btr().modify(|reg| {
-            reg.set_brp(prescaler - 1);
-            reg.set_ts(0, seg1 - 1);
-            reg.set_ts(1, seg2 - 1);
-            reg.set_sjw(sync_jump_width - 1);
-        });
-    }
-
-    /// Enables or disables silent mode: Disconnects the TX signal from the pin.
-    pub fn set_silent(&self, enabled: bool) {
-        let mode = match enabled {
-            false => stm32_metapac::can::vals::Silm::NORMAL,
-            true => stm32_metapac::can::vals::Silm::SILENT,
-        };
-        self.canregs.btr().modify(|reg| reg.set_silm(mode));
-    }
-
-    /// Enables or disables automatic retransmission of messages.
-    ///
-    /// If this is enabled, the CAN peripheral will automatically try to retransmit each frame
-    /// until it can be sent. Otherwise, it will try only once to send each frame.
-    ///
-    /// Automatic retransmission is enabled by default.
-    pub fn set_automatic_retransmit(&self, enabled: bool) {
-        self.canregs.mcr().modify(|reg| reg.set_nart(enabled));
-    }
-
-    /// Enables or disables loopback mode: Internally connects the TX and RX
-    /// signals together.
-    pub fn set_loopback(&self, enabled: bool) {
-        self.canregs.btr().modify(|reg| reg.set_lbkm(enabled));
-    }
-
-    /// Configures the automatic wake-up feature.
-    ///
-    /// This is turned off by default.
-    ///
-    /// When turned on, an incoming frame will cause the peripheral to wake up from sleep and
-    /// receive the frame. If enabled, [`Interrupt::Wakeup`] will also be triggered by the incoming
-    /// frame.
-    #[allow(dead_code)]
-    pub fn set_automatic_wakeup(&mut self, enabled: bool) {
-        self.canregs.mcr().modify(|reg| reg.set_awum(enabled));
-    }
-
-    /// Leaves initialization mode and enables the peripheral (non-blocking version).
-    ///
-    /// Usually, it is recommended to call [`CanConfig::enable`] instead. This method is only needed
-    /// if you want non-blocking initialization.
-    ///
-    /// If this returns [`WouldBlock`][nb::Error::WouldBlock], the peripheral will enable itself
-    /// in the background. The peripheral is enabled and ready to use when this method returns
-    /// successfully.
-    pub fn enable_non_blocking(&mut self) -> nb::Result<(), Infallible> {
-        let msr = self.canregs.msr().read();
-        if msr.slak() {
-            self.canregs.mcr().modify(|reg| {
-                reg.set_abom(true);
-                reg.set_sleep(false);
-            });
-            Err(nb::Error::WouldBlock)
-        } else {
-            Ok(())
-        }
-    }
-
-    /// Puts the peripheral in a sleep mode to save power.
-    ///
-    /// While in sleep mode, an incoming CAN frame will trigger [`Interrupt::Wakeup`] if enabled.
-    #[allow(dead_code)]
-    pub fn sleep(&mut self) {
-        self.canregs.mcr().modify(|reg| {
-            reg.set_sleep(true);
-            reg.set_inrq(false);
-        });
-        loop {
-            let msr = self.canregs.msr().read();
-            if msr.slak() && !msr.inak() {
-                break;
-            }
-        }
-    }
-
-    /// Disables the CAN interface.
-    ///
-    /// The peripheral is disabled by setting `RESET` in `CAN_MCR`, which causes the peripheral to
-    /// enter sleep mode.
-    pub fn reset(&self) {
-        self.canregs.mcr().write(|reg| reg.set_reset(true));
-    }
-
-    /// Wakes up from sleep mode.
-    ///
-    /// Note that this will not trigger [`Interrupt::Wakeup`], only reception of an incoming CAN
-    /// frame will cause that interrupt.
-    #[allow(dead_code)]
-    pub fn wakeup(&mut self) {
-        self.canregs.mcr().modify(|reg| {
-            reg.set_sleep(false);
-            reg.set_inrq(false);
-        });
-        loop {
-            let msr = self.canregs.msr().read();
-            if !msr.slak() && !msr.inak() {
-                break;
-            }
-        }
-    }
-
-    pub fn curr_error(&self) -> Option<BusError> {
-        let err = { self.canregs.esr().read() };
-        if err.boff() {
-            return Some(BusError::BusOff);
-        } else if err.epvf() {
-            return Some(BusError::BusPassive);
-        } else if err.ewgf() {
-            return Some(BusError::BusWarning);
-        } else if let Some(err) = err.lec().into_bus_err() {
-            return Some(err);
-        }
-        None
-    }
-
-    /// Puts a CAN frame in a transmit mailbox for transmission on the bus.
-    ///
-    /// Frames are transmitted to the bus based on their priority (see [`FramePriority`]).
-    /// Transmit order is preserved for frames with identical priority.
-    ///
-    /// If all transmit mailboxes are full, and `frame` has a higher priority than the
-    /// lowest-priority message in the transmit mailboxes, transmission of the enqueued frame is
-    /// cancelled and `frame` is enqueued instead. The frame that was replaced is returned as
-    /// [`TransmitStatus::dequeued_frame`].
-    pub fn transmit(&mut self, frame: &Frame) -> nb::Result<TransmitStatus, Infallible> {
-        // Get the index of the next free mailbox or the one with the lowest priority.
-        let tsr = self.canregs.tsr().read();
-        let idx = tsr.code() as usize;
-
-        let frame_is_pending = !tsr.tme(0) || !tsr.tme(1) || !tsr.tme(2);
-        let pending_frame = if frame_is_pending {
-            // High priority frames are transmitted first by the mailbox system.
-            // Frames with identical identifier shall be transmitted in FIFO order.
-            // The controller schedules pending frames of same priority based on the
-            // mailbox index instead. As a workaround check all pending mailboxes
-            // and only accept higher priority frames.
-            self.check_priority(0, frame.id().into())?;
-            self.check_priority(1, frame.id().into())?;
-            self.check_priority(2, frame.id().into())?;
-
-            let all_frames_are_pending = !tsr.tme(0) && !tsr.tme(1) && !tsr.tme(2);
-            if all_frames_are_pending {
-                // No free mailbox is available. This can only happen when three frames with
-                // ascending priority (descending IDs) were requested for transmission and all
-                // of them are blocked by bus traffic with even higher priority.
-                // To prevent a priority inversion abort and replace the lowest priority frame.
-                self.read_pending_mailbox(idx)
-            } else {
-                // There was a free mailbox.
-                None
-            }
-        } else {
-            // All mailboxes are available: Send frame without performing any checks.
-            None
-        };
-
-        self.write_mailbox(idx, frame);
-
-        let mailbox = match idx {
-            0 => Mailbox::Mailbox0,
-            1 => Mailbox::Mailbox1,
-            2 => Mailbox::Mailbox2,
-            _ => unreachable!(),
-        };
-        Ok(TransmitStatus {
-            dequeued_frame: pending_frame,
-            mailbox,
-        })
-    }
-
-    /// Returns `Ok` when the mailbox is free or if it contains pending frame with a
-    /// lower priority (higher ID) than the identifier `id`.
-    fn check_priority(&self, idx: usize, id: IdReg) -> nb::Result<(), Infallible> {
-        // Read the pending frame's id to check its priority.
-        assert!(idx < 3);
-        let tir = &self.canregs.tx(idx).tir().read();
-        //let tir = &can.tx[idx].tir.read();
-
-        // Check the priority by comparing the identifiers. But first make sure the
-        // frame has not finished the transmission (`TXRQ` == 0) in the meantime.
-        if tir.txrq() && id <= IdReg::from_register(tir.0) {
-            // There's a mailbox whose priority is higher or equal
-            // the priority of the new frame.
-            return Err(nb::Error::WouldBlock);
-        }
-
-        Ok(())
-    }
-
-    fn write_mailbox(&mut self, idx: usize, frame: &Frame) {
-        debug_assert!(idx < 3);
-
-        let mb = self.canregs.tx(idx);
-        mb.tdtr().write(|w| w.set_dlc(frame.header().len() as u8));
-
-        mb.tdlr()
-            .write(|w| w.0 = u32::from_ne_bytes(frame.data()[0..4].try_into().unwrap()));
-        mb.tdhr()
-            .write(|w| w.0 = u32::from_ne_bytes(frame.data()[4..8].try_into().unwrap()));
-        let id: IdReg = frame.id().into();
-        mb.tir().write(|w| {
-            w.0 = id.0;
-            w.set_txrq(true);
-        });
-    }
-
-    fn read_pending_mailbox(&mut self, idx: usize) -> Option<Frame> {
-        if self.abort_by_index(idx) {
-            debug_assert!(idx < 3);
-
-            let mb = self.canregs.tx(idx);
-
-            let id = IdReg(mb.tir().read().0);
-            let mut data = [0xff; 8];
-            data[0..4].copy_from_slice(&mb.tdlr().read().0.to_ne_bytes());
-            data[4..8].copy_from_slice(&mb.tdhr().read().0.to_ne_bytes());
-            let len = mb.tdtr().read().dlc();
-
-            Some(Frame::new(Header::new(id.id(), len, id.rtr()), &data).unwrap())
-        } else {
-            // Abort request failed because the frame was already sent (or being sent) on
-            // the bus. All mailboxes are now free. This can happen for small prescaler
-            // values (e.g. 1MBit/s bit timing with a source clock of 8MHz) or when an ISR
-            // has preempted the execution.
-            None
-        }
-    }
-
-    /// Tries to abort a pending frame. Returns `true` when aborted.
-    fn abort_by_index(&mut self, idx: usize) -> bool {
-        self.canregs.tsr().write(|reg| reg.set_abrq(idx, true));
-
-        // Wait for the abort request to be finished.
-        loop {
-            let tsr = self.canregs.tsr().read();
-            if false == tsr.abrq(idx) {
-                break tsr.txok(idx) == false;
-            }
-        }
-    }
-
-    /// Attempts to abort the sending of a frame that is pending in a mailbox.
-    ///
-    /// If there is no frame in the provided mailbox, or its transmission succeeds before it can be
-    /// aborted, this function has no effect and returns `false`.
-    ///
-    /// If there is a frame in the provided mailbox, and it is canceled successfully, this function
-    /// returns `true`.
-    pub fn abort(&mut self, mailbox: Mailbox) -> bool {
-        // If the mailbox is empty, the value of TXOKx depends on what happened with the previous
-        // frame in that mailbox. Only call abort_by_index() if the mailbox is not empty.
-        let tsr = self.canregs.tsr().read();
-        let mailbox_empty = match mailbox {
-            Mailbox::Mailbox0 => tsr.tme(0),
-            Mailbox::Mailbox1 => tsr.tme(1),
-            Mailbox::Mailbox2 => tsr.tme(2),
-        };
-        if mailbox_empty {
-            false
-        } else {
-            self.abort_by_index(mailbox as usize)
-        }
-    }
-
-    /// Returns `true` if no frame is pending for transmission.
-    pub fn is_idle(&self) -> bool {
-        let tsr = self.canregs.tsr().read();
-        tsr.tme(0) && tsr.tme(1) && tsr.tme(2)
-    }
-
-    /// Clears the request complete flag for all mailboxes.
-    pub fn clear_interrupt_flags(&mut self) {
-        self.canregs.tsr().write(|reg| {
-            reg.set_rqcp(0, true);
-            reg.set_rqcp(1, true);
-            reg.set_rqcp(2, true);
-        });
-    }
-
-    pub fn receive_frame_available(&self) -> bool {
-        if self.canregs.rfr(0).read().fmp() != 0 {
-            true
-        } else if self.canregs.rfr(1).read().fmp() != 0 {
-            true
-        } else {
-            false
-        }
-    }
-
-    pub fn receive_fifo(&self, fifo: crate::can::_version::bx::RxFifo) -> Option<Envelope> {
-        // Generate timestamp as early as possible
-        #[cfg(feature = "time")]
-        let ts = embassy_time::Instant::now();
-
-        use crate::pac::can::vals::Ide;
-
-        let fifo_idx = match fifo {
-            crate::can::_version::bx::RxFifo::Fifo0 => 0usize,
-            crate::can::_version::bx::RxFifo::Fifo1 => 1usize,
-        };
-        let rfr = self.canregs.rfr(fifo_idx);
-        let fifo = self.canregs.rx(fifo_idx);
-
-        // If there are no pending messages, there is nothing to do
-        if rfr.read().fmp() == 0 {
-            return None;
-        }
-
-        let rir = fifo.rir().read();
-        let id: embedded_can::Id = if rir.ide() == Ide::STANDARD {
-            embedded_can::StandardId::new(rir.stid()).unwrap().into()
-        } else {
-            let stid = (rir.stid() & 0x7FF) as u32;
-            let exid = rir.exid() & 0x3FFFF;
-            let id = (stid << 18) | (exid);
-            embedded_can::ExtendedId::new(id).unwrap().into()
-        };
-        let rdtr = fifo.rdtr().read();
-        let data_len = rdtr.dlc();
-        let rtr = rir.rtr() == stm32_metapac::can::vals::Rtr::REMOTE;
-
-        #[cfg(not(feature = "time"))]
-        let ts = rdtr.time();
-
-        let mut data: [u8; 8] = [0; 8];
-        data[0..4].copy_from_slice(&fifo.rdlr().read().0.to_ne_bytes());
-        data[4..8].copy_from_slice(&fifo.rdhr().read().0.to_ne_bytes());
-
-        let frame = Frame::new(Header::new(id, data_len, rtr), &data).unwrap();
-        let envelope = Envelope { ts, frame };
-
-        rfr.modify(|v| v.set_rfom(true));
-
-        Some(envelope)
-    }
-}
-
-/// Configuration proxy returned by [`Can::modify_config`].
-#[must_use = "`CanConfig` leaves the peripheral in uninitialized state, call `CanConfig::enable` or explicitly drop the value"]
-pub struct CanConfig<'a, I: Instance> {
-    can: &'a mut Can<I>,
-}
-
-impl<I: Instance> CanConfig<'_, I> {
-    /// Configures the bit timings.
-    ///
-    /// You can use <http://www.bittiming.can-wiki.info/> to calculate the `btr` parameter. Enter
-    /// parameters as follows:
-    ///
-    /// - *Clock Rate*: The input clock speed to the CAN peripheral (*not* the CPU clock speed).
-    ///   This is the clock rate of the peripheral bus the CAN peripheral is attached to (eg. APB1).
-    /// - *Sample Point*: Should normally be left at the default value of 87.5%.
-    /// - *SJW*: Should normally be left at the default value of 1.
-    ///
-    /// Then copy the `CAN_BUS_TIME` register value from the table and pass it as the `btr`
-    /// parameter to this method.
-    pub fn set_bit_timing(self, bt: crate::can::util::NominalBitTiming) -> Self {
-        self.can.registers.set_bit_timing(bt);
-        self
-    }
-
-    /// Enables or disables loopback mode: Internally connects the TX and RX
-    /// signals together.
-    pub fn set_loopback(self, enabled: bool) -> Self {
-        self.can.registers.set_loopback(enabled);
-        self
-    }
-
-    /// Enables or disables silent mode: Disconnects the TX signal from the pin.
-    pub fn set_silent(self, enabled: bool) -> Self {
-        self.can.registers.set_silent(enabled);
-        self
-    }
-
-    /// Enables or disables automatic retransmission of messages.
-    ///
-    /// If this is enabled, the CAN peripheral will automatically try to retransmit each frame
-    /// until it can be sent. Otherwise, it will try only once to send each frame.
-    ///
-    /// Automatic retransmission is enabled by default.
-    pub fn set_automatic_retransmit(self, enabled: bool) -> Self {
-        self.can.registers.set_automatic_retransmit(enabled);
-        self
-    }
-
-    /// Leaves initialization mode and enables the peripheral.
-    ///
-    /// To sync with the CAN bus, this will block until 11 consecutive recessive bits are detected
-    /// on the bus.
-    ///
-    /// If you want to finish configuration without enabling the peripheral, you can call
-    /// [`CanConfig::leave_disabled`] or [`drop`] the [`CanConfig`] instead.
-    pub fn enable(self) {
-        self.can.registers.leave_init_mode();
-
-        match nb::block!(self.can.registers.enable_non_blocking()) {
-            Ok(()) => {}
-            Err(void) => match void {},
-        }
-
-        // Don't run the destructor.
-        mem::forget(self);
-    }
-
-    /// Leaves initialization mode, but keeps the peripheral in sleep mode.
-    ///
-    /// Before the [`Can`] instance can be used, you have to enable it by calling
-    /// [`Can::enable_non_blocking`].
-    pub fn leave_disabled(self) {
-        self.can.registers.leave_init_mode();
-    }
-}
-
-impl<I: Instance> Drop for CanConfig<'_, I> {
-    #[inline]
-    fn drop(&mut self) {
-        self.can.registers.leave_init_mode();
-    }
-}
-
-/// Builder returned by [`Can::builder`].
-#[must_use = "`CanBuilder` leaves the peripheral in uninitialized state, call `CanBuilder::enable` or `CanBuilder::leave_disabled`"]
-pub struct CanBuilder<I: Instance> {
-    can: Can<I>,
-}
-
-impl<I: Instance> CanBuilder<I> {
-    /// Configures the bit timings.
-    ///
-    /// You can use <http://www.bittiming.can-wiki.info/> to calculate the `btr` parameter. Enter
-    /// parameters as follows:
-    ///
-    /// - *Clock Rate*: The input clock speed to the CAN peripheral (*not* the CPU clock speed).
-    ///   This is the clock rate of the peripheral bus the CAN peripheral is attached to (eg. APB1).
-    /// - *Sample Point*: Should normally be left at the default value of 87.5%.
-    /// - *SJW*: Should normally be left at the default value of 1.
-    ///
-    /// Then copy the `CAN_BUS_TIME` register value from the table and pass it as the `btr`
-    /// parameter to this method.
-    pub fn set_bit_timing(mut self, bt: crate::can::util::NominalBitTiming) -> Self {
-        self.can.registers.set_bit_timing(bt);
-        self
-    }
-    /// Enables or disables loopback mode: Internally connects the TX and RX
-    /// signals together.
-    pub fn set_loopback(self, enabled: bool) -> Self {
-        self.can.registers.set_loopback(enabled);
-        self
-    }
-
-    /// Enables or disables silent mode: Disconnects the TX signal from the pin.
-    pub fn set_silent(self, enabled: bool) -> Self {
-        self.can.registers.set_silent(enabled);
-        self
-    }
-
-    /// Enables or disables automatic retransmission of messages.
-    ///
-    /// If this is enabled, the CAN peripheral will automatically try to retransmit each frame
-    /// until it can be sent. Otherwise, it will try only once to send each frame.
-    ///
-    /// Automatic retransmission is enabled by default.
-    pub fn set_automatic_retransmit(self, enabled: bool) -> Self {
-        self.can.registers.set_automatic_retransmit(enabled);
-        self
-    }
-
-    /// Leaves initialization mode and enables the peripheral.
-    ///
-    /// To sync with the CAN bus, this will block until 11 consecutive recessive bits are detected
-    /// on the bus.
-    ///
-    /// If you want to finish configuration without enabling the peripheral, you can call
-    /// [`CanBuilder::leave_disabled`] instead.
-    pub fn enable(mut self) -> Can<I> {
-        self.leave_init_mode();
-
-        match nb::block!(self.can.registers.enable_non_blocking()) {
-            Ok(()) => self.can,
-            Err(void) => match void {},
-        }
-    }
-
-    /// Returns the [`Can`] interface without enabling it.
-    ///
-    /// This leaves initialization mode, but keeps the peripheral in sleep mode instead of enabling
-    /// it.
-    ///
-    /// Before the [`Can`] instance can be used, you have to enable it by calling
-    /// [`Can::enable_non_blocking`].
-    pub fn leave_disabled(mut self) -> Can<I> {
-        self.leave_init_mode();
-        self.can
-    }
-
-    /// Leaves initialization mode, enters sleep mode.
-    fn leave_init_mode(&mut self) {
-        self.can.registers.leave_init_mode();
-    }
-}
-
-/// Interface to a bxCAN peripheral.
-pub struct Can<I: Instance> {
-    instance: I,
-    canregs: crate::pac::can::Can,
-    pub(crate) registers: Registers,
-}
-
-impl<I> Can<I>
-where
-    I: Instance,
-{
-    /// Creates a [`CanBuilder`] for constructing a CAN interface.
-    pub fn builder(instance: I, canregs: crate::pac::can::Can) -> CanBuilder<I> {
-        let mut can_builder = CanBuilder {
-            can: Can {
-                instance,
-                canregs,
-                registers: Registers { canregs },
-            },
-        };
-
-        can_builder.can.registers.enter_init_mode();
-
-        can_builder
-    }
-
-    /// Disables the CAN interface and returns back the raw peripheral it was created from.
-    ///
-    /// The peripheral is disabled by setting `RESET` in `CAN_MCR`, which causes the peripheral to
-    /// enter sleep mode.
-    pub fn free(self) -> I {
-        self.registers.reset();
-        self.instance
-    }
-
-    /// Configure bit timings and silent/loop-back mode.
-    ///
-    /// Calling this method will enter initialization mode.
-    pub fn modify_config(&mut self) -> CanConfig<'_, I> {
-        self.registers.enter_init_mode();
-
-        CanConfig { can: self }
-    }
-
-    /// Puts a CAN frame in a free transmit mailbox for transmission on the bus.
-    ///
-    /// Frames are transmitted to the bus based on their priority (see [`FramePriority`]).
-    /// Transmit order is preserved for frames with identical priority.
-    ///
-    /// If all transmit mailboxes are full, and `frame` has a higher priority than the
-    /// lowest-priority message in the transmit mailboxes, transmission of the enqueued frame is
-    /// cancelled and `frame` is enqueued instead. The frame that was replaced is returned as
-    /// [`TransmitStatus::dequeued_frame`].
-    pub fn transmit(&mut self, frame: &Frame) -> nb::Result<TransmitStatus, Infallible> {
-        // Safety: We have a `&mut self` and have unique access to the peripheral.
-        unsafe { Tx::<I>::conjure(self.canregs).transmit(frame) }
-    }
-
-    /// Returns `true` if no frame is pending for transmission.
-    pub fn is_transmitter_idle(&self) -> bool {
-        // Safety: Read-only operation.
-        unsafe { Tx::<I>::conjure(self.canregs).is_idle() }
-    }
-
-    /// Attempts to abort the sending of a frame that is pending in a mailbox.
-    ///
-    /// If there is no frame in the provided mailbox, or its transmission succeeds before it can be
-    /// aborted, this function has no effect and returns `false`.
-    ///
-    /// If there is a frame in the provided mailbox, and it is canceled successfully, this function
-    /// returns `true`.
-    pub fn abort(&mut self, mailbox: Mailbox) -> bool {
-        // Safety: We have a `&mut self` and have unique access to the peripheral.
-        unsafe { Tx::<I>::conjure(self.canregs).abort(mailbox) }
-    }
-
-    pub(crate) fn split_by_ref(&mut self) -> (Tx<I>, Rx<I>) {
-        // Safety: We take `&mut self` and the return value lifetimes are tied to `self`'s lifetime.
-        let tx = unsafe { Tx::conjure(self.canregs) };
-        let rx0 = unsafe { Rx::conjure() };
-        (tx, rx0)
-    }
-}
-
-impl<I: FilterOwner> Can<I> {
-    /// Accesses the filter banks owned by this CAN peripheral.
-    ///
-    /// To modify filters of a slave peripheral, `modify_filters` has to be called on the master
-    /// peripheral instead.
-    pub fn modify_filters(&mut self) -> MasterFilters<'_, I> {
-        unsafe { MasterFilters::new(self.canregs) }
-    }
-}
-
-/// Marker for Tx half
-pub struct Tx<I> {
-    _can: PhantomData<I>,
-    pub(crate) registers: Registers,
-}
-
-impl<I> Tx<I>
-where
-    I: Instance,
-{
-    unsafe fn conjure(canregs: crate::pac::can::Can) -> Self {
-        Self {
-            _can: PhantomData,
-            registers: Registers { canregs }, //canregs,
-        }
-    }
-
-    /// Puts a CAN frame in a transmit mailbox for transmission on the bus.
-    ///
-    /// Frames are transmitted to the bus based on their priority (see [`FramePriority`]).
-    /// Transmit order is preserved for frames with identical priority.
-    ///
-    /// If all transmit mailboxes are full, and `frame` has a higher priority than the
-    /// lowest-priority message in the transmit mailboxes, transmission of the enqueued frame is
-    /// cancelled and `frame` is enqueued instead. The frame that was replaced is returned as
-    /// [`TransmitStatus::dequeued_frame`].
-    pub fn transmit(&mut self, frame: &Frame) -> nb::Result<TransmitStatus, Infallible> {
-        self.registers.transmit(frame)
-    }
-
-    /// Attempts to abort the sending of a frame that is pending in a mailbox.
-    ///
-    /// If there is no frame in the provided mailbox, or its transmission succeeds before it can be
-    /// aborted, this function has no effect and returns `false`.
-    ///
-    /// If there is a frame in the provided mailbox, and it is canceled successfully, this function
-    /// returns `true`.
-    pub fn abort(&mut self, mailbox: Mailbox) -> bool {
-        self.registers.abort(mailbox)
-    }
-
-    /// Returns `true` if no frame is pending for transmission.
-    pub fn is_idle(&self) -> bool {
-        self.registers.is_idle()
-    }
-
-    /// Clears the request complete flag for all mailboxes.
-    pub fn clear_interrupt_flags(&mut self) {
-        self.registers.clear_interrupt_flags()
-    }
-}
-
-/// Marker for Rx half
-pub struct Rx<I> {
-    _can: PhantomData<I>,
-}
-
-impl<I> Rx<I>
-where
-    I: Instance,
-{
-    unsafe fn conjure() -> Self {
-        Self { _can: PhantomData }
-    }
-}
-
-/// Identifies one of the two receive FIFOs.
-#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
-#[cfg_attr(feature = "defmt", derive(defmt::Format))]
-pub enum Fifo {
-    /// First receive FIFO
-    Fifo0 = 0,
-    /// Second receive FIFO
-    Fifo1 = 1,
-}
-
-/// Identifies one of the three transmit mailboxes.
-#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq)]
-#[cfg_attr(feature = "defmt", derive(defmt::Format))]
-pub enum Mailbox {
-    /// Transmit mailbox 0
-    Mailbox0 = 0,
-    /// Transmit mailbox 1
-    Mailbox1 = 1,
-    /// Transmit mailbox 2
-    Mailbox2 = 2,
-}
-
-/// Contains information about a frame enqueued for transmission via [`Can::transmit`] or
-/// [`Tx::transmit`].
-pub struct TransmitStatus {
-    dequeued_frame: Option<Frame>,
-    mailbox: Mailbox,
-}
-
-impl TransmitStatus {
-    /// Returns the lower-priority frame that was dequeued to make space for the new frame.
-    #[inline]
-    pub fn dequeued_frame(&self) -> Option<&Frame> {
-        self.dequeued_frame.as_ref()
-    }
-
-    /// Returns the [`Mailbox`] the frame was enqueued in.
-    #[inline]
-    pub fn mailbox(&self) -> Mailbox {
-        self.mailbox
-    }
-}
diff --git a/embassy-stm32/src/can/bx/filter.rs b/embassy-stm32/src/can/bxcan/filter.rs
similarity index 99%
rename from embassy-stm32/src/can/bx/filter.rs
rename to embassy-stm32/src/can/bxcan/filter.rs
index 51766aa31..9940c7f50 100644
--- a/embassy-stm32/src/can/bx/filter.rs
+++ b/embassy-stm32/src/can/bxcan/filter.rs
@@ -2,7 +2,7 @@
 
 use core::marker::PhantomData;
 
-use crate::can::bx::{ExtendedId, Fifo, FilterOwner, Id, Instance, MasterInstance, StandardId};
+use super::{ExtendedId, Fifo, FilterOwner, Id, Instance, MasterInstance, StandardId};
 
 const F32_RTR: u32 = 0b010; // set the RTR bit to match remote frames
 const F32_IDE: u32 = 0b100; // set the IDE bit to match extended identifiers
diff --git a/embassy-stm32/src/can/bxcan.rs b/embassy-stm32/src/can/bxcan/mod.rs
similarity index 68%
rename from embassy-stm32/src/can/bxcan.rs
rename to embassy-stm32/src/can/bxcan/mod.rs
index fd6a79092..65fd0e9c2 100644
--- a/embassy-stm32/src/can/bxcan.rs
+++ b/embassy-stm32/src/can/bxcan/mod.rs
@@ -1,29 +1,27 @@
+pub mod filter;
+mod registers;
+
 use core::future::poll_fn;
 use core::marker::PhantomData;
-use core::ops::{Deref, DerefMut};
 use core::task::Poll;
 
-pub mod bx;
-
-pub use bx::{filter, Data, ExtendedId, Fifo, Frame, Header, Id, StandardId};
 use embassy_hal_internal::{into_ref, PeripheralRef};
 use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
 use embassy_sync::channel::Channel;
 use embassy_sync::waitqueue::AtomicWaker;
+pub use embedded_can::{ExtendedId, Id, StandardId};
 
+use self::filter::MasterFilters;
+use self::registers::{Registers, RxFifo};
+pub use super::common::{BufferedCanReceiver, BufferedCanSender};
+use super::frame::{Envelope, Frame};
+use super::util;
+use crate::can::enums::{BusError, TryReadError};
 use crate::gpio::AFType;
 use crate::interrupt::typelevel::Interrupt;
 use crate::rcc::RccPeripheral;
 use crate::{interrupt, peripherals, Peripheral};
 
-pub mod enums;
-pub mod frame;
-pub mod util;
-pub use frame::Envelope;
-
-mod common;
-pub use self::common::{BufferedCanReceiver, BufferedCanSender};
-
 /// Interrupt handler.
 pub struct TxInterruptHandler<T: Instance> {
     _phantom: PhantomData<T>,
@@ -80,9 +78,72 @@ impl<T: Instance> interrupt::typelevel::Handler<T::SCEInterrupt> for SceInterrup
     }
 }
 
+/// Configuration proxy returned by [`Can::modify_config`].
+pub struct CanConfig<'a, T: Instance> {
+    can: PhantomData<&'a mut T>,
+}
+
+impl<T: Instance> CanConfig<'_, T> {
+    /// Configures the bit timings.
+    ///
+    /// You can use <http://www.bittiming.can-wiki.info/> to calculate the `btr` parameter. Enter
+    /// parameters as follows:
+    ///
+    /// - *Clock Rate*: The input clock speed to the CAN peripheral (*not* the CPU clock speed).
+    ///   This is the clock rate of the peripheral bus the CAN peripheral is attached to (eg. APB1).
+    /// - *Sample Point*: Should normally be left at the default value of 87.5%.
+    /// - *SJW*: Should normally be left at the default value of 1.
+    ///
+    /// Then copy the `CAN_BUS_TIME` register value from the table and pass it as the `btr`
+    /// parameter to this method.
+    pub fn set_bit_timing(self, bt: crate::can::util::NominalBitTiming) -> Self {
+        Registers(T::regs()).set_bit_timing(bt);
+        self
+    }
+
+    /// Configure the CAN bit rate.
+    ///
+    /// This is a helper that internally calls `set_bit_timing()`[Self::set_bit_timing].
+    pub fn set_bitrate(self, bitrate: u32) -> Self {
+        let bit_timing = util::calc_can_timings(T::frequency(), bitrate).unwrap();
+        self.set_bit_timing(bit_timing)
+    }
+
+    /// Enables or disables loopback mode: Internally connects the TX and RX
+    /// signals together.
+    pub fn set_loopback(self, enabled: bool) -> Self {
+        Registers(T::regs()).set_loopback(enabled);
+        self
+    }
+
+    /// Enables or disables silent mode: Disconnects the TX signal from the pin.
+    pub fn set_silent(self, enabled: bool) -> Self {
+        Registers(T::regs()).set_silent(enabled);
+        self
+    }
+
+    /// Enables or disables automatic retransmission of messages.
+    ///
+    /// If this is enabled, the CAN peripheral will automatically try to retransmit each frame
+    /// until it can be sent. Otherwise, it will try only once to send each frame.
+    ///
+    /// Automatic retransmission is enabled by default.
+    pub fn set_automatic_retransmit(self, enabled: bool) -> Self {
+        Registers(T::regs()).set_automatic_retransmit(enabled);
+        self
+    }
+}
+
+impl<T: Instance> Drop for CanConfig<'_, T> {
+    #[inline]
+    fn drop(&mut self) {
+        Registers(T::regs()).leave_init_mode();
+    }
+}
+
 /// CAN driver
 pub struct Can<'d, T: Instance> {
-    can: crate::can::bx::Can<BxcanInstance<'d, T>>,
+    peri: PeripheralRef<'d, T>,
 }
 
 /// Error returned by `try_write`
@@ -145,14 +206,25 @@ impl<'d, T: Instance> Can<'d, T> {
         rx.set_as_af(rx.af_num(), AFType::Input);
         tx.set_as_af(tx.af_num(), AFType::OutputPushPull);
 
-        let can = crate::can::bx::Can::builder(BxcanInstance(peri), T::regs()).leave_disabled();
-        Self { can }
+        Registers(T::regs()).leave_init_mode();
+
+        Self { peri }
     }
 
     /// Set CAN bit rate.
     pub fn set_bitrate(&mut self, bitrate: u32) {
         let bit_timing = util::calc_can_timings(T::frequency(), bitrate).unwrap();
-        self.can.modify_config().set_bit_timing(bit_timing).leave_disabled();
+        self.modify_config().set_bit_timing(bit_timing);
+    }
+
+    /// Configure bit timings and silent/loop-back mode.
+    ///
+    /// Calling this method will enter initialization mode. You must enable the peripheral
+    /// again afterwards with [`enable`](Self::enable).
+    pub fn modify_config(&mut self) -> CanConfig<'_, T> {
+        Registers(T::regs()).enter_init_mode();
+
+        CanConfig { can: PhantomData }
     }
 
     /// Enables the peripheral and synchronizes with the bus.
@@ -160,7 +232,7 @@ impl<'d, T: Instance> Can<'d, T> {
     /// This will wait for 11 consecutive recessive bits (bus idle state).
     /// Contrary to enable method from bxcan library, this will not freeze the executor while waiting.
     pub async fn enable(&mut self) {
-        while self.registers.enable_non_blocking().is_err() {
+        while Registers(T::regs()).enable_non_blocking().is_err() {
             // SCE interrupt is only generated for entering sleep mode, but not leaving.
             // Yield to allow other tasks to execute while can bus is initializing.
             embassy_futures::yield_now().await;
@@ -170,19 +242,19 @@ impl<'d, T: Instance> Can<'d, T> {
     /// Queues the message to be sent.
     ///
     /// If the TX queue is full, this will wait until there is space, therefore exerting backpressure.
-    pub async fn write(&mut self, frame: &Frame) -> crate::can::bx::TransmitStatus {
+    pub async fn write(&mut self, frame: &Frame) -> TransmitStatus {
         self.split().0.write(frame).await
     }
 
     /// Attempts to transmit a frame without blocking.
     ///
     /// Returns [Err(TryWriteError::Full)] if all transmit mailboxes are full.
-    pub fn try_write(&mut self, frame: &Frame) -> Result<crate::can::bx::TransmitStatus, TryWriteError> {
+    pub fn try_write(&mut self, frame: &Frame) -> Result<TransmitStatus, TryWriteError> {
         self.split().0.try_write(frame)
     }
 
     /// Waits for a specific transmit mailbox to become empty
-    pub async fn flush(&self, mb: crate::can::bx::Mailbox) {
+    pub async fn flush(&self, mb: Mailbox) {
         CanTx::<T>::flush_inner(mb).await
     }
 
@@ -196,6 +268,22 @@ impl<'d, T: Instance> Can<'d, T> {
         CanTx::<T>::flush_all_inner().await
     }
 
+    /// Attempts to abort the sending of a frame that is pending in a mailbox.
+    ///
+    /// If there is no frame in the provided mailbox, or its transmission succeeds before it can be
+    /// aborted, this function has no effect and returns `false`.
+    ///
+    /// If there is a frame in the provided mailbox, and it is canceled successfully, this function
+    /// returns `true`.
+    pub fn abort(&mut self, mailbox: Mailbox) -> bool {
+        Registers(T::regs()).abort(mailbox)
+    }
+
+    /// Returns `true` if no frame is pending for transmission.
+    pub fn is_transmitter_idle(&self) -> bool {
+        Registers(T::regs()).is_idle()
+    }
+
     /// Read a CAN frame.
     ///
     /// If no CAN frame is in the RX buffer, this will wait until there is one.
@@ -221,8 +309,14 @@ impl<'d, T: Instance> Can<'d, T> {
     ///
     /// Useful for doing separate transmit/receive tasks.
     pub fn split<'c>(&'c mut self) -> (CanTx<'d, T>, CanRx<'d, T>) {
-        let (tx, rx) = self.can.split_by_ref();
-        (CanTx { tx }, CanRx { rx })
+        (
+            CanTx {
+                _peri: unsafe { self.peri.clone_unchecked() },
+            },
+            CanRx {
+                peri: unsafe { self.peri.clone_unchecked() },
+            },
+        )
     }
 
     /// Return a buffered instance of driver. User must supply Buffers
@@ -239,10 +333,13 @@ impl<'d, T: Instance> Can<'d, T> {
     }
 }
 
-impl<'d, T: Instance> AsMut<crate::can::bx::Can<BxcanInstance<'d, T>>> for Can<'d, T> {
-    /// Get mutable access to the lower-level driver from the `bxcan` crate.
-    fn as_mut(&mut self) -> &mut crate::can::bx::Can<BxcanInstance<'d, T>> {
-        &mut self.can
+impl<'d, T: FilterOwner> Can<'d, T> {
+    /// Accesses the filter banks owned by this CAN peripheral.
+    ///
+    /// To modify filters of a slave peripheral, `modify_filters` has to be called on the master
+    /// peripheral instead.
+    pub fn modify_filters(&mut self) -> MasterFilters<'_, T> {
+        unsafe { MasterFilters::new(T::regs()) }
     }
 }
 
@@ -288,17 +385,17 @@ impl<'d, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> Buffer
 
 /// CAN driver, transmit half.
 pub struct CanTx<'d, T: Instance> {
-    tx: crate::can::bx::Tx<BxcanInstance<'d, T>>,
+    _peri: PeripheralRef<'d, T>,
 }
 
 impl<'d, T: Instance> CanTx<'d, T> {
     /// Queues the message to be sent.
     ///
     /// If the TX queue is full, this will wait until there is space, therefore exerting backpressure.
-    pub async fn write(&mut self, frame: &Frame) -> crate::can::bx::TransmitStatus {
+    pub async fn write(&mut self, frame: &Frame) -> TransmitStatus {
         poll_fn(|cx| {
             T::state().tx_mode.register(cx.waker());
-            if let Ok(status) = self.tx.transmit(frame) {
+            if let Ok(status) = Registers(T::regs()).transmit(frame) {
                 return Poll::Ready(status);
             }
 
@@ -310,11 +407,11 @@ impl<'d, T: Instance> CanTx<'d, T> {
     /// Attempts to transmit a frame without blocking.
     ///
     /// Returns [Err(TryWriteError::Full)] if all transmit mailboxes are full.
-    pub fn try_write(&mut self, frame: &Frame) -> Result<crate::can::bx::TransmitStatus, TryWriteError> {
-        self.tx.transmit(frame).map_err(|_| TryWriteError::Full)
+    pub fn try_write(&mut self, frame: &Frame) -> Result<TransmitStatus, TryWriteError> {
+        Registers(T::regs()).transmit(frame).map_err(|_| TryWriteError::Full)
     }
 
-    async fn flush_inner(mb: crate::can::bx::Mailbox) {
+    async fn flush_inner(mb: Mailbox) {
         poll_fn(|cx| {
             T::state().tx_mode.register(cx.waker());
             if T::regs().tsr().read().tme(mb.index()) {
@@ -327,7 +424,7 @@ impl<'d, T: Instance> CanTx<'d, T> {
     }
 
     /// Waits for a specific transmit mailbox to become empty
-    pub async fn flush(&self, mb: crate::can::bx::Mailbox) {
+    pub async fn flush(&self, mb: Mailbox) {
         Self::flush_inner(mb).await
     }
 
@@ -336,9 +433,9 @@ impl<'d, T: Instance> CanTx<'d, T> {
             T::state().tx_mode.register(cx.waker());
 
             let tsr = T::regs().tsr().read();
-            if tsr.tme(crate::can::bx::Mailbox::Mailbox0.index())
-                || tsr.tme(crate::can::bx::Mailbox::Mailbox1.index())
-                || tsr.tme(crate::can::bx::Mailbox::Mailbox2.index())
+            if tsr.tme(Mailbox::Mailbox0.index())
+                || tsr.tme(Mailbox::Mailbox1.index())
+                || tsr.tme(Mailbox::Mailbox2.index())
             {
                 return Poll::Ready(());
             }
@@ -358,9 +455,9 @@ impl<'d, T: Instance> CanTx<'d, T> {
             T::state().tx_mode.register(cx.waker());
 
             let tsr = T::regs().tsr().read();
-            if tsr.tme(crate::can::bx::Mailbox::Mailbox0.index())
-                && tsr.tme(crate::can::bx::Mailbox::Mailbox1.index())
-                && tsr.tme(crate::can::bx::Mailbox::Mailbox2.index())
+            if tsr.tme(Mailbox::Mailbox0.index())
+                && tsr.tme(Mailbox::Mailbox1.index())
+                && tsr.tme(Mailbox::Mailbox2.index())
             {
                 return Poll::Ready(());
             }
@@ -375,12 +472,28 @@ impl<'d, T: Instance> CanTx<'d, T> {
         Self::flush_all_inner().await
     }
 
+    /// Attempts to abort the sending of a frame that is pending in a mailbox.
+    ///
+    /// If there is no frame in the provided mailbox, or its transmission succeeds before it can be
+    /// aborted, this function has no effect and returns `false`.
+    ///
+    /// If there is a frame in the provided mailbox, and it is canceled successfully, this function
+    /// returns `true`.
+    pub fn abort(&mut self, mailbox: Mailbox) -> bool {
+        Registers(T::regs()).abort(mailbox)
+    }
+
+    /// Returns `true` if no frame is pending for transmission.
+    pub fn is_idle(&self) -> bool {
+        Registers(T::regs()).is_idle()
+    }
+
     /// Return a buffered instance of driver. User must supply Buffers
     pub fn buffered<const TX_BUF_SIZE: usize>(
         self,
         txb: &'static mut TxBuf<TX_BUF_SIZE>,
     ) -> BufferedCanTx<'d, T, TX_BUF_SIZE> {
-        BufferedCanTx::new(self.tx, txb)
+        BufferedCanTx::new(self, txb)
     }
 }
 
@@ -389,19 +502,19 @@ pub type TxBuf<const BUF_SIZE: usize> = Channel<CriticalSectionRawMutex, Frame,
 
 /// Buffered CAN driver, transmit half.
 pub struct BufferedCanTx<'d, T: Instance, const TX_BUF_SIZE: usize> {
-    _tx: crate::can::bx::Tx<BxcanInstance<'d, T>>,
+    _tx: CanTx<'d, T>,
     tx_buf: &'static TxBuf<TX_BUF_SIZE>,
 }
 
 impl<'d, T: Instance, const TX_BUF_SIZE: usize> BufferedCanTx<'d, T, TX_BUF_SIZE> {
-    fn new(_tx: crate::can::bx::Tx<BxcanInstance<'d, T>>, tx_buf: &'static TxBuf<TX_BUF_SIZE>) -> Self {
+    fn new(_tx: CanTx<'d, T>, tx_buf: &'static TxBuf<TX_BUF_SIZE>) -> Self {
         Self { _tx, tx_buf }.setup()
     }
 
     fn setup(self) -> Self {
         // We don't want interrupts being processed while we change modes.
         critical_section::with(|_| unsafe {
-            let tx_inner = self::common::ClassicBufferedTxInner {
+            let tx_inner = super::common::ClassicBufferedTxInner {
                 tx_receiver: self.tx_buf.receiver().into(),
             };
             T::mut_state().tx_mode = TxMode::Buffered(tx_inner);
@@ -435,7 +548,7 @@ impl<'d, T: Instance, const TX_BUF_SIZE: usize> Drop for BufferedCanTx<'d, T, TX
 /// CAN driver, receive half.
 #[allow(dead_code)]
 pub struct CanRx<'d, T: Instance> {
-    rx: crate::can::bx::Rx<BxcanInstance<'d, T>>,
+    peri: PeripheralRef<'d, T>,
 }
 
 impl<'d, T: Instance> CanRx<'d, T> {
@@ -465,7 +578,7 @@ impl<'d, T: Instance> CanRx<'d, T> {
         self,
         rxb: &'static mut RxBuf<RX_BUF_SIZE>,
     ) -> BufferedCanRx<'d, T, RX_BUF_SIZE> {
-        BufferedCanRx::new(self.rx, rxb)
+        BufferedCanRx::new(self, rxb)
     }
 }
 
@@ -474,19 +587,19 @@ pub type RxBuf<const BUF_SIZE: usize> = Channel<CriticalSectionRawMutex, Result<
 
 /// CAN driver, receive half in Buffered mode.
 pub struct BufferedCanRx<'d, T: Instance, const RX_BUF_SIZE: usize> {
-    _rx: crate::can::bx::Rx<BxcanInstance<'d, T>>,
+    _rx: CanRx<'d, T>,
     rx_buf: &'static RxBuf<RX_BUF_SIZE>,
 }
 
 impl<'d, T: Instance, const RX_BUF_SIZE: usize> BufferedCanRx<'d, T, RX_BUF_SIZE> {
-    fn new(_rx: crate::can::bx::Rx<BxcanInstance<'d, T>>, rx_buf: &'static RxBuf<RX_BUF_SIZE>) -> Self {
+    fn new(_rx: CanRx<'d, T>, rx_buf: &'static RxBuf<RX_BUF_SIZE>) -> Self {
         BufferedCanRx { _rx, rx_buf }.setup()
     }
 
     fn setup(self) -> Self {
         // We don't want interrupts being processed while we change modes.
         critical_section::with(|_| unsafe {
-            let rx_inner = self::common::ClassicBufferedRxInner {
+            let rx_inner = super::common::ClassicBufferedRxInner {
                 rx_sender: self.rx_buf.sender().into(),
             };
             T::mut_state().rx_mode = RxMode::Buffered(rx_inner);
@@ -511,8 +624,7 @@ impl<'d, T: Instance, const RX_BUF_SIZE: usize> BufferedCanRx<'d, T, RX_BUF_SIZE
                         Err(e) => Err(TryReadError::BusError(e)),
                     }
                 } else {
-                    let registers = crate::can::bx::Registers { canregs: T::regs() };
-                    if let Some(err) = registers.curr_error() {
+                    if let Some(err) = Registers(T::regs()).curr_error() {
                         return Err(TryReadError::BusError(err));
                     } else {
                         Err(TryReadError::Empty)
@@ -544,8 +656,6 @@ impl<'d, T: Instance, const RX_BUF_SIZE: usize> Drop for BufferedCanRx<'d, T, RX
     }
 }
 
-use crate::can::bx::RxFifo;
-
 impl<'d, T: Instance> Drop for Can<'d, T> {
     fn drop(&mut self) {
         // Cannot call `free()` because it moves the instance.
@@ -555,35 +665,62 @@ impl<'d, T: Instance> Drop for Can<'d, T> {
     }
 }
 
-impl<'d, T: Instance> Deref for Can<'d, T> {
-    type Target = crate::can::bx::Can<BxcanInstance<'d, T>>;
-
-    fn deref(&self) -> &Self::Target {
-        &self.can
-    }
+/// Identifies one of the two receive FIFOs.
+#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
+#[cfg_attr(feature = "defmt", derive(defmt::Format))]
+pub enum Fifo {
+    /// First receive FIFO
+    Fifo0 = 0,
+    /// Second receive FIFO
+    Fifo1 = 1,
 }
 
-impl<'d, T: Instance> DerefMut for Can<'d, T> {
-    fn deref_mut(&mut self) -> &mut Self::Target {
-        &mut self.can
-    }
+/// Identifies one of the three transmit mailboxes.
+#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq)]
+#[cfg_attr(feature = "defmt", derive(defmt::Format))]
+pub enum Mailbox {
+    /// Transmit mailbox 0
+    Mailbox0 = 0,
+    /// Transmit mailbox 1
+    Mailbox1 = 1,
+    /// Transmit mailbox 2
+    Mailbox2 = 2,
 }
 
-use crate::can::enums::{BusError, TryReadError};
+/// Contains information about a frame enqueued for transmission via [`Can::transmit`] or
+/// [`Tx::transmit`].
+pub struct TransmitStatus {
+    dequeued_frame: Option<Frame>,
+    mailbox: Mailbox,
+}
+
+impl TransmitStatus {
+    /// Returns the lower-priority frame that was dequeued to make space for the new frame.
+    #[inline]
+    pub fn dequeued_frame(&self) -> Option<&Frame> {
+        self.dequeued_frame.as_ref()
+    }
+
+    /// Returns the [`Mailbox`] the frame was enqueued in.
+    #[inline]
+    pub fn mailbox(&self) -> Mailbox {
+        self.mailbox
+    }
+}
 
 pub(crate) enum RxMode {
     NonBuffered(AtomicWaker),
-    Buffered(crate::can::_version::common::ClassicBufferedRxInner),
+    Buffered(super::common::ClassicBufferedRxInner),
 }
 
 impl RxMode {
-    pub fn on_interrupt<T: Instance>(&self, fifo: crate::can::_version::bx::RxFifo) {
+    pub fn on_interrupt<T: Instance>(&self, fifo: RxFifo) {
         match self {
             Self::NonBuffered(waker) => {
                 // Disable interrupts until read
                 let fifo_idx = match fifo {
-                    crate::can::_version::bx::RxFifo::Fifo0 => 0usize,
-                    crate::can::_version::bx::RxFifo::Fifo1 => 1usize,
+                    RxFifo::Fifo0 => 0usize,
+                    RxFifo::Fifo1 => 1usize,
                 };
                 T::regs().ier().write(|w| {
                     w.set_fmpie(fifo_idx, false);
@@ -591,10 +728,8 @@ impl RxMode {
                 waker.wake();
             }
             Self::Buffered(buf) => {
-                let regsisters = crate::can::bx::Registers { canregs: T::regs() };
-
                 loop {
-                    match regsisters.receive_fifo(fifo) {
+                    match Registers(T::regs()).receive_fifo(fifo) {
                         Some(envelope) => {
                             // NOTE: consensus was reached that if rx_queue is full, packets should be dropped
                             let _ = buf.rx_sender.try_send(Ok(envelope));
@@ -628,13 +763,13 @@ impl RxMode {
     pub fn try_read<T: Instance>(&self) -> Result<Envelope, TryReadError> {
         match self {
             Self::NonBuffered(_) => {
-                let registers = crate::can::bx::Registers { canregs: T::regs() };
-                if let Some(msg) = registers.receive_fifo(super::bx::RxFifo::Fifo0) {
+                let registers = Registers(T::regs());
+                if let Some(msg) = registers.receive_fifo(RxFifo::Fifo0) {
                     T::regs().ier().write(|w| {
                         w.set_fmpie(0, true);
                     });
                     Ok(msg)
-                } else if let Some(msg) = registers.receive_fifo(super::bx::RxFifo::Fifo1) {
+                } else if let Some(msg) = registers.receive_fifo(RxFifo::Fifo1) {
                     T::regs().ier().write(|w| {
                         w.set_fmpie(1, true);
                     });
@@ -655,8 +790,7 @@ impl RxMode {
             Self::NonBuffered(waker) => {
                 poll_fn(|cx| {
                     waker.register(cx.waker());
-                    let registers = crate::can::bx::Registers { canregs: T::regs() };
-                    if registers.receive_frame_available() {
+                    if Registers(T::regs()).receive_frame_available() {
                         Poll::Ready(())
                     } else {
                         Poll::Pending
@@ -673,15 +807,13 @@ impl RxMode {
 
 enum TxMode {
     NonBuffered(AtomicWaker),
-    Buffered(self::common::ClassicBufferedTxInner),
+    Buffered(super::common::ClassicBufferedTxInner),
 }
 
 impl TxMode {
     pub fn buffer_free<T: Instance>(&self) -> bool {
         let tsr = T::regs().tsr().read();
-        tsr.tme(crate::can::bx::Mailbox::Mailbox0.index())
-            || tsr.tme(crate::can::bx::Mailbox::Mailbox1.index())
-            || tsr.tme(crate::can::bx::Mailbox::Mailbox2.index())
+        tsr.tme(Mailbox::Mailbox0.index()) || tsr.tme(Mailbox::Mailbox1.index()) || tsr.tme(Mailbox::Mailbox2.index())
     }
     pub fn on_interrupt<T: Instance>(&self) {
         match &T::state().tx_mode {
@@ -690,8 +822,7 @@ impl TxMode {
                 while self.buffer_free::<T>() {
                     match buf.tx_receiver.try_receive() {
                         Ok(frame) => {
-                            let mut registers = crate::can::bx::Registers { canregs: T::regs() };
-                            _ = registers.transmit(&frame);
+                            _ = Registers(T::regs()).transmit(&frame);
                         }
                         Err(_) => {
                             break;
@@ -738,7 +869,7 @@ trait SealedInstance {
 
 /// CAN instance trait.
 #[allow(private_bounds)]
-pub trait Instance: SealedInstance + RccPeripheral + 'static {
+pub trait Instance: Peripheral<P = Self> + SealedInstance + RccPeripheral + 'static {
     /// TX interrupt for this instance.
     type TXInterrupt: crate::interrupt::typelevel::Interrupt;
     /// RX0 interrupt for this instance.
@@ -749,10 +880,35 @@ pub trait Instance: SealedInstance + RccPeripheral + 'static {
     type SCEInterrupt: crate::interrupt::typelevel::Interrupt;
 }
 
-/// BXCAN instance newtype.
-pub struct BxcanInstance<'a, T>(PeripheralRef<'a, T>);
+/// A bxCAN instance that owns filter banks.
+///
+/// In master-slave-instance setups, only the master instance owns the filter banks, and needs to
+/// split some of them off for use by the slave instance. In that case, the master instance should
+/// implement [`FilterOwner`] and [`MasterInstance`], while the slave instance should only implement
+/// [`Instance`].
+///
+/// In single-instance configurations, the instance owns all filter banks and they can not be split
+/// off. In that case, the instance should implement [`Instance`] and [`FilterOwner`].
+///
+/// # Safety
+///
+/// This trait must only be implemented if the instance does, in fact, own its associated filter
+/// banks, and `NUM_FILTER_BANKS` must be correct.
+pub unsafe trait FilterOwner: Instance {
+    /// The total number of filter banks available to the instance.
+    ///
+    /// This is usually either 14 or 28, and should be specified in the chip's reference manual or datasheet.
+    const NUM_FILTER_BANKS: u8;
+}
 
-unsafe impl<'d, T: Instance> crate::can::bx::Instance for BxcanInstance<'d, T> {}
+/// A bxCAN master instance that shares filter banks with a slave instance.
+///
+/// In master-slave-instance setups, this trait should be implemented for the master instance.
+///
+/// # Safety
+///
+/// This trait must only be implemented when there is actually an associated slave instance.
+pub unsafe trait MasterInstance: FilterOwner {}
 
 foreach_peripheral!(
     (can, $inst:ident) => {
@@ -782,7 +938,7 @@ foreach_peripheral!(
 
 foreach_peripheral!(
     (can, CAN) => {
-        unsafe impl<'d> crate::can::bx::FilterOwner for BxcanInstance<'d, peripherals::CAN> {
+        unsafe impl FilterOwner for peripherals::CAN {
             const NUM_FILTER_BANKS: u8 = 14;
         }
     };
@@ -797,19 +953,19 @@ foreach_peripheral!(
             ))] {
                 // Most L4 devices and some F7 devices use the name "CAN1"
                 // even if there is no "CAN2" peripheral.
-                unsafe impl<'d> crate::can::bx::FilterOwner for BxcanInstance<'d, peripherals::CAN1> {
+                unsafe impl FilterOwner for peripherals::CAN1 {
                     const NUM_FILTER_BANKS: u8 = 14;
                 }
             } else {
-                unsafe impl<'d> crate::can::bx::FilterOwner for BxcanInstance<'d, peripherals::CAN1> {
+                unsafe impl FilterOwner for peripherals::CAN1 {
                     const NUM_FILTER_BANKS: u8 = 28;
                 }
-                unsafe impl<'d> crate::can::bx::MasterInstance for BxcanInstance<'d, peripherals::CAN1> {}
+                unsafe impl MasterInstance for peripherals::CAN1 {}
             }
         }
     };
     (can, CAN3) => {
-        unsafe impl<'d> crate::can::bx::FilterOwner for BxcanInstance<'d, peripherals::CAN3> {
+        unsafe impl FilterOwner for peripherals::CAN3 {
             const NUM_FILTER_BANKS: u8 = 14;
         }
     };
@@ -822,12 +978,12 @@ trait Index {
     fn index(&self) -> usize;
 }
 
-impl Index for crate::can::bx::Mailbox {
+impl Index for Mailbox {
     fn index(&self) -> usize {
         match self {
-            crate::can::bx::Mailbox::Mailbox0 => 0,
-            crate::can::bx::Mailbox::Mailbox1 => 1,
-            crate::can::bx::Mailbox::Mailbox2 => 2,
+            Mailbox::Mailbox0 => 0,
+            Mailbox::Mailbox1 => 1,
+            Mailbox::Mailbox2 => 2,
         }
     }
 }
diff --git a/embassy-stm32/src/can/bxcan/registers.rs b/embassy-stm32/src/can/bxcan/registers.rs
new file mode 100644
index 000000000..732567797
--- /dev/null
+++ b/embassy-stm32/src/can/bxcan/registers.rs
@@ -0,0 +1,510 @@
+use core::cmp::Ordering;
+use core::convert::Infallible;
+
+pub use embedded_can::{ExtendedId, Id, StandardId};
+use stm32_metapac::can::vals::Lec;
+
+use super::{Mailbox, TransmitStatus};
+use crate::can::enums::BusError;
+use crate::can::frame::{Envelope, Frame, Header};
+
+pub(crate) struct Registers(pub crate::pac::can::Can);
+
+impl Registers {
+    pub fn enter_init_mode(&mut self) {
+        self.0.mcr().modify(|reg| {
+            reg.set_sleep(false);
+            reg.set_inrq(true);
+        });
+        loop {
+            let msr = self.0.msr().read();
+            if !msr.slak() && msr.inak() {
+                break;
+            }
+        }
+    }
+
+    // Leaves initialization mode, enters sleep mode.
+    pub fn leave_init_mode(&mut self) {
+        self.0.mcr().modify(|reg| {
+            reg.set_sleep(true);
+            reg.set_inrq(false);
+        });
+        loop {
+            let msr = self.0.msr().read();
+            if msr.slak() && !msr.inak() {
+                break;
+            }
+        }
+    }
+
+    pub fn set_bit_timing(&mut self, bt: crate::can::util::NominalBitTiming) {
+        let prescaler = u16::from(bt.prescaler) & 0x1FF;
+        let seg1 = u8::from(bt.seg1);
+        let seg2 = u8::from(bt.seg2) & 0x7F;
+        let sync_jump_width = u8::from(bt.sync_jump_width) & 0x7F;
+        self.0.btr().modify(|reg| {
+            reg.set_brp(prescaler - 1);
+            reg.set_ts(0, seg1 - 1);
+            reg.set_ts(1, seg2 - 1);
+            reg.set_sjw(sync_jump_width - 1);
+        });
+    }
+
+    /// Enables or disables silent mode: Disconnects the TX signal from the pin.
+    pub fn set_silent(&self, enabled: bool) {
+        let mode = match enabled {
+            false => stm32_metapac::can::vals::Silm::NORMAL,
+            true => stm32_metapac::can::vals::Silm::SILENT,
+        };
+        self.0.btr().modify(|reg| reg.set_silm(mode));
+    }
+
+    /// Enables or disables automatic retransmission of messages.
+    ///
+    /// If this is enabled, the CAN peripheral will automatically try to retransmit each frame
+    /// until it can be sent. Otherwise, it will try only once to send each frame.
+    ///
+    /// Automatic retransmission is enabled by default.
+    pub fn set_automatic_retransmit(&self, enabled: bool) {
+        self.0.mcr().modify(|reg| reg.set_nart(enabled));
+    }
+
+    /// Enables or disables loopback mode: Internally connects the TX and RX
+    /// signals together.
+    pub fn set_loopback(&self, enabled: bool) {
+        self.0.btr().modify(|reg| reg.set_lbkm(enabled));
+    }
+
+    /// Configures the automatic wake-up feature.
+    ///
+    /// This is turned off by default.
+    ///
+    /// When turned on, an incoming frame will cause the peripheral to wake up from sleep and
+    /// receive the frame. If enabled, [`Interrupt::Wakeup`] will also be triggered by the incoming
+    /// frame.
+    #[allow(dead_code)]
+    pub fn set_automatic_wakeup(&mut self, enabled: bool) {
+        self.0.mcr().modify(|reg| reg.set_awum(enabled));
+    }
+
+    /// Leaves initialization mode and enables the peripheral (non-blocking version).
+    ///
+    /// Usually, it is recommended to call [`CanConfig::enable`] instead. This method is only needed
+    /// if you want non-blocking initialization.
+    ///
+    /// If this returns [`WouldBlock`][nb::Error::WouldBlock], the peripheral will enable itself
+    /// in the background. The peripheral is enabled and ready to use when this method returns
+    /// successfully.
+    pub fn enable_non_blocking(&mut self) -> nb::Result<(), Infallible> {
+        let msr = self.0.msr().read();
+        if msr.slak() {
+            self.0.mcr().modify(|reg| {
+                reg.set_abom(true);
+                reg.set_sleep(false);
+            });
+            Err(nb::Error::WouldBlock)
+        } else {
+            Ok(())
+        }
+    }
+
+    /// Puts the peripheral in a sleep mode to save power.
+    ///
+    /// While in sleep mode, an incoming CAN frame will trigger [`Interrupt::Wakeup`] if enabled.
+    #[allow(dead_code)]
+    pub fn sleep(&mut self) {
+        self.0.mcr().modify(|reg| {
+            reg.set_sleep(true);
+            reg.set_inrq(false);
+        });
+        loop {
+            let msr = self.0.msr().read();
+            if msr.slak() && !msr.inak() {
+                break;
+            }
+        }
+    }
+
+    /// Wakes up from sleep mode.
+    ///
+    /// Note that this will not trigger [`Interrupt::Wakeup`], only reception of an incoming CAN
+    /// frame will cause that interrupt.
+    #[allow(dead_code)]
+    pub fn wakeup(&mut self) {
+        self.0.mcr().modify(|reg| {
+            reg.set_sleep(false);
+            reg.set_inrq(false);
+        });
+        loop {
+            let msr = self.0.msr().read();
+            if !msr.slak() && !msr.inak() {
+                break;
+            }
+        }
+    }
+
+    pub fn curr_error(&self) -> Option<BusError> {
+        let err = { self.0.esr().read() };
+        if err.boff() {
+            return Some(BusError::BusOff);
+        } else if err.epvf() {
+            return Some(BusError::BusPassive);
+        } else if err.ewgf() {
+            return Some(BusError::BusWarning);
+        } else if err.lec() != Lec::NOERROR {
+            return Some(match err.lec() {
+                Lec::STUFF => BusError::Stuff,
+                Lec::FORM => BusError::Form,
+                Lec::ACK => BusError::Acknowledge,
+                Lec::BITRECESSIVE => BusError::BitRecessive,
+                Lec::BITDOMINANT => BusError::BitDominant,
+                Lec::CRC => BusError::Crc,
+                Lec::CUSTOM => BusError::Software,
+                Lec::NOERROR => unreachable!(),
+            });
+        }
+        None
+    }
+
+    /// Puts a CAN frame in a transmit mailbox for transmission on the bus.
+    ///
+    /// Frames are transmitted to the bus based on their priority (see [`FramePriority`]).
+    /// Transmit order is preserved for frames with identical priority.
+    ///
+    /// If all transmit mailboxes are full, and `frame` has a higher priority than the
+    /// lowest-priority message in the transmit mailboxes, transmission of the enqueued frame is
+    /// cancelled and `frame` is enqueued instead. The frame that was replaced is returned as
+    /// [`TransmitStatus::dequeued_frame`].
+    pub fn transmit(&mut self, frame: &Frame) -> nb::Result<TransmitStatus, Infallible> {
+        // Get the index of the next free mailbox or the one with the lowest priority.
+        let tsr = self.0.tsr().read();
+        let idx = tsr.code() as usize;
+
+        let frame_is_pending = !tsr.tme(0) || !tsr.tme(1) || !tsr.tme(2);
+        let pending_frame = if frame_is_pending {
+            // High priority frames are transmitted first by the mailbox system.
+            // Frames with identical identifier shall be transmitted in FIFO order.
+            // The controller schedules pending frames of same priority based on the
+            // mailbox index instead. As a workaround check all pending mailboxes
+            // and only accept higher priority frames.
+            self.check_priority(0, frame.id().into())?;
+            self.check_priority(1, frame.id().into())?;
+            self.check_priority(2, frame.id().into())?;
+
+            let all_frames_are_pending = !tsr.tme(0) && !tsr.tme(1) && !tsr.tme(2);
+            if all_frames_are_pending {
+                // No free mailbox is available. This can only happen when three frames with
+                // ascending priority (descending IDs) were requested for transmission and all
+                // of them are blocked by bus traffic with even higher priority.
+                // To prevent a priority inversion abort and replace the lowest priority frame.
+                self.read_pending_mailbox(idx)
+            } else {
+                // There was a free mailbox.
+                None
+            }
+        } else {
+            // All mailboxes are available: Send frame without performing any checks.
+            None
+        };
+
+        self.write_mailbox(idx, frame);
+
+        let mailbox = match idx {
+            0 => Mailbox::Mailbox0,
+            1 => Mailbox::Mailbox1,
+            2 => Mailbox::Mailbox2,
+            _ => unreachable!(),
+        };
+        Ok(TransmitStatus {
+            dequeued_frame: pending_frame,
+            mailbox,
+        })
+    }
+
+    /// Returns `Ok` when the mailbox is free or if it contains pending frame with a
+    /// lower priority (higher ID) than the identifier `id`.
+    fn check_priority(&self, idx: usize, id: IdReg) -> nb::Result<(), Infallible> {
+        // Read the pending frame's id to check its priority.
+        assert!(idx < 3);
+        let tir = &self.0.tx(idx).tir().read();
+        //let tir = &can.tx[idx].tir.read();
+
+        // Check the priority by comparing the identifiers. But first make sure the
+        // frame has not finished the transmission (`TXRQ` == 0) in the meantime.
+        if tir.txrq() && id <= IdReg::from_register(tir.0) {
+            // There's a mailbox whose priority is higher or equal
+            // the priority of the new frame.
+            return Err(nb::Error::WouldBlock);
+        }
+
+        Ok(())
+    }
+
+    fn write_mailbox(&mut self, idx: usize, frame: &Frame) {
+        debug_assert!(idx < 3);
+
+        let mb = self.0.tx(idx);
+        mb.tdtr().write(|w| w.set_dlc(frame.header().len() as u8));
+
+        mb.tdlr()
+            .write(|w| w.0 = u32::from_ne_bytes(frame.data()[0..4].try_into().unwrap()));
+        mb.tdhr()
+            .write(|w| w.0 = u32::from_ne_bytes(frame.data()[4..8].try_into().unwrap()));
+        let id: IdReg = frame.id().into();
+        mb.tir().write(|w| {
+            w.0 = id.0;
+            w.set_txrq(true);
+        });
+    }
+
+    fn read_pending_mailbox(&mut self, idx: usize) -> Option<Frame> {
+        if self.abort_by_index(idx) {
+            debug_assert!(idx < 3);
+
+            let mb = self.0.tx(idx);
+
+            let id = IdReg(mb.tir().read().0);
+            let mut data = [0xff; 8];
+            data[0..4].copy_from_slice(&mb.tdlr().read().0.to_ne_bytes());
+            data[4..8].copy_from_slice(&mb.tdhr().read().0.to_ne_bytes());
+            let len = mb.tdtr().read().dlc();
+
+            Some(Frame::new(Header::new(id.id(), len, id.rtr()), &data).unwrap())
+        } else {
+            // Abort request failed because the frame was already sent (or being sent) on
+            // the bus. All mailboxes are now free. This can happen for small prescaler
+            // values (e.g. 1MBit/s bit timing with a source clock of 8MHz) or when an ISR
+            // has preempted the execution.
+            None
+        }
+    }
+
+    /// Tries to abort a pending frame. Returns `true` when aborted.
+    fn abort_by_index(&mut self, idx: usize) -> bool {
+        self.0.tsr().write(|reg| reg.set_abrq(idx, true));
+
+        // Wait for the abort request to be finished.
+        loop {
+            let tsr = self.0.tsr().read();
+            if false == tsr.abrq(idx) {
+                break tsr.txok(idx) == false;
+            }
+        }
+    }
+
+    /// Attempts to abort the sending of a frame that is pending in a mailbox.
+    ///
+    /// If there is no frame in the provided mailbox, or its transmission succeeds before it can be
+    /// aborted, this function has no effect and returns `false`.
+    ///
+    /// If there is a frame in the provided mailbox, and it is canceled successfully, this function
+    /// returns `true`.
+    pub fn abort(&mut self, mailbox: Mailbox) -> bool {
+        // If the mailbox is empty, the value of TXOKx depends on what happened with the previous
+        // frame in that mailbox. Only call abort_by_index() if the mailbox is not empty.
+        let tsr = self.0.tsr().read();
+        let mailbox_empty = match mailbox {
+            Mailbox::Mailbox0 => tsr.tme(0),
+            Mailbox::Mailbox1 => tsr.tme(1),
+            Mailbox::Mailbox2 => tsr.tme(2),
+        };
+        if mailbox_empty {
+            false
+        } else {
+            self.abort_by_index(mailbox as usize)
+        }
+    }
+
+    /// Returns `true` if no frame is pending for transmission.
+    pub fn is_idle(&self) -> bool {
+        let tsr = self.0.tsr().read();
+        tsr.tme(0) && tsr.tme(1) && tsr.tme(2)
+    }
+
+    pub fn receive_frame_available(&self) -> bool {
+        if self.0.rfr(0).read().fmp() != 0 {
+            true
+        } else if self.0.rfr(1).read().fmp() != 0 {
+            true
+        } else {
+            false
+        }
+    }
+
+    pub fn receive_fifo(&self, fifo: RxFifo) -> Option<Envelope> {
+        // Generate timestamp as early as possible
+        #[cfg(feature = "time")]
+        let ts = embassy_time::Instant::now();
+
+        use crate::pac::can::vals::Ide;
+
+        let fifo_idx = match fifo {
+            RxFifo::Fifo0 => 0usize,
+            RxFifo::Fifo1 => 1usize,
+        };
+        let rfr = self.0.rfr(fifo_idx);
+        let fifo = self.0.rx(fifo_idx);
+
+        // If there are no pending messages, there is nothing to do
+        if rfr.read().fmp() == 0 {
+            return None;
+        }
+
+        let rir = fifo.rir().read();
+        let id: embedded_can::Id = if rir.ide() == Ide::STANDARD {
+            embedded_can::StandardId::new(rir.stid()).unwrap().into()
+        } else {
+            let stid = (rir.stid() & 0x7FF) as u32;
+            let exid = rir.exid() & 0x3FFFF;
+            let id = (stid << 18) | (exid);
+            embedded_can::ExtendedId::new(id).unwrap().into()
+        };
+        let rdtr = fifo.rdtr().read();
+        let data_len = rdtr.dlc();
+        let rtr = rir.rtr() == stm32_metapac::can::vals::Rtr::REMOTE;
+
+        #[cfg(not(feature = "time"))]
+        let ts = rdtr.time();
+
+        let mut data: [u8; 8] = [0; 8];
+        data[0..4].copy_from_slice(&fifo.rdlr().read().0.to_ne_bytes());
+        data[4..8].copy_from_slice(&fifo.rdhr().read().0.to_ne_bytes());
+
+        let frame = Frame::new(Header::new(id, data_len, rtr), &data).unwrap();
+        let envelope = Envelope { ts, frame };
+
+        rfr.modify(|v| v.set_rfom(true));
+
+        Some(envelope)
+    }
+}
+
+/// Identifier of a CAN message.
+///
+/// Can be either a standard identifier (11bit, Range: 0..0x3FF) or a
+/// extendended identifier (29bit , Range: 0..0x1FFFFFFF).
+///
+/// The `Ord` trait can be used to determine the frame’s priority this ID
+/// belongs to.
+/// Lower identifier values have a higher priority. Additionally standard frames
+/// have a higher priority than extended frames and data frames have a higher
+/// priority than remote frames.
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+#[cfg_attr(feature = "defmt", derive(defmt::Format))]
+pub(crate) struct IdReg(u32);
+
+impl IdReg {
+    const STANDARD_SHIFT: u32 = 21;
+
+    const EXTENDED_SHIFT: u32 = 3;
+
+    const IDE_MASK: u32 = 0x0000_0004;
+
+    const RTR_MASK: u32 = 0x0000_0002;
+
+    /// Creates a new standard identifier (11bit, Range: 0..0x7FF)
+    ///
+    /// Panics for IDs outside the allowed range.
+    fn new_standard(id: StandardId) -> Self {
+        Self(u32::from(id.as_raw()) << Self::STANDARD_SHIFT)
+    }
+
+    /// Creates a new extendended identifier (29bit , Range: 0..0x1FFFFFFF).
+    ///
+    /// Panics for IDs outside the allowed range.
+    fn new_extended(id: ExtendedId) -> IdReg {
+        Self(id.as_raw() << Self::EXTENDED_SHIFT | Self::IDE_MASK)
+    }
+
+    fn from_register(reg: u32) -> IdReg {
+        Self(reg & 0xFFFF_FFFE)
+    }
+
+    /// Returns the identifier.
+    fn to_id(self) -> Id {
+        if self.is_extended() {
+            Id::Extended(unsafe { ExtendedId::new_unchecked(self.0 >> Self::EXTENDED_SHIFT) })
+        } else {
+            Id::Standard(unsafe { StandardId::new_unchecked((self.0 >> Self::STANDARD_SHIFT) as u16) })
+        }
+    }
+
+    /// Returns the identifier.
+    fn id(self) -> embedded_can::Id {
+        if self.is_extended() {
+            embedded_can::ExtendedId::new(self.0 >> Self::EXTENDED_SHIFT)
+                .unwrap()
+                .into()
+        } else {
+            embedded_can::StandardId::new((self.0 >> Self::STANDARD_SHIFT) as u16)
+                .unwrap()
+                .into()
+        }
+    }
+
+    /// Returns `true` if the identifier is an extended identifier.
+    fn is_extended(self) -> bool {
+        self.0 & Self::IDE_MASK != 0
+    }
+
+    /// Returns `true` if the identifer is part of a remote frame (RTR bit set).
+    fn rtr(self) -> bool {
+        self.0 & Self::RTR_MASK != 0
+    }
+}
+
+impl From<&embedded_can::Id> for IdReg {
+    fn from(eid: &embedded_can::Id) -> Self {
+        match eid {
+            embedded_can::Id::Standard(id) => IdReg::new_standard(StandardId::new(id.as_raw()).unwrap()),
+            embedded_can::Id::Extended(id) => IdReg::new_extended(ExtendedId::new(id.as_raw()).unwrap()),
+        }
+    }
+}
+
+impl From<IdReg> for embedded_can::Id {
+    fn from(idr: IdReg) -> Self {
+        idr.id()
+    }
+}
+
+/// `IdReg` is ordered by priority.
+impl Ord for IdReg {
+    fn cmp(&self, other: &Self) -> Ordering {
+        // When the IDs match, data frames have priority over remote frames.
+        let rtr = self.rtr().cmp(&other.rtr()).reverse();
+
+        let id_a = self.to_id();
+        let id_b = other.to_id();
+        match (id_a, id_b) {
+            (Id::Standard(a), Id::Standard(b)) => {
+                // Lower IDs have priority over higher IDs.
+                a.as_raw().cmp(&b.as_raw()).reverse().then(rtr)
+            }
+            (Id::Extended(a), Id::Extended(b)) => a.as_raw().cmp(&b.as_raw()).reverse().then(rtr),
+            (Id::Standard(a), Id::Extended(b)) => {
+                // Standard frames have priority over extended frames if their Base IDs match.
+                a.as_raw()
+                    .cmp(&b.standard_id().as_raw())
+                    .reverse()
+                    .then(Ordering::Greater)
+            }
+            (Id::Extended(a), Id::Standard(b)) => {
+                a.standard_id().as_raw().cmp(&b.as_raw()).reverse().then(Ordering::Less)
+            }
+        }
+    }
+}
+
+impl PartialOrd for IdReg {
+    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+        Some(self.cmp(other))
+    }
+}
+
+#[derive(Debug, Copy, Clone, Eq, PartialEq)]
+pub(crate) enum RxFifo {
+    Fifo0,
+    Fifo1,
+}
diff --git a/embassy-stm32/src/can/common.rs b/embassy-stm32/src/can/common.rs
index 570761b19..a54b54f6e 100644
--- a/embassy-stm32/src/can/common.rs
+++ b/embassy-stm32/src/can/common.rs
@@ -1,7 +1,7 @@
 use embassy_sync::channel::{DynamicReceiver, DynamicSender};
 
-use crate::can::_version::enums::*;
-use crate::can::_version::frame::*;
+use super::enums::*;
+use super::frame::*;
 
 pub(crate) struct ClassicBufferedRxInner {
     pub rx_sender: DynamicSender<'static, Result<Envelope, BusError>>,
diff --git a/embassy-stm32/src/can/fdcan.rs b/embassy-stm32/src/can/fdcan.rs
index 2ccf4b093..e31821ca2 100644
--- a/embassy-stm32/src/can/fdcan.rs
+++ b/embassy-stm32/src/can/fdcan.rs
@@ -14,19 +14,15 @@ use crate::interrupt::typelevel::Interrupt;
 use crate::rcc::RccPeripheral;
 use crate::{interrupt, peripherals, Peripheral};
 
-mod common;
-pub mod enums;
 pub(crate) mod fd;
-pub mod frame;
-mod util;
 
-use enums::*;
-use fd::config::*;
-use fd::filter::*;
-pub use fd::{config, filter};
-use frame::*;
-
-pub use self::common::{BufferedCanReceiver, BufferedCanSender};
+use self::fd::config::*;
+use self::fd::filter::*;
+pub use self::fd::{config, filter};
+pub use super::common::{BufferedCanReceiver, BufferedCanSender};
+use super::enums::*;
+use super::frame::*;
+use super::util;
 
 /// Timestamp for incoming packets. Use Embassy time when enabled.
 #[cfg(feature = "time")]
@@ -439,10 +435,10 @@ impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize>
     fn setup(self) -> Self {
         // We don't want interrupts being processed while we change modes.
         critical_section::with(|_| unsafe {
-            let rx_inner = self::common::ClassicBufferedRxInner {
+            let rx_inner = super::common::ClassicBufferedRxInner {
                 rx_sender: self.rx_buf.sender().into(),
             };
-            let tx_inner = self::common::ClassicBufferedTxInner {
+            let tx_inner = super::common::ClassicBufferedTxInner {
                 tx_receiver: self.tx_buf.receiver().into(),
             };
             T::mut_state().rx_mode = RxMode::ClassicBuffered(rx_inner);
@@ -555,10 +551,10 @@ impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize>
     fn setup(self) -> Self {
         // We don't want interrupts being processed while we change modes.
         critical_section::with(|_| unsafe {
-            let rx_inner = self::common::FdBufferedRxInner {
+            let rx_inner = super::common::FdBufferedRxInner {
                 rx_sender: self.rx_buf.sender().into(),
             };
-            let tx_inner = self::common::FdBufferedTxInner {
+            let tx_inner = super::common::FdBufferedTxInner {
                 tx_receiver: self.tx_buf.receiver().into(),
             };
             T::mut_state().rx_mode = RxMode::FdBuffered(rx_inner);
@@ -649,8 +645,8 @@ impl<'c, 'd, T: Instance> CanRx<'d, T> {
 
 enum RxMode {
     NonBuffered(AtomicWaker),
-    ClassicBuffered(self::common::ClassicBufferedRxInner),
-    FdBuffered(self::common::FdBufferedRxInner),
+    ClassicBuffered(super::common::ClassicBufferedRxInner),
+    FdBuffered(super::common::FdBufferedRxInner),
 }
 
 impl RxMode {
@@ -758,8 +754,8 @@ impl RxMode {
 
 enum TxMode {
     NonBuffered(AtomicWaker),
-    ClassicBuffered(self::common::ClassicBufferedTxInner),
-    FdBuffered(self::common::FdBufferedTxInner),
+    ClassicBuffered(super::common::ClassicBufferedTxInner),
+    FdBuffered(super::common::FdBufferedTxInner),
 }
 
 impl TxMode {
diff --git a/embassy-stm32/src/can/mod.rs b/embassy-stm32/src/can/mod.rs
index 915edb3a6..410a6bfcb 100644
--- a/embassy-stm32/src/can/mod.rs
+++ b/embassy-stm32/src/can/mod.rs
@@ -1,7 +1,14 @@
 //! Controller Area Network (CAN)
 #![macro_use]
 
-#[cfg_attr(can_bxcan, path = "bxcan.rs")]
+#[cfg_attr(can_bxcan, path = "bxcan/mod.rs")]
 #[cfg_attr(any(can_fdcan_v1, can_fdcan_h7), path = "fdcan.rs")]
 mod _version;
 pub use _version::*;
+
+mod common;
+pub mod enums;
+pub mod frame;
+pub mod util;
+
+pub use frame::Frame;
diff --git a/examples/stm32f1/src/bin/can.rs b/examples/stm32f1/src/bin/can.rs
index 90cb9e46b..1c13d623d 100644
--- a/examples/stm32f1/src/bin/can.rs
+++ b/examples/stm32f1/src/bin/can.rs
@@ -3,8 +3,9 @@
 
 use defmt::*;
 use embassy_executor::Spawner;
+use embassy_stm32::can::frame::Envelope;
 use embassy_stm32::can::{
-    filter, Can, Envelope, Fifo, Frame, Id, Rx0InterruptHandler, Rx1InterruptHandler, SceInterruptHandler, StandardId,
+    filter, Can, Fifo, Frame, Id, Rx0InterruptHandler, Rx1InterruptHandler, SceInterruptHandler, StandardId,
     TxInterruptHandler,
 };
 use embassy_stm32::peripherals::CAN;
@@ -55,17 +56,13 @@ async fn main(_spawner: Spawner) {
 
     let mut can = Can::new(p.CAN, p.PB8, p.PB9, Irqs);
 
-    can.as_mut()
-        .modify_filters()
+    can.modify_filters()
         .enable_bank(0, Fifo::Fifo0, filter::Mask32::accept_all());
 
-    can.as_mut()
-        .modify_config()
+    can.modify_config()
         .set_loopback(false)
         .set_silent(false)
-        .leave_disabled();
-
-    can.set_bitrate(250_000);
+        .set_bitrate(250_000);
 
     can.enable().await;
     let mut i: u8 = 0;
diff --git a/examples/stm32f4/src/bin/can.rs b/examples/stm32f4/src/bin/can.rs
index 71b9453eb..cedc057a7 100644
--- a/examples/stm32f4/src/bin/can.rs
+++ b/examples/stm32f4/src/bin/can.rs
@@ -35,17 +35,12 @@ async fn main(_spawner: Spawner) {
 
     let mut can = Can::new(p.CAN1, p.PA11, p.PA12, Irqs);
 
-    can.as_mut()
-        .modify_filters()
-        .enable_bank(0, Fifo::Fifo0, Mask32::accept_all());
+    can.modify_filters().enable_bank(0, Fifo::Fifo0, Mask32::accept_all());
 
-    can.as_mut()
-        .modify_config()
+    can.modify_config()
         .set_loopback(true) // Receive own frames
         .set_silent(true)
-        .leave_disabled();
-
-    can.set_bitrate(1_000_000);
+        .set_bitrate(1_000_000);
 
     can.enable().await;
 
diff --git a/examples/stm32f7/src/bin/can.rs b/examples/stm32f7/src/bin/can.rs
index 221ac2a05..e32b4d3df 100644
--- a/examples/stm32f7/src/bin/can.rs
+++ b/examples/stm32f7/src/bin/can.rs
@@ -47,20 +47,18 @@ async fn main(spawner: Spawner) {
 
     static CAN: StaticCell<Can<'static, CAN3>> = StaticCell::new();
     let can = CAN.init(Can::new(p.CAN3, p.PA8, p.PA15, Irqs));
-    can.as_mut()
-        .modify_filters()
-        .enable_bank(0, Fifo::Fifo0, Mask32::accept_all());
+    can.modify_filters().enable_bank(0, Fifo::Fifo0, Mask32::accept_all());
 
-    can.as_mut()
-        .modify_config()
+    can.modify_config()
         .set_bit_timing(can::util::NominalBitTiming {
             prescaler: NonZeroU16::new(2).unwrap(),
             seg1: NonZeroU8::new(13).unwrap(),
             seg2: NonZeroU8::new(2).unwrap(),
             sync_jump_width: NonZeroU8::new(1).unwrap(),
         }) // http://www.bittiming.can-wiki.info/
-        .set_loopback(true)
-        .enable();
+        .set_loopback(true);
+
+    can.enable().await;
 
     let (tx, mut rx) = can.split();
 
diff --git a/tests/stm32/src/bin/can.rs b/tests/stm32/src/bin/can.rs
index 74d84c42f..551764458 100644
--- a/tests/stm32/src/bin/can.rs
+++ b/tests/stm32/src/bin/can.rs
@@ -8,9 +8,10 @@ mod common;
 use common::*;
 use embassy_executor::Spawner;
 use embassy_stm32::bind_interrupts;
-use embassy_stm32::can::bx::filter::Mask32;
-use embassy_stm32::can::bx::Fifo;
-use embassy_stm32::can::{Can, Rx0InterruptHandler, Rx1InterruptHandler, SceInterruptHandler, TxInterruptHandler};
+use embassy_stm32::can::filter::Mask32;
+use embassy_stm32::can::{
+    Can, Fifo, Rx0InterruptHandler, Rx1InterruptHandler, SceInterruptHandler, TxInterruptHandler,
+};
 use embassy_stm32::gpio::{Input, Pull};
 use embassy_stm32::peripherals::CAN1;
 use embassy_time::Duration;
@@ -51,17 +52,15 @@ async fn main(_spawner: Spawner) {
 
     info!("Configuring can...");
 
-    can.as_mut()
-        .modify_filters()
-        .enable_bank(0, Fifo::Fifo0, Mask32::accept_all());
+    can.modify_filters().enable_bank(0, Fifo::Fifo0, Mask32::accept_all());
 
-    can.set_bitrate(1_000_000);
-    can.as_mut()
-        .modify_config()
+    can.modify_config()
         .set_loopback(true) // Receive own frames
         .set_silent(true)
         // .set_bit_timing(0x001c0003)
-        .enable();
+        .set_bitrate(1_000_000);
+
+    can.enable().await;
 
     info!("Can configured");