diff --git a/embassy-stm32/src/can/bx/mod.rs b/embassy-stm32/src/can/bx/mod.rs
index c508ef2fe..253bcee13 100644
--- a/embassy-stm32/src/can/bx/mod.rs
+++ b/embassy-stm32/src/can/bx/mod.rs
@@ -40,12 +40,11 @@ pub type Header = crate::can::frame::Header;
 /// Data for a CAN Frame
 pub type Data = crate::can::frame::ClassicData;
 
-/// CAN Frame
-pub type Frame = crate::can::frame::ClassicFrame;
-
 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)]
diff --git a/embassy-stm32/src/can/bxcan.rs b/embassy-stm32/src/can/bxcan.rs
index be2e34963..fd6a79092 100644
--- a/embassy-stm32/src/can/bxcan.rs
+++ b/embassy-stm32/src/can/bxcan.rs
@@ -19,22 +19,10 @@ 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, Timestamp};
-
-/// Contains CAN frame and additional metadata.
-///
-/// Timestamp is available if `time` feature is enabled.
-#[derive(Debug, Clone)]
-#[cfg_attr(feature = "defmt", derive(defmt::Format))]
-pub struct Envelope {
-    /// Reception time.
-    #[cfg(feature = "time")]
-    pub ts: embassy_time::Instant,
-    /// The actual CAN frame.
-    pub frame: Frame,
-}
+pub use self::common::{BufferedCanReceiver, BufferedCanSender};
 
 /// Interrupt handler.
 pub struct TxInterruptHandler<T: Instance> {
@@ -276,7 +264,7 @@ impl<'d, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> Buffer
     }
 
     /// Async read frame from RX buffer.
-    pub async fn read(&mut self) -> Result<(Frame, Timestamp), BusError> {
+    pub async fn read(&mut self) -> Result<Envelope, BusError> {
         self.rx.read().await
     }
 
@@ -482,8 +470,7 @@ impl<'d, T: Instance> CanRx<'d, T> {
 }
 
 /// User supplied buffer for RX Buffering
-pub type RxBuf<const BUF_SIZE: usize> =
-    Channel<CriticalSectionRawMutex, Result<(Frame, Timestamp), BusError>, BUF_SIZE>;
+pub type RxBuf<const BUF_SIZE: usize> = Channel<CriticalSectionRawMutex, Result<Envelope, BusError>, BUF_SIZE>;
 
 /// CAN driver, receive half in Buffered mode.
 pub struct BufferedCanRx<'d, T: Instance, const RX_BUF_SIZE: usize> {
@@ -508,7 +495,7 @@ impl<'d, T: Instance, const RX_BUF_SIZE: usize> BufferedCanRx<'d, T, RX_BUF_SIZE
     }
 
     /// Async read frame from RX buffer.
-    pub async fn read(&mut self) -> Result<(Frame, Timestamp), BusError> {
+    pub async fn read(&mut self) -> Result<Envelope, BusError> {
         self.rx_buf.receive().await
     }
 
@@ -520,7 +507,7 @@ impl<'d, T: Instance, const RX_BUF_SIZE: usize> BufferedCanRx<'d, T, RX_BUF_SIZE
             RxMode::Buffered(_) => {
                 if let Ok(result) = self.rx_buf.try_receive() {
                     match result {
-                        Ok((frame, ts)) => Ok(Envelope { ts, frame }),
+                        Ok(envelope) => Ok(envelope),
                         Err(e) => Err(TryReadError::BusError(e)),
                     }
                 } else {
@@ -610,7 +597,7 @@ impl RxMode {
                     match regsisters.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.frame, envelope.ts)));
+                            let _ = buf.rx_sender.try_send(Ok(envelope));
                         }
                         None => return,
                     };
diff --git a/embassy-stm32/src/can/common.rs b/embassy-stm32/src/can/common.rs
index b0d177a6d..570761b19 100644
--- a/embassy-stm32/src/can/common.rs
+++ b/embassy-stm32/src/can/common.rs
@@ -3,25 +3,17 @@ use embassy_sync::channel::{DynamicReceiver, DynamicSender};
 use crate::can::_version::enums::*;
 use crate::can::_version::frame::*;
 
-/// Timestamp for incoming packets. Use Embassy time when enabled.
-#[cfg(feature = "time")]
-pub type Timestamp = embassy_time::Instant;
-
-/// Timestamp for incoming packets.
-#[cfg(not(feature = "time"))]
-pub type Timestamp = u16;
-
 pub(crate) struct ClassicBufferedRxInner {
-    pub rx_sender: DynamicSender<'static, Result<(ClassicFrame, Timestamp), BusError>>,
+    pub rx_sender: DynamicSender<'static, Result<Envelope, BusError>>,
 }
 pub(crate) struct ClassicBufferedTxInner {
-    pub tx_receiver: DynamicReceiver<'static, ClassicFrame>,
+    pub tx_receiver: DynamicReceiver<'static, Frame>,
 }
 
 #[cfg(any(can_fdcan_v1, can_fdcan_h7))]
 
 pub(crate) struct FdBufferedRxInner {
-    pub rx_sender: DynamicSender<'static, Result<(FdFrame, Timestamp), BusError>>,
+    pub rx_sender: DynamicSender<'static, Result<FdEnvelope, BusError>>,
 }
 
 #[cfg(any(can_fdcan_v1, can_fdcan_h7))]
@@ -32,20 +24,20 @@ pub(crate) struct FdBufferedTxInner {
 /// Sender that can be used for sending CAN frames.
 #[derive(Copy, Clone)]
 pub struct BufferedCanSender {
-    pub(crate) tx_buf: embassy_sync::channel::DynamicSender<'static, ClassicFrame>,
+    pub(crate) tx_buf: embassy_sync::channel::DynamicSender<'static, Frame>,
     pub(crate) waker: fn(),
 }
 
 impl BufferedCanSender {
     /// Async write frame to TX buffer.
-    pub fn try_write(&mut self, frame: ClassicFrame) -> Result<(), embassy_sync::channel::TrySendError<ClassicFrame>> {
+    pub fn try_write(&mut self, frame: Frame) -> Result<(), embassy_sync::channel::TrySendError<Frame>> {
         self.tx_buf.try_send(frame)?;
         (self.waker)();
         Ok(())
     }
 
     /// Async write frame to TX buffer.
-    pub async fn write(&mut self, frame: ClassicFrame) {
+    pub async fn write(&mut self, frame: Frame) {
         self.tx_buf.send(frame).await;
         (self.waker)();
     }
@@ -57,5 +49,4 @@ impl BufferedCanSender {
 }
 
 /// Receiver that can be used for receiving CAN frames. Note, each CAN frame will only be received by one receiver.
-pub type BufferedCanReceiver =
-    embassy_sync::channel::DynamicReceiver<'static, Result<(ClassicFrame, Timestamp), BusError>>;
+pub type BufferedCanReceiver = embassy_sync::channel::DynamicReceiver<'static, Result<Envelope, BusError>>;
diff --git a/embassy-stm32/src/can/fd/peripheral.rs b/embassy-stm32/src/can/fd/peripheral.rs
index 76b76afe1..e32f19d91 100644
--- a/embassy-stm32/src/can/fd/peripheral.rs
+++ b/embassy-stm32/src/can/fd/peripheral.rs
@@ -397,13 +397,13 @@ impl Registers {
 
     /// Moves out of ConfigMode and into specified mode
     #[inline]
-    pub fn into_mode(mut self, config: FdCanConfig, mode: crate::can::_version::FdcanOperatingMode) {
+    pub fn into_mode(mut self, config: FdCanConfig, mode: crate::can::_version::OperatingMode) {
         match mode {
-            crate::can::FdcanOperatingMode::InternalLoopbackMode => self.set_loopback_mode(LoopbackMode::Internal),
-            crate::can::FdcanOperatingMode::ExternalLoopbackMode => self.set_loopback_mode(LoopbackMode::External),
-            crate::can::FdcanOperatingMode::NormalOperationMode => self.set_normal_operations(true),
-            crate::can::FdcanOperatingMode::RestrictedOperationMode => self.set_restricted_operations(true),
-            crate::can::FdcanOperatingMode::BusMonitoringMode => self.set_bus_monitoring_mode(true),
+            crate::can::OperatingMode::InternalLoopbackMode => self.set_loopback_mode(LoopbackMode::Internal),
+            crate::can::OperatingMode::ExternalLoopbackMode => self.set_loopback_mode(LoopbackMode::External),
+            crate::can::OperatingMode::NormalOperationMode => self.set_normal_operations(true),
+            crate::can::OperatingMode::RestrictedOperationMode => self.set_restricted_operations(true),
+            crate::can::OperatingMode::BusMonitoringMode => self.set_bus_monitoring_mode(true),
         }
         self.leave_init_mode(config);
     }
diff --git a/embassy-stm32/src/can/fdcan.rs b/embassy-stm32/src/can/fdcan.rs
index e58d8c0ec..2ccf4b093 100644
--- a/embassy-stm32/src/can/fdcan.rs
+++ b/embassy-stm32/src/can/fdcan.rs
@@ -110,7 +110,7 @@ impl<T: Instance> interrupt::typelevel::Handler<T::IT1Interrupt> for IT1Interrup
 #[derive(Debug, Copy, Clone, Eq, PartialEq)]
 #[cfg_attr(feature = "defmt", derive(defmt::Format))]
 /// Different operating modes
-pub enum FdcanOperatingMode {
+pub enum OperatingMode {
     //PoweredDownMode,
     //ConfigMode,
     /// This mode can be used for a “Hot Selftest”, meaning the FDCAN can be tested without
@@ -148,7 +148,7 @@ pub enum FdcanOperatingMode {
 
 /// FDCAN Configuration instance instance
 /// Create instance of this first
-pub struct FdcanConfigurator<'d, T: Instance> {
+pub struct CanConfigurator<'d, T: Instance> {
     config: crate::can::fd::config::FdCanConfig,
     /// Reference to internals.
     instance: FdcanInstance<'d, T>,
@@ -169,7 +169,7 @@ fn calc_ns_per_timer_tick<T: Instance>(mode: crate::can::fd::config::FrameTransm
     }
 }
 
-impl<'d, T: Instance> FdcanConfigurator<'d, T> {
+impl<'d, T: Instance> CanConfigurator<'d, T> {
     /// Creates a new Fdcan instance, keeping the peripheral in sleep mode.
     /// You must call [Fdcan::enable_non_blocking] to use the peripheral.
     pub fn new(
@@ -179,7 +179,7 @@ impl<'d, T: Instance> FdcanConfigurator<'d, T> {
         _irqs: impl interrupt::typelevel::Binding<T::IT0Interrupt, IT0InterruptHandler<T>>
             + interrupt::typelevel::Binding<T::IT1Interrupt, IT1InterruptHandler<T>>
             + 'd,
-    ) -> FdcanConfigurator<'d, T> {
+    ) -> CanConfigurator<'d, T> {
         into_ref!(peri, rx, tx);
 
         rx.set_as_af(rx.af_num(), AFType::Input);
@@ -273,13 +273,13 @@ impl<'d, T: Instance> FdcanConfigurator<'d, T> {
     }
 
     /// Start in mode.
-    pub fn start(self, mode: FdcanOperatingMode) -> Fdcan<'d, T> {
+    pub fn start(self, mode: OperatingMode) -> Can<'d, T> {
         let ns_per_timer_tick = calc_ns_per_timer_tick::<T>(self.config.frame_transmit);
         critical_section::with(|_| unsafe {
             T::mut_state().ns_per_timer_tick = ns_per_timer_tick;
         });
         T::registers().into_mode(self.config, mode);
-        let ret = Fdcan {
+        let ret = Can {
             config: self.config,
             instance: self.instance,
             _mode: mode,
@@ -288,30 +288,30 @@ impl<'d, T: Instance> FdcanConfigurator<'d, T> {
     }
 
     /// Start, entering mode. Does same as start(mode)
-    pub fn into_normal_mode(self) -> Fdcan<'d, T> {
-        self.start(FdcanOperatingMode::NormalOperationMode)
+    pub fn into_normal_mode(self) -> Can<'d, T> {
+        self.start(OperatingMode::NormalOperationMode)
     }
 
     /// Start, entering mode. Does same as start(mode)
-    pub fn into_internal_loopback_mode(self) -> Fdcan<'d, T> {
-        self.start(FdcanOperatingMode::InternalLoopbackMode)
+    pub fn into_internal_loopback_mode(self) -> Can<'d, T> {
+        self.start(OperatingMode::InternalLoopbackMode)
     }
 
     /// Start, entering mode. Does same as start(mode)
-    pub fn into_external_loopback_mode(self) -> Fdcan<'d, T> {
-        self.start(FdcanOperatingMode::ExternalLoopbackMode)
+    pub fn into_external_loopback_mode(self) -> Can<'d, T> {
+        self.start(OperatingMode::ExternalLoopbackMode)
     }
 }
 
 /// FDCAN Instance
-pub struct Fdcan<'d, T: Instance> {
+pub struct Can<'d, T: Instance> {
     config: crate::can::fd::config::FdCanConfig,
     /// Reference to internals.
     instance: FdcanInstance<'d, T>,
-    _mode: FdcanOperatingMode,
+    _mode: OperatingMode,
 }
 
-impl<'d, T: Instance> Fdcan<'d, T> {
+impl<'d, T: Instance> Can<'d, T> {
     /// Flush one of the TX mailboxes.
     pub async fn flush(&self, idx: usize) {
         poll_fn(|cx| {
@@ -334,12 +334,12 @@ impl<'d, T: Instance> Fdcan<'d, T> {
     /// frame is dropped from the mailbox, it is returned.  If no lower-priority frames
     /// can be replaced, this call asynchronously waits for a frame to be successfully
     /// transmitted, then tries again.
-    pub async fn write(&mut self, frame: &ClassicFrame) -> Option<ClassicFrame> {
+    pub async fn write(&mut self, frame: &Frame) -> Option<Frame> {
         T::state().tx_mode.write::<T>(frame).await
     }
 
     /// Returns the next received message frame
-    pub async fn read(&mut self) -> Result<(ClassicFrame, Timestamp), BusError> {
+    pub async fn read(&mut self) -> Result<Envelope, BusError> {
         T::state().rx_mode.read_classic::<T>().await
     }
 
@@ -352,19 +352,19 @@ impl<'d, T: Instance> Fdcan<'d, T> {
     }
 
     /// Returns the next received message frame
-    pub async fn read_fd(&mut self) -> Result<(FdFrame, Timestamp), BusError> {
+    pub async fn read_fd(&mut self) -> Result<FdEnvelope, BusError> {
         T::state().rx_mode.read_fd::<T>().await
     }
 
     /// Split instance into separate Tx(write) and Rx(read) portions
-    pub fn split(self) -> (FdcanTx<'d, T>, FdcanRx<'d, T>) {
+    pub fn split(self) -> (CanTx<'d, T>, CanRx<'d, T>) {
         (
-            FdcanTx {
+            CanTx {
                 config: self.config,
                 _instance: self.instance,
                 _mode: self._mode,
             },
-            FdcanRx {
+            CanRx {
                 _instance1: PhantomData::<T>,
                 _instance2: T::regs(),
                 _mode: self._mode,
@@ -373,8 +373,8 @@ impl<'d, T: Instance> Fdcan<'d, T> {
     }
 
     /// Join split rx and tx portions back together
-    pub fn join(tx: FdcanTx<'d, T>, rx: FdcanRx<'d, T>) -> Self {
-        Fdcan {
+    pub fn join(tx: CanTx<'d, T>, rx: CanRx<'d, T>) -> Self {
+        Can {
             config: tx.config,
             //_instance2: T::regs(),
             instance: tx._instance,
@@ -402,17 +402,16 @@ impl<'d, T: Instance> Fdcan<'d, T> {
 }
 
 /// User supplied buffer for RX Buffering
-pub type RxBuf<const BUF_SIZE: usize> =
-    Channel<CriticalSectionRawMutex, Result<(ClassicFrame, Timestamp), BusError>, BUF_SIZE>;
+pub type RxBuf<const BUF_SIZE: usize> = Channel<CriticalSectionRawMutex, Result<Envelope, BusError>, BUF_SIZE>;
 
 /// User supplied buffer for TX buffering
-pub type TxBuf<const BUF_SIZE: usize> = Channel<CriticalSectionRawMutex, ClassicFrame, BUF_SIZE>;
+pub type TxBuf<const BUF_SIZE: usize> = Channel<CriticalSectionRawMutex, Frame, BUF_SIZE>;
 
 /// Buffered FDCAN Instance
 pub struct BufferedCan<'d, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> {
     _instance1: PhantomData<T>,
     _instance2: &'d crate::pac::can::Fdcan,
-    _mode: FdcanOperatingMode,
+    _mode: OperatingMode,
     tx_buf: &'static TxBuf<TX_BUF_SIZE>,
     rx_buf: &'static RxBuf<RX_BUF_SIZE>,
 }
@@ -423,7 +422,7 @@ impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize>
     fn new(
         _instance1: PhantomData<T>,
         _instance2: &'d crate::pac::can::Fdcan,
-        _mode: FdcanOperatingMode,
+        _mode: OperatingMode,
         tx_buf: &'static TxBuf<TX_BUF_SIZE>,
         rx_buf: &'static RxBuf<RX_BUF_SIZE>,
     ) -> Self {
@@ -453,13 +452,13 @@ impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize>
     }
 
     /// Async write frame to TX buffer.
-    pub async fn write(&mut self, frame: ClassicFrame) {
+    pub async fn write(&mut self, frame: Frame) {
         self.tx_buf.send(frame).await;
         T::IT0Interrupt::pend(); // Wake for Tx
     }
 
     /// Async read frame from RX buffer.
-    pub async fn read(&mut self) -> Result<(ClassicFrame, Timestamp), BusError> {
+    pub async fn read(&mut self) -> Result<Envelope, BusError> {
         self.rx_buf.receive().await
     }
 
@@ -489,8 +488,7 @@ impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> Dr
 }
 
 /// User supplied buffer for RX Buffering
-pub type RxFdBuf<const BUF_SIZE: usize> =
-    Channel<CriticalSectionRawMutex, Result<(FdFrame, Timestamp), BusError>, BUF_SIZE>;
+pub type RxFdBuf<const BUF_SIZE: usize> = Channel<CriticalSectionRawMutex, Result<FdEnvelope, BusError>, BUF_SIZE>;
 
 /// User supplied buffer for TX buffering
 pub type TxFdBuf<const BUF_SIZE: usize> = Channel<CriticalSectionRawMutex, FdFrame, BUF_SIZE>;
@@ -499,7 +497,7 @@ pub type TxFdBuf<const BUF_SIZE: usize> = Channel<CriticalSectionRawMutex, FdFra
 pub struct BufferedCanFd<'d, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> {
     _instance1: PhantomData<T>,
     _instance2: &'d crate::pac::can::Fdcan,
-    _mode: FdcanOperatingMode,
+    _mode: OperatingMode,
     tx_buf: &'static TxFdBuf<TX_BUF_SIZE>,
     rx_buf: &'static RxFdBuf<RX_BUF_SIZE>,
 }
@@ -532,7 +530,7 @@ impl BufferedFdCanSender {
 }
 
 /// Receiver that can be used for receiving CAN frames. Note, each CAN frame will only be received by one receiver.
-pub type BufferedFdCanReceiver = DynamicReceiver<'static, Result<(FdFrame, Timestamp), BusError>>;
+pub type BufferedFdCanReceiver = DynamicReceiver<'static, Result<FdEnvelope, BusError>>;
 
 impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize>
     BufferedCanFd<'d, T, TX_BUF_SIZE, RX_BUF_SIZE>
@@ -540,7 +538,7 @@ impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize>
     fn new(
         _instance1: PhantomData<T>,
         _instance2: &'d crate::pac::can::Fdcan,
-        _mode: FdcanOperatingMode,
+        _mode: OperatingMode,
         tx_buf: &'static TxFdBuf<TX_BUF_SIZE>,
         rx_buf: &'static RxFdBuf<RX_BUF_SIZE>,
     ) -> Self {
@@ -576,7 +574,7 @@ impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize>
     }
 
     /// Async read frame from RX buffer.
-    pub async fn read(&mut self) -> Result<(FdFrame, Timestamp), BusError> {
+    pub async fn read(&mut self) -> Result<FdEnvelope, BusError> {
         self.rx_buf.receive().await
     }
 
@@ -606,25 +604,25 @@ impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> Dr
 }
 
 /// FDCAN Rx only Instance
-pub struct FdcanRx<'d, T: Instance> {
+pub struct CanRx<'d, T: Instance> {
     _instance1: PhantomData<T>,
     _instance2: &'d crate::pac::can::Fdcan,
-    _mode: FdcanOperatingMode,
+    _mode: OperatingMode,
 }
 
 /// FDCAN Tx only Instance
-pub struct FdcanTx<'d, T: Instance> {
+pub struct CanTx<'d, T: Instance> {
     config: crate::can::fd::config::FdCanConfig,
     _instance: FdcanInstance<'d, T>, //(PeripheralRef<'a, T>);
-    _mode: FdcanOperatingMode,
+    _mode: OperatingMode,
 }
 
-impl<'c, 'd, T: Instance> FdcanTx<'d, T> {
+impl<'c, 'd, T: Instance> CanTx<'d, T> {
     /// Queues the message to be sent but exerts backpressure.  If a lower-priority
     /// frame is dropped from the mailbox, it is returned.  If no lower-priority frames
     /// can be replaced, this call asynchronously waits for a frame to be successfully
     /// transmitted, then tries again.
-    pub async fn write(&mut self, frame: &ClassicFrame) -> Option<ClassicFrame> {
+    pub async fn write(&mut self, frame: &Frame) -> Option<Frame> {
         T::state().tx_mode.write::<T>(frame).await
     }
 
@@ -637,14 +635,14 @@ impl<'c, 'd, T: Instance> FdcanTx<'d, T> {
     }
 }
 
-impl<'c, 'd, T: Instance> FdcanRx<'d, T> {
+impl<'c, 'd, T: Instance> CanRx<'d, T> {
     /// Returns the next received message frame
-    pub async fn read(&mut self) -> Result<(ClassicFrame, Timestamp), BusError> {
+    pub async fn read(&mut self) -> Result<Envelope, BusError> {
         T::state().rx_mode.read_classic::<T>().await
     }
 
     /// Returns the next received message frame
-    pub async fn read_fd(&mut self) -> Result<(FdFrame, Timestamp), BusError> {
+    pub async fn read_fd(&mut self) -> Result<FdEnvelope, BusError> {
         T::state().rx_mode.read_fd::<T>().await
     }
 }
@@ -672,18 +670,50 @@ impl RxMode {
                 waker.wake();
             }
             RxMode::ClassicBuffered(buf) => {
-                if let Some(result) = self.read::<T, _>() {
+                if let Some(result) = self.try_read::<T>() {
                     let _ = buf.rx_sender.try_send(result);
                 }
             }
             RxMode::FdBuffered(buf) => {
-                if let Some(result) = self.read::<T, _>() {
+                if let Some(result) = self.try_read_fd::<T>() {
                     let _ = buf.rx_sender.try_send(result);
                 }
             }
         }
     }
 
+    //async fn read_classic<T: Instance>(&self) -> Result<Envelope, BusError> {
+    fn try_read<T: Instance>(&self) -> Option<Result<Envelope, BusError>> {
+        if let Some((frame, ts)) = T::registers().read(0) {
+            let ts = T::calc_timestamp(T::state().ns_per_timer_tick, ts);
+            Some(Ok(Envelope { ts, frame }))
+        } else if let Some((frame, ts)) = T::registers().read(1) {
+            let ts = T::calc_timestamp(T::state().ns_per_timer_tick, ts);
+            Some(Ok(Envelope { ts, frame }))
+        } else if let Some(err) = T::registers().curr_error() {
+            // TODO: this is probably wrong
+            Some(Err(err))
+        } else {
+            None
+        }
+    }
+
+    //async fn read_classic<T: Instance>(&self) -> Result<Envelope, BusError> {
+    fn try_read_fd<T: Instance>(&self) -> Option<Result<FdEnvelope, BusError>> {
+        if let Some((frame, ts)) = T::registers().read(0) {
+            let ts = T::calc_timestamp(T::state().ns_per_timer_tick, ts);
+            Some(Ok(FdEnvelope { ts, frame }))
+        } else if let Some((frame, ts)) = T::registers().read(1) {
+            let ts = T::calc_timestamp(T::state().ns_per_timer_tick, ts);
+            Some(Ok(FdEnvelope { ts, frame }))
+        } else if let Some(err) = T::registers().curr_error() {
+            // TODO: this is probably wrong
+            Some(Err(err))
+        } else {
+            None
+        }
+    }
+
     fn read<T: Instance, F: CanHeader>(&self) -> Option<Result<(F, Timestamp), BusError>> {
         if let Some((msg, ts)) = T::registers().read(0) {
             let ts = T::calc_timestamp(T::state().ns_per_timer_tick, ts);
@@ -711,12 +741,18 @@ impl RxMode {
         .await
     }
 
-    async fn read_classic<T: Instance>(&self) -> Result<(ClassicFrame, Timestamp), BusError> {
-        self.read_async::<T, _>().await
+    async fn read_classic<T: Instance>(&self) -> Result<Envelope, BusError> {
+        match self.read_async::<T, _>().await {
+            Ok((frame, ts)) => Ok(Envelope { ts, frame }),
+            Err(e) => Err(e),
+        }
     }
 
-    async fn read_fd<T: Instance>(&self) -> Result<(FdFrame, Timestamp), BusError> {
-        self.read_async::<T, _>().await
+    async fn read_fd<T: Instance>(&self) -> Result<FdEnvelope, BusError> {
+        match self.read_async::<T, _>().await {
+            Ok((frame, ts)) => Ok(FdEnvelope { ts, frame }),
+            Err(e) => Err(e),
+        }
     }
 }
 
@@ -761,7 +797,7 @@ impl TxMode {
     /// frame is dropped from the mailbox, it is returned.  If no lower-priority frames
     /// can be replaced, this call asynchronously waits for a frame to be successfully
     /// transmitted, then tries again.
-    async fn write<T: Instance>(&self, frame: &ClassicFrame) -> Option<ClassicFrame> {
+    async fn write<T: Instance>(&self, frame: &Frame) -> Option<Frame> {
         self.write_generic::<T, _>(frame).await
     }
 
diff --git a/embassy-stm32/src/can/frame.rs b/embassy-stm32/src/can/frame.rs
index 14fc32c51..fb032aee2 100644
--- a/embassy-stm32/src/can/frame.rs
+++ b/embassy-stm32/src/can/frame.rs
@@ -136,19 +136,20 @@ impl ClassicData {
     }
 }
 
-/// Frame with up to 8 bytes of data payload as per Classic CAN
+/// Frame with up to 8 bytes of data payload as per Classic(non-FD) CAN
+/// For CAN-FD support use FdFrame
 #[derive(Debug, Copy, Clone)]
 #[cfg_attr(feature = "defmt", derive(defmt::Format))]
-pub struct ClassicFrame {
+pub struct Frame {
     can_header: Header,
     data: ClassicData,
 }
 
-impl ClassicFrame {
+impl Frame {
     /// Create a new CAN classic Frame
     pub fn new(can_header: Header, raw_data: &[u8]) -> Result<Self, FrameCreateError> {
         let data = ClassicData::new(raw_data)?;
-        Ok(ClassicFrame { can_header, data: data })
+        Ok(Frame { can_header, data: data })
     }
 
     /// Creates a new data frame.
@@ -206,9 +207,9 @@ impl ClassicFrame {
     }
 }
 
-impl embedded_can::Frame for ClassicFrame {
+impl embedded_can::Frame for Frame {
     fn new(id: impl Into<embedded_can::Id>, raw_data: &[u8]) -> Option<Self> {
-        let frameopt = ClassicFrame::new(Header::new(id.into(), raw_data.len() as u8, false), raw_data);
+        let frameopt = Frame::new(Header::new(id.into(), raw_data.len() as u8, false), raw_data);
         match frameopt {
             Ok(frame) => Some(frame),
             Err(_) => None,
@@ -216,7 +217,7 @@ impl embedded_can::Frame for ClassicFrame {
     }
     fn new_remote(id: impl Into<embedded_can::Id>, len: usize) -> Option<Self> {
         if len <= 8 {
-            let frameopt = ClassicFrame::new(Header::new(id.into(), len as u8, true), &[0; 8]);
+            let frameopt = Frame::new(Header::new(id.into(), len as u8, true), &[0; 8]);
             match frameopt {
                 Ok(frame) => Some(frame),
                 Err(_) => None,
@@ -245,7 +246,7 @@ impl embedded_can::Frame for ClassicFrame {
     }
 }
 
-impl CanHeader for ClassicFrame {
+impl CanHeader for Frame {
     fn from_header(header: Header, data: &[u8]) -> Result<Self, FrameCreateError> {
         Self::new(header, data)
     }
@@ -255,10 +256,32 @@ impl CanHeader for ClassicFrame {
     }
 }
 
+/// Contains CAN frame and additional metadata.
+///
+/// Timestamp is available if `time` feature is enabled.
+/// For CAN-FD support use FdEnvelope
+#[derive(Debug, Clone)]
+#[cfg_attr(feature = "defmt", derive(defmt::Format))]
+pub struct Envelope {
+    /// Reception time.
+    #[cfg(feature = "time")]
+    pub ts: embassy_time::Instant,
+    /// The actual CAN frame.
+    pub frame: Frame,
+}
+
+impl Envelope {
+    /// Convert into a tuple
+    pub fn parts(self) -> (Frame, embassy_time::Instant) {
+        (self.frame, self.ts)
+    }
+}
+
 /// Payload of a (FD)CAN data frame.
 ///
 /// Contains 0 to 64 Bytes of data.
 #[derive(Debug, Copy, Clone)]
+#[cfg_attr(feature = "defmt", derive(defmt::Format))]
 pub struct FdData {
     pub(crate) bytes: [u8; 64],
 }
@@ -308,6 +331,7 @@ impl FdData {
 
 /// Frame with up to 8 bytes of data payload as per Fd CAN
 #[derive(Debug, Copy, Clone)]
+#[cfg_attr(feature = "defmt", derive(defmt::Format))]
 pub struct FdFrame {
     can_header: Header,
     data: FdData,
@@ -410,3 +434,23 @@ impl CanHeader for FdFrame {
         self.header()
     }
 }
+
+/// Contains CAN FD frame and additional metadata.
+///
+/// Timestamp is available if `time` feature is enabled.
+#[derive(Debug, Clone)]
+#[cfg_attr(feature = "defmt", derive(defmt::Format))]
+pub struct FdEnvelope {
+    /// Reception time.
+    #[cfg(feature = "time")]
+    pub ts: embassy_time::Instant,
+    /// The actual CAN frame.
+    pub frame: FdFrame,
+}
+
+impl FdEnvelope {
+    /// Convert into a tuple
+    pub fn parts(self) -> (FdFrame, embassy_time::Instant) {
+        (self.frame, self.ts)
+    }
+}
diff --git a/examples/stm32f1/Cargo.toml b/examples/stm32f1/Cargo.toml
index df5d32f70..4f282f326 100644
--- a/examples/stm32f1/Cargo.toml
+++ b/examples/stm32f1/Cargo.toml
@@ -23,6 +23,7 @@ panic-probe = { version = "0.3", features = ["print-defmt"] }
 futures = { version = "0.3.17", default-features = false, features = ["async-await"] }
 heapless = { version = "0.8", default-features = false }
 nb = "1.0.0"
+static_cell = "2.0.0"
 
 [profile.dev]
 opt-level = "s"
diff --git a/examples/stm32f1/src/bin/can.rs b/examples/stm32f1/src/bin/can.rs
index ac337e8a0..90cb9e46b 100644
--- a/examples/stm32f1/src/bin/can.rs
+++ b/examples/stm32f1/src/bin/can.rs
@@ -4,11 +4,12 @@
 use defmt::*;
 use embassy_executor::Spawner;
 use embassy_stm32::can::{
-    filter, Can, Fifo, Frame, Id, Rx0InterruptHandler, Rx1InterruptHandler, SceInterruptHandler, StandardId,
+    filter, Can, Envelope, Fifo, Frame, Id, Rx0InterruptHandler, Rx1InterruptHandler, SceInterruptHandler, StandardId,
     TxInterruptHandler,
 };
 use embassy_stm32::peripherals::CAN;
 use embassy_stm32::{bind_interrupts, Config};
+use static_cell::StaticCell;
 use {defmt_rtt as _, panic_probe as _};
 
 bind_interrupts!(struct Irqs {
@@ -21,6 +22,27 @@ bind_interrupts!(struct Irqs {
 // This example is configured to work with real CAN transceivers on B8/B9.
 // See other examples for loopback.
 
+fn handle_frame(env: Envelope, read_mode: &str) {
+    match env.frame.id() {
+        Id::Extended(id) => {
+            defmt::println!(
+                "{} Extended Frame id={:x} {:02x}",
+                read_mode,
+                id.as_raw(),
+                env.frame.data()
+            );
+        }
+        Id::Standard(id) => {
+            defmt::println!(
+                "{} Standard Frame id={:x} {:02x}",
+                read_mode,
+                id.as_raw(),
+                env.frame.data()
+            );
+        }
+    }
+}
+
 #[embassy_executor::main]
 async fn main(_spawner: Spawner) {
     let p = embassy_stm32::init(Config::default());
@@ -28,6 +50,9 @@ async fn main(_spawner: Spawner) {
     // Set alternate pin mapping to B8/B9
     embassy_stm32::pac::AFIO.mapr().modify(|w| w.set_can1_remap(2));
 
+    static RX_BUF: StaticCell<embassy_stm32::can::RxBuf<10>> = StaticCell::new();
+    static TX_BUF: StaticCell<embassy_stm32::can::TxBuf<10>> = StaticCell::new();
+
     let mut can = Can::new(p.CAN, p.PB8, p.PB9, Irqs);
 
     can.as_mut()
@@ -43,21 +68,72 @@ async fn main(_spawner: Spawner) {
     can.set_bitrate(250_000);
 
     can.enable().await;
-
     let mut i: u8 = 0;
+
+    /*
+       // Example for using buffered Tx and Rx without needing to
+       // split first as is done below.
+       let mut can = can.buffered(
+           TX_BUF.init(embassy_stm32::can::TxBuf::<10>::new()),
+           RX_BUF.init(embassy_stm32::can::RxBuf::<10>::new()));
+       loop {
+           let tx_frame = Frame::new_data(unwrap!(StandardId::new(i as _)), &[i, 0, 1, 2, 3, 4, 5, 6]).unwrap();
+           can.write(&tx_frame).await;
+
+           match can.read().await {
+               Ok((frame, ts)) => {
+                   handle_frame(Envelope { ts, frame }, "Buf");
+               }
+               Err(err) => {
+                   defmt::println!("Error {}", err);
+               }
+           }
+           i += 1;
+       }
+
+    */
+    let (mut tx, mut rx) = can.split();
+
+    // This example shows using the wait_not_empty API before try read
+    while i < 3 {
+        let tx_frame = Frame::new_data(unwrap!(StandardId::new(i as _)), &[i, 0, 1, 2, 3, 4, 5, 6]).unwrap();
+        tx.write(&tx_frame).await;
+
+        rx.wait_not_empty().await;
+        let env = rx.try_read().unwrap();
+        handle_frame(env, "Wait");
+        i += 1;
+    }
+
+    // This example shows using the full async non-buffered API
+    while i < 6 {
+        let tx_frame = Frame::new_data(unwrap!(StandardId::new(i as _)), &[i, 0, 1, 2, 3, 4, 5, 6]).unwrap();
+        tx.write(&tx_frame).await;
+
+        match rx.read().await {
+            Ok(env) => {
+                handle_frame(env, "NoBuf");
+            }
+            Err(err) => {
+                defmt::println!("Error {}", err);
+            }
+        }
+        i += 1;
+    }
+
+    // This example shows using buffered RX and TX. User passes in desired buffer (size)
+    // It's possible this way to have just RX or TX buffered.
+    let mut rx = rx.buffered(RX_BUF.init(embassy_stm32::can::RxBuf::<10>::new()));
+    let mut tx = tx.buffered(TX_BUF.init(embassy_stm32::can::TxBuf::<10>::new()));
+
     loop {
         let tx_frame = Frame::new_data(unwrap!(StandardId::new(i as _)), &[i, 0, 1, 2, 3, 4, 5, 6]).unwrap();
-        can.write(&tx_frame).await;
+        tx.write(&tx_frame).await;
 
-        match can.read().await {
-            Ok(env) => match env.frame.id() {
-                Id::Extended(id) => {
-                    defmt::println!("Extended Frame id={:x} {:02x}", id.as_raw(), env.frame.data());
-                }
-                Id::Standard(id) => {
-                    defmt::println!("Standard Frame id={:x} {:02x}", id.as_raw(), env.frame.data());
-                }
-            },
+        match rx.read().await {
+            Ok(envelope) => {
+                handle_frame(envelope, "Buf");
+            }
             Err(err) => {
                 defmt::println!("Error {}", err);
             }
diff --git a/examples/stm32g4/src/bin/can.rs b/examples/stm32g4/src/bin/can.rs
index 4373a89a8..2ed632a93 100644
--- a/examples/stm32g4/src/bin/can.rs
+++ b/examples/stm32g4/src/bin/can.rs
@@ -36,7 +36,7 @@ async fn main(_spawner: Spawner) {
     }
     let peripherals = embassy_stm32::init(config);
 
-    let mut can = can::FdcanConfigurator::new(peripherals.FDCAN1, peripherals.PA11, peripherals.PA12, Irqs);
+    let mut can = can::CanConfigurator::new(peripherals.FDCAN1, peripherals.PA11, peripherals.PA12, Irqs);
 
     can.set_extended_filter(
         can::filter::ExtendedFilterSlot::_0,
@@ -56,21 +56,22 @@ async fn main(_spawner: Spawner) {
     info!("Configured");
 
     let mut can = can.start(match use_fd {
-        true => can::FdcanOperatingMode::InternalLoopbackMode,
-        false => can::FdcanOperatingMode::NormalOperationMode,
+        true => can::OperatingMode::InternalLoopbackMode,
+        false => can::OperatingMode::NormalOperationMode,
     });
 
     let mut i = 0;
     let mut last_read_ts = embassy_time::Instant::now();
 
     loop {
-        let frame = can::frame::ClassicFrame::new_extended(0x123456F, &[i; 8]).unwrap();
+        let frame = can::frame::Frame::new_extended(0x123456F, &[i; 8]).unwrap();
         info!("Writing frame");
 
         _ = can.write(&frame).await;
 
         match can.read().await {
-            Ok((rx_frame, ts)) => {
+            Ok(envelope) => {
+                let (ts, rx_frame) = (envelope.ts, envelope.frame);
                 let delta = (ts - last_read_ts).as_millis();
                 last_read_ts = ts;
                 info!(
@@ -105,7 +106,8 @@ async fn main(_spawner: Spawner) {
         }
 
         match can.read_fd().await {
-            Ok((rx_frame, ts)) => {
+            Ok(envelope) => {
+                let (ts, rx_frame) = (envelope.ts, envelope.frame);
                 let delta = (ts - last_read_ts).as_millis();
                 last_read_ts = ts;
                 info!(
@@ -129,12 +131,13 @@ async fn main(_spawner: Spawner) {
     let (mut tx, mut rx) = can.split();
     // With split
     loop {
-        let frame = can::frame::ClassicFrame::new_extended(0x123456F, &[i; 8]).unwrap();
+        let frame = can::frame::Frame::new_extended(0x123456F, &[i; 8]).unwrap();
         info!("Writing frame");
         _ = tx.write(&frame).await;
 
         match rx.read().await {
-            Ok((rx_frame, ts)) => {
+            Ok(envelope) => {
+                let (ts, rx_frame) = (envelope.ts, envelope.frame);
                 let delta = (ts - last_read_ts).as_millis();
                 last_read_ts = ts;
                 info!(
@@ -156,7 +159,7 @@ async fn main(_spawner: Spawner) {
         }
     }
 
-    let can = can::Fdcan::join(tx, rx);
+    let can = can::Can::join(tx, rx);
 
     info!("\n\n\nBuffered\n");
     if use_fd {
@@ -173,7 +176,8 @@ async fn main(_spawner: Spawner) {
             _ = can.write(frame).await;
 
             match can.read().await {
-                Ok((rx_frame, ts)) => {
+                Ok(envelope) => {
+                    let (ts, rx_frame) = (envelope.ts, envelope.frame);
                     let delta = (ts - last_read_ts).as_millis();
                     last_read_ts = ts;
                     info!(
@@ -198,7 +202,7 @@ async fn main(_spawner: Spawner) {
             RX_BUF.init(can::RxBuf::<10>::new()),
         );
         loop {
-            let frame = can::frame::ClassicFrame::new_extended(0x123456F, &[i; 8]).unwrap();
+            let frame = can::frame::Frame::new_extended(0x123456F, &[i; 8]).unwrap();
             info!("Writing frame");
 
             // You can use any of these approaches to send. The writer makes it
@@ -208,7 +212,8 @@ async fn main(_spawner: Spawner) {
             can.writer().write(frame).await;
 
             match can.read().await {
-                Ok((rx_frame, ts)) => {
+                Ok(envelope) => {
+                    let (ts, rx_frame) = (envelope.ts, envelope.frame);
                     let delta = (ts - last_read_ts).as_millis();
                     last_read_ts = ts;
                     info!(
diff --git a/examples/stm32h5/src/bin/can.rs b/examples/stm32h5/src/bin/can.rs
index 643df27f9..dd625c90a 100644
--- a/examples/stm32h5/src/bin/can.rs
+++ b/examples/stm32h5/src/bin/can.rs
@@ -24,7 +24,7 @@ async fn main(_spawner: Spawner) {
 
     let peripherals = embassy_stm32::init(config);
 
-    let mut can = can::FdcanConfigurator::new(peripherals.FDCAN1, peripherals.PA11, peripherals.PA12, Irqs);
+    let mut can = can::CanConfigurator::new(peripherals.FDCAN1, peripherals.PA11, peripherals.PA12, Irqs);
 
     // 250k bps
     can.set_bitrate(250_000);
@@ -38,12 +38,13 @@ async fn main(_spawner: Spawner) {
     let mut last_read_ts = embassy_time::Instant::now();
 
     loop {
-        let frame = can::frame::ClassicFrame::new_extended(0x123456F, &[i; 8]).unwrap();
+        let frame = can::frame::Frame::new_extended(0x123456F, &[i; 8]).unwrap();
         info!("Writing frame");
         _ = can.write(&frame).await;
 
         match can.read().await {
-            Ok((rx_frame, ts)) => {
+            Ok(envelope) => {
+                let (rx_frame, ts) = envelope.parts();
                 let delta = (ts - last_read_ts).as_millis();
                 last_read_ts = ts;
                 info!(
@@ -69,12 +70,13 @@ async fn main(_spawner: Spawner) {
     let (mut tx, mut rx) = can.split();
     // With split
     loop {
-        let frame = can::frame::ClassicFrame::new_extended(0x123456F, &[i; 8]).unwrap();
+        let frame = can::frame::Frame::new_extended(0x123456F, &[i; 8]).unwrap();
         info!("Writing frame");
         _ = tx.write(&frame).await;
 
         match rx.read().await {
-            Ok((rx_frame, ts)) => {
+            Ok(envelope) => {
+                let (rx_frame, ts) = envelope.parts();
                 let delta = (ts - last_read_ts).as_millis();
                 last_read_ts = ts;
                 info!(
diff --git a/examples/stm32h7/src/bin/can.rs b/examples/stm32h7/src/bin/can.rs
index 13a6a5051..22cb27481 100644
--- a/examples/stm32h7/src/bin/can.rs
+++ b/examples/stm32h7/src/bin/can.rs
@@ -24,7 +24,7 @@ async fn main(_spawner: Spawner) {
 
     let peripherals = embassy_stm32::init(config);
 
-    let mut can = can::FdcanConfigurator::new(peripherals.FDCAN1, peripherals.PA11, peripherals.PA12, Irqs);
+    let mut can = can::CanConfigurator::new(peripherals.FDCAN1, peripherals.PA11, peripherals.PA12, Irqs);
 
     // 250k bps
     can.set_bitrate(250_000);
@@ -38,12 +38,13 @@ async fn main(_spawner: Spawner) {
     let mut last_read_ts = embassy_time::Instant::now();
 
     loop {
-        let frame = can::frame::ClassicFrame::new_extended(0x123456F, &[i; 8]).unwrap();
+        let frame = can::frame::Frame::new_extended(0x123456F, &[i; 8]).unwrap();
         info!("Writing frame");
         _ = can.write(&frame).await;
 
         match can.read().await {
-            Ok((rx_frame, ts)) => {
+            Ok(envelope) => {
+                let (rx_frame, ts) = envelope.parts();
                 let delta = (ts - last_read_ts).as_millis();
                 last_read_ts = ts;
                 info!(
@@ -69,12 +70,13 @@ async fn main(_spawner: Spawner) {
     let (mut tx, mut rx) = can.split();
     // With split
     loop {
-        let frame = can::frame::ClassicFrame::new_extended(0x123456F, &[i; 8]).unwrap();
+        let frame = can::frame::Frame::new_extended(0x123456F, &[i; 8]).unwrap();
         info!("Writing frame");
         _ = tx.write(&frame).await;
 
         match rx.read().await {
-            Ok((rx_frame, ts)) => {
+            Ok(envelope) => {
+                let (rx_frame, ts) = envelope.parts();
                 let delta = (ts - last_read_ts).as_millis();
                 last_read_ts = ts;
                 info!(
diff --git a/tests/stm32/src/bin/fdcan.rs b/tests/stm32/src/bin/fdcan.rs
index c7373e294..bddfa7684 100644
--- a/tests/stm32/src/bin/fdcan.rs
+++ b/tests/stm32/src/bin/fdcan.rs
@@ -79,8 +79,8 @@ async fn main(_spawner: Spawner) {
     let options = options();
     let peripherals = embassy_stm32::init(options.config);
 
-    let mut can = can::FdcanConfigurator::new(peripherals.FDCAN1, peripherals.PB8, peripherals.PB9, Irqs1);
-    let mut can2 = can::FdcanConfigurator::new(peripherals.FDCAN2, peripherals.PB12, peripherals.PB13, Irqs2);
+    let mut can = can::CanConfigurator::new(peripherals.FDCAN1, peripherals.PB8, peripherals.PB9, Irqs1);
+    let mut can2 = can::CanConfigurator::new(peripherals.FDCAN2, peripherals.PB12, peripherals.PB13, Irqs2);
 
     // 250k bps
     can.set_bitrate(250_000);
@@ -102,13 +102,13 @@ async fn main(_spawner: Spawner) {
 
     let mut i: u8 = 0;
     loop {
-        let tx_frame = can::frame::ClassicFrame::new_standard(0x123, &[i; 1]).unwrap();
+        let tx_frame = can::frame::Frame::new_standard(0x123, &[i; 1]).unwrap();
 
         info!("Transmitting frame...");
         let tx_ts = Instant::now();
         can.write(&tx_frame).await;
 
-        let (frame, timestamp) = can.read().await.unwrap();
+        let (frame, timestamp) = can.read().await.unwrap().parts();
         info!("Frame received!");
 
         // Check data.
@@ -139,13 +139,13 @@ async fn main(_spawner: Spawner) {
 
     let mut i: u8 = 0;
     loop {
-        let tx_frame = can::frame::ClassicFrame::new_standard(0x123, &[i; 1]).unwrap();
+        let tx_frame = can::frame::Frame::new_standard(0x123, &[i; 1]).unwrap();
 
         info!("Transmitting frame...");
         let tx_ts = Instant::now();
         can2.write(&tx_frame).await;
 
-        let (frame, timestamp) = can2.read().await.unwrap();
+        let (frame, timestamp) = can2.read().await.unwrap().parts();
         info!("Frame received!");
 
         //print_regs().await;
@@ -182,20 +182,20 @@ async fn main(_spawner: Spawner) {
     // in each FIFO so make sure we write enough to fill them both up before reading.
     for i in 0..3 {
         // Try filling up the RX FIFO0 buffers with standard packets
-        let tx_frame = can::frame::ClassicFrame::new_standard(0x123, &[i; 1]).unwrap();
+        let tx_frame = can::frame::Frame::new_standard(0x123, &[i; 1]).unwrap();
         info!("Transmitting frame {}", i);
         can.write(&tx_frame).await;
     }
     for i in 3..max_buffered {
         // Try filling up the RX FIFO0 buffers with extended packets
-        let tx_frame = can::frame::ClassicFrame::new_extended(0x1232344, &[i; 1]).unwrap();
+        let tx_frame = can::frame::Frame::new_extended(0x1232344, &[i; 1]).unwrap();
         info!("Transmitting frame {}", i);
         can.write(&tx_frame).await;
     }
 
     // Try and receive all 6 packets
     for i in 0..max_buffered {
-        let (frame, _ts) = can.read().await.unwrap();
+        let (frame, _ts) = can.read().await.unwrap().parts();
         match frame.id() {
             embedded_can::Id::Extended(id) => {
                 info!("Extended received! {:x} {} {}", id.as_raw(), frame.data()[0], i);
@@ -210,20 +210,20 @@ async fn main(_spawner: Spawner) {
     let (mut tx, mut rx) = can.split();
     for i in 0..3 {
         // Try filling up the RX FIFO0 buffers with standard packets
-        let tx_frame = can::frame::ClassicFrame::new_standard(0x123, &[i; 1]).unwrap();
+        let tx_frame = can::frame::Frame::new_standard(0x123, &[i; 1]).unwrap();
         info!("Transmitting frame {}", i);
         tx.write(&tx_frame).await;
     }
     for i in 3..max_buffered {
         // Try filling up the RX FIFO0 buffers with extended packets
-        let tx_frame = can::frame::ClassicFrame::new_extended(0x1232344, &[i; 1]).unwrap();
+        let tx_frame = can::frame::Frame::new_extended(0x1232344, &[i; 1]).unwrap();
         info!("Transmitting frame {}", i);
         tx.write(&tx_frame).await;
     }
 
     // Try and receive all 6 packets
     for i in 0..max_buffered {
-        let (frame, _ts) = rx.read().await.unwrap();
+        let (frame, _ts) = rx.read().await.unwrap().parts();
         match frame.id() {
             embedded_can::Id::Extended(id) => {
                 info!("Extended received! {:x} {} {}", id.as_raw(), frame.data()[0], i);