Repository: embassy-rs/embassy
Pull request #4266 (2025-05-29 03:10:28)

Allow `-> impl Future<Output = ()>` in #[task]
I tried to keep errors the same. They are a bit ugly on stable in the worst case, although they look ok in rust-analyzer.

![image](https://github.com/user-attachments/assets/21720f50-9af0-4483-a9cb-1ce109f8144b)


Patch:
diff --git a/docs/pages/bootloader.adoc b/docs/pages/bootloader.adoc
index b0f0331aa..53f85d995 100644
--- a/docs/pages/bootloader.adoc
+++ b/docs/pages/bootloader.adoc
@@ -2,13 +2,6 @@
 
 `embassy-boot` a lightweight bootloader supporting firmware application upgrades in a power-fail-safe way, with trial boots and rollbacks.
 
-The update method used is referred to as an A/B partition update scheme.
-
-With a general-purpose OS, A/B partition update is accomplished by directly booting either the A or B partition depending on the update state.
-To accomplish the same goal in a way that is portable across all microcontrollers, `embassy-boot` swaps data page by page (in both directions) between the DFU and the Active partition when a firmware update is triggered. +
-Because the original Active application is moved into the DFU partition during this update, the operation can be reversed if the update is interrupted or the new firmware does not flag that it booted successfully. +
-See the design section for more details on how this is implemented.
-
 The bootloader can be used either as a library or be flashed directly if you are happy with the default configuration and capabilities.
 
 By design, the bootloader does not provide any network capabilities. Networking capabilities for fetching new firmware can be provided by the user application, using the bootloader as a library for updating the firmware, or by using the bootloader as a library and adding this capability yourself.
diff --git a/embassy-executor-macros/src/macros/task.rs b/embassy-executor-macros/src/macros/task.rs
index 91d6beee8..91bf8e940 100644
--- a/embassy-executor-macros/src/macros/task.rs
+++ b/embassy-executor-macros/src/macros/task.rs
@@ -51,7 +51,11 @@ pub fn run(args: TokenStream, item: TokenStream) -> TokenStream {
         .embassy_executor
         .unwrap_or(Expr::Verbatim(TokenStream::from_str("::embassy_executor").unwrap()));
 
-    if f.sig.asyncness.is_none() {
+    let returns_impl_trait = match &f.sig.output {
+        ReturnType::Type(_, ty) => matches!(**ty, Type::ImplTrait(_)),
+        _ => false,
+    };
+    if f.sig.asyncness.is_none() && !returns_impl_trait {
         error(&mut errors, &f.sig, "task functions must be async");
     }
     if !f.sig.generics.params.is_empty() {
@@ -66,17 +70,19 @@ pub fn run(args: TokenStream, item: TokenStream) -> TokenStream {
     if !f.sig.variadic.is_none() {
         error(&mut errors, &f.sig, "task functions must not be variadic");
     }
-    match &f.sig.output {
-        ReturnType::Default => {}
-        ReturnType::Type(_, ty) => match &**ty {
-            Type::Tuple(tuple) if tuple.elems.is_empty() => {}
-            Type::Never(_) => {}
-            _ => error(
-                &mut errors,
-                &f.sig,
-                "task functions must either not return a value, return `()` or return `!`",
-            ),
-        },
+    if f.sig.asyncness.is_some() {
+        match &f.sig.output {
+            ReturnType::Default => {}
+            ReturnType::Type(_, ty) => match &**ty {
+                Type::Tuple(tuple) if tuple.elems.is_empty() => {}
+                Type::Never(_) => {}
+                _ => error(
+                    &mut errors,
+                    &f.sig,
+                    "task functions must either not return a value, return `()` or return `!`",
+                ),
+            },
+        }
     }
 
     let mut args = Vec::new();
@@ -128,12 +134,12 @@ pub fn run(args: TokenStream, item: TokenStream) -> TokenStream {
     #[cfg(feature = "nightly")]
     let mut task_outer_body = quote! {
         trait _EmbassyInternalTaskTrait {
-            type Fut: ::core::future::Future + 'static;
+            type Fut: ::core::future::Future<Output: #embassy_executor::_export::TaskReturnValue> + 'static;
             fn construct(#fargs) -> Self::Fut;
         }
 
         impl _EmbassyInternalTaskTrait for () {
-            type Fut = impl core::future::Future + 'static;
+            type Fut = impl core::future::Future<Output: #embassy_executor::_export::TaskReturnValue> + 'static;
             fn construct(#fargs) -> Self::Fut {
                 #task_inner_ident(#(#full_args,)*)
             }
diff --git a/embassy-executor/Cargo.toml b/embassy-executor/Cargo.toml
index f014ccf30..2dbf2c29a 100644
--- a/embassy-executor/Cargo.toml
+++ b/embassy-executor/Cargo.toml
@@ -59,6 +59,7 @@ avr-device = { version = "0.7.0", optional = true }
 critical-section = { version = "1.1", features = ["std"] }
 trybuild = "1.0"
 embassy-sync = { path = "../embassy-sync" }
+rustversion = "1.0.21"
 
 [features]
 
diff --git a/embassy-executor/src/lib.rs b/embassy-executor/src/lib.rs
index dfe420bab..e174a0594 100644
--- a/embassy-executor/src/lib.rs
+++ b/embassy-executor/src/lib.rs
@@ -65,8 +65,17 @@ pub mod _export {
 
     use crate::raw::TaskPool;
 
+    trait TaskReturnValue {}
+    impl TaskReturnValue for () {}
+    impl TaskReturnValue for Never {}
+
+    #[diagnostic::on_unimplemented(
+        message = "task futures must resolve to `()` or `!`",
+        note = "use `async fn` or change the return type to `impl Future<Output = ()>`"
+    )]
+    #[allow(private_bounds)]
     pub trait TaskFn<Args>: Copy {
-        type Fut: Future + 'static;
+        type Fut: Future<Output: TaskReturnValue> + 'static;
     }
 
     macro_rules! task_fn_impl {
@@ -74,7 +83,7 @@ pub mod _export {
             impl<F, Fut, $($Tn,)*> TaskFn<($($Tn,)*)> for F
             where
                 F: Copy + FnOnce($($Tn,)*) -> Fut,
-                Fut: Future + 'static,
+                Fut: Future<Output: TaskReturnValue> + 'static,
             {
                 type Fut = Fut;
             }
@@ -205,4 +214,42 @@ pub mod _export {
         Align268435456: 268435456,
         Align536870912: 536870912,
     );
+
+    #[allow(dead_code)]
+    trait HasOutput {
+        type Output;
+    }
+
+    impl<O> HasOutput for fn() -> O {
+        type Output = O;
+    }
+
+    #[allow(dead_code)]
+    type Never = <fn() -> ! as HasOutput>::Output;
+}
+
+/// Implementation details for embassy macros.
+/// Do not use. Used for macros and HALs only. Not covered by semver guarantees.
+#[doc(hidden)]
+#[cfg(feature = "nightly")]
+pub mod _export {
+    #[diagnostic::on_unimplemented(
+        message = "task futures must resolve to `()` or `!`",
+        note = "use `async fn` or change the return type to `impl Future<Output = ()>`"
+    )]
+    pub trait TaskReturnValue {}
+    impl TaskReturnValue for () {}
+    impl TaskReturnValue for Never {}
+
+    #[allow(dead_code)]
+    trait HasOutput {
+        type Output;
+    }
+
+    impl<O> HasOutput for fn() -> O {
+        type Output = O;
+    }
+
+    #[allow(dead_code)]
+    type Never = <fn() -> ! as HasOutput>::Output;
 }
diff --git a/embassy-executor/src/raw/mod.rs b/embassy-executor/src/raw/mod.rs
index 913da2e25..e7a27035a 100644
--- a/embassy-executor/src/raw/mod.rs
+++ b/embassy-executor/src/raw/mod.rs
@@ -11,7 +11,7 @@
 #[cfg_attr(not(target_has_atomic = "ptr"), path = "run_queue_critical_section.rs")]
 mod run_queue;
 
-#[cfg_attr(all(cortex_m, target_has_atomic = "32"), path = "state_atomics_arm.rs")]
+#[cfg_attr(all(cortex_m, target_has_atomic = "8"), path = "state_atomics_arm.rs")]
 #[cfg_attr(all(not(cortex_m), target_has_atomic = "8"), path = "state_atomics.rs")]
 #[cfg_attr(not(target_has_atomic = "8"), path = "state_critical_section.rs")]
 mod state;
diff --git a/embassy-executor/src/raw/state_atomics.rs b/embassy-executor/src/raw/state_atomics.rs
index e813548ae..b6576bfc2 100644
--- a/embassy-executor/src/raw/state_atomics.rs
+++ b/embassy-executor/src/raw/state_atomics.rs
@@ -1,4 +1,4 @@
-use core::sync::atomic::{AtomicU8, Ordering};
+use core::sync::atomic::{AtomicU32, Ordering};
 
 #[derive(Clone, Copy)]
 pub(crate) struct Token(());
@@ -11,18 +11,18 @@ pub(crate) fn locked<R>(f: impl FnOnce(Token) -> R) -> R {
 }
 
 /// Task is spawned (has a future)
-pub(crate) const STATE_SPAWNED: u8 = 1 << 0;
+pub(crate) const STATE_SPAWNED: u32 = 1 << 0;
 /// Task is in the executor run queue
-pub(crate) const STATE_RUN_QUEUED: u8 = 1 << 1;
+pub(crate) const STATE_RUN_QUEUED: u32 = 1 << 1;
 
 pub(crate) struct State {
-    state: AtomicU8,
+    state: AtomicU32,
 }
 
 impl State {
     pub const fn new() -> State {
         Self {
-            state: AtomicU8::new(0),
+            state: AtomicU32::new(0),
         }
     }
 
diff --git a/embassy-executor/src/raw/state_critical_section.rs b/embassy-executor/src/raw/state_critical_section.rs
index ec08f2f58..6b627ff79 100644
--- a/embassy-executor/src/raw/state_critical_section.rs
+++ b/embassy-executor/src/raw/state_critical_section.rs
@@ -4,12 +4,12 @@ pub(crate) use critical_section::{with as locked, CriticalSection as Token};
 use critical_section::{CriticalSection, Mutex};
 
 /// Task is spawned (has a future)
-pub(crate) const STATE_SPAWNED: u8 = 1 << 0;
+pub(crate) const STATE_SPAWNED: u32 = 1 << 0;
 /// Task is in the executor run queue
-pub(crate) const STATE_RUN_QUEUED: u8 = 1 << 1;
+pub(crate) const STATE_RUN_QUEUED: u32 = 1 << 1;
 
 pub(crate) struct State {
-    state: Mutex<Cell<u8>>,
+    state: Mutex<Cell<u32>>,
 }
 
 impl State {
@@ -19,11 +19,11 @@ impl State {
         }
     }
 
-    fn update<R>(&self, f: impl FnOnce(&mut u8) -> R) -> R {
+    fn update<R>(&self, f: impl FnOnce(&mut u32) -> R) -> R {
         critical_section::with(|cs| self.update_with_cs(cs, f))
     }
 
-    fn update_with_cs<R>(&self, cs: CriticalSection<'_>, f: impl FnOnce(&mut u8) -> R) -> R {
+    fn update_with_cs<R>(&self, cs: CriticalSection<'_>, f: impl FnOnce(&mut u32) -> R) -> R {
         let s = self.state.borrow(cs);
         let mut val = s.get();
         let r = f(&mut val);
diff --git a/embassy-rp/src/gpio.rs b/embassy-rp/src/gpio.rs
index 9b5faac15..2fb2d65c2 100644
--- a/embassy-rp/src/gpio.rs
+++ b/embassy-rp/src/gpio.rs
@@ -146,12 +146,6 @@ impl<'d> Input<'d> {
         self.pin.get_level()
     }
 
-    /// Configure the input logic inversion of this pin.
-    #[inline]
-    pub fn set_inversion(&mut self, invert: bool) {
-        self.pin.set_input_inversion(invert)
-    }
-
     /// Wait until the pin is high. If it is already high, return immediately.
     #[inline]
     pub async fn wait_for_high(&mut self) {
@@ -388,12 +382,6 @@ impl<'d> Output<'d> {
         self.pin.set_slew_rate(slew_rate)
     }
 
-    /// Configure the output logic inversion of this pin.
-    #[inline]
-    pub fn set_inversion(&mut self, invert: bool) {
-        self.pin.set_output_inversion(invert)
-    }
-
     /// Set the output as high.
     #[inline]
     pub fn set_high(&mut self) {
@@ -697,30 +685,6 @@ impl<'d> Flex<'d> {
         self.pin.sio_oe().value_xor().write_value(self.bit())
     }
 
-    /// Configure the input logic inversion of this pin.
-    #[inline]
-    pub fn set_input_inversion(&mut self, invert: bool) {
-        self.pin.gpio().ctrl().modify(|w| {
-            w.set_inover(if invert {
-                pac::io::vals::Inover::INVERT
-            } else {
-                pac::io::vals::Inover::NORMAL
-            })
-        });
-    }
-
-    /// Configure the output logic inversion of this pin.
-    #[inline]
-    pub fn set_output_inversion(&mut self, invert: bool) {
-        self.pin.gpio().ctrl().modify(|w| {
-            w.set_outover(if invert {
-                pac::io::vals::Outover::INVERT
-            } else {
-                pac::io::vals::Outover::NORMAL
-            })
-        });
-    }
-
     /// Get whether the pin input level is high.
     #[inline]
     pub fn is_high(&self) -> bool {
@@ -851,8 +815,6 @@ impl<'d> Drop for Flex<'d> {
         self.pin.pad_ctrl().write(|_| {});
         self.pin.gpio().ctrl().write(|w| {
             w.set_funcsel(pac::io::vals::Gpio0ctrlFuncsel::NULL as _);
-            w.set_inover(pac::io::vals::Inover::NORMAL);
-            w.set_outover(pac::io::vals::Outover::NORMAL);
         });
         self.pin.io().int_dormant_wake().inte(idx / 8).write_clear(|w| {
             w.set_edge_high(idx % 8, true);
diff --git a/embassy-stm32/src/adc/ringbuffered_v2.rs b/embassy-stm32/src/adc/ringbuffered_v2.rs
index 6f69e8486..fabf0284b 100644
--- a/embassy-stm32/src/adc/ringbuffered_v2.rs
+++ b/embassy-stm32/src/adc/ringbuffered_v2.rs
@@ -199,16 +199,16 @@ impl<'d, T: Instance> RingBufferedAdc<'d, T> {
             Sequence::Four => T::regs().sqr3().modify(|w| w.set_sq(3, channel.channel())),
             Sequence::Five => T::regs().sqr3().modify(|w| w.set_sq(4, channel.channel())),
             Sequence::Six => T::regs().sqr3().modify(|w| w.set_sq(5, channel.channel())),
-            Sequence::Seven => T::regs().sqr2().modify(|w| w.set_sq(0, channel.channel())),
-            Sequence::Eight => T::regs().sqr2().modify(|w| w.set_sq(1, channel.channel())),
-            Sequence::Nine => T::regs().sqr2().modify(|w| w.set_sq(2, channel.channel())),
-            Sequence::Ten => T::regs().sqr2().modify(|w| w.set_sq(3, channel.channel())),
-            Sequence::Eleven => T::regs().sqr2().modify(|w| w.set_sq(4, channel.channel())),
-            Sequence::Twelve => T::regs().sqr2().modify(|w| w.set_sq(5, channel.channel())),
-            Sequence::Thirteen => T::regs().sqr1().modify(|w| w.set_sq(0, channel.channel())),
-            Sequence::Fourteen => T::regs().sqr1().modify(|w| w.set_sq(1, channel.channel())),
-            Sequence::Fifteen => T::regs().sqr1().modify(|w| w.set_sq(2, channel.channel())),
-            Sequence::Sixteen => T::regs().sqr1().modify(|w| w.set_sq(3, channel.channel())),
+            Sequence::Seven => T::regs().sqr2().modify(|w| w.set_sq(6, channel.channel())),
+            Sequence::Eight => T::regs().sqr2().modify(|w| w.set_sq(7, channel.channel())),
+            Sequence::Nine => T::regs().sqr2().modify(|w| w.set_sq(8, channel.channel())),
+            Sequence::Ten => T::regs().sqr2().modify(|w| w.set_sq(9, channel.channel())),
+            Sequence::Eleven => T::regs().sqr2().modify(|w| w.set_sq(10, channel.channel())),
+            Sequence::Twelve => T::regs().sqr2().modify(|w| w.set_sq(11, channel.channel())),
+            Sequence::Thirteen => T::regs().sqr1().modify(|w| w.set_sq(12, channel.channel())),
+            Sequence::Fourteen => T::regs().sqr1().modify(|w| w.set_sq(13, channel.channel())),
+            Sequence::Fifteen => T::regs().sqr1().modify(|w| w.set_sq(14, channel.channel())),
+            Sequence::Sixteen => T::regs().sqr1().modify(|w| w.set_sq(15, channel.channel())),
         };
 
         if !was_on {
diff --git a/embassy-stm32/src/can/common.rs b/embassy-stm32/src/can/common.rs
index 386d4467c..e12111910 100644
--- a/embassy-stm32/src/can/common.rs
+++ b/embassy-stm32/src/can/common.rs
@@ -1,29 +1,29 @@
-use embassy_sync::channel::{SendDynamicReceiver, SendDynamicSender};
+use embassy_sync::channel::{DynamicReceiver, DynamicSender};
 
 use super::enums::*;
 use super::frame::*;
 
 pub(crate) struct ClassicBufferedRxInner {
-    pub rx_sender: SendDynamicSender<'static, Result<Envelope, BusError>>,
+    pub rx_sender: DynamicSender<'static, Result<Envelope, BusError>>,
 }
 pub(crate) struct ClassicBufferedTxInner {
-    pub tx_receiver: SendDynamicReceiver<'static, Frame>,
+    pub tx_receiver: DynamicReceiver<'static, Frame>,
 }
 
 #[cfg(any(can_fdcan_v1, can_fdcan_h7))]
 
 pub(crate) struct FdBufferedRxInner {
-    pub rx_sender: SendDynamicSender<'static, Result<FdEnvelope, BusError>>,
+    pub rx_sender: DynamicSender<'static, Result<FdEnvelope, BusError>>,
 }
 
 #[cfg(any(can_fdcan_v1, can_fdcan_h7))]
 pub(crate) struct FdBufferedTxInner {
-    pub tx_receiver: SendDynamicReceiver<'static, FdFrame>,
+    pub tx_receiver: DynamicReceiver<'static, FdFrame>,
 }
 
 /// Sender that can be used for sending CAN frames.
 pub struct BufferedSender<'ch, FRAME> {
-    pub(crate) tx_buf: embassy_sync::channel::SendDynamicSender<'ch, FRAME>,
+    pub(crate) tx_buf: embassy_sync::channel::DynamicSender<'ch, FRAME>,
     pub(crate) waker: fn(),
     pub(crate) internal_operation: fn(InternalOperation),
 }
@@ -70,7 +70,7 @@ pub type BufferedCanSender = BufferedSender<'static, Frame>;
 
 /// Receiver that can be used for receiving CAN frames. Note, each CAN frame will only be received by one receiver.
 pub struct BufferedReceiver<'ch, ENVELOPE> {
-    pub(crate) rx_buf: embassy_sync::channel::SendDynamicReceiver<'ch, Result<ENVELOPE, BusError>>,
+    pub(crate) rx_buf: embassy_sync::channel::DynamicReceiver<'ch, Result<ENVELOPE, BusError>>,
     pub(crate) internal_operation: fn(InternalOperation),
 }
 
diff --git a/embassy-stm32/src/can/fd/peripheral.rs b/embassy-stm32/src/can/fd/peripheral.rs
index 0a22f2c91..4873ee444 100644
--- a/embassy-stm32/src/can/fd/peripheral.rs
+++ b/embassy-stm32/src/can/fd/peripheral.rs
@@ -71,23 +71,6 @@ impl Registers {
         }
     }
 
-    #[cfg(feature = "time")]
-    pub fn calc_timestamp(&self, ns_per_timer_tick: u64, ts_val: u16) -> Timestamp {
-        let now_embassy = embassy_time::Instant::now();
-        if ns_per_timer_tick == 0 {
-            return now_embassy;
-        }
-        let cantime = { self.regs.tscv().read().tsc() };
-        let delta = cantime.overflowing_sub(ts_val).0 as u64;
-        let ns = ns_per_timer_tick * delta as u64;
-        now_embassy - embassy_time::Duration::from_nanos(ns)
-    }
-
-    #[cfg(not(feature = "time"))]
-    pub fn calc_timestamp(&self, _ns_per_timer_tick: u64, ts_val: u16) -> Timestamp {
-        ts_val
-    }
-
     pub fn put_tx_frame(&self, bufidx: usize, header: &Header, buffer: &[u8]) {
         let mailbox = self.tx_buffer_element(bufidx);
         mailbox.reset();
diff --git a/embassy-stm32/src/can/fdcan.rs b/embassy-stm32/src/can/fdcan.rs
index 97d22315a..a7815f79b 100644
--- a/embassy-stm32/src/can/fdcan.rs
+++ b/embassy-stm32/src/can/fdcan.rs
@@ -52,39 +52,36 @@ impl<T: Instance> interrupt::typelevel::Handler<T::IT0Interrupt> for IT0Interrup
             regs.ir().write(|w| w.set_tefn(true));
         }
 
-        T::info().state.lock(|s| {
-            let state = s.borrow_mut();
-            match &state.tx_mode {
-                TxMode::NonBuffered(waker) => waker.wake(),
-                TxMode::ClassicBuffered(buf) => {
-                    if !T::registers().tx_queue_is_full() {
-                        match buf.tx_receiver.try_receive() {
-                            Ok(frame) => {
-                                _ = T::registers().write(&frame);
-                            }
-                            Err(_) => {}
+        match &T::state().tx_mode {
+            TxMode::NonBuffered(waker) => waker.wake(),
+            TxMode::ClassicBuffered(buf) => {
+                if !T::registers().tx_queue_is_full() {
+                    match buf.tx_receiver.try_receive() {
+                        Ok(frame) => {
+                            _ = T::registers().write(&frame);
                         }
+                        Err(_) => {}
                     }
                 }
-                TxMode::FdBuffered(buf) => {
-                    if !T::registers().tx_queue_is_full() {
-                        match buf.tx_receiver.try_receive() {
-                            Ok(frame) => {
-                                _ = T::registers().write(&frame);
-                            }
-                            Err(_) => {}
+            }
+            TxMode::FdBuffered(buf) => {
+                if !T::registers().tx_queue_is_full() {
+                    match buf.tx_receiver.try_receive() {
+                        Ok(frame) => {
+                            _ = T::registers().write(&frame);
                         }
+                        Err(_) => {}
                     }
                 }
             }
+        }
 
-            if ir.rfn(0) {
-                state.rx_mode.on_interrupt::<T>(0, state.ns_per_timer_tick);
-            }
-            if ir.rfn(1) {
-                state.rx_mode.on_interrupt::<T>(1, state.ns_per_timer_tick);
-            }
-        });
+        if ir.rfn(0) {
+            T::state().rx_mode.on_interrupt::<T>(0);
+        }
+        if ir.rfn(1) {
+            T::state().rx_mode.on_interrupt::<T>(1);
+        }
 
         if ir.bo() {
             regs.ir().write(|w| w.set_bo(true));
@@ -168,6 +165,7 @@ pub struct CanConfigurator<'d> {
     _phantom: PhantomData<&'d ()>,
     config: crate::can::fd::config::FdCanConfig,
     info: &'static Info,
+    state: &'static State,
     /// Reference to internals.
     properties: Properties,
     periph_clock: crate::time::Hertz,
@@ -190,10 +188,9 @@ impl<'d> CanConfigurator<'d> {
         rcc::enable_and_reset::<T>();
 
         let info = T::info();
-        T::info().state.lock(|s| {
-            s.borrow_mut().tx_pin_port = Some(tx.pin_port());
-            s.borrow_mut().rx_pin_port = Some(rx.pin_port());
-        });
+        let state = unsafe { T::mut_state() };
+        state.tx_pin_port = Some(tx.pin_port());
+        state.rx_pin_port = Some(rx.pin_port());
         (info.internal_operation)(InternalOperation::NotifySenderCreated);
         (info.internal_operation)(InternalOperation::NotifyReceiverCreated);
 
@@ -212,6 +209,7 @@ impl<'d> CanConfigurator<'d> {
             _phantom: PhantomData,
             config,
             info,
+            state,
             properties: Properties::new(T::info()),
             periph_clock: T::frequency(),
         }
@@ -263,8 +261,12 @@ impl<'d> CanConfigurator<'d> {
     /// Start in mode.
     pub fn start(self, mode: OperatingMode) -> Can<'d> {
         let ns_per_timer_tick = calc_ns_per_timer_tick(self.info, self.periph_clock, self.config.frame_transmit);
-        self.info.state.lock(|s| {
-            s.borrow_mut().ns_per_timer_tick = ns_per_timer_tick;
+        critical_section::with(|_| {
+            let state = self.state as *const State;
+            unsafe {
+                let mut_state = state as *mut State;
+                (*mut_state).ns_per_timer_tick = ns_per_timer_tick;
+            }
         });
         self.info.regs.into_mode(self.config, mode);
         (self.info.internal_operation)(InternalOperation::NotifySenderCreated);
@@ -273,6 +275,7 @@ impl<'d> CanConfigurator<'d> {
             _phantom: PhantomData,
             config: self.config,
             info: self.info,
+            state: self.state,
             _mode: mode,
             properties: Properties::new(self.info),
         }
@@ -306,6 +309,7 @@ pub struct Can<'d> {
     _phantom: PhantomData<&'d ()>,
     config: crate::can::fd::config::FdCanConfig,
     info: &'static Info,
+    state: &'static State,
     _mode: OperatingMode,
     properties: Properties,
 }
@@ -319,9 +323,7 @@ impl<'d> Can<'d> {
     /// Flush one of the TX mailboxes.
     pub async fn flush(&self, idx: usize) {
         poll_fn(|cx| {
-            self.info.state.lock(|s| {
-                s.borrow_mut().tx_mode.register(cx.waker());
-            });
+            self.state.tx_mode.register(cx.waker());
 
             if idx > 3 {
                 panic!("Bad mailbox");
@@ -341,12 +343,12 @@ impl<'d> Can<'d> {
     /// can be replaced, this call asynchronously waits for a frame to be successfully
     /// transmitted, then tries again.
     pub async fn write(&mut self, frame: &Frame) -> Option<Frame> {
-        TxMode::write(self.info, frame).await
+        self.state.tx_mode.write(self.info, frame).await
     }
 
     /// Returns the next received message frame
     pub async fn read(&mut self) -> Result<Envelope, BusError> {
-        RxMode::read_classic(self.info).await
+        self.state.rx_mode.read_classic(self.info, self.state).await
     }
 
     /// Queues the message to be sent but exerts backpressure.  If a lower-priority
@@ -354,12 +356,12 @@ impl<'d> Can<'d> {
     /// can be replaced, this call asynchronously waits for a frame to be successfully
     /// transmitted, then tries again.
     pub async fn write_fd(&mut self, frame: &FdFrame) -> Option<FdFrame> {
-        TxMode::write_fd(self.info, frame).await
+        self.state.tx_mode.write_fd(self.info, frame).await
     }
 
     /// Returns the next received message frame
     pub async fn read_fd(&mut self) -> Result<FdEnvelope, BusError> {
-        RxMode::read_fd(self.info).await
+        self.state.rx_mode.read_fd(self.info, self.state).await
     }
 
     /// Split instance into separate portions: Tx(write), Rx(read), common properties
@@ -370,12 +372,14 @@ impl<'d> Can<'d> {
             CanTx {
                 _phantom: PhantomData,
                 info: self.info,
+                state: self.state,
                 config: self.config,
                 _mode: self._mode,
             },
             CanRx {
                 _phantom: PhantomData,
                 info: self.info,
+                state: self.state,
                 _mode: self._mode,
             },
             Properties {
@@ -391,6 +395,7 @@ impl<'d> Can<'d> {
             _phantom: PhantomData,
             config: tx.config,
             info: tx.info,
+            state: tx.state,
             _mode: rx._mode,
             properties: Properties::new(tx.info),
         }
@@ -402,7 +407,7 @@ impl<'d> Can<'d> {
         tx_buf: &'static mut TxBuf<TX_BUF_SIZE>,
         rxb: &'static mut RxBuf<RX_BUF_SIZE>,
     ) -> BufferedCan<'d, TX_BUF_SIZE, RX_BUF_SIZE> {
-        BufferedCan::new(self.info, self._mode, tx_buf, rxb)
+        BufferedCan::new(self.info, self.state, self._mode, tx_buf, rxb)
     }
 
     /// Return a buffered instance of driver with CAN FD support. User must supply Buffers
@@ -411,7 +416,7 @@ impl<'d> Can<'d> {
         tx_buf: &'static mut TxFdBuf<TX_BUF_SIZE>,
         rxb: &'static mut RxFdBuf<RX_BUF_SIZE>,
     ) -> BufferedCanFd<'d, TX_BUF_SIZE, RX_BUF_SIZE> {
-        BufferedCanFd::new(self.info, self._mode, tx_buf, rxb)
+        BufferedCanFd::new(self.info, self.state, self._mode, tx_buf, rxb)
     }
 }
 
@@ -432,6 +437,7 @@ pub type TxBuf<const BUF_SIZE: usize> = Channel<CriticalSectionRawMutex, Frame,
 pub struct BufferedCan<'d, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> {
     _phantom: PhantomData<&'d ()>,
     info: &'static Info,
+    state: &'static State,
     _mode: OperatingMode,
     tx_buf: &'static TxBuf<TX_BUF_SIZE>,
     rx_buf: &'static RxBuf<RX_BUF_SIZE>,
@@ -441,6 +447,7 @@ pub struct BufferedCan<'d, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> {
 impl<'c, 'd, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> BufferedCan<'d, TX_BUF_SIZE, RX_BUF_SIZE> {
     fn new(
         info: &'static Info,
+        state: &'static State,
         _mode: OperatingMode,
         tx_buf: &'static TxBuf<TX_BUF_SIZE>,
         rx_buf: &'static RxBuf<RX_BUF_SIZE>,
@@ -450,6 +457,7 @@ impl<'c, 'd, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> BufferedCan<'d,
         BufferedCan {
             _phantom: PhantomData,
             info,
+            state,
             _mode,
             tx_buf,
             rx_buf,
@@ -465,15 +473,19 @@ impl<'c, 'd, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> BufferedCan<'d,
 
     fn setup(self) -> Self {
         // We don't want interrupts being processed while we change modes.
-        self.info.state.lock(|s| {
+        critical_section::with(|_| {
             let rx_inner = super::common::ClassicBufferedRxInner {
                 rx_sender: self.rx_buf.sender().into(),
             };
             let tx_inner = super::common::ClassicBufferedTxInner {
                 tx_receiver: self.tx_buf.receiver().into(),
             };
-            s.borrow_mut().rx_mode = RxMode::ClassicBuffered(rx_inner);
-            s.borrow_mut().tx_mode = TxMode::ClassicBuffered(tx_inner);
+            let state = self.state as *const State;
+            unsafe {
+                let mut_state = state as *mut State;
+                (*mut_state).rx_mode = RxMode::ClassicBuffered(rx_inner);
+                (*mut_state).tx_mode = TxMode::ClassicBuffered(tx_inner);
+            }
         });
         self
     }
@@ -533,6 +545,7 @@ pub type BufferedFdCanReceiver = super::common::BufferedReceiver<'static, FdEnve
 pub struct BufferedCanFd<'d, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> {
     _phantom: PhantomData<&'d ()>,
     info: &'static Info,
+    state: &'static State,
     _mode: OperatingMode,
     tx_buf: &'static TxFdBuf<TX_BUF_SIZE>,
     rx_buf: &'static RxFdBuf<RX_BUF_SIZE>,
@@ -542,6 +555,7 @@ pub struct BufferedCanFd<'d, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize>
 impl<'c, 'd, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> BufferedCanFd<'d, TX_BUF_SIZE, RX_BUF_SIZE> {
     fn new(
         info: &'static Info,
+        state: &'static State,
         _mode: OperatingMode,
         tx_buf: &'static TxFdBuf<TX_BUF_SIZE>,
         rx_buf: &'static RxFdBuf<RX_BUF_SIZE>,
@@ -551,6 +565,7 @@ impl<'c, 'd, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> BufferedCanFd<'
         BufferedCanFd {
             _phantom: PhantomData,
             info,
+            state,
             _mode,
             tx_buf,
             rx_buf,
@@ -566,15 +581,19 @@ impl<'c, 'd, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> BufferedCanFd<'
 
     fn setup(self) -> Self {
         // We don't want interrupts being processed while we change modes.
-        self.info.state.lock(|s| {
+        critical_section::with(|_| {
             let rx_inner = super::common::FdBufferedRxInner {
                 rx_sender: self.rx_buf.sender().into(),
             };
             let tx_inner = super::common::FdBufferedTxInner {
                 tx_receiver: self.tx_buf.receiver().into(),
             };
-            s.borrow_mut().rx_mode = RxMode::FdBuffered(rx_inner);
-            s.borrow_mut().tx_mode = TxMode::FdBuffered(tx_inner);
+            let state = self.state as *const State;
+            unsafe {
+                let mut_state = state as *mut State;
+                (*mut_state).rx_mode = RxMode::FdBuffered(rx_inner);
+                (*mut_state).tx_mode = TxMode::FdBuffered(tx_inner);
+            }
         });
         self
     }
@@ -622,18 +641,19 @@ impl<'c, 'd, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> Drop for Buffer
 pub struct CanRx<'d> {
     _phantom: PhantomData<&'d ()>,
     info: &'static Info,
+    state: &'static State,
     _mode: OperatingMode,
 }
 
 impl<'d> CanRx<'d> {
     /// Returns the next received message frame
     pub async fn read(&mut self) -> Result<Envelope, BusError> {
-        RxMode::read_classic(&self.info).await
+        self.state.rx_mode.read_classic(&self.info, &self.state).await
     }
 
     /// Returns the next received message frame
     pub async fn read_fd(&mut self) -> Result<FdEnvelope, BusError> {
-        RxMode::read_fd(&self.info).await
+        self.state.rx_mode.read_fd(&self.info, &self.state).await
     }
 }
 
@@ -647,6 +667,7 @@ impl<'d> Drop for CanRx<'d> {
 pub struct CanTx<'d> {
     _phantom: PhantomData<&'d ()>,
     info: &'static Info,
+    state: &'static State,
     config: crate::can::fd::config::FdCanConfig,
     _mode: OperatingMode,
 }
@@ -657,7 +678,7 @@ impl<'c, 'd> CanTx<'d> {
     /// can be replaced, this call asynchronously waits for a frame to be successfully
     /// transmitted, then tries again.
     pub async fn write(&mut self, frame: &Frame) -> Option<Frame> {
-        TxMode::write(self.info, frame).await
+        self.state.tx_mode.write(self.info, frame).await
     }
 
     /// Queues the message to be sent but exerts backpressure.  If a lower-priority
@@ -665,7 +686,7 @@ impl<'c, 'd> CanTx<'d> {
     /// can be replaced, this call asynchronously waits for a frame to be successfully
     /// transmitted, then tries again.
     pub async fn write_fd(&mut self, frame: &FdFrame) -> Option<FdFrame> {
-        TxMode::write_fd(self.info, frame).await
+        self.state.tx_mode.write_fd(self.info, frame).await
     }
 }
 
@@ -691,19 +712,19 @@ impl RxMode {
         }
     }
 
-    fn on_interrupt<T: Instance>(&self, fifonr: usize, ns_per_timer_tick: u64) {
+    fn on_interrupt<T: Instance>(&self, fifonr: usize) {
         T::registers().regs.ir().write(|w| w.set_rfn(fifonr, true));
         match self {
             RxMode::NonBuffered(waker) => {
                 waker.wake();
             }
             RxMode::ClassicBuffered(buf) => {
-                if let Some(result) = self.try_read::<T>(ns_per_timer_tick) {
+                if let Some(result) = self.try_read::<T>() {
                     let _ = buf.rx_sender.try_send(result);
                 }
             }
             RxMode::FdBuffered(buf) => {
-                if let Some(result) = self.try_read_fd::<T>(ns_per_timer_tick) {
+                if let Some(result) = self.try_read_fd::<T>() {
                     let _ = buf.rx_sender.try_send(result);
                 }
             }
@@ -711,12 +732,12 @@ impl RxMode {
     }
 
     //async fn read_classic<T: Instance>(&self) -> Result<Envelope, BusError> {
-    fn try_read<T: Instance>(&self, ns_per_timer_tick: u64) -> Option<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::registers().calc_timestamp(ns_per_timer_tick, ts);
+            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::registers().calc_timestamp(ns_per_timer_tick, ts);
+            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
@@ -726,12 +747,12 @@ impl RxMode {
         }
     }
 
-    fn try_read_fd<T: Instance>(&self, ns_per_timer_tick: u64) -> Option<Result<FdEnvelope, BusError>> {
+    fn try_read_fd<T: Instance>(&self) -> Option<Result<FdEnvelope, BusError>> {
         if let Some((frame, ts)) = T::registers().read(0) {
-            let ts = T::registers().calc_timestamp(ns_per_timer_tick, ts);
+            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::registers().calc_timestamp(ns_per_timer_tick, ts);
+            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
@@ -741,12 +762,16 @@ impl RxMode {
         }
     }
 
-    fn read<F: CanHeader>(info: &'static Info, ns_per_timer_tick: u64) -> Option<Result<(F, Timestamp), BusError>> {
+    fn read<F: CanHeader>(
+        &self,
+        info: &'static Info,
+        state: &'static State,
+    ) -> Option<Result<(F, Timestamp), BusError>> {
         if let Some((msg, ts)) = info.regs.read(0) {
-            let ts = info.regs.calc_timestamp(ns_per_timer_tick, ts);
+            let ts = info.calc_timestamp(state.ns_per_timer_tick, ts);
             Some(Ok((msg, ts)))
         } else if let Some((msg, ts)) = info.regs.read(1) {
-            let ts = info.regs.calc_timestamp(ns_per_timer_tick, ts);
+            let ts = info.calc_timestamp(state.ns_per_timer_tick, ts);
             Some(Ok((msg, ts)))
         } else if let Some(err) = info.regs.curr_error() {
             // TODO: this is probably wrong
@@ -756,15 +781,16 @@ impl RxMode {
         }
     }
 
-    async fn read_async<F: CanHeader>(info: &'static Info) -> Result<(F, Timestamp), BusError> {
+    async fn read_async<F: CanHeader>(
+        &self,
+        info: &'static Info,
+        state: &'static State,
+    ) -> Result<(F, Timestamp), BusError> {
+        //let _ = self.read::<F>(info, state);
         poll_fn(move |cx| {
-            let ns_per_timer_tick = info.state.lock(|s| {
-                let state = s.borrow_mut();
-                state.err_waker.register(cx.waker());
-                state.rx_mode.register(cx.waker());
-                state.ns_per_timer_tick
-            });
-            match RxMode::read::<_>(info, ns_per_timer_tick) {
+            state.err_waker.register(cx.waker());
+            self.register(cx.waker());
+            match self.read::<_>(info, state) {
                 Some(result) => Poll::Ready(result),
                 None => Poll::Pending,
             }
@@ -772,15 +798,15 @@ impl RxMode {
         .await
     }
 
-    async fn read_classic(info: &'static Info) -> Result<Envelope, BusError> {
-        match RxMode::read_async::<_>(info).await {
+    async fn read_classic(&self, info: &'static Info, state: &'static State) -> Result<Envelope, BusError> {
+        match self.read_async::<_>(info, state).await {
             Ok((frame, ts)) => Ok(Envelope { ts, frame }),
             Err(e) => Err(e),
         }
     }
 
-    async fn read_fd(info: &'static Info) -> Result<FdEnvelope, BusError> {
-        match RxMode::read_async::<_>(info).await {
+    async fn read_fd(&self, info: &'static Info, state: &'static State) -> Result<FdEnvelope, BusError> {
+        match self.read_async::<_>(info, state).await {
             Ok((frame, ts)) => Ok(FdEnvelope { ts, frame }),
             Err(e) => Err(e),
         }
@@ -809,11 +835,9 @@ 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_generic<F: embedded_can::Frame + CanHeader>(info: &'static Info, frame: &F) -> Option<F> {
+    async fn write_generic<F: embedded_can::Frame + CanHeader>(&self, info: &'static Info, frame: &F) -> Option<F> {
         poll_fn(|cx| {
-            info.state.lock(|s| {
-                s.borrow_mut().tx_mode.register(cx.waker());
-            });
+            self.register(cx.waker());
 
             if let Ok(dropped) = info.regs.write(frame) {
                 return Poll::Ready(dropped);
@@ -830,16 +854,16 @@ 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(info: &'static Info, frame: &Frame) -> Option<Frame> {
-        TxMode::write_generic::<_>(info, frame).await
+    async fn write(&self, info: &'static Info, frame: &Frame) -> Option<Frame> {
+        self.write_generic::<_>(info, frame).await
     }
 
     /// 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.
-    async fn write_fd(info: &'static Info, frame: &FdFrame) -> Option<FdFrame> {
-        TxMode::write_generic::<_>(info, frame).await
+    async fn write_fd(&self, info: &'static Info, frame: &FdFrame) -> Option<FdFrame> {
+        self.write_generic::<_>(info, frame).await
     }
 }
 
@@ -937,14 +961,31 @@ impl State {
     }
 }
 
-type SharedState = embassy_sync::blocking_mutex::Mutex<CriticalSectionRawMutex, core::cell::RefCell<State>>;
 struct Info {
     regs: Registers,
     interrupt0: crate::interrupt::Interrupt,
     _interrupt1: crate::interrupt::Interrupt,
     tx_waker: fn(),
     internal_operation: fn(InternalOperation),
-    state: SharedState,
+}
+
+impl Info {
+    #[cfg(feature = "time")]
+    fn calc_timestamp(&self, ns_per_timer_tick: u64, ts_val: u16) -> Timestamp {
+        let now_embassy = embassy_time::Instant::now();
+        if ns_per_timer_tick == 0 {
+            return now_embassy;
+        }
+        let cantime = { self.regs.regs.tscv().read().tsc() };
+        let delta = cantime.overflowing_sub(ts_val).0 as u64;
+        let ns = ns_per_timer_tick * delta as u64;
+        now_embassy - embassy_time::Duration::from_nanos(ns)
+    }
+
+    #[cfg(not(feature = "time"))]
+    fn calc_timestamp(&self, _ns_per_timer_tick: u64, ts_val: u16) -> Timestamp {
+        ts_val
+    }
 }
 
 trait SealedInstance {
@@ -952,7 +993,10 @@ trait SealedInstance {
 
     fn info() -> &'static Info;
     fn registers() -> crate::can::fd::peripheral::Registers;
+    fn state() -> &'static State;
+    unsafe fn mut_state() -> &'static mut State;
     fn internal_operation(val: InternalOperation);
+    fn calc_timestamp(ns_per_timer_tick: u64, ts_val: u16) -> Timestamp;
 }
 
 /// Instance trait
@@ -975,30 +1019,32 @@ macro_rules! impl_fdcan {
             const MSG_RAM_OFFSET: usize = $msg_ram_offset;
 
             fn internal_operation(val: InternalOperation) {
-                peripherals::$inst::info().state.lock(|s| {
-                    let mut mut_state = s.borrow_mut();
-                    match val {
-                        InternalOperation::NotifySenderCreated => {
-                            mut_state.sender_instance_count += 1;
-                        }
-                        InternalOperation::NotifySenderDestroyed => {
-                            mut_state.sender_instance_count -= 1;
-                            if ( 0 == mut_state.sender_instance_count) {
-                                (*mut_state).tx_mode = TxMode::NonBuffered(embassy_sync::waitqueue::AtomicWaker::new());
+                critical_section::with(|_| {
+                    //let state = self.state as *const State;
+                    unsafe {
+                        //let mut_state = state as *mut State;
+                        let mut_state = peripherals::$inst::mut_state();
+                        match val {
+                            InternalOperation::NotifySenderCreated => {
+                                mut_state.sender_instance_count += 1;
                             }
-                        }
-                        InternalOperation::NotifyReceiverCreated => {
-                            mut_state.receiver_instance_count += 1;
-                        }
-                        InternalOperation::NotifyReceiverDestroyed => {
-                            mut_state.receiver_instance_count -= 1;
-                            if ( 0 == mut_state.receiver_instance_count) {
-                                (*mut_state).rx_mode = RxMode::NonBuffered(embassy_sync::waitqueue::AtomicWaker::new());
+                            InternalOperation::NotifySenderDestroyed => {
+                                mut_state.sender_instance_count -= 1;
+                                if ( 0 == mut_state.sender_instance_count) {
+                                    (*mut_state).tx_mode = TxMode::NonBuffered(embassy_sync::waitqueue::AtomicWaker::new());
+                                }
+                            }
+                            InternalOperation::NotifyReceiverCreated => {
+                                mut_state.receiver_instance_count += 1;
+                            }
+                            InternalOperation::NotifyReceiverDestroyed => {
+                                mut_state.receiver_instance_count -= 1;
+                                if ( 0 == mut_state.receiver_instance_count) {
+                                    (*mut_state).rx_mode = RxMode::NonBuffered(embassy_sync::waitqueue::AtomicWaker::new());
+                                }
                             }
                         }
-                    }
-                    if mut_state.sender_instance_count == 0 && mut_state.receiver_instance_count == 0 {
-                        unsafe {
+                        if mut_state.sender_instance_count == 0 && mut_state.receiver_instance_count == 0 {
                             let tx_pin = crate::gpio::AnyPin::steal(mut_state.tx_pin_port.unwrap());
                             tx_pin.set_as_disconnected();
                             let rx_pin = crate::gpio::AnyPin::steal(mut_state.rx_pin_port.unwrap());
@@ -1008,22 +1054,43 @@ macro_rules! impl_fdcan {
                     }
                 });
             }
-
             fn info() -> &'static Info {
-
                 static INFO: Info = Info {
                     regs: Registers{regs: crate::pac::$inst, msgram: crate::pac::$msg_ram_inst, msg_ram_offset: $msg_ram_offset},
                     interrupt0: crate::_generated::peripheral_interrupts::$inst::IT0::IRQ,
                     _interrupt1: crate::_generated::peripheral_interrupts::$inst::IT1::IRQ,
                     tx_waker: crate::_generated::peripheral_interrupts::$inst::IT0::pend,
                     internal_operation: peripherals::$inst::internal_operation,
-                    state: embassy_sync::blocking_mutex::Mutex::new(core::cell::RefCell::new(State::new())),
                 };
                 &INFO
             }
             fn registers() -> Registers {
                 Registers{regs: crate::pac::$inst, msgram: crate::pac::$msg_ram_inst, msg_ram_offset: Self::MSG_RAM_OFFSET}
             }
+            unsafe fn mut_state() -> &'static mut State {
+                static mut STATE: State = State::new();
+                &mut *core::ptr::addr_of_mut!(STATE)
+            }
+            fn state() -> &'static State {
+                unsafe { peripherals::$inst::mut_state() }
+            }
+
+            #[cfg(feature = "time")]
+            fn calc_timestamp(ns_per_timer_tick: u64, ts_val: u16) -> Timestamp {
+                let now_embassy = embassy_time::Instant::now();
+                if ns_per_timer_tick == 0 {
+                    return now_embassy;
+                }
+                let cantime = { Self::registers().regs.tscv().read().tsc() };
+                let delta = cantime.overflowing_sub(ts_val).0 as u64;
+                let ns = ns_per_timer_tick * delta as u64;
+                now_embassy - embassy_time::Duration::from_nanos(ns)
+            }
+
+            #[cfg(not(feature = "time"))]
+            fn calc_timestamp(_ns_per_timer_tick: u64, ts_val: u16) -> Timestamp {
+                ts_val
+            }
 
         }
 
diff --git a/embassy-stm32/src/qspi/enums.rs b/embassy-stm32/src/qspi/enums.rs
index 9ec4c1b43..ecade9b1a 100644
--- a/embassy-stm32/src/qspi/enums.rs
+++ b/embassy-stm32/src/qspi/enums.rs
@@ -9,9 +9,9 @@ pub(crate) enum QspiMode {
     MemoryMapped,
 }
 
-impl From<QspiMode> for u8 {
-    fn from(val: QspiMode) -> Self {
-        match val {
+impl Into<u8> for QspiMode {
+    fn into(self) -> u8 {
+        match self {
             QspiMode::IndirectWrite => 0b00,
             QspiMode::IndirectRead => 0b01,
             QspiMode::AutoPolling => 0b10,
@@ -34,9 +34,9 @@ pub enum QspiWidth {
     QUAD,
 }
 
-impl From<QspiWidth> for u8 {
-    fn from(val: QspiWidth) -> Self {
-        match val {
+impl Into<u8> for QspiWidth {
+    fn into(self) -> u8 {
+        match self {
             QspiWidth::NONE => 0b00,
             QspiWidth::SING => 0b01,
             QspiWidth::DUAL => 0b10,
@@ -55,9 +55,9 @@ pub enum FlashSelection {
     Flash2,
 }
 
-impl From<FlashSelection> for bool {
-    fn from(val: FlashSelection) -> Self {
-        match val {
+impl Into<bool> for FlashSelection {
+    fn into(self) -> bool {
+        match self {
             FlashSelection::Flash1 => false,
             FlashSelection::Flash2 => true,
         }
@@ -94,9 +94,9 @@ pub enum MemorySize {
     Other(u8),
 }
 
-impl From<MemorySize> for u8 {
-    fn from(val: MemorySize) -> Self {
-        match val {
+impl Into<u8> for MemorySize {
+    fn into(self) -> u8 {
+        match self {
             MemorySize::_1KiB => 9,
             MemorySize::_2KiB => 10,
             MemorySize::_4KiB => 11,
@@ -138,9 +138,9 @@ pub enum AddressSize {
     _32bit,
 }
 
-impl From<AddressSize> for u8 {
-    fn from(val: AddressSize) -> Self {
-        match val {
+impl Into<u8> for AddressSize {
+    fn into(self) -> u8 {
+        match self {
             AddressSize::_8Bit => 0b00,
             AddressSize::_16Bit => 0b01,
             AddressSize::_24bit => 0b10,
@@ -163,9 +163,9 @@ pub enum ChipSelectHighTime {
     _8Cycle,
 }
 
-impl From<ChipSelectHighTime> for u8 {
-    fn from(val: ChipSelectHighTime) -> Self {
-        match val {
+impl Into<u8> for ChipSelectHighTime {
+    fn into(self) -> u8 {
+        match self {
             ChipSelectHighTime::_1Cycle => 0,
             ChipSelectHighTime::_2Cycle => 1,
             ChipSelectHighTime::_3Cycle => 2,
@@ -216,9 +216,9 @@ pub enum FIFOThresholdLevel {
     _32Bytes,
 }
 
-impl From<FIFOThresholdLevel> for u8 {
-    fn from(val: FIFOThresholdLevel) -> Self {
-        match val {
+impl Into<u8> for FIFOThresholdLevel {
+    fn into(self) -> u8 {
+        match self {
             FIFOThresholdLevel::_1Bytes => 0,
             FIFOThresholdLevel::_2Bytes => 1,
             FIFOThresholdLevel::_3Bytes => 2,
@@ -293,9 +293,9 @@ pub enum DummyCycles {
     _31,
 }
 
-impl From<DummyCycles> for u8 {
-    fn from(val: DummyCycles) -> Self {
-        match val {
+impl Into<u8> for DummyCycles {
+    fn into(self) -> u8 {
+        match self {
             DummyCycles::_0 => 0,
             DummyCycles::_1 => 1,
             DummyCycles::_2 => 2,
diff --git a/embassy-stm32/src/rcc/bd.rs b/embassy-stm32/src/rcc/bd.rs
index e2c704405..57aaba1c7 100644
--- a/embassy-stm32/src/rcc/bd.rs
+++ b/embassy-stm32/src/rcc/bd.rs
@@ -92,17 +92,6 @@ pub struct LsConfig {
 }
 
 impl LsConfig {
-    /// Creates an [`LsConfig`] using the LSI when possible.
-    pub const fn new() -> Self {
-        // on L5, just the fact that LSI is enabled makes things crash.
-        // TODO: investigate.
-
-        #[cfg(not(stm32l5))]
-        return Self::default_lsi();
-        #[cfg(stm32l5)]
-        return Self::off();
-    }
-
     pub const fn default_lse() -> Self {
         Self {
             rtc: RtcClockSource::LSE,
@@ -135,7 +124,13 @@ impl LsConfig {
 
 impl Default for LsConfig {
     fn default() -> Self {
-        Self::new()
+        // on L5, just the fact that LSI is enabled makes things crash.
+        // TODO: investigate.
+
+        #[cfg(not(stm32l5))]
+        return Self::default_lsi();
+        #[cfg(stm32l5)]
+        return Self::off();
     }
 }
 
diff --git a/embassy-stm32/src/rcc/c0.rs b/embassy-stm32/src/rcc/c0.rs
index cac2a9149..0b749bcff 100644
--- a/embassy-stm32/src/rcc/c0.rs
+++ b/embassy-stm32/src/rcc/c0.rs
@@ -59,8 +59,9 @@ pub struct Config {
     pub mux: super::mux::ClockMux,
 }
 
-impl Config {
-    pub const fn new() -> Self {
+impl Default for Config {
+    #[inline]
+    fn default() -> Config {
         Config {
             hsi: Some(Hsi {
                 sys_div: HsiSysDiv::DIV4,
@@ -70,18 +71,12 @@ impl Config {
             sys: Sysclk::HSISYS,
             ahb_pre: AHBPrescaler::DIV1,
             apb1_pre: APBPrescaler::DIV1,
-            ls: crate::rcc::LsConfig::new(),
-            mux: super::mux::ClockMux::default(),
+            ls: Default::default(),
+            mux: Default::default(),
         }
     }
 }
 
-impl Default for Config {
-    fn default() -> Config {
-        Self::new()
-    }
-}
-
 pub(crate) unsafe fn init(config: Config) {
     // Turn on the HSI
     match config.hsi {
diff --git a/embassy-stm32/src/rcc/f013.rs b/embassy-stm32/src/rcc/f013.rs
index 1155b6acd..cfa223d1f 100644
--- a/embassy-stm32/src/rcc/f013.rs
+++ b/embassy-stm32/src/rcc/f013.rs
@@ -126,13 +126,13 @@ pub struct Config {
     pub ls: super::LsConfig,
 }
 
-impl Config {
-    pub const fn new() -> Self {
+impl Default for Config {
+    fn default() -> Self {
         Self {
             hsi: true,
             hse: None,
             #[cfg(crs)]
-            hsi48: Some(crate::rcc::Hsi48Config::new()),
+            hsi48: Some(Default::default()),
             sys: Sysclk::HSI,
             pll: None,
 
@@ -147,7 +147,7 @@ impl Config {
             apb1_pre: APBPrescaler::DIV1,
             #[cfg(not(stm32f0))]
             apb2_pre: APBPrescaler::DIV1,
-            ls: crate::rcc::LsConfig::new(),
+            ls: Default::default(),
 
             #[cfg(stm32f1)]
             // ensure ADC is not out of range by default even if APB2 is maxxed out (36mhz)
@@ -163,17 +163,11 @@ impl Config {
             #[cfg(stm32f107)]
             i2s3_src: I2s2src::SYS,
 
-            mux: super::mux::ClockMux::default(),
+            mux: Default::default(),
         }
     }
 }
 
-impl Default for Config {
-    fn default() -> Self {
-        Self::new()
-    }
-}
-
 /// Initialize and Set the clock frequencies
 pub(crate) unsafe fn init(config: Config) {
     // Turn on the HSI
diff --git a/embassy-stm32/src/rcc/f247.rs b/embassy-stm32/src/rcc/f247.rs
index 8f2e8db5f..ee67f1cc0 100644
--- a/embassy-stm32/src/rcc/f247.rs
+++ b/embassy-stm32/src/rcc/f247.rs
@@ -108,8 +108,8 @@ pub struct Config {
     pub voltage: VoltageScale,
 }
 
-impl Config {
-    pub const fn new() -> Self {
+impl Default for Config {
+    fn default() -> Self {
         Self {
             hsi: true,
             hse: None,
@@ -127,21 +127,15 @@ impl Config {
             apb1_pre: APBPrescaler::DIV1,
             apb2_pre: APBPrescaler::DIV1,
 
-            ls: crate::rcc::LsConfig::new(),
+            ls: Default::default(),
 
             #[cfg(stm32f2)]
             voltage: VoltageScale::Range3,
-            mux: super::mux::ClockMux::default(),
+            mux: Default::default(),
         }
     }
 }
 
-impl Default for Config {
-    fn default() -> Self {
-        Self::new()
-    }
-}
-
 pub(crate) unsafe fn init(config: Config) {
     // set VOS to SCALE1, if use PLL
     // TODO: check real clock speed before set VOS
diff --git a/embassy-stm32/src/rcc/g0.rs b/embassy-stm32/src/rcc/g0.rs
index ce6398afd..e391b1210 100644
--- a/embassy-stm32/src/rcc/g0.rs
+++ b/embassy-stm32/src/rcc/g0.rs
@@ -97,8 +97,9 @@ pub struct Config {
     pub mux: super::mux::ClockMux,
 }
 
-impl Config {
-    pub const fn new() -> Self {
+impl Default for Config {
+    #[inline]
+    fn default() -> Config {
         Config {
             hsi: Some(Hsi {
                 sys_div: HsiSysDiv::DIV1,
@@ -106,24 +107,18 @@ impl Config {
             hse: None,
             sys: Sysclk::HSI,
             #[cfg(crs)]
-            hsi48: Some(crate::rcc::Hsi48Config::new()),
+            hsi48: Some(Default::default()),
             pll: None,
             ahb_pre: AHBPrescaler::DIV1,
             apb1_pre: APBPrescaler::DIV1,
             low_power_run: false,
-            ls: crate::rcc::LsConfig::new(),
+            ls: Default::default(),
             voltage_range: VoltageRange::RANGE1,
-            mux: super::mux::ClockMux::default(),
+            mux: Default::default(),
         }
     }
 }
 
-impl Default for Config {
-    fn default() -> Config {
-        Self::new()
-    }
-}
-
 #[derive(Default)]
 pub struct PllFreq {
     pub pll_p: Option<Hertz>,
diff --git a/embassy-stm32/src/rcc/g4.rs b/embassy-stm32/src/rcc/g4.rs
index da13e16aa..d7d5c7388 100644
--- a/embassy-stm32/src/rcc/g4.rs
+++ b/embassy-stm32/src/rcc/g4.rs
@@ -91,31 +91,26 @@ pub struct Config {
     pub mux: super::mux::ClockMux,
 }
 
-impl Config {
-    pub const fn new() -> Self {
+impl Default for Config {
+    #[inline]
+    fn default() -> Config {
         Config {
             hsi: true,
             hse: None,
             sys: Sysclk::HSI,
-            hsi48: Some(crate::rcc::Hsi48Config::new()),
+            hsi48: Some(Default::default()),
             pll: None,
             ahb_pre: AHBPrescaler::DIV1,
             apb1_pre: APBPrescaler::DIV1,
             apb2_pre: APBPrescaler::DIV1,
             low_power_run: false,
-            ls: crate::rcc::LsConfig::new(),
+            ls: Default::default(),
             boost: false,
-            mux: super::mux::ClockMux::default(),
+            mux: Default::default(),
         }
     }
 }
 
-impl Default for Config {
-    fn default() -> Config {
-        Self::new()
-    }
-}
-
 #[derive(Default)]
 pub struct PllFreq {
     pub pll_p: Option<Hertz>,
diff --git a/embassy-stm32/src/rcc/h.rs b/embassy-stm32/src/rcc/h.rs
index 383f48874..eaba8cefb 100644
--- a/embassy-stm32/src/rcc/h.rs
+++ b/embassy-stm32/src/rcc/h.rs
@@ -218,13 +218,13 @@ pub struct Config {
     pub mux: super::mux::ClockMux,
 }
 
-impl Config {
-    pub const fn new() -> Self {
+impl Default for Config {
+    fn default() -> Self {
         Self {
             hsi: Some(HSIPrescaler::DIV1),
             hse: None,
             csi: false,
-            hsi48: Some(crate::rcc::Hsi48Config::new()),
+            hsi48: Some(Default::default()),
             sys: Sysclk::HSI,
             pll1: None,
             pll2: None,
@@ -248,22 +248,16 @@ impl Config {
             voltage_scale: VoltageScale::Scale0,
             #[cfg(rcc_h7rs)]
             voltage_scale: VoltageScale::HIGH,
-            ls: crate::rcc::LsConfig::new(),
+            ls: Default::default(),
 
             #[cfg(any(pwr_h7rm0399, pwr_h7rm0455, pwr_h7rm0468, pwr_h7rs))]
             supply_config: SupplyConfig::LDO,
 
-            mux: super::mux::ClockMux::default(),
+            mux: Default::default(),
         }
     }
 }
 
-impl Default for Config {
-    fn default() -> Self {
-        Self::new()
-    }
-}
-
 pub(crate) unsafe fn init(config: Config) {
     #[cfg(any(stm32h7))]
     let pwr_reg = PWR.cr3();
diff --git a/embassy-stm32/src/rcc/hsi48.rs b/embassy-stm32/src/rcc/hsi48.rs
index 3ea5c96c9..efabd059f 100644
--- a/embassy-stm32/src/rcc/hsi48.rs
+++ b/embassy-stm32/src/rcc/hsi48.rs
@@ -18,15 +18,9 @@ pub struct Hsi48Config {
     pub sync_from_usb: bool,
 }
 
-impl Hsi48Config {
-    pub const fn new() -> Self {
-        Self { sync_from_usb: false }
-    }
-}
-
 impl Default for Hsi48Config {
     fn default() -> Self {
-        Self::new()
+        Self { sync_from_usb: false }
     }
 }
 
diff --git a/embassy-stm32/src/rcc/l.rs b/embassy-stm32/src/rcc/l.rs
index 81b89046e..863942f1a 100644
--- a/embassy-stm32/src/rcc/l.rs
+++ b/embassy-stm32/src/rcc/l.rs
@@ -68,8 +68,9 @@ pub struct Config {
     pub mux: super::mux::ClockMux,
 }
 
-impl Config {
-    pub const fn new() -> Self {
+impl Default for Config {
+    #[inline]
+    fn default() -> Config {
         Config {
             hse: None,
             hsi: false,
@@ -89,21 +90,15 @@ impl Config {
             #[cfg(any(stm32l47x, stm32l48x, stm32l49x, stm32l4ax, rcc_l4plus, stm32l5))]
             pllsai2: None,
             #[cfg(crs)]
-            hsi48: Some(crate::rcc::Hsi48Config::new()),
-            ls: crate::rcc::LsConfig::new(),
+            hsi48: Some(Default::default()),
+            ls: Default::default(),
             #[cfg(any(stm32l0, stm32l1))]
             voltage_scale: VoltageScale::RANGE1,
-            mux: super::mux::ClockMux::default(),
+            mux: Default::default(),
         }
     }
 }
 
-impl Default for Config {
-    fn default() -> Config {
-        Self::new()
-    }
-}
-
 #[cfg(stm32wb)]
 pub const WPAN_DEFAULT: Config = Config {
     hse: Some(Hse {
diff --git a/embassy-stm32/src/rcc/u5.rs b/embassy-stm32/src/rcc/u5.rs
index ff70466b9..93a327be7 100644
--- a/embassy-stm32/src/rcc/u5.rs
+++ b/embassy-stm32/src/rcc/u5.rs
@@ -97,14 +97,14 @@ pub struct Config {
     pub mux: super::mux::ClockMux,
 }
 
-impl Config {
-    pub const fn new() -> Self {
+impl Default for Config {
+    fn default() -> Self {
         Self {
             msis: Some(Msirange::RANGE_4MHZ),
             msik: Some(Msirange::RANGE_4MHZ),
             hse: None,
             hsi: false,
-            hsi48: Some(crate::rcc::Hsi48Config::new()),
+            hsi48: Some(Default::default()),
             pll1: None,
             pll2: None,
             pll3: None,
@@ -114,18 +114,12 @@ impl Config {
             apb2_pre: APBPrescaler::DIV1,
             apb3_pre: APBPrescaler::DIV1,
             voltage_range: VoltageScale::RANGE1,
-            ls: crate::rcc::LsConfig::new(),
-            mux: super::mux::ClockMux::default(),
+            ls: Default::default(),
+            mux: Default::default(),
         }
     }
 }
 
-impl Default for Config {
-    fn default() -> Self {
-        Self::new()
-    }
-}
-
 pub(crate) unsafe fn init(config: Config) {
     // Set the requested power mode
     PWR.vosr().modify(|w| w.set_vos(config.voltage_range));
diff --git a/embassy-stm32/src/rcc/wba.rs b/embassy-stm32/src/rcc/wba.rs
index b9fc4e423..1fee648d4 100644
--- a/embassy-stm32/src/rcc/wba.rs
+++ b/embassy-stm32/src/rcc/wba.rs
@@ -37,8 +37,9 @@ pub struct Config {
     pub mux: super::mux::ClockMux,
 }
 
-impl Config {
-    pub const fn new() -> Self {
+impl Default for Config {
+    #[inline]
+    fn default() -> Config {
         Config {
             hse: None,
             hsi: true,
@@ -47,19 +48,13 @@ impl Config {
             apb1_pre: APBPrescaler::DIV1,
             apb2_pre: APBPrescaler::DIV1,
             apb7_pre: APBPrescaler::DIV1,
-            ls: crate::rcc::LsConfig::new(),
+            ls: Default::default(),
             voltage_scale: VoltageScale::RANGE2,
-            mux: super::mux::ClockMux::default(),
+            mux: Default::default(),
         }
     }
 }
 
-impl Default for Config {
-    fn default() -> Config {
-        Self::new()
-    }
-}
-
 fn hsi_enable() {
     RCC.cr().modify(|w| w.set_hsion(true));
     while !RCC.cr().read().hsirdy() {}
diff --git a/embassy-stm32/src/usart/ringbuffered.rs b/embassy-stm32/src/usart/ringbuffered.rs
index 1d4a44896..eaa9424c5 100644
--- a/embassy-stm32/src/usart/ringbuffered.rs
+++ b/embassy-stm32/src/usart/ringbuffered.rs
@@ -18,65 +18,6 @@ use crate::Peri;
 /// Rx-only Ring-buffered UART Driver
 ///
 /// Created with [UartRx::into_ring_buffered]
-///
-/// ### Notes on 'waiting for bytes'
-///
-/// The `read(buf)` (but not `read()`) and `read_exact(buf)` functions
-/// may need to wait for bytes to arrive, if the ring buffer does not
-/// contain enough bytes to fill the buffer passed by the caller of
-/// the function, or is empty.
-///
-/// Waiting for bytes operates in one of two modes, depending on
-/// the behavior of the sender and the size of the buffer passed
-/// to the function:
-///
-/// - If the sender sends intermittently, the 'idle line'
-/// condition will be detected when the sender stops, and any
-/// bytes in the ring buffer will be returned. If there are no
-/// bytes in the buffer, the check will be repeated each time the
-/// 'idle line' condition is detected, so if the sender sends just
-/// a single byte, it will be returned once the 'idle line'
-/// condition is detected.
-///
-/// - If the sender sends continuously, the call will wait until
-/// the DMA controller indicates that it has written to either the
-/// middle byte or last byte of the ring buffer ('half transfer'
-/// or 'transfer complete', respectively). This does not indicate
-/// the buffer is half-full or full, though, because the DMA
-/// controller does not detect those conditions; it sends an
-/// interrupt when those specific buffer addresses have been
-/// written.
-///
-/// In both cases this will result in variable latency due to the
-/// buffering effect. For example, if the baudrate is 2400 bps, and
-/// the configuration is 8 data bits, no parity bit, and one stop bit,
-/// then a byte will be received every ~4.16ms. If the ring buffer is
-/// 32 bytes, then a 'wait for bytes' delay may have to wait for 16
-/// bytes in the worst case, resulting in a delay (latency) of
-/// ~62.46ms for the first byte in the ring buffer. If the sender
-/// sends only 6 bytes and then stops, but the buffer was empty when
-/// the read function was called, then those bytes may not be returned
-/// until ~24.96ms after the first byte was received (time for 5
-/// additional bytes plus the 'idle frame' which triggers the 'idle
-/// line' condition).
-///
-/// Applications subject to this latency must be careful if they
-/// also apply timeouts during reception, as it may appear (to
-/// them) that the sender has stopped sending when it did not. In
-/// the example above, a 50ms timeout (12 bytes at 2400bps) might
-/// seem to be reasonable to detect that the sender has stopped
-/// sending, but would be falsely triggered in the worst-case
-/// buffer delay scenario.
-///
-/// Note: This latency is caused by the limited capabilities of the
-/// STM32 DMA controller; since it cannot generate an interrupt when
-/// it stores a byte into an empty ring buffer, or in any other
-/// configurable conditions, it is not possible to take notice of the
-/// contents of the ring buffer more quickly without introducing
-/// polling. As a result the latency can be reduced by calling the
-/// read functions repeatedly with smaller buffers to receive the
-/// available bytes, as each call to a read function will explicitly
-/// check the ring buffer for available bytes.
 pub struct RingBufferedUartRx<'d> {
     info: &'static Info,
     state: &'static State,
@@ -138,8 +79,7 @@ impl<'d> RingBufferedUartRx<'d> {
 
     /// Configure and start the DMA backed UART receiver
     ///
-    /// Note: This is also done automatically by the read functions if
-    /// required.
+    /// Note: This is also done automatically by [`read()`] if required.
     pub fn start_uart(&mut self) {
         // Clear the buffer so that it is ready to receive data
         compiler_fence(Ordering::SeqCst);
@@ -199,16 +139,14 @@ impl<'d> RingBufferedUartRx<'d> {
         Ok(())
     }
 
-    /// Read bytes that are available in the ring buffer, or wait for
-    /// bytes to become available and return them.
+    /// Read bytes that are readily available in the ring buffer.
+    /// If no bytes are currently available in the buffer the call waits until the some
+    /// bytes are available (at least one byte and at most half the buffer size)
     ///
-    /// Background reception is started if necessary (if `start_uart()` had
-    /// not previously been called, or if an error was detected which
-    /// caused background reception to be stopped).
+    /// Background receive is started if `start()` has not been previously called.
     ///
-    /// Background reception is terminated when an error is returned.
-    /// It must be started again by calling `start_uart()` or by
-    /// calling a read function again.
+    /// Receive in the background is terminated if an error is returned.
+    /// It must then manually be started again by calling `start()` or by re-calling `read()`.
     pub async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Error> {
         self.start_dma_or_check_errors()?;
 
@@ -264,8 +202,7 @@ impl<'d> RingBufferedUartRx<'d> {
         });
 
         let mut dma_init = false;
-        // Future which completes when the DMA controller indicates it
-        // has written to the ring buffer's middle byte, or last byte
+        // Future which completes when there is dma is half full or full
         let dma = poll_fn(|cx| {
             self.ring_buf.set_waker(cx.waker());
 
diff --git a/embassy-sync/src/channel.rs b/embassy-sync/src/channel.rs
index 856551417..f97cb2b8e 100644
--- a/embassy-sync/src/channel.rs
+++ b/embassy-sync/src/channel.rs
@@ -390,21 +390,21 @@ where
 
 /// Receive-only access to a [`Channel`] without knowing channel size.
 /// This version can be sent between threads but can only be created if the underlying mutex is Sync.
-pub struct SendDynamicReceiver<'ch, T> {
+pub struct SendableDynamicReceiver<'ch, T> {
     pub(crate) channel: &'ch dyn DynamicChannel<T>,
 }
 
-impl<'ch, T> Clone for SendDynamicReceiver<'ch, T> {
+impl<'ch, T> Clone for SendableDynamicReceiver<'ch, T> {
     fn clone(&self) -> Self {
         *self
     }
 }
 
-impl<'ch, T> Copy for SendDynamicReceiver<'ch, T> {}
-unsafe impl<'ch, T: Send> Send for SendDynamicReceiver<'ch, T> {}
-unsafe impl<'ch, T: Send> Sync for SendDynamicReceiver<'ch, T> {}
+impl<'ch, T> Copy for SendableDynamicReceiver<'ch, T> {}
+unsafe impl<'ch, T: Send> Send for SendableDynamicReceiver<'ch, T> {}
+unsafe impl<'ch, T: Send> Sync for SendableDynamicReceiver<'ch, T> {}
 
-impl<'ch, T> SendDynamicReceiver<'ch, T> {
+impl<'ch, T> SendableDynamicReceiver<'ch, T> {
     /// Receive the next value.
     ///
     /// See [`Channel::receive()`].
@@ -434,7 +434,7 @@ impl<'ch, T> SendDynamicReceiver<'ch, T> {
     }
 }
 
-impl<'ch, M, T, const N: usize> From<Receiver<'ch, M, T, N>> for SendDynamicReceiver<'ch, T>
+impl<'ch, M, T, const N: usize> From<Receiver<'ch, M, T, N>> for SendableDynamicReceiver<'ch, T>
 where
     M: RawMutex + Sync + Send,
 {
diff --git a/examples/mimxrt6/src/bin/button.rs b/examples/mimxrt6/src/bin/button.rs
deleted file mode 100644
index efb7f14af..000000000
--- a/examples/mimxrt6/src/bin/button.rs
+++ /dev/null
@@ -1,29 +0,0 @@
-#![no_std]
-#![no_main]
-
-use defmt::info;
-use embassy_executor::Spawner;
-use embassy_futures::select::{select, Either};
-use embassy_imxrt::gpio;
-use {defmt_rtt as _, embassy_imxrt_examples as _, panic_probe as _};
-
-#[embassy_executor::main]
-async fn main(_spawner: Spawner) {
-    let p = embassy_imxrt::init(Default::default());
-
-    let mut user1 = gpio::Input::new(p.PIO1_1, gpio::Pull::None, gpio::Inverter::Disabled);
-    let mut user2 = gpio::Input::new(p.PIO0_10, gpio::Pull::None, gpio::Inverter::Disabled);
-
-    loop {
-        let res = select(user1.wait_for_falling_edge(), user2.wait_for_falling_edge()).await;
-
-        match res {
-            Either::First(()) => {
-                info!("Button `USER1' pressed");
-            }
-            Either::Second(()) => {
-                info!("Button `USER2' pressed");
-            }
-        }
-    }
-}


Test patch:
diff --git a/embassy-executor/tests/test.rs b/embassy-executor/tests/test.rs
index 78c49c071..c1e7ec5d7 100644
--- a/embassy-executor/tests/test.rs
+++ b/embassy-executor/tests/test.rs
@@ -1,7 +1,8 @@
 #![cfg_attr(feature = "nightly", feature(impl_trait_in_assoc_type))]
+#![cfg_attr(feature = "nightly", feature(never_type))]
 
 use std::boxed::Box;
-use std::future::poll_fn;
+use std::future::{poll_fn, Future};
 use std::sync::{Arc, Mutex};
 use std::task::Poll;
 
@@ -58,6 +59,39 @@ fn executor_task() {
         trace.push("poll task1")
     }
 
+    #[task]
+    async fn task2() -> ! {
+        panic!()
+    }
+
+    let (executor, trace) = setup();
+    executor.spawner().spawn(task1(trace.clone())).unwrap();
+
+    unsafe { executor.poll() };
+    unsafe { executor.poll() };
+
+    assert_eq!(
+        trace.get(),
+        &[
+            "pend",       // spawning a task pends the executor
+            "poll task1", // poll only once.
+        ]
+    )
+}
+
+#[test]
+fn executor_task_rpit() {
+    #[task]
+    fn task1(trace: Trace) -> impl Future<Output = ()> {
+        async move { trace.push("poll task1") }
+    }
+
+    #[cfg(feature = "nightly")]
+    #[task]
+    fn task2() -> impl Future<Output = !> {
+        async { panic!() }
+    }
+
     let (executor, trace) = setup();
     executor.spawner().spawn(task1(trace.clone())).unwrap();
 
diff --git a/embassy-executor/tests/ui.rs b/embassy-executor/tests/ui.rs
index 278a4b903..c4a1a601c 100644
--- a/embassy-executor/tests/ui.rs
+++ b/embassy-executor/tests/ui.rs
@@ -17,6 +17,15 @@ fn ui() {
     t.compile_fail("tests/ui/nonstatic_struct_elided.rs");
     t.compile_fail("tests/ui/nonstatic_struct_generic.rs");
     t.compile_fail("tests/ui/not_async.rs");
+    if rustversion::cfg!(stable) {
+        // output is slightly different on nightly
+        t.compile_fail("tests/ui/bad_return_impl_future.rs");
+        t.compile_fail("tests/ui/return_impl_send.rs");
+    }
+    if cfg!(feature = "nightly") {
+        t.compile_fail("tests/ui/bad_return_impl_future_nightly.rs");
+        t.compile_fail("tests/ui/return_impl_send_nightly.rs");
+    }
     t.compile_fail("tests/ui/self_ref.rs");
     t.compile_fail("tests/ui/self.rs");
     t.compile_fail("tests/ui/type_error.rs");
diff --git a/embassy-executor/tests/ui/bad_return_impl_future.rs b/embassy-executor/tests/ui/bad_return_impl_future.rs
new file mode 100644
index 000000000..baaa7dc5a
--- /dev/null
+++ b/embassy-executor/tests/ui/bad_return_impl_future.rs
@@ -0,0 +1,9 @@
+#![cfg_attr(feature = "nightly", feature(impl_trait_in_assoc_type))]
+use core::future::Future;
+
+#[embassy_executor::task]
+fn task() -> impl Future<Output = u32> {
+    async { 5 }
+}
+
+fn main() {}
diff --git a/embassy-executor/tests/ui/bad_return_impl_future.stderr b/embassy-executor/tests/ui/bad_return_impl_future.stderr
new file mode 100644
index 000000000..2980fd18b
--- /dev/null
+++ b/embassy-executor/tests/ui/bad_return_impl_future.stderr
@@ -0,0 +1,120 @@
+error[E0277]: task futures must resolve to `()` or `!`
+ --> tests/ui/bad_return_impl_future.rs:5:4
+  |
+4 | #[embassy_executor::task]
+  | ------------------------- required by a bound introduced by this call
+5 | fn task() -> impl Future<Output = u32> {
+  |    ^^^^ the trait `TaskFn<_>` is not implemented for fn item `fn() -> impl Future<Output = u32> {__task_task}`
+  |
+  = note: use `async fn` or change the return type to `impl Future<Output = ()>`
+note: required by a bound in `task_pool_size`
+ --> src/lib.rs
+  |
+  |     pub const fn task_pool_size<F, Args, Fut, const POOL_SIZE: usize>(_: F) -> usize
+  |                  -------------- required by a bound in this function
+  |     where
+  |         F: TaskFn<Args, Fut = Fut>,
+  |                         ^^^^^^^^^ required by this bound in `task_pool_size`
+
+error[E0277]: task futures must resolve to `()` or `!`
+ --> tests/ui/bad_return_impl_future.rs:4:1
+  |
+4 | #[embassy_executor::task]
+  | ^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `TaskFn<_>` is not implemented for fn item `fn() -> impl Future<Output = u32> {__task_task}`
+  |
+  = note: use `async fn` or change the return type to `impl Future<Output = ()>`
+note: required by a bound in `task_pool_size`
+ --> src/lib.rs
+  |
+  |     pub const fn task_pool_size<F, Args, Fut, const POOL_SIZE: usize>(_: F) -> usize
+  |                  -------------- required by a bound in this function
+  |     where
+  |         F: TaskFn<Args, Fut = Fut>,
+  |            ^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `task_pool_size`
+  = note: this error originates in the attribute macro `embassy_executor::task` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: task futures must resolve to `()` or `!`
+ --> tests/ui/bad_return_impl_future.rs:5:4
+  |
+4 | #[embassy_executor::task]
+  | ------------------------- required by a bound introduced by this call
+5 | fn task() -> impl Future<Output = u32> {
+  |    ^^^^ the trait `TaskFn<_>` is not implemented for fn item `fn() -> impl Future<Output = u32> {__task_task}`
+  |
+  = note: use `async fn` or change the return type to `impl Future<Output = ()>`
+note: required by a bound in `task_pool_align`
+ --> src/lib.rs
+  |
+  |     pub const fn task_pool_align<F, Args, Fut, const POOL_SIZE: usize>(_: F) -> usize
+  |                  --------------- required by a bound in this function
+  |     where
+  |         F: TaskFn<Args, Fut = Fut>,
+  |                         ^^^^^^^^^ required by this bound in `task_pool_align`
+
+error[E0277]: task futures must resolve to `()` or `!`
+ --> tests/ui/bad_return_impl_future.rs:4:1
+  |
+4 | #[embassy_executor::task]
+  | ^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `TaskFn<_>` is not implemented for fn item `fn() -> impl Future<Output = u32> {__task_task}`
+  |
+  = note: use `async fn` or change the return type to `impl Future<Output = ()>`
+note: required by a bound in `task_pool_align`
+ --> src/lib.rs
+  |
+  |     pub const fn task_pool_align<F, Args, Fut, const POOL_SIZE: usize>(_: F) -> usize
+  |                  --------------- required by a bound in this function
+  |     where
+  |         F: TaskFn<Args, Fut = Fut>,
+  |            ^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `task_pool_align`
+  = note: this error originates in the attribute macro `embassy_executor::task` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: task futures must resolve to `()` or `!`
+ --> tests/ui/bad_return_impl_future.rs:5:4
+  |
+4 | #[embassy_executor::task]
+  | ------------------------- required by a bound introduced by this call
+5 | fn task() -> impl Future<Output = u32> {
+  |    ^^^^ the trait `TaskFn<_>` is not implemented for fn item `fn() -> impl Future<Output = u32> {__task_task}`
+  |
+  = note: use `async fn` or change the return type to `impl Future<Output = ()>`
+note: required by a bound in `task_pool_new`
+ --> src/lib.rs
+  |
+  |     pub const fn task_pool_new<F, Args, Fut, const POOL_SIZE: usize>(_: F) -> TaskPool<Fut, POOL_SIZE>
+  |                  ------------- required by a bound in this function
+  |     where
+  |         F: TaskFn<Args, Fut = Fut>,
+  |                         ^^^^^^^^^ required by this bound in `task_pool_new`
+
+error[E0277]: task futures must resolve to `()` or `!`
+ --> tests/ui/bad_return_impl_future.rs:4:1
+  |
+4 | #[embassy_executor::task]
+  | ^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `TaskFn<_>` is not implemented for fn item `fn() -> impl Future<Output = u32> {__task_task}`
+  |
+  = note: use `async fn` or change the return type to `impl Future<Output = ()>`
+note: required by a bound in `task_pool_new`
+ --> src/lib.rs
+  |
+  |     pub const fn task_pool_new<F, Args, Fut, const POOL_SIZE: usize>(_: F) -> TaskPool<Fut, POOL_SIZE>
+  |                  ------------- required by a bound in this function
+  |     where
+  |         F: TaskFn<Args, Fut = Fut>,
+  |            ^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `task_pool_new`
+  = note: this error originates in the attribute macro `embassy_executor::task` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: task futures must resolve to `()` or `!`
+ --> tests/ui/bad_return_impl_future.rs:5:4
+  |
+4 | #[embassy_executor::task]
+  | ------------------------- required by a bound introduced by this call
+5 | fn task() -> impl Future<Output = u32> {
+  |    ^^^^ the trait `TaskFn<_>` is not implemented for fn item `fn() -> impl Future<Output = u32> {__task_task}`
+  |
+  = note: use `async fn` or change the return type to `impl Future<Output = ()>`
+note: required by a bound in `__task_pool_get`
+ --> tests/ui/bad_return_impl_future.rs:4:1
+  |
+4 | #[embassy_executor::task]
+  | ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `__task_pool_get`
+  = note: this error originates in the attribute macro `embassy_executor::task` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/embassy-executor/tests/ui/bad_return_impl_future_nightly.rs b/embassy-executor/tests/ui/bad_return_impl_future_nightly.rs
new file mode 100644
index 000000000..baaa7dc5a
--- /dev/null
+++ b/embassy-executor/tests/ui/bad_return_impl_future_nightly.rs
@@ -0,0 +1,9 @@
+#![cfg_attr(feature = "nightly", feature(impl_trait_in_assoc_type))]
+use core::future::Future;
+
+#[embassy_executor::task]
+fn task() -> impl Future<Output = u32> {
+    async { 5 }
+}
+
+fn main() {}
diff --git a/embassy-executor/tests/ui/bad_return_impl_future_nightly.stderr b/embassy-executor/tests/ui/bad_return_impl_future_nightly.stderr
new file mode 100644
index 000000000..73ceb989d
--- /dev/null
+++ b/embassy-executor/tests/ui/bad_return_impl_future_nightly.stderr
@@ -0,0 +1,10 @@
+error[E0277]: task futures must resolve to `()` or `!`
+ --> tests/ui/bad_return_impl_future_nightly.rs:4:1
+  |
+4 | #[embassy_executor::task]
+  | ^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `TaskReturnValue` is not implemented for `u32`
+  |
+  = note: use `async fn` or change the return type to `impl Future<Output = ()>`
+  = help: the following other types implement trait `TaskReturnValue`:
+            ()
+            <fn() -> ! as _export::HasOutput>::Output
diff --git a/embassy-executor/tests/ui/return_impl_send.rs b/embassy-executor/tests/ui/return_impl_send.rs
new file mode 100644
index 000000000..6ddb0e722
--- /dev/null
+++ b/embassy-executor/tests/ui/return_impl_send.rs
@@ -0,0 +1,6 @@
+#![cfg_attr(feature = "nightly", feature(impl_trait_in_assoc_type))]
+
+#[embassy_executor::task]
+fn task() -> impl Send {}
+
+fn main() {}
diff --git a/embassy-executor/tests/ui/return_impl_send.stderr b/embassy-executor/tests/ui/return_impl_send.stderr
new file mode 100644
index 000000000..7e3e468b8
--- /dev/null
+++ b/embassy-executor/tests/ui/return_impl_send.stderr
@@ -0,0 +1,137 @@
+error[E0277]: task futures must resolve to `()` or `!`
+ --> tests/ui/return_impl_send.rs:4:4
+  |
+3 | #[embassy_executor::task]
+  | ------------------------- required by a bound introduced by this call
+4 | fn task() -> impl Send {}
+  |    ^^^^ the trait `TaskFn<_>` is not implemented for fn item `fn() -> impl Send {__task_task}`
+  |
+  = note: use `async fn` or change the return type to `impl Future<Output = ()>`
+note: required by a bound in `task_pool_size`
+ --> src/lib.rs
+  |
+  |     pub const fn task_pool_size<F, Args, Fut, const POOL_SIZE: usize>(_: F) -> usize
+  |                  -------------- required by a bound in this function
+  |     where
+  |         F: TaskFn<Args, Fut = Fut>,
+  |                         ^^^^^^^^^ required by this bound in `task_pool_size`
+
+error[E0277]: task futures must resolve to `()` or `!`
+ --> tests/ui/return_impl_send.rs:3:1
+  |
+3 | #[embassy_executor::task]
+  | ^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `TaskFn<_>` is not implemented for fn item `fn() -> impl Send {__task_task}`
+  |
+  = note: use `async fn` or change the return type to `impl Future<Output = ()>`
+note: required by a bound in `task_pool_size`
+ --> src/lib.rs
+  |
+  |     pub const fn task_pool_size<F, Args, Fut, const POOL_SIZE: usize>(_: F) -> usize
+  |                  -------------- required by a bound in this function
+  |     where
+  |         F: TaskFn<Args, Fut = Fut>,
+  |            ^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `task_pool_size`
+  = note: this error originates in the attribute macro `embassy_executor::task` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: task futures must resolve to `()` or `!`
+ --> tests/ui/return_impl_send.rs:4:4
+  |
+3 | #[embassy_executor::task]
+  | ------------------------- required by a bound introduced by this call
+4 | fn task() -> impl Send {}
+  |    ^^^^ the trait `TaskFn<_>` is not implemented for fn item `fn() -> impl Send {__task_task}`
+  |
+  = note: use `async fn` or change the return type to `impl Future<Output = ()>`
+note: required by a bound in `task_pool_align`
+ --> src/lib.rs
+  |
+  |     pub const fn task_pool_align<F, Args, Fut, const POOL_SIZE: usize>(_: F) -> usize
+  |                  --------------- required by a bound in this function
+  |     where
+  |         F: TaskFn<Args, Fut = Fut>,
+  |                         ^^^^^^^^^ required by this bound in `task_pool_align`
+
+error[E0277]: task futures must resolve to `()` or `!`
+ --> tests/ui/return_impl_send.rs:3:1
+  |
+3 | #[embassy_executor::task]
+  | ^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `TaskFn<_>` is not implemented for fn item `fn() -> impl Send {__task_task}`
+  |
+  = note: use `async fn` or change the return type to `impl Future<Output = ()>`
+note: required by a bound in `task_pool_align`
+ --> src/lib.rs
+  |
+  |     pub const fn task_pool_align<F, Args, Fut, const POOL_SIZE: usize>(_: F) -> usize
+  |                  --------------- required by a bound in this function
+  |     where
+  |         F: TaskFn<Args, Fut = Fut>,
+  |            ^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `task_pool_align`
+  = note: this error originates in the attribute macro `embassy_executor::task` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: task futures must resolve to `()` or `!`
+ --> tests/ui/return_impl_send.rs:4:4
+  |
+3 | #[embassy_executor::task]
+  | ------------------------- required by a bound introduced by this call
+4 | fn task() -> impl Send {}
+  |    ^^^^ the trait `TaskFn<_>` is not implemented for fn item `fn() -> impl Send {__task_task}`
+  |
+  = note: use `async fn` or change the return type to `impl Future<Output = ()>`
+note: required by a bound in `task_pool_new`
+ --> src/lib.rs
+  |
+  |     pub const fn task_pool_new<F, Args, Fut, const POOL_SIZE: usize>(_: F) -> TaskPool<Fut, POOL_SIZE>
+  |                  ------------- required by a bound in this function
+  |     where
+  |         F: TaskFn<Args, Fut = Fut>,
+  |                         ^^^^^^^^^ required by this bound in `task_pool_new`
+
+error[E0277]: task futures must resolve to `()` or `!`
+ --> tests/ui/return_impl_send.rs:3:1
+  |
+3 | #[embassy_executor::task]
+  | ^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `TaskFn<_>` is not implemented for fn item `fn() -> impl Send {__task_task}`
+  |
+  = note: use `async fn` or change the return type to `impl Future<Output = ()>`
+note: required by a bound in `task_pool_new`
+ --> src/lib.rs
+  |
+  |     pub const fn task_pool_new<F, Args, Fut, const POOL_SIZE: usize>(_: F) -> TaskPool<Fut, POOL_SIZE>
+  |                  ------------- required by a bound in this function
+  |     where
+  |         F: TaskFn<Args, Fut = Fut>,
+  |            ^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `task_pool_new`
+  = note: this error originates in the attribute macro `embassy_executor::task` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: task futures must resolve to `()` or `!`
+ --> tests/ui/return_impl_send.rs:4:4
+  |
+3 | #[embassy_executor::task]
+  | ------------------------- required by a bound introduced by this call
+4 | fn task() -> impl Send {}
+  |    ^^^^ the trait `TaskFn<_>` is not implemented for fn item `fn() -> impl Send {__task_task}`
+  |
+  = note: use `async fn` or change the return type to `impl Future<Output = ()>`
+note: required by a bound in `__task_pool_get`
+ --> tests/ui/return_impl_send.rs:3:1
+  |
+3 | #[embassy_executor::task]
+  | ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `__task_pool_get`
+  = note: this error originates in the attribute macro `embassy_executor::task` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: `impl Send` is not a future
+ --> tests/ui/return_impl_send.rs:3:1
+  |
+3 | #[embassy_executor::task]
+  | ^^^^^^^^^^^^^^^^^^^^^^^^^ `impl Send` is not a future
+  |
+  = help: the trait `Future` is not implemented for `impl Send`
+note: required by a bound in `TaskPool::<F, N>::_spawn_async_fn`
+ --> src/raw/mod.rs
+  |
+  | impl<F: Future + 'static, const N: usize> TaskPool<F, N> {
+  |         ^^^^^^ required by this bound in `TaskPool::<F, N>::_spawn_async_fn`
+...
+  |     pub unsafe fn _spawn_async_fn<FutFn>(&'static self, future: FutFn) -> SpawnToken<impl Sized>
+  |                   --------------- required by a bound in this associated function
+  = note: this error originates in the attribute macro `embassy_executor::task` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/embassy-executor/tests/ui/return_impl_send_nightly.rs b/embassy-executor/tests/ui/return_impl_send_nightly.rs
new file mode 100644
index 000000000..6ddb0e722
--- /dev/null
+++ b/embassy-executor/tests/ui/return_impl_send_nightly.rs
@@ -0,0 +1,6 @@
+#![cfg_attr(feature = "nightly", feature(impl_trait_in_assoc_type))]
+
+#[embassy_executor::task]
+fn task() -> impl Send {}
+
+fn main() {}
diff --git a/embassy-executor/tests/ui/return_impl_send_nightly.stderr b/embassy-executor/tests/ui/return_impl_send_nightly.stderr
new file mode 100644
index 000000000..de9ba6243
--- /dev/null
+++ b/embassy-executor/tests/ui/return_impl_send_nightly.stderr
@@ -0,0 +1,10 @@
+error[E0277]: `impl Send` is not a future
+ --> tests/ui/return_impl_send_nightly.rs:3:1
+  |
+3 | #[embassy_executor::task]
+  | ^^^^^^^^^^^^^^^^^^^^^^^^^
+  | |
+  | `impl Send` is not a future
+  | return type was inferred to be `impl Send` here
+  |
+  = help: the trait `Future` is not implemented for `impl Send`
diff --git a/tests/rp/src/bin/gpio.rs b/tests/rp/src/bin/gpio.rs
index 8bd0df8d8..614b6317a 100644
--- a/tests/rp/src/bin/gpio.rs
+++ b/tests/rp/src/bin/gpio.rs
@@ -67,40 +67,6 @@ async fn main(_spawner: Spawner) {
         }
     }
 
-    // Test input inversion
-    {
-        let mut b = Input::new(b.reborrow(), Pull::None);
-        b.set_inversion(true);
-        // no pull, the status is undefined
-
-        let mut a = Output::new(a.reborrow(), Level::Low);
-        delay();
-        assert!(b.is_high());
-        a.set_high();
-        delay();
-        assert!(b.is_low());
-
-        b.set_inversion(false);
-        a.set_inversion(true);
-
-        a.set_low();
-        delay();
-        assert!(b.is_high());
-
-        a.set_high();
-        delay();
-        assert!(b.is_low());
-
-        b.set_inversion(true);
-        a.set_high();
-        delay();
-        assert!(b.is_high());
-
-        a.set_high();
-        delay();
-        assert!(b.is_high());
-    }
-
     // Test input no pull
     {
         let b = Input::new(b.reborrow(), Pull::None);