From a3c1522ce64b00c6d310947ebc6dad9fe1e28d55 Mon Sep 17 00:00:00 2001
From: Quentin Smith <quentin@mit.edu>
Date: Tue, 9 Aug 2022 16:25:42 -0400
Subject: [PATCH 01/21] Add support for rtos-trace behind a feature flag

---
 embassy-executor/Cargo.toml                   |  1 +
 embassy-executor/src/executor/raw/mod.rs      | 35 +++++++++++++++++++
 embassy-executor/src/lib.rs                   | 21 +++++++++++
 .../src/macros/cortex_m_interrupt_take.rs     |  8 ++++-
 4 files changed, 64 insertions(+), 1 deletion(-)

diff --git a/embassy-executor/Cargo.toml b/embassy-executor/Cargo.toml
index d8ac4ac00..d10752b3e 100644
--- a/embassy-executor/Cargo.toml
+++ b/embassy-executor/Cargo.toml
@@ -53,6 +53,7 @@ time-tick-16mhz = ["time"]
 [dependencies]
 defmt = { version = "0.3", optional = true }
 log = { version = "0.4.14", optional = true }
+rtos-trace = { version = "0.1.2", optional = true }
 
 embedded-hal-02 = { package = "embedded-hal", version = "0.2.6" }
 embedded-hal-1 = { package = "embedded-hal", version = "1.0.0-alpha.8", optional = true}
diff --git a/embassy-executor/src/executor/raw/mod.rs b/embassy-executor/src/executor/raw/mod.rs
index fb4cc6288..c943ecd84 100644
--- a/embassy-executor/src/executor/raw/mod.rs
+++ b/embassy-executor/src/executor/raw/mod.rs
@@ -22,6 +22,8 @@ use core::{mem, ptr};
 
 use atomic_polyfill::{AtomicU32, Ordering};
 use critical_section::CriticalSection;
+#[cfg(feature = "rtos-trace")]
+use rtos_trace::trace;
 
 use self::run_queue::{RunQueue, RunQueueItem};
 use self::util::UninitCell;
@@ -306,6 +308,9 @@ impl Executor {
     /// - `task` must NOT be already enqueued (in this executor or another one).
     #[inline(always)]
     unsafe fn enqueue(&self, cs: CriticalSection, task: NonNull<TaskHeader>) {
+        #[cfg(feature = "rtos-trace")]
+        trace::task_ready_begin(task.as_ptr() as u32);
+
         if self.run_queue.enqueue(cs, task) {
             (self.signal_fn)(self.signal_ctx)
         }
@@ -323,6 +328,9 @@ impl Executor {
     pub(super) unsafe fn spawn(&'static self, task: NonNull<TaskHeader>) {
         task.as_ref().executor.set(self);
 
+        #[cfg(feature = "rtos-trace")]
+        trace::task_new(task.as_ptr() as u32);
+
         critical_section::with(|cs| {
             self.enqueue(cs, task);
         })
@@ -365,9 +373,15 @@ impl Executor {
                 return;
             }
 
+            #[cfg(feature = "rtos-trace")]
+            trace::task_exec_begin(p.as_ptr() as u32);
+
             // Run the task
             task.poll_fn.read()(p as _);
 
+            #[cfg(feature = "rtos-trace")]
+            trace::task_exec_end();
+
             // Enqueue or update into timer_queue
             #[cfg(feature = "time")]
             self.timer_queue.update(p);
@@ -381,6 +395,9 @@ impl Executor {
             let next_expiration = self.timer_queue.next_expiration();
             driver::set_alarm(self.alarm, next_expiration.as_ticks());
         }
+
+        #[cfg(feature = "rtos-trace")]
+        trace::system_idle();
     }
 
     /// Get a spawner that spawns tasks in this executor.
@@ -425,3 +442,21 @@ pub(crate) unsafe fn register_timer(at: Instant, waker: &core::task::Waker) {
     let expires_at = task.expires_at.get();
     task.expires_at.set(expires_at.min(at));
 }
+
+#[cfg(feature = "rtos-trace")]
+impl rtos_trace::RtosTraceOSCallbacks for Executor {
+    fn task_list() {
+        // We don't know what tasks exist, so we can't send them.
+    }
+    #[cfg(feature = "time")]
+    fn time() -> u64 {
+        Instant::now().as_micros()
+    }
+    #[cfg(not(feature = "time"))]
+    fn time() -> u64 {
+        0
+    }
+}
+
+#[cfg(feature = "rtos-trace")]
+rtos_trace::global_os_callbacks!{Executor}
diff --git a/embassy-executor/src/lib.rs b/embassy-executor/src/lib.rs
index 69e4aeb4b..dd99f9e52 100644
--- a/embassy-executor/src/lib.rs
+++ b/embassy-executor/src/lib.rs
@@ -19,4 +19,25 @@ pub use embassy_macros::{main, task};
 /// Implementation details for embassy macros. DO NOT USE.
 pub mod export {
     pub use atomic_polyfill as atomic;
+
+    #[cfg(feature = "rtos-trace")]
+    pub use rtos_trace::trace;
+
+    /// Expands the given block of code when `embassy-executor` is compiled with
+    /// the `rtos-trace` feature.
+    #[doc(hidden)]
+    #[macro_export]
+    #[cfg(feature = "rtos-trace")]
+    macro_rules! rtos_trace {
+        ($($tt:tt)*) => { $($tt)* };
+    }
+
+    /// Does not expand the given block of code when `embassy-executor` is
+    /// compiled without the `rtos-trace` feature.
+    #[doc(hidden)]
+    #[macro_export]
+    #[cfg(not(feature = "rtos-trace"))]
+    macro_rules! rtos_trace {
+        ($($tt:tt)*) => {};
+    }
 }
diff --git a/embassy-macros/src/macros/cortex_m_interrupt_take.rs b/embassy-macros/src/macros/cortex_m_interrupt_take.rs
index 133eb5c26..5431704da 100644
--- a/embassy-macros/src/macros/cortex_m_interrupt_take.rs
+++ b/embassy-macros/src/macros/cortex_m_interrupt_take.rs
@@ -19,7 +19,13 @@ pub fn run(name: syn::Ident) -> Result<TokenStream, TokenStream> {
                 let func = HANDLER.func.load(::embassy_executor::export::atomic::Ordering::Relaxed);
                 let ctx = HANDLER.ctx.load(::embassy_executor::export::atomic::Ordering::Relaxed);
                 let func: fn(*mut ()) = ::core::mem::transmute(func);
-                func(ctx)
+                ::embassy_executor::rtos_trace! {
+                    ::embassy_executor::export::trace::isr_enter();
+                }
+                func(ctx);
+                ::embassy_executor::rtos_trace! {
+                    ::embassy_executor::export::trace::isr_exit();
+                }
             }
 
             static TAKEN: ::embassy_executor::export::atomic::AtomicBool = ::embassy_executor::export::atomic::AtomicBool::new(false);

From 145af0e4ab75d931cba401f1755f383bcc713892 Mon Sep 17 00:00:00 2001
From: Quentin Smith <quentin@mit.edu>
Date: Wed, 10 Aug 2022 17:09:11 -0400
Subject: [PATCH 02/21] cargo fmt

---
 embassy-executor/src/executor/raw/mod.rs | 2 +-
 embassy-executor/src/lib.rs              | 1 -
 2 files changed, 1 insertion(+), 2 deletions(-)

diff --git a/embassy-executor/src/executor/raw/mod.rs b/embassy-executor/src/executor/raw/mod.rs
index c943ecd84..56220d10e 100644
--- a/embassy-executor/src/executor/raw/mod.rs
+++ b/embassy-executor/src/executor/raw/mod.rs
@@ -459,4 +459,4 @@ impl rtos_trace::RtosTraceOSCallbacks for Executor {
 }
 
 #[cfg(feature = "rtos-trace")]
-rtos_trace::global_os_callbacks!{Executor}
+rtos_trace::global_os_callbacks! {Executor}
diff --git a/embassy-executor/src/lib.rs b/embassy-executor/src/lib.rs
index dd99f9e52..32724c15c 100644
--- a/embassy-executor/src/lib.rs
+++ b/embassy-executor/src/lib.rs
@@ -19,7 +19,6 @@ pub use embassy_macros::{main, task};
 /// Implementation details for embassy macros. DO NOT USE.
 pub mod export {
     pub use atomic_polyfill as atomic;
-
     #[cfg(feature = "rtos-trace")]
     pub use rtos_trace::trace;
 

From 0bf178dd1b11d97f20cb93c5fdb0c779259be0f8 Mon Sep 17 00:00:00 2001
From: Quentin Smith <quentin@mit.edu>
Date: Tue, 16 Aug 2022 00:42:08 -0400
Subject: [PATCH 03/21] Add separate feature flag to enable interrupt tracing

---
 embassy-executor/Cargo.toml                          |  3 +++
 embassy-executor/src/lib.rs                          | 12 ++++++------
 embassy-macros/src/macros/cortex_m_interrupt_take.rs |  4 ++--
 3 files changed, 11 insertions(+), 8 deletions(-)

diff --git a/embassy-executor/Cargo.toml b/embassy-executor/Cargo.toml
index d10752b3e..ca00f2e71 100644
--- a/embassy-executor/Cargo.toml
+++ b/embassy-executor/Cargo.toml
@@ -50,6 +50,9 @@ time-tick-1000hz = ["time"]
 time-tick-1mhz = ["time"]
 time-tick-16mhz = ["time"]
 
+# Trace interrupt invocations with rtos-trace.
+rtos-trace-interrupt = ["rtos-trace"]
+
 [dependencies]
 defmt = { version = "0.3", optional = true }
 log = { version = "0.4.14", optional = true }
diff --git a/embassy-executor/src/lib.rs b/embassy-executor/src/lib.rs
index 32724c15c..47c0c1d64 100644
--- a/embassy-executor/src/lib.rs
+++ b/embassy-executor/src/lib.rs
@@ -23,20 +23,20 @@ pub mod export {
     pub use rtos_trace::trace;
 
     /// Expands the given block of code when `embassy-executor` is compiled with
-    /// the `rtos-trace` feature.
+    /// the `rtos-trace-interrupt` feature.
     #[doc(hidden)]
     #[macro_export]
-    #[cfg(feature = "rtos-trace")]
-    macro_rules! rtos_trace {
+    #[cfg(feature = "rtos-trace-interrupt")]
+    macro_rules! rtos_trace_interrupt {
         ($($tt:tt)*) => { $($tt)* };
     }
 
     /// Does not expand the given block of code when `embassy-executor` is
-    /// compiled without the `rtos-trace` feature.
+    /// compiled without the `rtos-trace-interrupt` feature.
     #[doc(hidden)]
     #[macro_export]
-    #[cfg(not(feature = "rtos-trace"))]
-    macro_rules! rtos_trace {
+    #[cfg(not(feature = "rtos-trace-interrupt"))]
+    macro_rules! rtos_trace_interrupt {
         ($($tt:tt)*) => {};
     }
 }
diff --git a/embassy-macros/src/macros/cortex_m_interrupt_take.rs b/embassy-macros/src/macros/cortex_m_interrupt_take.rs
index 5431704da..62249807e 100644
--- a/embassy-macros/src/macros/cortex_m_interrupt_take.rs
+++ b/embassy-macros/src/macros/cortex_m_interrupt_take.rs
@@ -19,11 +19,11 @@ pub fn run(name: syn::Ident) -> Result<TokenStream, TokenStream> {
                 let func = HANDLER.func.load(::embassy_executor::export::atomic::Ordering::Relaxed);
                 let ctx = HANDLER.ctx.load(::embassy_executor::export::atomic::Ordering::Relaxed);
                 let func: fn(*mut ()) = ::core::mem::transmute(func);
-                ::embassy_executor::rtos_trace! {
+                ::embassy_executor::rtos_trace_interrupt! {
                     ::embassy_executor::export::trace::isr_enter();
                 }
                 func(ctx);
-                ::embassy_executor::rtos_trace! {
+                ::embassy_executor::rtos_trace_interrupt! {
                     ::embassy_executor::export::trace::isr_exit();
                 }
             }

From c1d8c8cf36e3d13daf0eb93b56d8e149acf55b27 Mon Sep 17 00:00:00 2001
From: Quentin Smith <quentin@mit.edu>
Date: Tue, 16 Aug 2022 01:17:28 -0400
Subject: [PATCH 04/21] Add example of rtos-trace / SystemView

---
 examples/nrf/Cargo.toml            | 68 ++++++++++++++++++++++++------
 examples/nrf/build.rs              |  1 +
 examples/nrf/src/bin/rtos_trace.rs | 64 ++++++++++++++++++++++++++++
 3 files changed, 121 insertions(+), 12 deletions(-)
 create mode 100644 examples/nrf/src/bin/rtos_trace.rs

diff --git a/examples/nrf/Cargo.toml b/examples/nrf/Cargo.toml
index 91edbd36d..2f877b6a1 100644
--- a/examples/nrf/Cargo.toml
+++ b/examples/nrf/Cargo.toml
@@ -4,28 +4,72 @@ name = "embassy-nrf-examples"
 version = "0.1.0"
 
 [features]
-default = ["nightly"]
+default = ["defmt", "nightly"]
 nightly = ["embassy-executor/nightly", "embassy-nrf/nightly", "embassy-nrf/unstable-traits", "embassy-usb", "embassy-usb-serial", "embassy-usb-hid", "embassy-usb-ncm", "embedded-io/async", "embassy-net"]
+defmt = [
+    "dep:defmt",
+    "dep:defmt-rtt",
+    "embassy-util/defmt",
+    "embassy-executor/defmt",
+    "embassy-executor/defmt-timestamp-uptime",
+    "embassy-nrf/defmt",
+    "embassy-net/defmt",
+    "embassy-usb/defmt",
+    "embassy-usb-serial/defmt",
+    "embassy-usb-hid/defmt",
+    "embassy-usb-ncm/defmt",
+    "panic-probe/print-defmt",
+]
+log = [
+    "dep:log",
+    "embassy-util/log",
+    "embassy-executor/log",
+    "embassy-nrf/log",
+    "embassy-net/log",
+    "embassy-usb-ncm/log",
+    # Currently broken:
+    # "embassy-usb/log",
+    # "embassy-usb-serial/log",
+    # "embassy-usb-hid/log",
+]
+rtos-trace = [
+    "dep:rtos-trace",
+    "dep:systemview-target",
+    "log",
+    "embassy-executor/rtos-trace",
+    "embassy-executor/rtos-trace-interrupt",
+]
 
 [dependencies]
-embassy-util = { version = "0.1.0", path = "../../embassy-util", features = ["defmt"] }
-embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["defmt", "defmt-timestamp-uptime"] }
-embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac"] }
-embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "pool-16"], optional = true }
-embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"], optional = true }
-embassy-usb-serial = { version = "0.1.0", path = "../../embassy-usb-serial", features = ["defmt"], optional = true }
-embassy-usb-hid = { version = "0.1.0", path = "../../embassy-usb-hid", features = ["defmt"], optional = true }
-embassy-usb-ncm = { version = "0.1.0", path = "../../embassy-usb-ncm", features = ["defmt"], optional = true }
+embassy-util = { version = "0.1.0", path = "../../embassy-util" }
+embassy-executor = { version = "0.1.0", path = "../../embassy-executor" }
+embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac"] }
+embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["tcp", "dhcpv4", "medium-ethernet", "pool-16"], optional = true }
+embassy-usb = { version = "0.1.0", path = "../../embassy-usb", optional = true }
+embassy-usb-serial = { version = "0.1.0", path = "../../embassy-usb-serial", optional = true }
+embassy-usb-hid = { version = "0.1.0", path = "../../embassy-usb-hid", optional = true }
+embassy-usb-ncm = { version = "0.1.0", path = "../../embassy-usb-ncm", optional = true }
 embedded-io = "0.3.0"
 
-defmt = "0.3"
-defmt-rtt = "0.3"
+defmt = { version = "0.3", optional = true }
+defmt-rtt = { version = "0.3", optional = true }
 
 cortex-m = "0.7.3"
 cortex-m-rt = "0.7.0"
-panic-probe = { version = "0.3", features = ["print-defmt"] }
+panic-probe = { version = "0.3" }
 futures = { version = "0.3.17", default-features = false, features = ["async-await"] }
 rand = { version = "0.8.4", default-features = false }
 embedded-storage = "0.3.0"
 usbd-hid = "0.5.2"
 serde = { version = "1.0.136", default-features = false }
+rtos-trace = { version = "0.1.3", optional = true }
+systemview-target = { version = "0.1.1", optional = true, features = ["callbacks-app", "callbacks-os", "log", "cortex-m"] }
+log = { version = "0.4.17", optional = true }
+
+[[bin]]
+name = "rtos_trace"
+required-features = ["nightly", "rtos-trace", "log"]
+
+[patch.crates-io]
+rtos-trace = { git = "https://gitlab.com/quentinmit/rtos-trace.git", branch = "build-fix" }
+systemview-target = { git = "https://gitlab.com/quentinmit/rtos-trace.git", branch = "build-fix" }
diff --git a/examples/nrf/build.rs b/examples/nrf/build.rs
index 30691aa97..36cdb65a8 100644
--- a/examples/nrf/build.rs
+++ b/examples/nrf/build.rs
@@ -31,5 +31,6 @@ fn main() {
 
     println!("cargo:rustc-link-arg-bins=--nmagic");
     println!("cargo:rustc-link-arg-bins=-Tlink.x");
+    #[cfg(feature = "defmt")]
     println!("cargo:rustc-link-arg-bins=-Tdefmt.x");
 }
diff --git a/examples/nrf/src/bin/rtos_trace.rs b/examples/nrf/src/bin/rtos_trace.rs
new file mode 100644
index 000000000..8b4f5b755
--- /dev/null
+++ b/examples/nrf/src/bin/rtos_trace.rs
@@ -0,0 +1,64 @@
+#![no_std]
+#![no_main]
+#![feature(type_alias_impl_trait)]
+
+use core::task::Poll;
+
+use embassy_executor::executor::Spawner;
+use embassy_executor::time::{Duration, Instant, Timer};
+use embassy_nrf::Peripherals;
+
+// N.B. systemview_target cannot be used at the same time as defmt_rtt.
+
+use rtos_trace;
+use systemview_target::SystemView;
+use panic_probe as _;
+use log::*;
+
+static LOGGER: systemview_target::SystemView = systemview_target::SystemView::new();
+rtos_trace::global_trace!{SystemView}
+
+struct TraceInfo();
+
+impl rtos_trace::RtosTraceApplicationCallbacks for TraceInfo {
+    fn system_description() {}
+    fn sysclock() -> u32 {
+        64000000
+    }
+}
+rtos_trace::global_application_callbacks!{TraceInfo}
+
+#[embassy_executor::task]
+async fn run1() {
+    loop {
+        info!("DING DONG");
+        Timer::after(Duration::from_ticks(16000)).await;
+    }
+}
+
+#[embassy_executor::task]
+async fn run2() {
+    loop {
+        Timer::at(Instant::from_ticks(0)).await;
+    }
+}
+
+#[embassy_executor::task]
+async fn run3() {
+    futures::future::poll_fn(|cx| {
+        cx.waker().wake_by_ref();
+        Poll::<()>::Pending
+    })
+    .await;
+}
+
+#[embassy_executor::main]
+async fn main(spawner: Spawner, _p: Peripherals) {
+    LOGGER.init();
+    ::log::set_logger(&LOGGER).ok();
+    ::log::set_max_level(::log::LevelFilter::Trace);
+
+    spawner.spawn(run1()).unwrap();
+    spawner.spawn(run2()).unwrap();
+    spawner.spawn(run3()).unwrap();
+}

From cd561b19ef411c296c86afc6f0df4f39caa1c9e9 Mon Sep 17 00:00:00 2001
From: Quentin Smith <quentin@mit.edu>
Date: Tue, 16 Aug 2022 01:20:07 -0400
Subject: [PATCH 05/21] Allow rtos_trace example to be used without log

---
 examples/nrf/Cargo.toml            |  3 +--
 examples/nrf/src/bin/rtos_trace.rs | 11 +++++++++--
 2 files changed, 10 insertions(+), 4 deletions(-)

diff --git a/examples/nrf/Cargo.toml b/examples/nrf/Cargo.toml
index 2f877b6a1..8704f27c3 100644
--- a/examples/nrf/Cargo.toml
+++ b/examples/nrf/Cargo.toml
@@ -35,7 +35,6 @@ log = [
 rtos-trace = [
     "dep:rtos-trace",
     "dep:systemview-target",
-    "log",
     "embassy-executor/rtos-trace",
     "embassy-executor/rtos-trace-interrupt",
 ]
@@ -68,7 +67,7 @@ log = { version = "0.4.17", optional = true }
 
 [[bin]]
 name = "rtos_trace"
-required-features = ["nightly", "rtos-trace", "log"]
+required-features = ["nightly", "rtos-trace"]
 
 [patch.crates-io]
 rtos-trace = { git = "https://gitlab.com/quentinmit/rtos-trace.git", branch = "build-fix" }
diff --git a/examples/nrf/src/bin/rtos_trace.rs b/examples/nrf/src/bin/rtos_trace.rs
index 8b4f5b755..461e174c9 100644
--- a/examples/nrf/src/bin/rtos_trace.rs
+++ b/examples/nrf/src/bin/rtos_trace.rs
@@ -13,6 +13,7 @@ use embassy_nrf::Peripherals;
 use rtos_trace;
 use systemview_target::SystemView;
 use panic_probe as _;
+#[cfg(feature = "log")]
 use log::*;
 
 static LOGGER: systemview_target::SystemView = systemview_target::SystemView::new();
@@ -31,7 +32,10 @@ rtos_trace::global_application_callbacks!{TraceInfo}
 #[embassy_executor::task]
 async fn run1() {
     loop {
+        #[cfg(feature = "log")]
         info!("DING DONG");
+        #[cfg(not(feature = "log"))]
+        rtos_trace::trace::marker(13);
         Timer::after(Duration::from_ticks(16000)).await;
     }
 }
@@ -55,8 +59,11 @@ async fn run3() {
 #[embassy_executor::main]
 async fn main(spawner: Spawner, _p: Peripherals) {
     LOGGER.init();
-    ::log::set_logger(&LOGGER).ok();
-    ::log::set_max_level(::log::LevelFilter::Trace);
+    #[cfg(feature = "log")]
+    {
+        ::log::set_logger(&LOGGER).ok();
+        ::log::set_max_level(::log::LevelFilter::Trace);
+    }
 
     spawner.spawn(run1()).unwrap();
     spawner.spawn(run2()).unwrap();

From 7dfe119fe0c7b99d7a6d73af6ac3fc6f7cef9d12 Mon Sep 17 00:00:00 2001
From: Quentin Smith <quentin@mit.edu>
Date: Tue, 16 Aug 2022 01:47:18 -0400
Subject: [PATCH 06/21] Run cargo fmt

---
 examples/nrf/src/bin/rtos_trace.rs | 14 ++++++--------
 1 file changed, 6 insertions(+), 8 deletions(-)

diff --git a/examples/nrf/src/bin/rtos_trace.rs b/examples/nrf/src/bin/rtos_trace.rs
index 461e174c9..5699fe8e2 100644
--- a/examples/nrf/src/bin/rtos_trace.rs
+++ b/examples/nrf/src/bin/rtos_trace.rs
@@ -7,17 +7,15 @@ use core::task::Poll;
 use embassy_executor::executor::Spawner;
 use embassy_executor::time::{Duration, Instant, Timer};
 use embassy_nrf::Peripherals;
-
-// N.B. systemview_target cannot be used at the same time as defmt_rtt.
-
-use rtos_trace;
-use systemview_target::SystemView;
-use panic_probe as _;
 #[cfg(feature = "log")]
 use log::*;
+use panic_probe as _;
+// N.B. systemview_target cannot be used at the same time as defmt_rtt.
+use rtos_trace;
+use systemview_target::SystemView;
 
 static LOGGER: systemview_target::SystemView = systemview_target::SystemView::new();
-rtos_trace::global_trace!{SystemView}
+rtos_trace::global_trace! {SystemView}
 
 struct TraceInfo();
 
@@ -27,7 +25,7 @@ impl rtos_trace::RtosTraceApplicationCallbacks for TraceInfo {
         64000000
     }
 }
-rtos_trace::global_application_callbacks!{TraceInfo}
+rtos_trace::global_application_callbacks! {TraceInfo}
 
 #[embassy_executor::task]
 async fn run1() {

From 2edf532f8d8ce048137990bf74b07759428ed7c1 Mon Sep 17 00:00:00 2001
From: Quentin Smith <quentin@mit.edu>
Date: Thu, 18 Aug 2022 01:38:58 -0400
Subject: [PATCH 07/21] Move rtos-trace example to a separate project to
 simplify Cargo.toml

---
 examples/nrf-rtos-trace/.cargo/config.toml    |  9 +++
 examples/nrf-rtos-trace/Cargo.toml            | 51 ++++++++++++++
 examples/nrf-rtos-trace/build.rs              | 36 ++++++++++
 examples/nrf-rtos-trace/memory.x              |  7 ++
 .../src/bin/rtos_trace.rs                     |  0
 examples/nrf/Cargo.toml                       | 67 ++++---------------
 examples/nrf/build.rs                         |  1 -
 7 files changed, 115 insertions(+), 56 deletions(-)
 create mode 100644 examples/nrf-rtos-trace/.cargo/config.toml
 create mode 100644 examples/nrf-rtos-trace/Cargo.toml
 create mode 100644 examples/nrf-rtos-trace/build.rs
 create mode 100644 examples/nrf-rtos-trace/memory.x
 rename examples/{nrf => nrf-rtos-trace}/src/bin/rtos_trace.rs (100%)

diff --git a/examples/nrf-rtos-trace/.cargo/config.toml b/examples/nrf-rtos-trace/.cargo/config.toml
new file mode 100644
index 000000000..8ca28df39
--- /dev/null
+++ b/examples/nrf-rtos-trace/.cargo/config.toml
@@ -0,0 +1,9 @@
+[target.'cfg(all(target_arch = "arm", target_os = "none"))']
+# replace nRF82840_xxAA with your chip as listed in `probe-run --list-chips`
+runner = "probe-run --chip nRF52840_xxAA"
+
+[build]
+target = "thumbv7em-none-eabi"
+
+[env]
+DEFMT_LOG = "trace"
diff --git a/examples/nrf-rtos-trace/Cargo.toml b/examples/nrf-rtos-trace/Cargo.toml
new file mode 100644
index 000000000..9c749a388
--- /dev/null
+++ b/examples/nrf-rtos-trace/Cargo.toml
@@ -0,0 +1,51 @@
+[package]
+edition = "2021"
+name = "embassy-nrf-examples"
+version = "0.1.0"
+
+[features]
+default = ["log", "nightly"]
+nightly = ["embassy-executor/nightly", "embassy-nrf/nightly", "embassy-nrf/unstable-traits", "embassy-usb", "embassy-usb-serial", "embassy-usb-hid", "embassy-usb-ncm", "embedded-io/async", "embassy-net"]
+log = [
+    "dep:log",
+    "embassy-util/log",
+    "embassy-executor/log",
+    "embassy-nrf/log",
+    "embassy-net/log",
+    "embassy-usb-ncm/log",
+    # Currently broken:
+    # "embassy-usb/log",
+    # "embassy-usb-serial/log",
+    # "embassy-usb-hid/log",
+]
+
+[dependencies]
+embassy-util = { version = "0.1.0", path = "../../embassy-util" }
+embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features=["rtos-trace", "rtos-trace-interrupt"] }
+embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac"] }
+embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["tcp", "dhcpv4", "medium-ethernet", "pool-16"], optional = true }
+embassy-usb = { version = "0.1.0", path = "../../embassy-usb", optional = true }
+embassy-usb-serial = { version = "0.1.0", path = "../../embassy-usb-serial", optional = true }
+embassy-usb-hid = { version = "0.1.0", path = "../../embassy-usb-hid", optional = true }
+embassy-usb-ncm = { version = "0.1.0", path = "../../embassy-usb-ncm", optional = true }
+embedded-io = "0.3.0"
+
+cortex-m = "0.7.3"
+cortex-m-rt = "0.7.0"
+panic-probe = { version = "0.3" }
+futures = { version = "0.3.17", default-features = false, features = ["async-await"] }
+rand = { version = "0.8.4", default-features = false }
+embedded-storage = "0.3.0"
+usbd-hid = "0.5.2"
+serde = { version = "1.0.136", default-features = false }
+rtos-trace = "0.1.3"
+systemview-target = { version = "0.1.1", features = ["callbacks-app", "callbacks-os", "log", "cortex-m"] }
+log = { version = "0.4.17", optional = true }
+
+[[bin]]
+name = "rtos_trace"
+required-features = ["nightly"]
+
+[patch.crates-io]
+rtos-trace = { git = "https://gitlab.com/quentinmit/rtos-trace.git", branch = "build-fix" }
+systemview-target = { git = "https://gitlab.com/quentinmit/rtos-trace.git", branch = "build-fix" }
diff --git a/examples/nrf-rtos-trace/build.rs b/examples/nrf-rtos-trace/build.rs
new file mode 100644
index 000000000..36cdb65a8
--- /dev/null
+++ b/examples/nrf-rtos-trace/build.rs
@@ -0,0 +1,36 @@
+//! This build script copies the `memory.x` file from the crate root into
+//! a directory where the linker can always find it at build time.
+//! For many projects this is optional, as the linker always searches the
+//! project root directory -- wherever `Cargo.toml` is. However, if you
+//! are using a workspace or have a more complicated build setup, this
+//! build script becomes required. Additionally, by requesting that
+//! Cargo re-run the build script whenever `memory.x` is changed,
+//! updating `memory.x` ensures a rebuild of the application with the
+//! new memory settings.
+
+use std::env;
+use std::fs::File;
+use std::io::Write;
+use std::path::PathBuf;
+
+fn main() {
+    // Put `memory.x` in our output directory and ensure it's
+    // on the linker search path.
+    let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap());
+    File::create(out.join("memory.x"))
+        .unwrap()
+        .write_all(include_bytes!("memory.x"))
+        .unwrap();
+    println!("cargo:rustc-link-search={}", out.display());
+
+    // By default, Cargo will re-run a build script whenever
+    // any file in the project changes. By specifying `memory.x`
+    // here, we ensure the build script is only re-run when
+    // `memory.x` is changed.
+    println!("cargo:rerun-if-changed=memory.x");
+
+    println!("cargo:rustc-link-arg-bins=--nmagic");
+    println!("cargo:rustc-link-arg-bins=-Tlink.x");
+    #[cfg(feature = "defmt")]
+    println!("cargo:rustc-link-arg-bins=-Tdefmt.x");
+}
diff --git a/examples/nrf-rtos-trace/memory.x b/examples/nrf-rtos-trace/memory.x
new file mode 100644
index 000000000..9b04edec0
--- /dev/null
+++ b/examples/nrf-rtos-trace/memory.x
@@ -0,0 +1,7 @@
+MEMORY
+{
+  /* NOTE 1 K = 1 KiBi = 1024 bytes */
+  /* These values correspond to the NRF52840 with Softdevices S140 7.0.1 */
+  FLASH : ORIGIN = 0x00000000, LENGTH = 1024K
+  RAM : ORIGIN = 0x20000000, LENGTH = 256K
+}
diff --git a/examples/nrf/src/bin/rtos_trace.rs b/examples/nrf-rtos-trace/src/bin/rtos_trace.rs
similarity index 100%
rename from examples/nrf/src/bin/rtos_trace.rs
rename to examples/nrf-rtos-trace/src/bin/rtos_trace.rs
diff --git a/examples/nrf/Cargo.toml b/examples/nrf/Cargo.toml
index 8704f27c3..91edbd36d 100644
--- a/examples/nrf/Cargo.toml
+++ b/examples/nrf/Cargo.toml
@@ -4,71 +4,28 @@ name = "embassy-nrf-examples"
 version = "0.1.0"
 
 [features]
-default = ["defmt", "nightly"]
+default = ["nightly"]
 nightly = ["embassy-executor/nightly", "embassy-nrf/nightly", "embassy-nrf/unstable-traits", "embassy-usb", "embassy-usb-serial", "embassy-usb-hid", "embassy-usb-ncm", "embedded-io/async", "embassy-net"]
-defmt = [
-    "dep:defmt",
-    "dep:defmt-rtt",
-    "embassy-util/defmt",
-    "embassy-executor/defmt",
-    "embassy-executor/defmt-timestamp-uptime",
-    "embassy-nrf/defmt",
-    "embassy-net/defmt",
-    "embassy-usb/defmt",
-    "embassy-usb-serial/defmt",
-    "embassy-usb-hid/defmt",
-    "embassy-usb-ncm/defmt",
-    "panic-probe/print-defmt",
-]
-log = [
-    "dep:log",
-    "embassy-util/log",
-    "embassy-executor/log",
-    "embassy-nrf/log",
-    "embassy-net/log",
-    "embassy-usb-ncm/log",
-    # Currently broken:
-    # "embassy-usb/log",
-    # "embassy-usb-serial/log",
-    # "embassy-usb-hid/log",
-]
-rtos-trace = [
-    "dep:rtos-trace",
-    "dep:systemview-target",
-    "embassy-executor/rtos-trace",
-    "embassy-executor/rtos-trace-interrupt",
-]
 
 [dependencies]
-embassy-util = { version = "0.1.0", path = "../../embassy-util" }
-embassy-executor = { version = "0.1.0", path = "../../embassy-executor" }
-embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac"] }
-embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["tcp", "dhcpv4", "medium-ethernet", "pool-16"], optional = true }
-embassy-usb = { version = "0.1.0", path = "../../embassy-usb", optional = true }
-embassy-usb-serial = { version = "0.1.0", path = "../../embassy-usb-serial", optional = true }
-embassy-usb-hid = { version = "0.1.0", path = "../../embassy-usb-hid", optional = true }
-embassy-usb-ncm = { version = "0.1.0", path = "../../embassy-usb-ncm", optional = true }
+embassy-util = { version = "0.1.0", path = "../../embassy-util", features = ["defmt"] }
+embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["defmt", "defmt-timestamp-uptime"] }
+embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac"] }
+embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "pool-16"], optional = true }
+embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"], optional = true }
+embassy-usb-serial = { version = "0.1.0", path = "../../embassy-usb-serial", features = ["defmt"], optional = true }
+embassy-usb-hid = { version = "0.1.0", path = "../../embassy-usb-hid", features = ["defmt"], optional = true }
+embassy-usb-ncm = { version = "0.1.0", path = "../../embassy-usb-ncm", features = ["defmt"], optional = true }
 embedded-io = "0.3.0"
 
-defmt = { version = "0.3", optional = true }
-defmt-rtt = { version = "0.3", optional = true }
+defmt = "0.3"
+defmt-rtt = "0.3"
 
 cortex-m = "0.7.3"
 cortex-m-rt = "0.7.0"
-panic-probe = { version = "0.3" }
+panic-probe = { version = "0.3", features = ["print-defmt"] }
 futures = { version = "0.3.17", default-features = false, features = ["async-await"] }
 rand = { version = "0.8.4", default-features = false }
 embedded-storage = "0.3.0"
 usbd-hid = "0.5.2"
 serde = { version = "1.0.136", default-features = false }
-rtos-trace = { version = "0.1.3", optional = true }
-systemview-target = { version = "0.1.1", optional = true, features = ["callbacks-app", "callbacks-os", "log", "cortex-m"] }
-log = { version = "0.4.17", optional = true }
-
-[[bin]]
-name = "rtos_trace"
-required-features = ["nightly", "rtos-trace"]
-
-[patch.crates-io]
-rtos-trace = { git = "https://gitlab.com/quentinmit/rtos-trace.git", branch = "build-fix" }
-systemview-target = { git = "https://gitlab.com/quentinmit/rtos-trace.git", branch = "build-fix" }
diff --git a/examples/nrf/build.rs b/examples/nrf/build.rs
index 36cdb65a8..30691aa97 100644
--- a/examples/nrf/build.rs
+++ b/examples/nrf/build.rs
@@ -31,6 +31,5 @@ fn main() {
 
     println!("cargo:rustc-link-arg-bins=--nmagic");
     println!("cargo:rustc-link-arg-bins=-Tlink.x");
-    #[cfg(feature = "defmt")]
     println!("cargo:rustc-link-arg-bins=-Tdefmt.x");
 }

From 5ce18f49158e23a2a3c775343126d9670f212fc5 Mon Sep 17 00:00:00 2001
From: Quentin Smith <quentin@mit.edu>
Date: Fri, 19 Aug 2022 00:54:53 -0400
Subject: [PATCH 08/21] Fix package name for the new nrf-rtos-trace example

---
 examples/nrf-rtos-trace/Cargo.toml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/examples/nrf-rtos-trace/Cargo.toml b/examples/nrf-rtos-trace/Cargo.toml
index dad74235f..bdf49f574 100644
--- a/examples/nrf-rtos-trace/Cargo.toml
+++ b/examples/nrf-rtos-trace/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 edition = "2021"
-name = "embassy-nrf-examples"
+name = "embassy-nrf-rtos-trace-examples"
 version = "0.1.0"
 
 [features]

From a833e02363dac8ba5b9a421804acc8b2b6bd751c Mon Sep 17 00:00:00 2001
From: Vincent Stakenburg <v.stakenburg@cosinuss.nl>
Date: Thu, 9 Jun 2022 15:17:03 +0200
Subject: [PATCH 09/21] implement support for LPUART

---
 embassy-stm32/build.rs              |  12 +--
 embassy-stm32/src/usart/buffered.rs |  28 +++----
 embassy-stm32/src/usart/mod.rs      | 121 ++++++++++++++++++----------
 stm32-data                          |   2 +-
 4 files changed, 99 insertions(+), 64 deletions(-)

diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs
index c892007a3..a4709f4ca 100644
--- a/embassy-stm32/build.rs
+++ b/embassy-stm32/build.rs
@@ -244,11 +244,11 @@ fn main() {
         (("usart", "CTS"), quote!(crate::usart::CtsPin)),
         (("usart", "RTS"), quote!(crate::usart::RtsPin)),
         (("usart", "CK"), quote!(crate::usart::CkPin)),
-        (("usart", "TX"), quote!(crate::usart::TxPin)),
-        (("usart", "RX"), quote!(crate::usart::RxPin)),
-        (("usart", "CTS"), quote!(crate::usart::CtsPin)),
-        (("usart", "RTS"), quote!(crate::usart::RtsPin)),
-        (("usart", "CK"), quote!(crate::usart::CkPin)),
+        (("lpuart", "TX"), quote!(crate::usart::TxPin)),
+        (("lpuart", "RX"), quote!(crate::usart::RxPin)),
+        (("lpuart", "CTS"), quote!(crate::usart::CtsPin)),
+        (("lpuart", "RTS"), quote!(crate::usart::RtsPin)),
+        (("lpuart", "CK"), quote!(crate::usart::CkPin)),
         (("spi", "SCK"), quote!(crate::spi::SckPin)),
         (("spi", "MOSI"), quote!(crate::spi::MosiPin)),
         (("spi", "MISO"), quote!(crate::spi::MisoPin)),
@@ -497,6 +497,8 @@ fn main() {
         // (kind, signal) => trait
         (("usart", "RX"), quote!(crate::usart::RxDma)),
         (("usart", "TX"), quote!(crate::usart::TxDma)),
+        (("lpuart", "RX"), quote!(crate::usart::RxDma)),
+        (("lpuart", "TX"), quote!(crate::usart::TxDma)),
         (("spi", "RX"), quote!(crate::spi::RxDma)),
         (("spi", "TX"), quote!(crate::spi::TxDma)),
         (("i2c", "RX"), quote!(crate::i2c::RxDma)),
diff --git a/embassy-stm32/src/usart/buffered.rs b/embassy-stm32/src/usart/buffered.rs
index 0e8d0d682..ec2231e43 100644
--- a/embassy-stm32/src/usart/buffered.rs
+++ b/embassy-stm32/src/usart/buffered.rs
@@ -9,14 +9,14 @@ use futures::future::poll_fn;
 
 use super::*;
 
-pub struct State<'d, T: Instance>(StateStorage<StateInner<'d, T>>);
-impl<'d, T: Instance> State<'d, T> {
+pub struct State<'d, T: BasicInstance>(StateStorage<StateInner<'d, T>>);
+impl<'d, T: BasicInstance> State<'d, T> {
     pub fn new() -> Self {
         Self(StateStorage::new())
     }
 }
 
-struct StateInner<'d, T: Instance> {
+struct StateInner<'d, T: BasicInstance> {
     phantom: PhantomData<&'d mut T>,
 
     rx_waker: WakerRegistration,
@@ -26,16 +26,16 @@ struct StateInner<'d, T: Instance> {
     tx: RingBuffer<'d>,
 }
 
-unsafe impl<'d, T: Instance> Send for StateInner<'d, T> {}
-unsafe impl<'d, T: Instance> Sync for StateInner<'d, T> {}
+unsafe impl<'d, T: BasicInstance> Send for StateInner<'d, T> {}
+unsafe impl<'d, T: BasicInstance> Sync for StateInner<'d, T> {}
 
-pub struct BufferedUart<'d, T: Instance> {
+pub struct BufferedUart<'d, T: BasicInstance> {
     inner: PeripheralMutex<'d, StateInner<'d, T>>,
 }
 
-impl<'d, T: Instance> Unpin for BufferedUart<'d, T> {}
+impl<'d, T: BasicInstance> Unpin for BufferedUart<'d, T> {}
 
-impl<'d, T: Instance> BufferedUart<'d, T> {
+impl<'d, T: BasicInstance> BufferedUart<'d, T> {
     pub fn new(
         state: &'d mut State<'d, T>,
         _uart: Uart<'d, T, NoDma, NoDma>,
@@ -66,7 +66,7 @@ impl<'d, T: Instance> BufferedUart<'d, T> {
     }
 }
 
-impl<'d, T: Instance> StateInner<'d, T>
+impl<'d, T: BasicInstance> StateInner<'d, T>
 where
     Self: 'd,
 {
@@ -135,7 +135,7 @@ where
     }
 }
 
-impl<'d, T: Instance> PeripheralState for StateInner<'d, T>
+impl<'d, T: BasicInstance> PeripheralState for StateInner<'d, T>
 where
     Self: 'd,
 {
@@ -152,11 +152,11 @@ impl embedded_io::Error for Error {
     }
 }
 
-impl<'d, T: Instance> embedded_io::Io for BufferedUart<'d, T> {
+impl<'d, T: BasicInstance> embedded_io::Io for BufferedUart<'d, T> {
     type Error = Error;
 }
 
-impl<'d, T: Instance> embedded_io::asynch::Read for BufferedUart<'d, T> {
+impl<'d, T: BasicInstance> embedded_io::asynch::Read for BufferedUart<'d, T> {
     type ReadFuture<'a> = impl Future<Output = Result<usize, Self::Error>>
     where
         Self: 'a;
@@ -194,7 +194,7 @@ impl<'d, T: Instance> embedded_io::asynch::Read for BufferedUart<'d, T> {
     }
 }
 
-impl<'d, T: Instance> embedded_io::asynch::BufRead for BufferedUart<'d, T> {
+impl<'d, T: BasicInstance> embedded_io::asynch::BufRead for BufferedUart<'d, T> {
     type FillBufFuture<'a> = impl Future<Output = Result<&'a [u8], Self::Error>>
     where
         Self: 'a;
@@ -231,7 +231,7 @@ impl<'d, T: Instance> embedded_io::asynch::BufRead for BufferedUart<'d, T> {
     }
 }
 
-impl<'d, T: Instance> embedded_io::asynch::Write for BufferedUart<'d, T> {
+impl<'d, T: BasicInstance> embedded_io::asynch::Write for BufferedUart<'d, T> {
     type WriteFuture<'a> = impl Future<Output = Result<usize, Self::Error>>
     where
         Self: 'a;
diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs
index ca75bab41..511850971 100644
--- a/embassy-stm32/src/usart/mod.rs
+++ b/embassy-stm32/src/usart/mod.rs
@@ -6,9 +6,7 @@ use embassy_hal_common::{into_ref, PeripheralRef};
 
 use crate::dma::NoDma;
 use crate::gpio::sealed::AFType;
-use crate::interrupt::Interrupt;
-use crate::pac::usart::{regs, vals};
-use crate::rcc::RccPeripheral;
+use crate::pac::lpuart::{regs, vals};
 use crate::{peripherals, Peripheral};
 
 #[derive(Clone, Copy, PartialEq, Eq, Debug)]
@@ -71,22 +69,23 @@ pub enum Error {
     Parity,
 }
 
-pub struct Uart<'d, T: Instance, TxDma = NoDma, RxDma = NoDma> {
+pub struct Uart<'d, T: BasicInstance, TxDma = NoDma, RxDma = NoDma> {
+    phantom: PhantomData<&'d mut T>,
     tx: UartTx<'d, T, TxDma>,
     rx: UartRx<'d, T, RxDma>,
 }
 
-pub struct UartTx<'d, T: Instance, TxDma = NoDma> {
+pub struct UartTx<'d, T: BasicInstance, TxDma = NoDma> {
     phantom: PhantomData<&'d mut T>,
     tx_dma: PeripheralRef<'d, TxDma>,
 }
 
-pub struct UartRx<'d, T: Instance, RxDma = NoDma> {
+pub struct UartRx<'d, T: BasicInstance, RxDma = NoDma> {
     phantom: PhantomData<&'d mut T>,
     rx_dma: PeripheralRef<'d, RxDma>,
 }
 
-impl<'d, T: Instance, TxDma> UartTx<'d, T, TxDma> {
+impl<'d, T: BasicInstance, TxDma> UartTx<'d, T, TxDma> {
     fn new(tx_dma: PeripheralRef<'d, TxDma>) -> Self {
         Self {
             tx_dma,
@@ -132,7 +131,7 @@ impl<'d, T: Instance, TxDma> UartTx<'d, T, TxDma> {
     }
 }
 
-impl<'d, T: Instance, RxDma> UartRx<'d, T, RxDma> {
+impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> {
     fn new(rx_dma: PeripheralRef<'d, RxDma>) -> Self {
         Self {
             rx_dma,
@@ -187,7 +186,7 @@ impl<'d, T: Instance, RxDma> UartRx<'d, T, RxDma> {
     }
 }
 
-impl<'d, T: Instance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> {
+impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> {
     pub fn new(
         _inner: impl Peripheral<P = T> + 'd,
         rx: impl Peripheral<P = impl RxPin<T>> + 'd,
@@ -203,7 +202,7 @@ impl<'d, T: Instance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> {
         let pclk_freq = T::frequency();
 
         // TODO: better calculation, including error checking and OVER8 if possible.
-        let div = (pclk_freq.0 + (config.baudrate / 2)) / config.baudrate;
+        let div = (pclk_freq.0 + (config.baudrate / 2)) / config.baudrate * T::MULTIPLIER;
 
         let r = T::regs();
 
@@ -235,6 +234,7 @@ impl<'d, T: Instance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> {
         Self {
             tx: UartTx::new(tx_dma),
             rx: UartRx::new(rx_dma),
+            phantom: PhantomData {},
         }
     }
 
@@ -275,7 +275,7 @@ impl<'d, T: Instance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> {
 mod eh02 {
     use super::*;
 
-    impl<'d, T: Instance, RxDma> embedded_hal_02::serial::Read<u8> for UartRx<'d, T, RxDma> {
+    impl<'d, T: BasicInstance, RxDma> embedded_hal_02::serial::Read<u8> for UartRx<'d, T, RxDma> {
         type Error = Error;
         fn read(&mut self) -> Result<u8, nb::Error<Self::Error>> {
             let r = T::regs();
@@ -302,7 +302,7 @@ mod eh02 {
         }
     }
 
-    impl<'d, T: Instance, TxDma> embedded_hal_02::blocking::serial::Write<u8> for UartTx<'d, T, TxDma> {
+    impl<'d, T: BasicInstance, TxDma> embedded_hal_02::blocking::serial::Write<u8> for UartTx<'d, T, TxDma> {
         type Error = Error;
         fn bwrite_all(&mut self, buffer: &[u8]) -> Result<(), Self::Error> {
             self.blocking_write(buffer)
@@ -312,14 +312,14 @@ mod eh02 {
         }
     }
 
-    impl<'d, T: Instance, TxDma, RxDma> embedded_hal_02::serial::Read<u8> for Uart<'d, T, TxDma, RxDma> {
+    impl<'d, T: BasicInstance, TxDma, RxDma> embedded_hal_02::serial::Read<u8> for Uart<'d, T, TxDma, RxDma> {
         type Error = Error;
         fn read(&mut self) -> Result<u8, nb::Error<Self::Error>> {
             embedded_hal_02::serial::Read::read(&mut self.rx)
         }
     }
 
-    impl<'d, T: Instance, TxDma, RxDma> embedded_hal_02::blocking::serial::Write<u8> for Uart<'d, T, TxDma, RxDma> {
+    impl<'d, T: BasicInstance, TxDma, RxDma> embedded_hal_02::blocking::serial::Write<u8> for Uart<'d, T, TxDma, RxDma> {
         type Error = Error;
         fn bwrite_all(&mut self, buffer: &[u8]) -> Result<(), Self::Error> {
             self.blocking_write(buffer)
@@ -345,15 +345,15 @@ mod eh1 {
         }
     }
 
-    impl<'d, T: Instance, TxDma, RxDma> embedded_hal_1::serial::ErrorType for Uart<'d, T, TxDma, RxDma> {
+    impl<'d, T: BasicInstance, TxDma, RxDma> embedded_hal_1::serial::ErrorType for Uart<'d, T, TxDma, RxDma> {
         type Error = Error;
     }
 
-    impl<'d, T: Instance, TxDma> embedded_hal_1::serial::ErrorType for UartTx<'d, T, TxDma> {
+    impl<'d, T: BasicInstance, TxDma> embedded_hal_1::serial::ErrorType for UartTx<'d, T, TxDma> {
         type Error = Error;
     }
 
-    impl<'d, T: Instance, RxDma> embedded_hal_1::serial::ErrorType for UartRx<'d, T, RxDma> {
+    impl<'d, T: BasicInstance, RxDma> embedded_hal_1::serial::ErrorType for UartRx<'d, T, RxDma> {
         type Error = Error;
     }
 }
@@ -362,7 +362,7 @@ cfg_if::cfg_if! {
     if #[cfg(all(feature = "unstable-traits", feature = "nightly", feature = "_todo_embedded_hal_serial"))] {
         use core::future::Future;
 
-        impl<'d, T: Instance, TxDma> embedded_hal_async::serial::Write for UartTx<'d, T, TxDma>
+        impl<'d, T: UartInstance, TxDma> embedded_hal_async::serial::Write for UartTx<'d, T, TxDma>
         where
             TxDma: crate::usart::TxDma<T>,
         {
@@ -379,7 +379,7 @@ cfg_if::cfg_if! {
             }
         }
 
-        impl<'d, T: Instance, RxDma> embedded_hal_async::serial::Read for UartRx<'d, T, RxDma>
+        impl<'d, T: UartInstance, RxDma> embedded_hal_async::serial::Read for UartRx<'d, T, RxDma>
         where
             RxDma: crate::usart::RxDma<T>,
         {
@@ -390,7 +390,7 @@ cfg_if::cfg_if! {
             }
         }
 
-        impl<'d, T: Instance, TxDma, RxDma> embedded_hal_async::serial::Write for Uart<'d, T, TxDma, RxDma>
+        impl<'d, T: UartInstance, TxDma, RxDma> embedded_hal_async::serial::Write for Uart<'d, T, TxDma, RxDma>
         where
             TxDma: crate::usart::TxDma<T>,
         {
@@ -407,7 +407,7 @@ cfg_if::cfg_if! {
             }
         }
 
-        impl<'d, T: Instance, TxDma, RxDma> embedded_hal_async::serial::Read for Uart<'d, T, TxDma, RxDma>
+        impl<'d, T: UartInstance, TxDma, RxDma> embedded_hal_async::serial::Read for Uart<'d, T, TxDma, RxDma>
         where
             RxDma: crate::usart::RxDma<T>,
         {
@@ -447,55 +447,88 @@ unsafe fn clear_interrupt_flags(_r: crate::pac::usart::Usart, _sr: regs::Sr) {
 }
 
 #[cfg(usart_v2)]
-fn tdr(r: crate::pac::usart::Usart) -> *mut u8 {
+fn tdr(r: crate::pac::lpuart::Lpuart) -> *mut u8 {
     r.tdr().ptr() as _
 }
 
 #[cfg(usart_v2)]
-fn rdr(r: crate::pac::usart::Usart) -> *mut u8 {
+fn rdr(r: crate::pac::lpuart::Lpuart) -> *mut u8 {
     r.rdr().ptr() as _
 }
 
 #[cfg(usart_v2)]
-fn sr(r: crate::pac::usart::Usart) -> crate::pac::common::Reg<regs::Ixr, crate::pac::common::R> {
+fn sr(r: crate::pac::lpuart::Lpuart) -> crate::pac::common::Reg<regs::Isr, crate::pac::common::R> {
     r.isr()
 }
 
 #[cfg(usart_v2)]
 #[allow(unused)]
-unsafe fn clear_interrupt_flags(r: crate::pac::usart::Usart, sr: regs::Ixr) {
-    r.icr().write(|w| *w = sr);
+unsafe fn clear_interrupt_flags(r: crate::pac::lpuart::Lpuart, sr: regs::Isr) {
+    r.icr().write(|w| *w = regs::Icr(sr.0));
 }
 
 pub(crate) mod sealed {
-    pub trait Instance {
-        fn regs() -> crate::pac::usart::Usart;
+
+    pub trait BasicInstance: crate::rcc::RccPeripheral {
+        const MULTIPLIER: u32;
+        type Interrupt: crate::interrupt::Interrupt;
+
+        fn regs() -> crate::pac::lpuart::Lpuart;
+    }
+
+    pub trait FullInstance: BasicInstance {
+        fn regs_uart() -> crate::pac::usart::Usart;
     }
 }
 
-pub trait Instance: sealed::Instance + RccPeripheral {
-    type Interrupt: Interrupt;
+pub trait BasicInstance: sealed::BasicInstance {}
+
+pub trait FullInstance: sealed::FullInstance {}
+
+pin_trait!(RxPin, BasicInstance);
+pin_trait!(TxPin, BasicInstance);
+pin_trait!(CtsPin, BasicInstance);
+pin_trait!(RtsPin, BasicInstance);
+pin_trait!(CkPin, BasicInstance);
+
+dma_trait!(TxDma, BasicInstance);
+dma_trait!(RxDma, BasicInstance);
+
+macro_rules! impl_lpuart {
+    ($inst:ident, $irq:ident, $mul:expr) => {
+        impl sealed::BasicInstance for crate::peripherals::$inst {
+            const MULTIPLIER: u32 = $mul;
+            type Interrupt = crate::interrupt::$irq;
+
+            fn regs() -> crate::pac::lpuart::Lpuart {
+                crate::pac::lpuart::Lpuart(crate::pac::$inst.0)
+            }
+        }
+    };
 }
 
-pin_trait!(RxPin, Instance);
-pin_trait!(TxPin, Instance);
-pin_trait!(CtsPin, Instance);
-pin_trait!(RtsPin, Instance);
-pin_trait!(CkPin, Instance);
-
-dma_trait!(TxDma, Instance);
-dma_trait!(RxDma, Instance);
-
 foreach_interrupt!(
-    ($inst:ident, usart, $block:ident, $signal_name:ident, $irq:ident) => {
-        impl sealed::Instance for peripherals::$inst {
-            fn regs() -> crate::pac::usart::Usart {
+    ($inst:ident, lpuart, LPUART, $signal_name:ident, $irq:ident) => {
+        impl_lpuart!($inst, $irq, 255);
+
+        impl BasicInstance for peripherals::$inst {
+        }
+    };
+
+    ($inst:ident, usart, USART, $signal_name:ident, $irq:ident) => {
+        impl_lpuart!($inst, $irq, 1);
+
+        impl BasicInstance for peripherals::$inst {
+        }
+
+        impl sealed::FullInstance for peripherals::$inst {
+
+            fn regs_uart() -> crate::pac::usart::Usart {
                 crate::pac::$inst
             }
         }
 
-        impl Instance for peripherals::$inst {
-            type Interrupt = crate::interrupt::$irq;
+        impl FullInstance for peripherals::$inst {
         }
     };
 );
diff --git a/stm32-data b/stm32-data
index 758c9e746..f47995849 160000
--- a/stm32-data
+++ b/stm32-data
@@ -1 +1 @@
-Subproject commit 758c9e74625c68bc23d66ced8bfeb5643c63cec9
+Subproject commit f47995849a1a66cc92143ff94c84b11dc2701ccb

From 51359e7d24051c0fa70cf17cd2b9eb3cfceb67de Mon Sep 17 00:00:00 2001
From: Vincent Stakenburg <v.stakenburg@cosinuss.nl>
Date: Fri, 19 Aug 2022 15:27:11 +0200
Subject: [PATCH 10/21] fix lpuart implementation when there isn't one present

---
 embassy-stm32/src/usart/mod.rs | 42 +++++++++++++++++-----------------
 1 file changed, 21 insertions(+), 21 deletions(-)

diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs
index 511850971..2ad85c675 100644
--- a/embassy-stm32/src/usart/mod.rs
+++ b/embassy-stm32/src/usart/mod.rs
@@ -6,7 +6,10 @@ use embassy_hal_common::{into_ref, PeripheralRef};
 
 use crate::dma::NoDma;
 use crate::gpio::sealed::AFType;
-use crate::pac::lpuart::{regs, vals};
+#[cfg(any(lpuart_v1, lpuart_v2))]
+use crate::pac::lpuart::{regs, vals, Lpuart as Regs};
+#[cfg(not(any(lpuart_v1, lpuart_v2)))]
+use crate::pac::usart::{regs, vals, Usart as Regs};
 use crate::{peripherals, Peripheral};
 
 #[derive(Clone, Copy, PartialEq, Eq, Debug)]
@@ -362,7 +365,7 @@ cfg_if::cfg_if! {
     if #[cfg(all(feature = "unstable-traits", feature = "nightly", feature = "_todo_embedded_hal_serial"))] {
         use core::future::Future;
 
-        impl<'d, T: UartInstance, TxDma> embedded_hal_async::serial::Write for UartTx<'d, T, TxDma>
+        impl<'d, T: BasicInstance, TxDma> embedded_hal_async::serial::Write for UartTx<'d, T, TxDma>
         where
             TxDma: crate::usart::TxDma<T>,
         {
@@ -379,7 +382,7 @@ cfg_if::cfg_if! {
             }
         }
 
-        impl<'d, T: UartInstance, RxDma> embedded_hal_async::serial::Read for UartRx<'d, T, RxDma>
+        impl<'d, T: BasicInstance, RxDma> embedded_hal_async::serial::Read for UartRx<'d, T, RxDma>
         where
             RxDma: crate::usart::RxDma<T>,
         {
@@ -390,7 +393,7 @@ cfg_if::cfg_if! {
             }
         }
 
-        impl<'d, T: UartInstance, TxDma, RxDma> embedded_hal_async::serial::Write for Uart<'d, T, TxDma, RxDma>
+        impl<'d, T: BasicInstance, TxDma, RxDma> embedded_hal_async::serial::Write for Uart<'d, T, TxDma, RxDma>
         where
             TxDma: crate::usart::TxDma<T>,
         {
@@ -407,7 +410,7 @@ cfg_if::cfg_if! {
             }
         }
 
-        impl<'d, T: UartInstance, TxDma, RxDma> embedded_hal_async::serial::Read for Uart<'d, T, TxDma, RxDma>
+        impl<'d, T: BasicInstance, TxDma, RxDma> embedded_hal_async::serial::Read for Uart<'d, T, TxDma, RxDma>
         where
             RxDma: crate::usart::RxDma<T>,
         {
@@ -442,38 +445,39 @@ fn sr(r: crate::pac::usart::Usart) -> crate::pac::common::Reg<regs::Sr, crate::p
 
 #[cfg(usart_v1)]
 #[allow(unused)]
-unsafe fn clear_interrupt_flags(_r: crate::pac::usart::Usart, _sr: regs::Sr) {
+unsafe fn clear_interrupt_flags(_r: Regs, _sr: regs::Sr) {
     // On v1 the flags are cleared implicitly by reads and writes to DR.
 }
 
 #[cfg(usart_v2)]
-fn tdr(r: crate::pac::lpuart::Lpuart) -> *mut u8 {
+fn tdr(r: Regs) -> *mut u8 {
     r.tdr().ptr() as _
 }
 
 #[cfg(usart_v2)]
-fn rdr(r: crate::pac::lpuart::Lpuart) -> *mut u8 {
+fn rdr(r: Regs) -> *mut u8 {
     r.rdr().ptr() as _
 }
 
 #[cfg(usart_v2)]
-fn sr(r: crate::pac::lpuart::Lpuart) -> crate::pac::common::Reg<regs::Isr, crate::pac::common::R> {
+fn sr(r: Regs) -> crate::pac::common::Reg<regs::Isr, crate::pac::common::R> {
     r.isr()
 }
 
 #[cfg(usart_v2)]
 #[allow(unused)]
-unsafe fn clear_interrupt_flags(r: crate::pac::lpuart::Lpuart, sr: regs::Isr) {
+unsafe fn clear_interrupt_flags(r: Regs, sr: regs::Isr) {
     r.icr().write(|w| *w = regs::Icr(sr.0));
 }
 
 pub(crate) mod sealed {
+    use super::*;
 
     pub trait BasicInstance: crate::rcc::RccPeripheral {
         const MULTIPLIER: u32;
         type Interrupt: crate::interrupt::Interrupt;
 
-        fn regs() -> crate::pac::lpuart::Lpuart;
+        fn regs() -> Regs;
     }
 
     pub trait FullInstance: BasicInstance {
@@ -500,27 +504,23 @@ macro_rules! impl_lpuart {
             const MULTIPLIER: u32 = $mul;
             type Interrupt = crate::interrupt::$irq;
 
-            fn regs() -> crate::pac::lpuart::Lpuart {
-                crate::pac::lpuart::Lpuart(crate::pac::$inst.0)
+            fn regs() -> Regs {
+                Regs(crate::pac::$inst.0)
             }
         }
+
+        impl BasicInstance for peripherals::$inst {}
     };
 }
 
 foreach_interrupt!(
-    ($inst:ident, lpuart, LPUART, $signal_name:ident, $irq:ident) => {
+    ($inst:ident, lpuart, $block:ident, $signal_name:ident, $irq:ident) => {
         impl_lpuart!($inst, $irq, 255);
-
-        impl BasicInstance for peripherals::$inst {
-        }
     };
 
-    ($inst:ident, usart, USART, $signal_name:ident, $irq:ident) => {
+    ($inst:ident, usart, $block:ident, $signal_name:ident, $irq:ident) => {
         impl_lpuart!($inst, $irq, 1);
 
-        impl BasicInstance for peripherals::$inst {
-        }
-
         impl sealed::FullInstance for peripherals::$inst {
 
             fn regs_uart() -> crate::pac::usart::Usart {

From 52c1e48edb2c0036537c061df20ccc17e4d20f4e Mon Sep 17 00:00:00 2001
From: Vincent Stakenburg <v.stakenburg@cosinuss.nl>
Date: Fri, 19 Aug 2022 15:31:26 +0200
Subject: [PATCH 11/21] update stm32-data

---
 stm32-data | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/stm32-data b/stm32-data
index f47995849..14a448c31 160000
--- a/stm32-data
+++ b/stm32-data
@@ -1 +1 @@
-Subproject commit f47995849a1a66cc92143ff94c84b11dc2701ccb
+Subproject commit 14a448c318192fe9da1c95a4de1beb4ec4892f1c

From 0c7ad547935fa684b32c6fc59ac9d911f2e021a3 Mon Sep 17 00:00:00 2001
From: Quentin Smith <quentin@mit.edu>
Date: Fri, 19 Aug 2022 11:58:45 -0400
Subject: [PATCH 12/21] Fetch systemview-target from upstream git

---
 examples/nrf-rtos-trace/Cargo.toml | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/examples/nrf-rtos-trace/Cargo.toml b/examples/nrf-rtos-trace/Cargo.toml
index bdf49f574..52b4bb7ee 100644
--- a/examples/nrf-rtos-trace/Cargo.toml
+++ b/examples/nrf-rtos-trace/Cargo.toml
@@ -35,5 +35,4 @@ name = "rtos_trace"
 required-features = ["nightly"]
 
 [patch.crates-io]
-rtos-trace = { git = "https://gitlab.com/quentinmit/rtos-trace.git", branch = "build-fix" }
-systemview-target = { git = "https://gitlab.com/quentinmit/rtos-trace.git", branch = "build-fix" }
+systemview-target = { git = "https://gitlab.com/bern-rtos/tools/rtos-trace.git", rev = "3f68ec60f07aa87c191628568263f57073aa3dab" }

From 461cce255eb35a8835437fa2238b12dcaf5acad3 Mon Sep 17 00:00:00 2001
From: Dario Nieuwenhuis <dirbaio@dirbaio.net>
Date: Sat, 20 Aug 2022 02:52:21 +0200
Subject: [PATCH 13/21] tests/stm32: add lpuart test on stm32wb55

---
 tests/stm32/src/bin/usart.rs     | 8 +-------
 tests/stm32/src/bin/usart_dma.rs | 8 +-------
 2 files changed, 2 insertions(+), 14 deletions(-)

diff --git a/tests/stm32/src/bin/usart.rs b/tests/stm32/src/bin/usart.rs
index fb4b3fcca..7673bfe6d 100644
--- a/tests/stm32/src/bin/usart.rs
+++ b/tests/stm32/src/bin/usart.rs
@@ -15,12 +15,6 @@ async fn main(_spawner: Spawner) {
     let p = embassy_stm32::init(config());
     info!("Hello World!");
 
-    #[cfg(feature = "stm32wb55rg")]
-    {
-        info!("Test SKIPPED");
-        cortex_m::asm::bkpt();
-    }
-
     // Arduino pins D0 and D1
     // They're connected together with a 1K resistor.
     #[cfg(feature = "stm32f103c8")]
@@ -32,7 +26,7 @@ async fn main(_spawner: Spawner) {
     #[cfg(feature = "stm32f429zi")]
     let (tx, rx, usart) = (p.PG14, p.PG9, p.USART6);
     #[cfg(feature = "stm32wb55rg")]
-    let (tx, rx, usart) = (p.PA9, p.PA10, p.USART1); // TODO this is wrong
+    let (tx, rx, usart) = (p.PA2, p.PA3, p.LPUART1);
     #[cfg(feature = "stm32h755zi")]
     let (tx, rx, usart) = (p.PB6, p.PB7, p.USART1);
     #[cfg(feature = "stm32u585ai")]
diff --git a/tests/stm32/src/bin/usart_dma.rs b/tests/stm32/src/bin/usart_dma.rs
index 09382a022..e0389446f 100644
--- a/tests/stm32/src/bin/usart_dma.rs
+++ b/tests/stm32/src/bin/usart_dma.rs
@@ -14,12 +14,6 @@ async fn main(_spawner: Spawner) {
     let p = embassy_stm32::init(config());
     info!("Hello World!");
 
-    #[cfg(feature = "stm32wb55rg")]
-    {
-        info!("Test SKIPPED");
-        cortex_m::asm::bkpt();
-    }
-
     // Arduino pins D0 and D1
     // They're connected together with a 1K resistor.
     #[cfg(feature = "stm32f103c8")]
@@ -31,7 +25,7 @@ async fn main(_spawner: Spawner) {
     #[cfg(feature = "stm32f429zi")]
     let (tx, rx, usart, tx_dma, rx_dma) = (p.PG14, p.PG9, p.USART6, p.DMA2_CH6, p.DMA2_CH1);
     #[cfg(feature = "stm32wb55rg")]
-    let (tx, rx, usart, tx_dma, rx_dma) = (p.PA9, p.PA10, p.USART1, p.DMA1_CH1, p.DMA1_CH2); // TODO this is wrong
+    let (tx, rx, usart, tx_dma, rx_dma) = (p.PA2, p.PA3, p.LPUART1, p.DMA1_CH1, p.DMA1_CH2);
     #[cfg(feature = "stm32h755zi")]
     let (tx, rx, usart, tx_dma, rx_dma) = (p.PB6, p.PB7, p.USART1, p.DMA1_CH0, p.DMA1_CH1);
     #[cfg(feature = "stm32u585ai")]

From 614b894ff871add9f0394fcf9ef220f133c4aae4 Mon Sep 17 00:00:00 2001
From: Quentin Smith <quentin@mit.edu>
Date: Sat, 20 Aug 2022 14:16:06 -0400
Subject: [PATCH 14/21] Switch to crates.io version of systemview-target

---
 examples/nrf-rtos-trace/Cargo.toml | 5 +----
 1 file changed, 1 insertion(+), 4 deletions(-)

diff --git a/examples/nrf-rtos-trace/Cargo.toml b/examples/nrf-rtos-trace/Cargo.toml
index 52b4bb7ee..b0907f92c 100644
--- a/examples/nrf-rtos-trace/Cargo.toml
+++ b/examples/nrf-rtos-trace/Cargo.toml
@@ -27,12 +27,9 @@ futures = { version = "0.3.17", default-features = false, features = ["async-awa
 rand = { version = "0.8.4", default-features = false }
 serde = { version = "1.0.136", default-features = false }
 rtos-trace = "0.1.3"
-systemview-target = { version = "0.1.1", features = ["callbacks-app", "callbacks-os", "log", "cortex-m"] }
+systemview-target = { version = "0.1.2", features = ["callbacks-app", "callbacks-os", "log", "cortex-m"] }
 log = { version = "0.4.17", optional = true }
 
 [[bin]]
 name = "rtos_trace"
 required-features = ["nightly"]
-
-[patch.crates-io]
-systemview-target = { git = "https://gitlab.com/bern-rtos/tools/rtos-trace.git", rev = "3f68ec60f07aa87c191628568263f57073aa3dab" }

From 478f4727846f6a43c28fff3b09cb639c0b800465 Mon Sep 17 00:00:00 2001
From: Dario Nieuwenhuis <dirbaio@dirbaio.net>
Date: Mon, 22 Aug 2022 15:51:44 +0200
Subject: [PATCH 15/21] Remove Forever, switch to static_cell.

---
 embassy-cortex-m/src/executor.rs              |  2 +-
 .../src/shared_bus/asynch/i2c.rs              |  4 +-
 .../src/shared_bus/asynch/spi.rs              |  4 +-
 .../src/shared_bus/blocking/i2c.rs            |  4 +-
 .../src/shared_bus/blocking/spi.rs            |  4 +-
 embassy-executor/Cargo.toml                   |  1 +
 embassy-executor/src/arch/cortex_m.rs         |  2 +-
 embassy-executor/src/arch/riscv32.rs          |  2 +-
 embassy-executor/src/arch/std.rs              |  2 +-
 embassy-executor/src/arch/wasm.rs             |  2 +-
 embassy-executor/src/arch/xtensa.rs           |  2 +-
 embassy-executor/src/lib.rs                   |  6 ++
 embassy-macros/src/macros/main.rs             |  4 +-
 embassy-util/Cargo.toml                       |  1 +
 embassy-util/src/channel/mpmc.rs              | 10 +-
 embassy-util/src/forever.rs                   | 95 -------------------
 embassy-util/src/lib.rs                       |  2 -
 embassy-util/src/pipe.rs                      |  6 +-
 examples/nrf/Cargo.toml                       |  1 +
 .../nrf/src/bin/channel_sender_receiver.rs    |  6 +-
 examples/nrf/src/bin/multiprio.rs             | 14 +--
 examples/nrf/src/bin/raw_spawn.rs             |  6 +-
 examples/nrf/src/bin/usb_ethernet.rs          | 14 +--
 examples/nrf/src/bin/usb_serial_multitask.rs  |  6 +-
 examples/std/Cargo.toml                       |  1 +
 examples/std/src/bin/net.rs                   | 16 ++--
 examples/std/src/bin/net_udp.rs               | 16 ++--
 examples/std/src/bin/serial.rs                |  6 +-
 examples/stm32f3/Cargo.toml                   |  1 +
 examples/stm32f3/src/bin/multiprio.rs         | 14 +--
 examples/stm32f4/Cargo.toml                   |  1 +
 examples/stm32f4/src/bin/multiprio.rs         | 14 +--
 examples/stm32f7/Cargo.toml                   |  1 +
 examples/stm32f7/src/bin/eth.rs               | 14 +--
 examples/stm32h7/Cargo.toml                   |  1 +
 examples/stm32h7/src/bin/eth.rs               | 14 +--
 examples/stm32h7/src/bin/eth_client.rs        | 14 +--
 examples/stm32h7/src/bin/spi.rs               |  6 +-
 examples/stm32h7/src/bin/spi_dma.rs           |  6 +-
 examples/stm32h7/src/bin/usart.rs             |  6 +-
 examples/stm32h7/src/bin/usart_dma.rs         |  6 +-
 examples/stm32l0/Cargo.toml                   |  1 +
 examples/stm32l0/src/bin/raw_spawn.rs         |  6 +-
 examples/stm32l5/Cargo.toml                   |  1 +
 examples/stm32l5/src/bin/usb_ethernet.rs      | 14 +--
 45 files changed, 139 insertions(+), 220 deletions(-)
 delete mode 100644 embassy-util/src/forever.rs

diff --git a/embassy-cortex-m/src/executor.rs b/embassy-cortex-m/src/executor.rs
index 80c452f84..0d1745d8a 100644
--- a/embassy-cortex-m/src/executor.rs
+++ b/embassy-cortex-m/src/executor.rs
@@ -71,7 +71,7 @@ impl<I: Interrupt> InterruptExecutor<I> {
     /// Executor instance in a place where it'll live forever and grants you mutable
     /// access. There's a few ways to do this:
     ///
-    /// - a [Forever](embassy_util::Forever) (safe)
+    /// - a [StaticCell](https://docs.rs/static_cell/latest/static_cell/) (safe)
     /// - a `static mut` (unsafe)
     /// - a local variable in a function you know never returns (like `fn main() -> !`), upgrading its lifetime with `transmute`. (unsafe)
     pub fn start(&'static mut self) -> SendSpawner {
diff --git a/embassy-embedded-hal/src/shared_bus/asynch/i2c.rs b/embassy-embedded-hal/src/shared_bus/asynch/i2c.rs
index bd023fb6a..dc483b826 100644
--- a/embassy-embedded-hal/src/shared_bus/asynch/i2c.rs
+++ b/embassy-embedded-hal/src/shared_bus/asynch/i2c.rs
@@ -7,12 +7,12 @@
 //! use embassy_util::mutex::Mutex;
 //! use embassy_util::blocking_mutex::raw::ThreadModeRawMutex;
 //!
-//! static I2C_BUS: Forever<Mutex::<ThreadModeRawMutex, Twim<TWISPI0>>> = Forever::new();
+//! static I2C_BUS: StaticCell<Mutex::<ThreadModeRawMutex, Twim<TWISPI0>>> = StaticCell::new();
 //! let config = twim::Config::default();
 //! let irq = interrupt::take!(SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0);
 //! let i2c = Twim::new(p.TWISPI0, irq, p.P0_03, p.P0_04, config);
 //! let i2c_bus = Mutex::<ThreadModeRawMutex, _>::new(i2c);
-//! let i2c_bus = I2C_BUS.put(i2c_bus);
+//! let i2c_bus = I2C_BUS.init(i2c_bus);
 //!
 //! // Device 1, using embedded-hal-async compatible driver for QMC5883L compass
 //! let i2c_dev1 = I2cDevice::new(i2c_bus);
diff --git a/embassy-embedded-hal/src/shared_bus/asynch/spi.rs b/embassy-embedded-hal/src/shared_bus/asynch/spi.rs
index caa37f6f3..bb419d6a6 100644
--- a/embassy-embedded-hal/src/shared_bus/asynch/spi.rs
+++ b/embassy-embedded-hal/src/shared_bus/asynch/spi.rs
@@ -7,13 +7,13 @@
 //! use embassy_util::mutex::Mutex;
 //! use embassy_util::blocking_mutex::raw::ThreadModeRawMutex;
 //!
-//! static SPI_BUS: Forever<Mutex<ThreadModeRawMutex, spim::Spim<SPI3>>> = Forever::new();
+//! static SPI_BUS: StaticCell<Mutex<ThreadModeRawMutex, spim::Spim<SPI3>>> = StaticCell::new();
 //! let mut config = spim::Config::default();
 //! config.frequency = spim::Frequency::M32;
 //! let irq = interrupt::take!(SPIM3);
 //! let spi = spim::Spim::new_txonly(p.SPI3, irq, p.P0_15, p.P0_18, config);
 //! let spi_bus = Mutex::<ThreadModeRawMutex, _>::new(spi);
-//! let spi_bus = SPI_BUS.put(spi_bus);
+//! let spi_bus = SPI_BUS.init(spi_bus);
 //!
 //! // Device 1, using embedded-hal-async compatible driver for ST7735 LCD display
 //! let cs_pin1 = Output::new(p.P0_24, Level::Low, OutputDrive::Standard);
diff --git a/embassy-embedded-hal/src/shared_bus/blocking/i2c.rs b/embassy-embedded-hal/src/shared_bus/blocking/i2c.rs
index 1fc343d15..837312e87 100644
--- a/embassy-embedded-hal/src/shared_bus/blocking/i2c.rs
+++ b/embassy-embedded-hal/src/shared_bus/blocking/i2c.rs
@@ -6,11 +6,11 @@
 //! use embassy_embedded_hal::shared_bus::blocking::i2c::I2cDevice;
 //! use embassy_util::blocking_mutex::{NoopMutex, raw::NoopRawMutex};
 //!
-//! static I2C_BUS: Forever<NoopMutex<RefCell<Twim<TWISPI0>>>> = Forever::new();
+//! static I2C_BUS: StaticCell<NoopMutex<RefCell<Twim<TWISPI0>>>> = StaticCell::new();
 //! let irq = interrupt::take!(SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0);
 //! let i2c = Twim::new(p.TWISPI0, irq, p.P0_03, p.P0_04, Config::default());
 //! let i2c_bus = NoopMutex::new(RefCell::new(i2c));
-//! let i2c_bus = I2C_BUS.put(i2c_bus);
+//! let i2c_bus = I2C_BUS.init(i2c_bus);
 //!
 //! let i2c_dev1 = I2cDevice::new(i2c_bus);
 //! let mpu = Mpu6050::new(i2c_dev1);
diff --git a/embassy-embedded-hal/src/shared_bus/blocking/spi.rs b/embassy-embedded-hal/src/shared_bus/blocking/spi.rs
index a61326594..a48d9183c 100644
--- a/embassy-embedded-hal/src/shared_bus/blocking/spi.rs
+++ b/embassy-embedded-hal/src/shared_bus/blocking/spi.rs
@@ -6,11 +6,11 @@
 //! use embassy_embedded_hal::shared_bus::blocking::spi::SpiDevice;
 //! use embassy_util::blocking_mutex::{NoopMutex, raw::NoopRawMutex};
 //!
-//! static SPI_BUS: Forever<NoopMutex<RefCell<Spim<SPI3>>>> = Forever::new();
+//! static SPI_BUS: StaticCell<NoopMutex<RefCell<Spim<SPI3>>>> = StaticCell::new();
 //! let irq = interrupt::take!(SPIM3);
 //! let spi = Spim::new_txonly(p.SPI3, irq, p.P0_15, p.P0_18, Config::default());
 //! let spi_bus = NoopMutex::new(RefCell::new(spi));
-//! let spi_bus = SPI_BUS.put(spi_bus);
+//! let spi_bus = SPI_BUS.init(spi_bus);
 //!
 //! // Device 1, using embedded-hal compatible driver for ST7735 LCD display
 //! let cs_pin1 = Output::new(p.P0_24, Level::Low, OutputDrive::Standard);
diff --git a/embassy-executor/Cargo.toml b/embassy-executor/Cargo.toml
index 7d5c4a045..184e770cd 100644
--- a/embassy-executor/Cargo.toml
+++ b/embassy-executor/Cargo.toml
@@ -44,6 +44,7 @@ embassy-time  = { version = "0.1.0", path = "../embassy-time", optional = true}
 atomic-polyfill = "1.0.1"
 critical-section = "1.1"
 cfg-if = "1.0.0"
+static_cell = "1.0"
 
 # WASM dependencies
 wasm-bindgen = { version = "0.2.76", features = ["nightly"], optional = true }
diff --git a/embassy-executor/src/arch/cortex_m.rs b/embassy-executor/src/arch/cortex_m.rs
index d6e758dfb..4b27a264e 100644
--- a/embassy-executor/src/arch/cortex_m.rs
+++ b/embassy-executor/src/arch/cortex_m.rs
@@ -41,7 +41,7 @@ impl Executor {
     /// Executor instance in a place where it'll live forever and grants you mutable
     /// access. There's a few ways to do this:
     ///
-    /// - a [Forever](crate::util::Forever) (safe)
+    /// - a [StaticCell](https://docs.rs/static_cell/latest/static_cell/) (safe)
     /// - a `static mut` (unsafe)
     /// - a local variable in a function you know never returns (like `fn main() -> !`), upgrading its lifetime with `transmute`. (unsafe)
     ///
diff --git a/embassy-executor/src/arch/riscv32.rs b/embassy-executor/src/arch/riscv32.rs
index 7a7d5698c..2a4b006da 100644
--- a/embassy-executor/src/arch/riscv32.rs
+++ b/embassy-executor/src/arch/riscv32.rs
@@ -43,7 +43,7 @@ impl Executor {
     /// Executor instance in a place where it'll live forever and grants you mutable
     /// access. There's a few ways to do this:
     ///
-    /// - a [Forever](crate::util::Forever) (safe)
+    /// - a [StaticCell](https://docs.rs/static_cell/latest/static_cell/) (safe)
     /// - a `static mut` (unsafe)
     /// - a local variable in a function you know never returns (like `fn main() -> !`), upgrading its lifetime with `transmute`. (unsafe)
     ///
diff --git a/embassy-executor/src/arch/std.rs b/embassy-executor/src/arch/std.rs
index b93ab8a79..701f0eb18 100644
--- a/embassy-executor/src/arch/std.rs
+++ b/embassy-executor/src/arch/std.rs
@@ -40,7 +40,7 @@ impl Executor {
     /// Executor instance in a place where it'll live forever and grants you mutable
     /// access. There's a few ways to do this:
     ///
-    /// - a [Forever](crate::util::Forever) (safe)
+    /// - a [StaticCell](https://docs.rs/static_cell/latest/static_cell/) (safe)
     /// - a `static mut` (unsafe)
     /// - a local variable in a function you know never returns (like `fn main() -> !`), upgrading its lifetime with `transmute`. (unsafe)
     ///
diff --git a/embassy-executor/src/arch/wasm.rs b/embassy-executor/src/arch/wasm.rs
index 9d5aa31ed..98091cfbb 100644
--- a/embassy-executor/src/arch/wasm.rs
+++ b/embassy-executor/src/arch/wasm.rs
@@ -59,7 +59,7 @@ impl Executor {
     /// Executor instance in a place where it'll live forever and grants you mutable
     /// access. There's a few ways to do this:
     ///
-    /// - a [Forever](crate::util::Forever) (safe)
+    /// - a [StaticCell](https://docs.rs/static_cell/latest/static_cell/) (safe)
     /// - a `static mut` (unsafe)
     /// - a local variable in a function you know never returns (like `fn main() -> !`), upgrading its lifetime with `transmute`. (unsafe)
     pub fn start(&'static mut self, init: impl FnOnce(Spawner)) {
diff --git a/embassy-executor/src/arch/xtensa.rs b/embassy-executor/src/arch/xtensa.rs
index 20bd7b8a5..f908aaa70 100644
--- a/embassy-executor/src/arch/xtensa.rs
+++ b/embassy-executor/src/arch/xtensa.rs
@@ -43,7 +43,7 @@ impl Executor {
     /// Executor instance in a place where it'll live forever and grants you mutable
     /// access. There's a few ways to do this:
     ///
-    /// - a [Forever](crate::util::Forever) (safe)
+    /// - a [StaticCell](https://docs.rs/static_cell/latest/static_cell/) (safe)
     /// - a `static mut` (unsafe)
     /// - a local variable in a function you know never returns (like `fn main() -> !`), upgrading its lifetime with `transmute`. (unsafe)
     ///
diff --git a/embassy-executor/src/lib.rs b/embassy-executor/src/lib.rs
index 93f2eaa6d..e4cbd04b9 100644
--- a/embassy-executor/src/lib.rs
+++ b/embassy-executor/src/lib.rs
@@ -67,3 +67,9 @@ pub mod raw;
 
 mod spawner;
 pub use spawner::*;
+
+/// Do not use. Used for macros and HALs only. Not covered by semver guarantees.
+#[doc(hidden)]
+pub mod _export {
+    pub use static_cell::StaticCell;
+}
diff --git a/embassy-macros/src/macros/main.rs b/embassy-macros/src/macros/main.rs
index 52987d7d2..afe9bd3e2 100644
--- a/embassy-macros/src/macros/main.rs
+++ b/embassy-macros/src/macros/main.rs
@@ -34,8 +34,8 @@ pub fn run(args: syn::AttributeArgs, f: syn::ItemFn) -> Result<TokenStream, Toke
     let main = quote! {
         #[wasm_bindgen::prelude::wasm_bindgen(start)]
         pub fn main() -> Result<(), wasm_bindgen::JsValue> {
-            static EXECUTOR: ::embassy_util::Forever<::embassy_executor::Executor> = ::embassy_util::Forever::new();
-            let executor = EXECUTOR.put(::embassy_executor::Executor::new());
+            static EXECUTOR: ::embassy_executor::_export::StaticCell<::embassy_executor::Executor> = ::embassy_executor::_export::StaticCell::new();
+            let executor = EXECUTOR.init(::embassy_executor::Executor::new());
 
             executor.start(|spawner| {
                 spawner.spawn(__embassy_main(spawner)).unwrap();
diff --git a/embassy-util/Cargo.toml b/embassy-util/Cargo.toml
index d4708d735..b54a58b46 100644
--- a/embassy-util/Cargo.toml
+++ b/embassy-util/Cargo.toml
@@ -31,3 +31,4 @@ futures-util = { version = "0.3.17", features = [ "channel" ] }
 
 # Enable critical-section implementation for std, for tests
 critical-section = { version = "1.1", features = ["std"] }
+static_cell = "1.0"
diff --git a/embassy-util/src/channel/mpmc.rs b/embassy-util/src/channel/mpmc.rs
index 535f77e6f..263f29bfc 100644
--- a/embassy-util/src/channel/mpmc.rs
+++ b/embassy-util/src/channel/mpmc.rs
@@ -471,10 +471,10 @@ mod tests {
     use futures_executor::ThreadPool;
     use futures_timer::Delay;
     use futures_util::task::SpawnExt;
+    use static_cell::StaticCell;
 
     use super::*;
     use crate::blocking_mutex::raw::{CriticalSectionRawMutex, NoopRawMutex};
-    use crate::Forever;
 
     fn capacity<T, const N: usize>(c: &ChannelState<T, N>) -> usize {
         c.queue.capacity() - c.queue.len()
@@ -549,8 +549,8 @@ mod tests {
     async fn receiver_receives_given_try_send_async() {
         let executor = ThreadPool::new().unwrap();
 
-        static CHANNEL: Forever<Channel<CriticalSectionRawMutex, u32, 3>> = Forever::new();
-        let c = &*CHANNEL.put(Channel::new());
+        static CHANNEL: StaticCell<Channel<CriticalSectionRawMutex, u32, 3>> = StaticCell::new();
+        let c = &*CHANNEL.init(Channel::new());
         let c2 = c;
         assert!(executor
             .spawn(async move {
@@ -571,8 +571,8 @@ mod tests {
     async fn senders_sends_wait_until_capacity() {
         let executor = ThreadPool::new().unwrap();
 
-        static CHANNEL: Forever<Channel<CriticalSectionRawMutex, u32, 1>> = Forever::new();
-        let c = &*CHANNEL.put(Channel::new());
+        static CHANNEL: StaticCell<Channel<CriticalSectionRawMutex, u32, 1>> = StaticCell::new();
+        let c = &*CHANNEL.init(Channel::new());
         assert!(c.try_send(1).is_ok());
 
         let c2 = c;
diff --git a/embassy-util/src/forever.rs b/embassy-util/src/forever.rs
deleted file mode 100644
index 4f3698211..000000000
--- a/embassy-util/src/forever.rs
+++ /dev/null
@@ -1,95 +0,0 @@
-use core::cell::UnsafeCell;
-use core::mem::MaybeUninit;
-
-use atomic_polyfill::{AtomicBool, Ordering};
-
-/// Type with static lifetime that may be written to once at runtime.
-///
-/// This may be used to initialize static objects at runtime, typically in the init routine.
-/// This is useful for objects such as Embassy's RTC, which cannot be initialized in a const
-/// context.
-///
-/// Note: IF a global mutable variable is desired, use a CriticalSectionMutex or ThreadModeMutex instead.
-///
-/// ```
-/// use embassy_util::Forever;
-/// // Using an integer for the sake of keeping this example self-contained,
-/// // see https://github.com/embassy-rs/embassy/wiki/Getting-Started for a more "proper" example.
-/// static SOME_INT: Forever<u32> =Forever::new();
-///
-/// // put returns a mutable pointer to the object stored in the forever, which may then be passed
-/// // around.
-/// let mut x = SOME_INT.put(42);
-/// assert_eq!(*x, 42);
-/// ```
-pub struct Forever<T> {
-    used: AtomicBool,
-    t: UnsafeCell<MaybeUninit<T>>,
-}
-
-unsafe impl<T> Send for Forever<T> {}
-unsafe impl<T> Sync for Forever<T> {}
-
-impl<T> Forever<T> {
-    /// Create a new `Forever`.
-    #[inline(always)]
-    pub const fn new() -> Self {
-        Self {
-            used: AtomicBool::new(false),
-            t: UnsafeCell::new(MaybeUninit::uninit()),
-        }
-    }
-
-    /// Store a value in this `Forever`, returning a mutable reference to it.
-    ///
-    /// Using this method, the compiler usually constructs `val` in the stack and then moves
-    /// it into the `Forever`. If `T` is big, this is likely to cause stack overflows.
-    /// Considering using [`Signal::put_with`] instead, which will construct it in-place inside the `Forever`.
-    ///
-    /// # Panics
-    ///
-    /// Panics if this `Forever` already has a value stored in it.
-    #[inline(always)]
-    #[allow(clippy::mut_from_ref)]
-    pub fn put(&'static self, val: T) -> &'static mut T {
-        self.put_with(|| val)
-    }
-
-    /// Store the closure return value in this `Forever`, returning a mutable reference to it.
-    ///
-    /// The advantage over [`Forever::put`] is that this method allows the closure to construct
-    /// the `T` value in-place directly inside the `Forever`, saving stack space.
-    ///
-    /// # Panics
-    ///
-    /// Panics if this `Forever` already has a value stored in it.
-    #[inline(always)]
-    #[allow(clippy::mut_from_ref)]
-    pub fn put_with(&'static self, val: impl FnOnce() -> T) -> &'static mut T {
-        if self
-            .used
-            .compare_exchange(false, true, Ordering::Relaxed, Ordering::Relaxed)
-            .is_err()
-        {
-            panic!("Forever.put() called multiple times");
-        }
-
-        let p: &'static mut MaybeUninit<T> = unsafe { &mut *self.t.get() };
-        p.write(val())
-    }
-
-    /// Unsafely get a mutable reference to the contents of this Forever.
-    ///
-    /// # Safety
-    ///
-    /// This is undefined behavior if:
-    ///
-    /// - The `Forever` has not been initialized yet (with `put' or `put_with`), or
-    /// - A reference to the contents (mutable or not) already exists.
-    #[inline(always)]
-    #[allow(clippy::mut_from_ref)]
-    pub unsafe fn steal(&self) -> &mut T {
-        let p: &mut MaybeUninit<T> = &mut *self.t.get();
-        p.assume_init_mut()
-    }
-}
diff --git a/embassy-util/src/lib.rs b/embassy-util/src/lib.rs
index 110c72811..8ec3300d9 100644
--- a/embassy-util/src/lib.rs
+++ b/embassy-util/src/lib.rs
@@ -16,10 +16,8 @@ pub mod mutex;
 pub mod pipe;
 pub mod waitqueue;
 
-mod forever;
 mod select;
 mod yield_now;
 
-pub use forever::*;
 pub use select::*;
 pub use yield_now::*;
diff --git a/embassy-util/src/pipe.rs b/embassy-util/src/pipe.rs
index 9c20aeeff..d85b843e4 100644
--- a/embassy-util/src/pipe.rs
+++ b/embassy-util/src/pipe.rs
@@ -461,10 +461,10 @@ mod io_impls {
 mod tests {
     use futures_executor::ThreadPool;
     use futures_util::task::SpawnExt;
+    use static_cell::StaticCell;
 
     use super::*;
     use crate::blocking_mutex::raw::{CriticalSectionRawMutex, NoopRawMutex};
-    use crate::Forever;
 
     fn capacity<const N: usize>(c: &PipeState<N>) -> usize {
         N - c.buffer.len()
@@ -528,8 +528,8 @@ mod tests {
     async fn receiver_receives_given_try_write_async() {
         let executor = ThreadPool::new().unwrap();
 
-        static CHANNEL: Forever<Pipe<CriticalSectionRawMutex, 3>> = Forever::new();
-        let c = &*CHANNEL.put(Pipe::new());
+        static CHANNEL: StaticCell<Pipe<CriticalSectionRawMutex, 3>> = StaticCell::new();
+        let c = &*CHANNEL.init(Pipe::new());
         let c2 = c;
         let f = async move {
             assert_eq!(c2.try_write(&[42]), Ok(1));
diff --git a/examples/nrf/Cargo.toml b/examples/nrf/Cargo.toml
index 2fcc31221..17f29b8fb 100644
--- a/examples/nrf/Cargo.toml
+++ b/examples/nrf/Cargo.toml
@@ -22,6 +22,7 @@ embedded-io = "0.3.0"
 defmt = "0.3"
 defmt-rtt = "0.3"
 
+static_cell = "1.0"
 cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] }
 cortex-m-rt = "0.7.0"
 panic-probe = { version = "0.3", features = ["print-defmt"] }
diff --git a/examples/nrf/src/bin/channel_sender_receiver.rs b/examples/nrf/src/bin/channel_sender_receiver.rs
index c9c458aec..d250b6a5c 100644
--- a/examples/nrf/src/bin/channel_sender_receiver.rs
+++ b/examples/nrf/src/bin/channel_sender_receiver.rs
@@ -8,7 +8,7 @@ use embassy_nrf::gpio::{AnyPin, Level, Output, OutputDrive, Pin};
 use embassy_time::{Duration, Timer};
 use embassy_util::blocking_mutex::raw::NoopRawMutex;
 use embassy_util::channel::mpmc::{Channel, Receiver, Sender};
-use embassy_util::Forever;
+use static_cell::StaticCell;
 use {defmt_rtt as _, panic_probe as _};
 
 enum LedState {
@@ -16,7 +16,7 @@ enum LedState {
     Off,
 }
 
-static CHANNEL: Forever<Channel<NoopRawMutex, LedState, 1>> = Forever::new();
+static CHANNEL: StaticCell<Channel<NoopRawMutex, LedState, 1>> = StaticCell::new();
 
 #[embassy_executor::task]
 async fn send_task(sender: Sender<'static, NoopRawMutex, LedState, 1>) {
@@ -43,7 +43,7 @@ async fn recv_task(led: AnyPin, receiver: Receiver<'static, NoopRawMutex, LedSta
 #[embassy_executor::main]
 async fn main(spawner: Spawner) {
     let p = embassy_nrf::init(Default::default());
-    let channel = CHANNEL.put(Channel::new());
+    let channel = CHANNEL.init(Channel::new());
 
     unwrap!(spawner.spawn(send_task(channel.sender())));
     unwrap!(spawner.spawn(recv_task(p.P0_13.degrade(), channel.receiver())));
diff --git a/examples/nrf/src/bin/multiprio.rs b/examples/nrf/src/bin/multiprio.rs
index b653689a7..25806ae48 100644
--- a/examples/nrf/src/bin/multiprio.rs
+++ b/examples/nrf/src/bin/multiprio.rs
@@ -63,7 +63,7 @@ use embassy_nrf::executor::{Executor, InterruptExecutor};
 use embassy_nrf::interrupt;
 use embassy_nrf::interrupt::InterruptExt;
 use embassy_time::{Duration, Instant, Timer};
-use embassy_util::Forever;
+use static_cell::StaticCell;
 use {defmt_rtt as _, panic_probe as _};
 
 #[embassy_executor::task]
@@ -108,9 +108,9 @@ async fn run_low() {
     }
 }
 
-static EXECUTOR_HIGH: Forever<InterruptExecutor<interrupt::SWI1_EGU1>> = Forever::new();
-static EXECUTOR_MED: Forever<InterruptExecutor<interrupt::SWI0_EGU0>> = Forever::new();
-static EXECUTOR_LOW: Forever<Executor> = Forever::new();
+static EXECUTOR_HIGH: StaticCell<InterruptExecutor<interrupt::SWI1_EGU1>> = StaticCell::new();
+static EXECUTOR_MED: StaticCell<InterruptExecutor<interrupt::SWI0_EGU0>> = StaticCell::new();
+static EXECUTOR_LOW: StaticCell<Executor> = StaticCell::new();
 
 #[entry]
 fn main() -> ! {
@@ -121,19 +121,19 @@ fn main() -> ! {
     // High-priority executor: SWI1_EGU1, priority level 6
     let irq = interrupt::take!(SWI1_EGU1);
     irq.set_priority(interrupt::Priority::P6);
-    let executor = EXECUTOR_HIGH.put(InterruptExecutor::new(irq));
+    let executor = EXECUTOR_HIGH.init(InterruptExecutor::new(irq));
     let spawner = executor.start();
     unwrap!(spawner.spawn(run_high()));
 
     // Medium-priority executor: SWI0_EGU0, priority level 7
     let irq = interrupt::take!(SWI0_EGU0);
     irq.set_priority(interrupt::Priority::P7);
-    let executor = EXECUTOR_MED.put(InterruptExecutor::new(irq));
+    let executor = EXECUTOR_MED.init(InterruptExecutor::new(irq));
     let spawner = executor.start();
     unwrap!(spawner.spawn(run_med()));
 
     // Low priority executor: runs in thread mode, using WFE/SEV
-    let executor = EXECUTOR_LOW.put(Executor::new());
+    let executor = EXECUTOR_LOW.init(Executor::new());
     executor.run(|spawner| {
         unwrap!(spawner.spawn(run_low()));
     });
diff --git a/examples/nrf/src/bin/raw_spawn.rs b/examples/nrf/src/bin/raw_spawn.rs
index 415579be7..1b067f5e4 100644
--- a/examples/nrf/src/bin/raw_spawn.rs
+++ b/examples/nrf/src/bin/raw_spawn.rs
@@ -8,7 +8,7 @@ use defmt::{info, unwrap};
 use embassy_executor::raw::TaskStorage;
 use embassy_executor::Executor;
 use embassy_time::{Duration, Timer};
-use embassy_util::Forever;
+use static_cell::StaticCell;
 use {defmt_rtt as _, panic_probe as _};
 
 async fn run1() {
@@ -25,14 +25,14 @@ async fn run2() {
     }
 }
 
-static EXECUTOR: Forever<Executor> = Forever::new();
+static EXECUTOR: StaticCell<Executor> = StaticCell::new();
 
 #[entry]
 fn main() -> ! {
     info!("Hello World!");
 
     let _p = embassy_nrf::init(Default::default());
-    let executor = EXECUTOR.put(Executor::new());
+    let executor = EXECUTOR.init(Executor::new());
 
     let run1_task = TaskStorage::new();
     let run2_task = TaskStorage::new();
diff --git a/examples/nrf/src/bin/usb_ethernet.rs b/examples/nrf/src/bin/usb_ethernet.rs
index f0a870317..d427f7563 100644
--- a/examples/nrf/src/bin/usb_ethernet.rs
+++ b/examples/nrf/src/bin/usb_ethernet.rs
@@ -18,17 +18,17 @@ use embassy_usb::{Builder, Config, UsbDevice};
 use embassy_usb_ncm::{CdcNcmClass, Receiver, Sender, State};
 use embassy_util::blocking_mutex::raw::ThreadModeRawMutex;
 use embassy_util::channel::mpmc::Channel;
-use embassy_util::Forever;
 use embedded_io::asynch::{Read, Write};
+use static_cell::StaticCell;
 use {defmt_rtt as _, panic_probe as _};
 
 type MyDriver = Driver<'static, peripherals::USBD, PowerUsb>;
 
-macro_rules! forever {
+macro_rules! singleton {
     ($val:expr) => {{
         type T = impl Sized;
-        static FOREVER: Forever<T> = Forever::new();
-        FOREVER.put_with(move || $val)
+        static STATIC_CELL: StaticCell<T> = StaticCell::new();
+        STATIC_CELL.init_with(move || $val)
     }};
 }
 
@@ -116,7 +116,7 @@ async fn main(spawner: Spawner) {
         control_buf: [u8; 128],
         serial_state: State<'static>,
     }
-    let res: &mut Resources = forever!(Resources {
+    let res: &mut Resources = singleton!(Resources {
         device_descriptor: [0; 256],
         config_descriptor: [0; 256],
         bos_descriptor: [0; 256],
@@ -174,10 +174,10 @@ async fn main(spawner: Spawner) {
 
     // Init network stack
     let device = Device { mac_addr: our_mac_addr };
-    let stack = &*forever!(Stack::new(
+    let stack = &*singleton!(Stack::new(
         device,
         config,
-        forever!(StackResources::<1, 2, 8>::new()),
+        singleton!(StackResources::<1, 2, 8>::new()),
         seed
     ));
 
diff --git a/examples/nrf/src/bin/usb_serial_multitask.rs b/examples/nrf/src/bin/usb_serial_multitask.rs
index 4c1a93087..d62d7e520 100644
--- a/examples/nrf/src/bin/usb_serial_multitask.rs
+++ b/examples/nrf/src/bin/usb_serial_multitask.rs
@@ -12,7 +12,7 @@ use embassy_nrf::{interrupt, pac, peripherals};
 use embassy_usb::driver::EndpointError;
 use embassy_usb::{Builder, Config, UsbDevice};
 use embassy_usb_serial::{CdcAcmClass, State};
-use embassy_util::Forever;
+use static_cell::StaticCell;
 use {defmt_rtt as _, panic_probe as _};
 
 type MyDriver = Driver<'static, peripherals::USBD, PowerUsb>;
@@ -67,8 +67,8 @@ async fn main(spawner: Spawner) {
         control_buf: [u8; 64],
         serial_state: State<'static>,
     }
-    static RESOURCES: Forever<Resources> = Forever::new();
-    let res = RESOURCES.put(Resources {
+    static RESOURCES: StaticCell<Resources> = StaticCell::new();
+    let res = RESOURCES.init(Resources {
         device_descriptor: [0; 256],
         config_descriptor: [0; 256],
         bos_descriptor: [0; 256],
diff --git a/examples/std/Cargo.toml b/examples/std/Cargo.toml
index b7009017c..164a2b42d 100644
--- a/examples/std/Cargo.toml
+++ b/examples/std/Cargo.toml
@@ -20,3 +20,4 @@ libc = "0.2.101"
 clap = { version = "3.0.0-beta.5", features = ["derive"] }
 rand_core = { version = "0.6.3", features = ["std"] }
 heapless = { version = "0.7.5", default-features = false }
+static_cell = "1.0"
diff --git a/examples/std/src/bin/net.rs b/examples/std/src/bin/net.rs
index 528609260..9b1450b72 100644
--- a/examples/std/src/bin/net.rs
+++ b/examples/std/src/bin/net.rs
@@ -4,22 +4,22 @@ use clap::Parser;
 use embassy_executor::{Executor, Spawner};
 use embassy_net::tcp::TcpSocket;
 use embassy_net::{ConfigStrategy, Ipv4Address, Ipv4Cidr, Stack, StackResources};
-use embassy_util::Forever;
 use embedded_io::asynch::Write;
 use heapless::Vec;
 use log::*;
 use rand_core::{OsRng, RngCore};
+use static_cell::StaticCell;
 
 #[path = "../tuntap.rs"]
 mod tuntap;
 
 use crate::tuntap::TunTapDevice;
 
-macro_rules! forever {
+macro_rules! singleton {
     ($val:expr) => {{
         type T = impl Sized;
-        static FOREVER: Forever<T> = Forever::new();
-        FOREVER.put_with(move || $val)
+        static STATIC_CELL: StaticCell<T> = StaticCell::new();
+        STATIC_CELL.init_with(move || $val)
     }};
 }
 
@@ -63,10 +63,10 @@ async fn main_task(spawner: Spawner) {
     let seed = u64::from_le_bytes(seed);
 
     // Init network stack
-    let stack = &*forever!(Stack::new(
+    let stack = &*singleton!(Stack::new(
         device,
         config,
-        forever!(StackResources::<1, 2, 8>::new()),
+        singleton!(StackResources::<1, 2, 8>::new()),
         seed
     ));
 
@@ -97,7 +97,7 @@ async fn main_task(spawner: Spawner) {
     }
 }
 
-static EXECUTOR: Forever<Executor> = Forever::new();
+static EXECUTOR: StaticCell<Executor> = StaticCell::new();
 
 fn main() {
     env_logger::builder()
@@ -106,7 +106,7 @@ fn main() {
         .format_timestamp_nanos()
         .init();
 
-    let executor = EXECUTOR.put(Executor::new());
+    let executor = EXECUTOR.init(Executor::new());
     executor.run(|spawner| {
         spawner.spawn(main_task(spawner)).unwrap();
     });
diff --git a/examples/std/src/bin/net_udp.rs b/examples/std/src/bin/net_udp.rs
index 07e11c385..392a97f0d 100644
--- a/examples/std/src/bin/net_udp.rs
+++ b/examples/std/src/bin/net_udp.rs
@@ -4,21 +4,21 @@ use clap::Parser;
 use embassy_executor::{Executor, Spawner};
 use embassy_net::udp::UdpSocket;
 use embassy_net::{ConfigStrategy, Ipv4Address, Ipv4Cidr, PacketMetadata, Stack, StackResources};
-use embassy_util::Forever;
 use heapless::Vec;
 use log::*;
 use rand_core::{OsRng, RngCore};
+use static_cell::StaticCell;
 
 #[path = "../tuntap.rs"]
 mod tuntap;
 
 use crate::tuntap::TunTapDevice;
 
-macro_rules! forever {
+macro_rules! singleton {
     ($val:expr) => {{
         type T = impl Sized;
-        static FOREVER: Forever<T> = Forever::new();
-        FOREVER.put_with(move || $val)
+        static STATIC_CELL: StaticCell<T> = StaticCell::new();
+        STATIC_CELL.init_with(move || $val)
     }};
 }
 
@@ -62,10 +62,10 @@ async fn main_task(spawner: Spawner) {
     let seed = u64::from_le_bytes(seed);
 
     // Init network stack
-    let stack = &*forever!(Stack::new(
+    let stack = &*singleton!(Stack::new(
         device,
         config,
-        forever!(StackResources::<1, 2, 8>::new()),
+        singleton!(StackResources::<1, 2, 8>::new()),
         seed
     ));
 
@@ -93,7 +93,7 @@ async fn main_task(spawner: Spawner) {
     }
 }
 
-static EXECUTOR: Forever<Executor> = Forever::new();
+static EXECUTOR: StaticCell<Executor> = StaticCell::new();
 
 fn main() {
     env_logger::builder()
@@ -102,7 +102,7 @@ fn main() {
         .format_timestamp_nanos()
         .init();
 
-    let executor = EXECUTOR.put(Executor::new());
+    let executor = EXECUTOR.init(Executor::new());
     executor.run(|spawner| {
         spawner.spawn(main_task(spawner)).unwrap();
     });
diff --git a/examples/std/src/bin/serial.rs b/examples/std/src/bin/serial.rs
index 35cba4cee..85ee54f70 100644
--- a/examples/std/src/bin/serial.rs
+++ b/examples/std/src/bin/serial.rs
@@ -5,10 +5,10 @@ mod serial_port;
 
 use async_io::Async;
 use embassy_executor::Executor;
-use embassy_util::Forever;
 use embedded_io::asynch::Read;
 use log::*;
 use nix::sys::termios;
+use static_cell::StaticCell;
 
 use self::serial_port::SerialPort;
 
@@ -40,7 +40,7 @@ async fn run() {
     }
 }
 
-static EXECUTOR: Forever<Executor> = Forever::new();
+static EXECUTOR: StaticCell<Executor> = StaticCell::new();
 
 fn main() {
     env_logger::builder()
@@ -49,7 +49,7 @@ fn main() {
         .format_timestamp_nanos()
         .init();
 
-    let executor = EXECUTOR.put(Executor::new());
+    let executor = EXECUTOR.init(Executor::new());
     executor.run(|spawner| {
         spawner.spawn(run()).unwrap();
     });
diff --git a/examples/stm32f3/Cargo.toml b/examples/stm32f3/Cargo.toml
index b5ea28bb6..4e6b0ea1e 100644
--- a/examples/stm32f3/Cargo.toml
+++ b/examples/stm32f3/Cargo.toml
@@ -23,3 +23,4 @@ futures = { version = "0.3.17", default-features = false, features = ["async-awa
 heapless = { version = "0.7.5", default-features = false }
 nb = "1.0.0"
 embedded-storage = "0.3.0"
+static_cell = "1.0"
diff --git a/examples/stm32f3/src/bin/multiprio.rs b/examples/stm32f3/src/bin/multiprio.rs
index e96c31249..9e8228a4b 100644
--- a/examples/stm32f3/src/bin/multiprio.rs
+++ b/examples/stm32f3/src/bin/multiprio.rs
@@ -63,7 +63,7 @@ use embassy_stm32::executor::{Executor, InterruptExecutor};
 use embassy_stm32::interrupt;
 use embassy_stm32::interrupt::InterruptExt;
 use embassy_time::{Duration, Instant, Timer};
-use embassy_util::Forever;
+use static_cell::StaticCell;
 use {defmt_rtt as _, panic_probe as _};
 
 #[embassy_executor::task]
@@ -108,9 +108,9 @@ async fn run_low() {
     }
 }
 
-static EXECUTOR_HIGH: Forever<InterruptExecutor<interrupt::UART4>> = Forever::new();
-static EXECUTOR_MED: Forever<InterruptExecutor<interrupt::UART5>> = Forever::new();
-static EXECUTOR_LOW: Forever<Executor> = Forever::new();
+static EXECUTOR_HIGH: StaticCell<InterruptExecutor<interrupt::UART4>> = StaticCell::new();
+static EXECUTOR_MED: StaticCell<InterruptExecutor<interrupt::UART5>> = StaticCell::new();
+static EXECUTOR_LOW: StaticCell<Executor> = StaticCell::new();
 
 #[entry]
 fn main() -> ! {
@@ -121,19 +121,19 @@ fn main() -> ! {
     // High-priority executor: SWI1_EGU1, priority level 6
     let irq = interrupt::take!(UART4);
     irq.set_priority(interrupt::Priority::P6);
-    let executor = EXECUTOR_HIGH.put(InterruptExecutor::new(irq));
+    let executor = EXECUTOR_HIGH.init(InterruptExecutor::new(irq));
     let spawner = executor.start();
     unwrap!(spawner.spawn(run_high()));
 
     // Medium-priority executor: SWI0_EGU0, priority level 7
     let irq = interrupt::take!(UART5);
     irq.set_priority(interrupt::Priority::P7);
-    let executor = EXECUTOR_MED.put(InterruptExecutor::new(irq));
+    let executor = EXECUTOR_MED.init(InterruptExecutor::new(irq));
     let spawner = executor.start();
     unwrap!(spawner.spawn(run_med()));
 
     // Low priority executor: runs in thread mode, using WFE/SEV
-    let executor = EXECUTOR_LOW.put(Executor::new());
+    let executor = EXECUTOR_LOW.init(Executor::new());
     executor.run(|spawner| {
         unwrap!(spawner.spawn(run_low()));
     });
diff --git a/examples/stm32f4/Cargo.toml b/examples/stm32f4/Cargo.toml
index 04a217aff..f93a1d0f9 100644
--- a/examples/stm32f4/Cargo.toml
+++ b/examples/stm32f4/Cargo.toml
@@ -23,6 +23,7 @@ heapless = { version = "0.7.5", default-features = false }
 nb = "1.0.0"
 embedded-storage = "0.3.0"
 micromath = "2.0.0"
+static_cell = "1.0"
 
 usb-device = "0.2"
 usbd-serial = "0.1.1"
diff --git a/examples/stm32f4/src/bin/multiprio.rs b/examples/stm32f4/src/bin/multiprio.rs
index e96c31249..9e8228a4b 100644
--- a/examples/stm32f4/src/bin/multiprio.rs
+++ b/examples/stm32f4/src/bin/multiprio.rs
@@ -63,7 +63,7 @@ use embassy_stm32::executor::{Executor, InterruptExecutor};
 use embassy_stm32::interrupt;
 use embassy_stm32::interrupt::InterruptExt;
 use embassy_time::{Duration, Instant, Timer};
-use embassy_util::Forever;
+use static_cell::StaticCell;
 use {defmt_rtt as _, panic_probe as _};
 
 #[embassy_executor::task]
@@ -108,9 +108,9 @@ async fn run_low() {
     }
 }
 
-static EXECUTOR_HIGH: Forever<InterruptExecutor<interrupt::UART4>> = Forever::new();
-static EXECUTOR_MED: Forever<InterruptExecutor<interrupt::UART5>> = Forever::new();
-static EXECUTOR_LOW: Forever<Executor> = Forever::new();
+static EXECUTOR_HIGH: StaticCell<InterruptExecutor<interrupt::UART4>> = StaticCell::new();
+static EXECUTOR_MED: StaticCell<InterruptExecutor<interrupt::UART5>> = StaticCell::new();
+static EXECUTOR_LOW: StaticCell<Executor> = StaticCell::new();
 
 #[entry]
 fn main() -> ! {
@@ -121,19 +121,19 @@ fn main() -> ! {
     // High-priority executor: SWI1_EGU1, priority level 6
     let irq = interrupt::take!(UART4);
     irq.set_priority(interrupt::Priority::P6);
-    let executor = EXECUTOR_HIGH.put(InterruptExecutor::new(irq));
+    let executor = EXECUTOR_HIGH.init(InterruptExecutor::new(irq));
     let spawner = executor.start();
     unwrap!(spawner.spawn(run_high()));
 
     // Medium-priority executor: SWI0_EGU0, priority level 7
     let irq = interrupt::take!(UART5);
     irq.set_priority(interrupt::Priority::P7);
-    let executor = EXECUTOR_MED.put(InterruptExecutor::new(irq));
+    let executor = EXECUTOR_MED.init(InterruptExecutor::new(irq));
     let spawner = executor.start();
     unwrap!(spawner.spawn(run_med()));
 
     // Low priority executor: runs in thread mode, using WFE/SEV
-    let executor = EXECUTOR_LOW.put(Executor::new());
+    let executor = EXECUTOR_LOW.init(Executor::new());
     executor.run(|spawner| {
         unwrap!(spawner.spawn(run_low()));
     });
diff --git a/examples/stm32f7/Cargo.toml b/examples/stm32f7/Cargo.toml
index 29d6da4d8..e286d2310 100644
--- a/examples/stm32f7/Cargo.toml
+++ b/examples/stm32f7/Cargo.toml
@@ -24,3 +24,4 @@ nb = "1.0.0"
 rand_core = "0.6.3"
 critical-section = "1.1"
 embedded-storage = "0.3.0"
+static_cell = "1.0"
diff --git a/examples/stm32f7/src/bin/eth.rs b/examples/stm32f7/src/bin/eth.rs
index bdffabcb3..5202edf62 100644
--- a/examples/stm32f7/src/bin/eth.rs
+++ b/examples/stm32f7/src/bin/eth.rs
@@ -13,16 +13,16 @@ use embassy_stm32::rng::Rng;
 use embassy_stm32::time::mhz;
 use embassy_stm32::{interrupt, Config};
 use embassy_time::{Duration, Timer};
-use embassy_util::Forever;
 use embedded_io::asynch::Write;
 use rand_core::RngCore;
+use static_cell::StaticCell;
 use {defmt_rtt as _, panic_probe as _};
 
-macro_rules! forever {
+macro_rules! singleton {
     ($val:expr) => {{
         type T = impl Sized;
-        static FOREVER: Forever<T> = Forever::new();
-        FOREVER.put_with(move || $val)
+        static STATIC_CELL: StaticCell<T> = StaticCell::new();
+        STATIC_CELL.init_with(move || $val)
     }};
 }
 
@@ -52,7 +52,7 @@ async fn main(spawner: Spawner) -> ! {
 
     let device = unsafe {
         Ethernet::new(
-            forever!(State::new()),
+            singleton!(State::new()),
             p.ETH,
             eth_int,
             p.PA1,
@@ -78,10 +78,10 @@ async fn main(spawner: Spawner) -> ! {
     //});
 
     // Init network stack
-    let stack = &*forever!(Stack::new(
+    let stack = &*singleton!(Stack::new(
         device,
         config,
-        forever!(StackResources::<1, 2, 8>::new()),
+        singleton!(StackResources::<1, 2, 8>::new()),
         seed
     ));
 
diff --git a/examples/stm32h7/Cargo.toml b/examples/stm32h7/Cargo.toml
index a416796ea..fc5f74f99 100644
--- a/examples/stm32h7/Cargo.toml
+++ b/examples/stm32h7/Cargo.toml
@@ -28,6 +28,7 @@ critical-section = "1.1"
 micromath = "2.0.0"
 stm32-fmc = "0.2.4"
 embedded-storage = "0.3.0"
+static_cell = "1.0"
 
 # cargo build/run
 [profile.dev]
diff --git a/examples/stm32h7/src/bin/eth.rs b/examples/stm32h7/src/bin/eth.rs
index 83210bcb5..4ccc0b5ef 100644
--- a/examples/stm32h7/src/bin/eth.rs
+++ b/examples/stm32h7/src/bin/eth.rs
@@ -13,16 +13,16 @@ use embassy_stm32::rng::Rng;
 use embassy_stm32::time::mhz;
 use embassy_stm32::{interrupt, Config};
 use embassy_time::{Duration, Timer};
-use embassy_util::Forever;
 use embedded_io::asynch::Write;
 use rand_core::RngCore;
+use static_cell::StaticCell;
 use {defmt_rtt as _, panic_probe as _};
 
-macro_rules! forever {
+macro_rules! singleton {
     ($val:expr) => {{
         type T = impl Sized;
-        static FOREVER: Forever<T> = Forever::new();
-        FOREVER.put_with(move || $val)
+        static STATIC_CELL: StaticCell<T> = StaticCell::new();
+        STATIC_CELL.init_with(move || $val)
     }};
 }
 
@@ -53,7 +53,7 @@ async fn main(spawner: Spawner) -> ! {
 
     let device = unsafe {
         Ethernet::new(
-            forever!(State::new()),
+            singleton!(State::new()),
             p.ETH,
             eth_int,
             p.PA1,
@@ -79,10 +79,10 @@ async fn main(spawner: Spawner) -> ! {
     //});
 
     // Init network stack
-    let stack = &*forever!(Stack::new(
+    let stack = &*singleton!(Stack::new(
         device,
         config,
-        forever!(StackResources::<1, 2, 8>::new()),
+        singleton!(StackResources::<1, 2, 8>::new()),
         seed
     ));
 
diff --git a/examples/stm32h7/src/bin/eth_client.rs b/examples/stm32h7/src/bin/eth_client.rs
index 99946f504..64fd84141 100644
--- a/examples/stm32h7/src/bin/eth_client.rs
+++ b/examples/stm32h7/src/bin/eth_client.rs
@@ -13,17 +13,17 @@ use embassy_stm32::rng::Rng;
 use embassy_stm32::time::mhz;
 use embassy_stm32::{interrupt, Config};
 use embassy_time::{Duration, Timer};
-use embassy_util::Forever;
 use embedded_io::asynch::Write;
 use embedded_nal_async::{Ipv4Addr, SocketAddr, SocketAddrV4, TcpConnect};
 use rand_core::RngCore;
+use static_cell::StaticCell;
 use {defmt_rtt as _, panic_probe as _};
 
-macro_rules! forever {
+macro_rules! singleton {
     ($val:expr) => {{
         type T = impl Sized;
-        static FOREVER: Forever<T> = Forever::new();
-        FOREVER.put_with(move || $val)
+        static STATIC_CELL: StaticCell<T> = StaticCell::new();
+        STATIC_CELL.init_with(move || $val)
     }};
 }
 
@@ -54,7 +54,7 @@ async fn main(spawner: Spawner) -> ! {
 
     let device = unsafe {
         Ethernet::new(
-            forever!(State::new()),
+            singleton!(State::new()),
             p.ETH,
             eth_int,
             p.PA1,
@@ -80,10 +80,10 @@ async fn main(spawner: Spawner) -> ! {
     //});
 
     // Init network stack
-    let stack = &*forever!(Stack::new(
+    let stack = &*singleton!(Stack::new(
         device,
         config,
-        forever!(StackResources::<1, 2, 8>::new()),
+        singleton!(StackResources::<1, 2, 8>::new()),
         seed
     ));
 
diff --git a/examples/stm32h7/src/bin/spi.rs b/examples/stm32h7/src/bin/spi.rs
index c28f937a8..1f407f002 100644
--- a/examples/stm32h7/src/bin/spi.rs
+++ b/examples/stm32h7/src/bin/spi.rs
@@ -12,8 +12,8 @@ use embassy_stm32::dma::NoDma;
 use embassy_stm32::peripherals::SPI3;
 use embassy_stm32::time::mhz;
 use embassy_stm32::{spi, Config};
-use embassy_util::Forever;
 use heapless::String;
+use static_cell::StaticCell;
 use {defmt_rtt as _, panic_probe as _};
 
 #[embassy_executor::task]
@@ -31,7 +31,7 @@ async fn main_task(mut spi: spi::Spi<'static, SPI3, NoDma, NoDma>) {
     }
 }
 
-static EXECUTOR: Forever<Executor> = Forever::new();
+static EXECUTOR: StaticCell<Executor> = StaticCell::new();
 
 #[entry]
 fn main() -> ! {
@@ -54,7 +54,7 @@ fn main() -> ! {
         spi::Config::default(),
     );
 
-    let executor = EXECUTOR.put(Executor::new());
+    let executor = EXECUTOR.init(Executor::new());
 
     executor.run(|spawner| {
         unwrap!(spawner.spawn(main_task(spi)));
diff --git a/examples/stm32h7/src/bin/spi_dma.rs b/examples/stm32h7/src/bin/spi_dma.rs
index 6c78c194f..53004fc9b 100644
--- a/examples/stm32h7/src/bin/spi_dma.rs
+++ b/examples/stm32h7/src/bin/spi_dma.rs
@@ -11,8 +11,8 @@ use embassy_executor::Executor;
 use embassy_stm32::peripherals::{DMA1_CH3, DMA1_CH4, SPI3};
 use embassy_stm32::time::mhz;
 use embassy_stm32::{spi, Config};
-use embassy_util::Forever;
 use heapless::String;
+use static_cell::StaticCell;
 use {defmt_rtt as _, panic_probe as _};
 
 #[embassy_executor::task]
@@ -27,7 +27,7 @@ async fn main_task(mut spi: spi::Spi<'static, SPI3, DMA1_CH3, DMA1_CH4>) {
     }
 }
 
-static EXECUTOR: Forever<Executor> = Forever::new();
+static EXECUTOR: StaticCell<Executor> = StaticCell::new();
 
 #[entry]
 fn main() -> ! {
@@ -50,7 +50,7 @@ fn main() -> ! {
         spi::Config::default(),
     );
 
-    let executor = EXECUTOR.put(Executor::new());
+    let executor = EXECUTOR.init(Executor::new());
 
     executor.run(|spawner| {
         unwrap!(spawner.spawn(main_task(spi)));
diff --git a/examples/stm32h7/src/bin/usart.rs b/examples/stm32h7/src/bin/usart.rs
index 1384d54c6..87c2b1253 100644
--- a/examples/stm32h7/src/bin/usart.rs
+++ b/examples/stm32h7/src/bin/usart.rs
@@ -7,7 +7,7 @@ use defmt::*;
 use embassy_executor::Executor;
 use embassy_stm32::dma::NoDma;
 use embassy_stm32::usart::{Config, Uart};
-use embassy_util::Forever;
+use static_cell::StaticCell;
 use {defmt_rtt as _, panic_probe as _};
 
 #[embassy_executor::task]
@@ -27,13 +27,13 @@ async fn main_task() {
     }
 }
 
-static EXECUTOR: Forever<Executor> = Forever::new();
+static EXECUTOR: StaticCell<Executor> = StaticCell::new();
 
 #[entry]
 fn main() -> ! {
     info!("Hello World!");
 
-    let executor = EXECUTOR.put(Executor::new());
+    let executor = EXECUTOR.init(Executor::new());
 
     executor.run(|spawner| {
         unwrap!(spawner.spawn(main_task()));
diff --git a/examples/stm32h7/src/bin/usart_dma.rs b/examples/stm32h7/src/bin/usart_dma.rs
index f8d58bb84..3adffcbeb 100644
--- a/examples/stm32h7/src/bin/usart_dma.rs
+++ b/examples/stm32h7/src/bin/usart_dma.rs
@@ -9,8 +9,8 @@ use defmt::*;
 use embassy_executor::Executor;
 use embassy_stm32::dma::NoDma;
 use embassy_stm32::usart::{Config, Uart};
-use embassy_util::Forever;
 use heapless::String;
+use static_cell::StaticCell;
 use {defmt_rtt as _, panic_probe as _};
 
 #[embassy_executor::task]
@@ -30,13 +30,13 @@ async fn main_task() {
     }
 }
 
-static EXECUTOR: Forever<Executor> = Forever::new();
+static EXECUTOR: StaticCell<Executor> = StaticCell::new();
 
 #[entry]
 fn main() -> ! {
     info!("Hello World!");
 
-    let executor = EXECUTOR.put(Executor::new());
+    let executor = EXECUTOR.init(Executor::new());
 
     executor.run(|spawner| {
         unwrap!(spawner.spawn(main_task()));
diff --git a/examples/stm32l0/Cargo.toml b/examples/stm32l0/Cargo.toml
index fdb716d15..72365a640 100644
--- a/examples/stm32l0/Cargo.toml
+++ b/examples/stm32l0/Cargo.toml
@@ -29,3 +29,4 @@ panic-probe = { version = "0.3", features = ["print-defmt"] }
 futures = { version = "0.3.17", default-features = false, features = ["async-await"] }
 heapless = { version = "0.7.5", default-features = false }
 embedded-hal = "0.2.6"
+static_cell = "1.0"
diff --git a/examples/stm32l0/src/bin/raw_spawn.rs b/examples/stm32l0/src/bin/raw_spawn.rs
index bd87e62a4..edc17304a 100644
--- a/examples/stm32l0/src/bin/raw_spawn.rs
+++ b/examples/stm32l0/src/bin/raw_spawn.rs
@@ -8,7 +8,7 @@ use defmt::*;
 use embassy_executor::raw::TaskStorage;
 use embassy_executor::Executor;
 use embassy_time::{Duration, Timer};
-use embassy_util::Forever;
+use static_cell::StaticCell;
 use {defmt_rtt as _, panic_probe as _};
 
 async fn run1() {
@@ -25,14 +25,14 @@ async fn run2() {
     }
 }
 
-static EXECUTOR: Forever<Executor> = Forever::new();
+static EXECUTOR: StaticCell<Executor> = StaticCell::new();
 
 #[entry]
 fn main() -> ! {
     info!("Hello World!");
 
     let _p = embassy_stm32::init(Default::default());
-    let executor = EXECUTOR.put(Executor::new());
+    let executor = EXECUTOR.init(Executor::new());
 
     let run1_task = TaskStorage::new();
     let run2_task = TaskStorage::new();
diff --git a/examples/stm32l5/Cargo.toml b/examples/stm32l5/Cargo.toml
index 4d96d31fc..d8e78088a 100644
--- a/examples/stm32l5/Cargo.toml
+++ b/examples/stm32l5/Cargo.toml
@@ -28,3 +28,4 @@ futures = { version = "0.3.17", default-features = false, features = ["async-awa
 heapless = { version = "0.7.5", default-features = false }
 rand_core = { version = "0.6.3", default-features = false }
 embedded-io = { version = "0.3.0", features = ["async"] }
+static_cell = "1.0"
diff --git a/examples/stm32l5/src/bin/usb_ethernet.rs b/examples/stm32l5/src/bin/usb_ethernet.rs
index 7c53d03cc..959195518 100644
--- a/examples/stm32l5/src/bin/usb_ethernet.rs
+++ b/examples/stm32l5/src/bin/usb_ethernet.rs
@@ -19,18 +19,18 @@ use embassy_usb::{Builder, UsbDevice};
 use embassy_usb_ncm::{CdcNcmClass, Receiver, Sender, State};
 use embassy_util::blocking_mutex::raw::ThreadModeRawMutex;
 use embassy_util::channel::mpmc::Channel;
-use embassy_util::Forever;
 use embedded_io::asynch::{Read, Write};
 use rand_core::RngCore;
+use static_cell::StaticCell;
 use {defmt_rtt as _, panic_probe as _};
 
 type MyDriver = Driver<'static, embassy_stm32::peripherals::USB>;
 
-macro_rules! forever {
+macro_rules! singleton {
     ($val:expr) => {{
         type T = impl Sized;
-        static FOREVER: Forever<T> = Forever::new();
-        FOREVER.put_with(move || $val)
+        static STATIC_CELL: StaticCell<T> = StaticCell::new();
+        STATIC_CELL.init_with(move || $val)
     }};
 }
 
@@ -115,7 +115,7 @@ async fn main(spawner: Spawner) {
         control_buf: [u8; 128],
         serial_state: State<'static>,
     }
-    let res: &mut Resources = forever!(Resources {
+    let res: &mut Resources = singleton!(Resources {
         device_descriptor: [0; 256],
         config_descriptor: [0; 256],
         bos_descriptor: [0; 256],
@@ -171,10 +171,10 @@ async fn main(spawner: Spawner) {
 
     // Init network stack
     let device = Device { mac_addr: our_mac_addr };
-    let stack = &*forever!(Stack::new(
+    let stack = &*singleton!(Stack::new(
         device,
         config,
-        forever!(StackResources::<1, 2, 8>::new()),
+        singleton!(StackResources::<1, 2, 8>::new()),
         seed
     ));
 

From f48391a6856fdf713002cf9068087136b83da915 Mon Sep 17 00:00:00 2001
From: Dario Nieuwenhuis <dirbaio@dirbaio.net>
Date: Mon, 22 Aug 2022 16:22:37 +0200
Subject: [PATCH 16/21] rp: fix nvic prio bits (it's 2, not 3)

---
 embassy-rp/Cargo.toml  | 2 +-
 embassy-rp/src/gpio.rs | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/embassy-rp/Cargo.toml b/embassy-rp/Cargo.toml
index af7c8ee6e..0e53d3a35 100644
--- a/embassy-rp/Cargo.toml
+++ b/embassy-rp/Cargo.toml
@@ -30,7 +30,7 @@ unstable-traits = ["embedded-hal-1"]
 embassy-util = { version = "0.1.0", path = "../embassy-util" }
 embassy-executor = { version = "0.1.0", path = "../embassy-executor" }
 embassy-time = { version = "0.1.0", path = "../embassy-time", features = [ "tick-1mhz" ] }
-embassy-cortex-m = { version = "0.1.0", path = "../embassy-cortex-m", features = ["prio-bits-3"]}
+embassy-cortex-m = { version = "0.1.0", path = "../embassy-cortex-m", features = ["prio-bits-2"]}
 embassy-hal-common = {version = "0.1.0", path = "../embassy-hal-common" }
 embassy-embedded-hal = {version = "0.1.0", path = "../embassy-embedded-hal" }
 atomic-polyfill = "1.0.1"
diff --git a/embassy-rp/src/gpio.rs b/embassy-rp/src/gpio.rs
index f9fa8378b..90862fa32 100644
--- a/embassy-rp/src/gpio.rs
+++ b/embassy-rp/src/gpio.rs
@@ -189,7 +189,7 @@ impl<'d, T: Pin> InputFuture<'d, T> {
         unsafe {
             let irq = interrupt::IO_IRQ_BANK0::steal();
             irq.disable();
-            irq.set_priority(interrupt::Priority::P6);
+            irq.set_priority(interrupt::Priority::P3);
 
             // Each INTR register is divided into 8 groups, one group for each
             // pin, and each group consists of LEVEL_LOW, LEVEL_HIGH, EDGE_LOW,

From f2daad20ab9acb7e0b8fa3c8079ca8a573817fb0 Mon Sep 17 00:00:00 2001
From: Ulf Lilleengen <lulf@redhat.com>
Date: Mon, 22 Aug 2022 09:11:00 +0200
Subject: [PATCH 17/21] Remove warnings

---
 embassy-executor/src/raw/mod.rs | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/embassy-executor/src/raw/mod.rs b/embassy-executor/src/raw/mod.rs
index c55d10699..e1258ebb5 100644
--- a/embassy-executor/src/raw/mod.rs
+++ b/embassy-executor/src/raw/mod.rs
@@ -5,7 +5,7 @@
 //! ## WARNING: here be dragons!
 //!
 //! Using this module requires respecting subtle safety contracts. If you can, prefer using the safe
-//! executor wrappers in [`executor`](crate::executor) and the [`embassy_executor::task`](embassy_macros::task) macro, which are fully safe.
+//! [executor wrappers](crate::Executor) and the [`embassy_executor::task`](embassy_macros::task) macro, which are fully safe.
 
 mod run_queue;
 #[cfg(feature = "integrated-timers")]
@@ -249,7 +249,7 @@ impl<F: Future + 'static, const N: usize> TaskPool<F, N> {
 ///
 /// This is the core of the Embassy executor. It is low-level, requiring manual
 /// handling of wakeups and task polling. If you can, prefer using one of the
-/// higher level executors in [`crate::executor`].
+/// [higher level executors](crate::Executor).
 ///
 /// The raw executor leaves it up to you to handle wakeups and scheduling:
 ///

From 5fddff849eea74fb240147432a1739ae1759cb6c Mon Sep 17 00:00:00 2001
From: Ulf Lilleengen <lulf@redhat.com>
Date: Mon, 22 Aug 2022 09:11:24 +0200
Subject: [PATCH 18/21] Remove warnings for embassy-time

---
 embassy-time/src/driver.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/embassy-time/src/driver.rs b/embassy-time/src/driver.rs
index 216b27408..79ae14b91 100644
--- a/embassy-time/src/driver.rs
+++ b/embassy-time/src/driver.rs
@@ -6,7 +6,7 @@
 //!
 //! - Define a struct `MyDriver`
 //! - Implement [`Driver`] for it
-//! - Register it as the global driver with [`time_driver_impl`].
+//! - Register it as the global driver with [`time_driver_impl`](crate::time_driver_impl).
 //! - Enable the Cargo features `embassy-executor/time` and one of `embassy-time/tick-*` corresponding to the
 //!   tick rate of your driver.
 //!

From 3e155d2ec366379584bf7ba4a447109555aa0d77 Mon Sep 17 00:00:00 2001
From: Ulf Lilleengen <lulf@redhat.com>
Date: Mon, 22 Aug 2022 10:36:33 +0200
Subject: [PATCH 19/21] nRF documentation warning fixes

---
 embassy-nrf/src/buffered_uarte.rs |  9 +++++++++
 embassy-nrf/src/gpio.rs           | 21 ++++++++++++++++++++-
 embassy-nrf/src/nvmc.rs           | 10 +++++++++-
 embassy-nrf/src/ppi/mod.rs        | 12 ++++++++++++
 embassy-nrf/src/ppi/ppi.rs        |  3 +++
 embassy-usb/src/builder.rs        |  2 ++
 embassy-usb/src/control.rs        |  3 ++-
 embassy-usb/src/driver.rs         |  6 +++---
 8 files changed, 60 insertions(+), 6 deletions(-)

diff --git a/embassy-nrf/src/buffered_uarte.rs b/embassy-nrf/src/buffered_uarte.rs
index 21ff1d73b..08dfcbcf9 100644
--- a/embassy-nrf/src/buffered_uarte.rs
+++ b/embassy-nrf/src/buffered_uarte.rs
@@ -45,8 +45,10 @@ enum TxState {
     Transmitting(usize),
 }
 
+/// A type for storing the state of the UARTE peripheral that can be stored in a static.
 pub struct State<'d, U: UarteInstance, T: TimerInstance>(StateStorage<StateInner<'d, U, T>>);
 impl<'d, U: UarteInstance, T: TimerInstance> State<'d, U, T> {
+    /// Create an instance for storing UARTE peripheral state.
     pub fn new() -> Self {
         Self(StateStorage::new())
     }
@@ -75,6 +77,12 @@ pub struct BufferedUarte<'d, U: UarteInstance, T: TimerInstance> {
 impl<'d, U: UarteInstance, T: TimerInstance> Unpin for BufferedUarte<'d, U, T> {}
 
 impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> {
+    /// Create a new instance of a BufferedUarte.
+    ///
+    /// See the [module documentation](crate::buffered_uarte) for more details about the intended use.
+    ///
+    /// The BufferedUarte uses the provided state to store the buffers and peripheral state. The timer and ppi channels are used to 'emulate' idle line detection so that read operations
+    /// can return early if there is no data to receive.
     pub fn new(
         state: &'d mut State<'d, U, T>,
         peri: impl Peripheral<P = U> + 'd,
@@ -178,6 +186,7 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> {
         }
     }
 
+    /// Adjust the baud rate to the provided value.
     pub fn set_baudrate(&mut self, baudrate: Baudrate) {
         self.inner.with(|state| {
             let r = U::regs();
diff --git a/embassy-nrf/src/gpio.rs b/embassy-nrf/src/gpio.rs
index a61ff6aa5..924629908 100644
--- a/embassy-nrf/src/gpio.rs
+++ b/embassy-nrf/src/gpio.rs
@@ -1,3 +1,4 @@
+//! General purpose input/output for nRF.
 #![macro_use]
 
 use core::convert::Infallible;
@@ -26,8 +27,11 @@ pub enum Port {
 #[derive(Debug, Eq, PartialEq)]
 #[cfg_attr(feature = "defmt", derive(defmt::Format))]
 pub enum Pull {
+    /// No pull.
     None,
+    /// Internal pull-up resistor.
     Up,
+    /// Internal pull-down resistor.
     Down,
 }
 
@@ -37,6 +41,7 @@ pub struct Input<'d, T: Pin> {
 }
 
 impl<'d, T: Pin> Input<'d, T> {
+    /// Create GPIO input driver for a [Pin] with the provided [Pull] configuration.
     #[inline]
     pub fn new(pin: impl Peripheral<P = T> + 'd, pull: Pull) -> Self {
         let mut pin = Flex::new(pin);
@@ -45,11 +50,13 @@ impl<'d, T: Pin> Input<'d, T> {
         Self { pin }
     }
 
+    /// Test if current pin level is high.
     #[inline]
     pub fn is_high(&self) -> bool {
         self.pin.is_high()
     }
 
+    /// Test if current pin level is low.
     #[inline]
     pub fn is_low(&self) -> bool {
         self.pin.is_low()
@@ -66,7 +73,9 @@ impl<'d, T: Pin> Input<'d, T> {
 #[derive(Debug, Eq, PartialEq)]
 #[cfg_attr(feature = "defmt", derive(defmt::Format))]
 pub enum Level {
+    /// Logical low.
     Low,
+    /// Logical high.
     High,
 }
 
@@ -88,6 +97,7 @@ impl Into<bool> for Level {
     }
 }
 
+/// Drive strength settings for an output pin.
 // These numbers match DRIVE_A exactly so hopefully the compiler will unify them.
 #[derive(Clone, Copy, Debug, PartialEq)]
 #[cfg_attr(feature = "defmt", derive(defmt::Format))]
@@ -117,6 +127,7 @@ pub struct Output<'d, T: Pin> {
 }
 
 impl<'d, T: Pin> Output<'d, T> {
+    /// Create GPIO output driver for a [Pin] with the provided [Level] and [OutputDriver] configuration.
     #[inline]
     pub fn new(pin: impl Peripheral<P = T> + 'd, initial_output: Level, drive: OutputDrive) -> Self {
         let mut pin = Flex::new(pin);
@@ -264,11 +275,13 @@ impl<'d, T: Pin> Flex<'d, T> {
         self.pin.conf().reset();
     }
 
+    /// Test if current pin level is high.
     #[inline]
     pub fn is_high(&self) -> bool {
         !self.is_low()
     }
 
+    /// Test if current pin level is low.
     #[inline]
     pub fn is_low(&self) -> bool {
         self.pin.block().in_.read().bits() & (1 << self.pin.pin()) == 0
@@ -374,6 +387,7 @@ pub(crate) mod sealed {
     }
 }
 
+/// Interface for a Pin that can be configured by an [Input] or [Output] driver, or converted to an [AnyPin].
 pub trait Pin: Peripheral<P = Self> + Into<AnyPin> + sealed::Pin + Sized + 'static {
     /// Number of the pin within the port (0..31)
     #[inline]
@@ -392,6 +406,7 @@ pub trait Pin: Peripheral<P = Self> + Into<AnyPin> + sealed::Pin + Sized + 'stat
         }
     }
 
+    /// Peripheral port register value
     #[inline]
     fn psel_bits(&self) -> u32 {
         self.pin_port() as u32
@@ -406,12 +421,16 @@ pub trait Pin: Peripheral<P = Self> + Into<AnyPin> + sealed::Pin + Sized + 'stat
     }
 }
 
-// Type-erased GPIO pin
+/// Type-erased GPIO pin
 pub struct AnyPin {
     pin_port: u8,
 }
 
 impl AnyPin {
+    /// Create an [AnyPin] for a specific pin.
+    ///
+    /// # Safety
+    /// - `pin_port` should not in use by another driver.
     #[inline]
     pub unsafe fn steal(pin_port: u8) -> Self {
         Self { pin_port }
diff --git a/embassy-nrf/src/nvmc.rs b/embassy-nrf/src/nvmc.rs
index cd6100339..6f66f7a78 100644
--- a/embassy-nrf/src/nvmc.rs
+++ b/embassy-nrf/src/nvmc.rs
@@ -1,4 +1,4 @@
-//! Nvmcerature sensor interface.
+//! Non-Volatile Memory Controller (NVMC) module.
 
 use core::{ptr, slice};
 
@@ -10,13 +10,19 @@ use embedded_storage::nor_flash::{
 use crate::peripherals::NVMC;
 use crate::{pac, Peripheral};
 
+/// Erase size of NVMC flash in bytes.
 pub const PAGE_SIZE: usize = 4096;
+
+/// Size of NVMC flash in bytes.
 pub const FLASH_SIZE: usize = crate::chip::FLASH_SIZE;
 
+/// Error type for NVMC operations.
 #[derive(Debug, Copy, Clone, PartialEq, Eq)]
 #[cfg_attr(feature = "defmt", derive(defmt::Format))]
 pub enum Error {
+    /// Opration using a location not in flash.
     OutOfBounds,
+    /// Unaligned operation or using unaligned buffers.
     Unaligned,
 }
 
@@ -29,11 +35,13 @@ impl NorFlashError for Error {
     }
 }
 
+/// Non-Volatile Memory Controller (NVMC) that implements the `embedded-storage` traits.
 pub struct Nvmc<'d> {
     _p: PeripheralRef<'d, NVMC>,
 }
 
 impl<'d> Nvmc<'d> {
+    /// Create Nvmc driver.
     pub fn new(_p: impl Peripheral<P = NVMC> + 'd) -> Self {
         into_ref!(_p);
         Self { _p }
diff --git a/embassy-nrf/src/ppi/mod.rs b/embassy-nrf/src/ppi/mod.rs
index 23ab011bc..1fdd35717 100644
--- a/embassy-nrf/src/ppi/mod.rs
+++ b/embassy-nrf/src/ppi/mod.rs
@@ -26,6 +26,7 @@ mod dppi;
 #[cfg(feature = "_ppi")]
 mod ppi;
 
+/// An instance of the Programmable peripheral interconnect on nRF devices.
 pub struct Ppi<'d, C: Channel, const EVENT_COUNT: usize, const TASK_COUNT: usize> {
     ch: PeripheralRef<'d, C>,
     #[cfg(feature = "_dppi")]
@@ -48,6 +49,7 @@ impl Task {
         Self(unsafe { NonNull::new_unchecked(reg as *const _ as *mut _) })
     }
 
+    /// Address off subscription register for this task.
     pub fn subscribe_reg(&self) -> *mut u32 {
         unsafe { self.0.as_ptr().add(REGISTER_DPPI_CONFIG_OFFSET) }
     }
@@ -69,6 +71,7 @@ impl Event {
         Self(unsafe { NonNull::new_unchecked(reg as *const _ as *mut _) })
     }
 
+    /// Address of publish register for this event.
     pub fn publish_reg(&self) -> *mut u32 {
         unsafe { self.0.as_ptr().add(REGISTER_DPPI_CONFIG_OFFSET) }
     }
@@ -87,21 +90,29 @@ pub(crate) mod sealed {
     pub trait Group {}
 }
 
+/// Interface for PPI channels.
 pub trait Channel: sealed::Channel + Peripheral<P = Self> + Sized {
     /// Returns the number of the channel
     fn number(&self) -> usize;
 }
 
+/// Interface for PPI channels that can be configured.
 pub trait ConfigurableChannel: Channel + Into<AnyConfigurableChannel> {
+    /// Convert into a type erased configurable channel.
     fn degrade(self) -> AnyConfigurableChannel;
 }
 
+/// Interface for PPI channels that cannot be configured.
 pub trait StaticChannel: Channel + Into<AnyStaticChannel> {
+    /// Convert into a type erased static channel.
     fn degrade(self) -> AnyStaticChannel;
 }
 
+/// Interface for a group of PPI channels.
 pub trait Group: sealed::Group + Sized {
+    /// Returns the number of the group.
     fn number(&self) -> usize;
+    /// Convert into a type erased group.
     fn degrade(self) -> AnyGroup {
         AnyGroup {
             number: self.number() as u8,
@@ -196,6 +207,7 @@ macro_rules! impl_ppi_channel {
 // ======================
 //       groups
 
+/// A type erased PPI group.
 pub struct AnyGroup {
     number: u8,
 }
diff --git a/embassy-nrf/src/ppi/ppi.rs b/embassy-nrf/src/ppi/ppi.rs
index 450a290a2..19abc4e18 100644
--- a/embassy-nrf/src/ppi/ppi.rs
+++ b/embassy-nrf/src/ppi/ppi.rs
@@ -20,6 +20,7 @@ fn regs() -> &'static pac::ppi::RegisterBlock {
 
 #[cfg(not(feature = "nrf51"))] // Not for nrf51 because of the fork task
 impl<'d, C: StaticChannel> Ppi<'d, C, 0, 1> {
+    /// Configure PPI channel to trigger `task`.
     pub fn new_zero_to_one(ch: impl Peripheral<P = C> + 'd, task: Task) -> Self {
         into_ref!(ch);
 
@@ -32,6 +33,7 @@ impl<'d, C: StaticChannel> Ppi<'d, C, 0, 1> {
 }
 
 impl<'d, C: ConfigurableChannel> Ppi<'d, C, 1, 1> {
+    /// Configure PPI channel to trigger `task` on `event`.
     pub fn new_one_to_one(ch: impl Peripheral<P = C> + 'd, event: Event, task: Task) -> Self {
         into_ref!(ch);
 
@@ -46,6 +48,7 @@ impl<'d, C: ConfigurableChannel> Ppi<'d, C, 1, 1> {
 
 #[cfg(not(feature = "nrf51"))] // Not for nrf51 because of the fork task
 impl<'d, C: ConfigurableChannel> Ppi<'d, C, 1, 2> {
+    /// Configure PPI channel to trigger `task1` and `task2` on `event`.
     pub fn new_one_to_two(ch: impl Peripheral<P = C> + 'd, event: Event, task1: Task, task2: Task) -> Self {
         into_ref!(ch);
 
diff --git a/embassy-usb/src/builder.rs b/embassy-usb/src/builder.rs
index 1ca24cc08..6be88bc76 100644
--- a/embassy-usb/src/builder.rs
+++ b/embassy-usb/src/builder.rs
@@ -10,6 +10,7 @@ use crate::{Interface, STRING_INDEX_CUSTOM_START};
 #[derive(Debug, Copy, Clone)]
 #[cfg_attr(feature = "defmt", derive(defmt::Format))]
 #[non_exhaustive]
+/// Configuration used when creating [UsbDevice].
 pub struct Config<'a> {
     pub(crate) vendor_id: u16,
     pub(crate) product_id: u16,
@@ -96,6 +97,7 @@ pub struct Config<'a> {
 }
 
 impl<'a> Config<'a> {
+    /// Create default configuration with the provided vid and pid values.
     pub fn new(vid: u16, pid: u16) -> Self {
         Self {
             device_class: 0x00,
diff --git a/embassy-usb/src/control.rs b/embassy-usb/src/control.rs
index 12e5303c3..3e5749a01 100644
--- a/embassy-usb/src/control.rs
+++ b/embassy-usb/src/control.rs
@@ -1,3 +1,4 @@
+//! USB control data types.
 use core::mem;
 
 use super::types::*;
@@ -8,7 +9,7 @@ use super::types::*;
 #[cfg_attr(feature = "defmt", derive(defmt::Format))]
 pub enum RequestType {
     /// Request is a USB standard request. Usually handled by
-    /// [`UsbDevice`](crate::device::UsbDevice).
+    /// [`UsbDevice`](crate::UsbDevice).
     Standard = 0,
     /// Request is intended for a USB class.
     Class = 1,
diff --git a/embassy-usb/src/driver.rs b/embassy-usb/src/driver.rs
index 2a84ff9e7..7888f1639 100644
--- a/embassy-usb/src/driver.rs
+++ b/embassy-usb/src/driver.rs
@@ -12,7 +12,7 @@ pub trait Driver<'a> {
 
     /// Allocates an endpoint and specified endpoint parameters. This method is called by the device
     /// and class implementations to allocate endpoints, and can only be called before
-    /// [`start`](UsbBus::start) is called.
+    /// [`start`](Self::start) is called.
     ///
     /// # Arguments
     ///
@@ -95,7 +95,7 @@ pub trait Bus {
     ///
     /// # Errors
     ///
-    /// * [`Unsupported`](crate::UsbError::Unsupported) - This UsbBus implementation doesn't support
+    /// * [`Unsupported`](crate::driver::Unsupported) - This UsbBus implementation doesn't support
     ///   simulating a disconnect or it has not been enabled at creation time.
     fn force_reset(&mut self) -> Result<(), Unsupported> {
         Err(Unsupported)
@@ -105,7 +105,7 @@ pub trait Bus {
     ///
     /// # Errors
     ///
-    /// * [`Unsupported`](crate::UsbError::Unsupported) - This UsbBus implementation doesn't support
+    /// * [`Unsupported`](crate::driver::Unsupported) - This UsbBus implementation doesn't support
     ///   remote wakeup or it has not been enabled at creation time.
     fn remote_wakeup(&mut self) -> Self::RemoteWakeupFuture<'_>;
 }

From 21072bee48ff6ec19b79e0d9527ad8cc34a4e9e0 Mon Sep 17 00:00:00 2001
From: Dario Nieuwenhuis <dirbaio@dirbaio.net>
Date: Mon, 22 Aug 2022 21:46:09 +0200
Subject: [PATCH 20/21] split `embassy-util` into `embassy-futures`,
 `embassy-sync`.

---
 .github/workflows/rust.yml                    |   2 +-
 .vscode/settings.json                         |   2 +-
 embassy-boot/boot/Cargo.toml                  |   2 +-
 embassy-boot/nrf/Cargo.toml                   |   2 +-
 embassy-boot/stm32/Cargo.toml                 |   2 +-
 embassy-cortex-m/Cargo.toml                   |   2 +-
 embassy-embedded-hal/Cargo.toml               |   2 +-
 .../src/shared_bus/asynch/i2c.rs              |   8 +-
 .../src/shared_bus/asynch/spi.rs              |   8 +-
 .../src/shared_bus/blocking/i2c.rs            |   6 +-
 .../src/shared_bus/blocking/spi.rs            |   6 +-
 embassy-futures/Cargo.toml                    |  14 ++
 {embassy-util => embassy-futures}/src/fmt.rs  |   0
 embassy-futures/src/lib.rs                    |  12 +
 .../src/select.rs                             |   0
 .../src/yield_now.rs                          |   0
 embassy-lora/Cargo.toml                       |   2 +-
 embassy-lora/src/stm32wl/mod.rs               |   2 +-
 embassy-net/Cargo.toml                        |   2 +-
 embassy-net/src/stack.rs                      |   2 +-
 embassy-nrf/Cargo.toml                        |   4 +-
 embassy-nrf/src/buffered_uarte.rs             |   2 +-
 embassy-nrf/src/gpiote.rs                     |   2 +-
 embassy-nrf/src/qdec.rs                       |   2 +-
 embassy-nrf/src/qspi.rs                       |   2 +-
 embassy-nrf/src/rng.rs                        |   2 +-
 embassy-nrf/src/saadc.rs                      |   2 +-
 embassy-nrf/src/spim.rs                       |   2 +-
 embassy-nrf/src/temp.rs                       |   2 +-
 embassy-nrf/src/time_driver.rs                |   4 +-
 embassy-nrf/src/timer.rs                      |   6 +-
 embassy-nrf/src/twim.rs                       |   2 +-
 embassy-nrf/src/uarte.rs                      |   2 +-
 embassy-nrf/src/usb.rs                        |   2 +-
 embassy-rp/Cargo.toml                         |   2 +-
 embassy-rp/src/gpio.rs                        |   2 +-
 embassy-rp/src/timer.rs                       |   4 +-
 embassy-stm32/Cargo.toml                      |   4 +-
 embassy-stm32/src/dcmi.rs                     |   2 +-
 embassy-stm32/src/dma/bdma.rs                 |   2 +-
 embassy-stm32/src/dma/dma.rs                  |   2 +-
 embassy-stm32/src/dma/gpdma.rs                |   2 +-
 embassy-stm32/src/eth/v1/mod.rs               |   2 +-
 embassy-stm32/src/eth/v2/mod.rs               |   2 +-
 embassy-stm32/src/exti.rs                     |   2 +-
 embassy-stm32/src/i2c/v2.rs                   |   2 +-
 embassy-stm32/src/rng.rs                      |   2 +-
 embassy-stm32/src/sdmmc/mod.rs                |   6 +-
 embassy-stm32/src/time_driver.rs              |   4 +-
 embassy-stm32/src/usart/buffered.rs           |   2 +-
 embassy-stm32/src/usb/usb.rs                  |   2 +-
 {embassy-util => embassy-sync}/Cargo.toml     |   6 +-
 {embassy-util => embassy-sync}/build.rs       |   0
 .../src/blocking_mutex/mod.rs                 |   0
 .../src/blocking_mutex/raw.rs                 |   0
 .../src/channel/mod.rs                        |   0
 .../src/channel/mpmc.rs                       |   4 +-
 .../src/channel/pubsub/mod.rs                 |   6 +-
 .../src/channel/pubsub/publisher.rs           |   0
 .../src/channel/pubsub/subscriber.rs          |   0
 .../src/channel/signal.rs                     |   2 +-
 embassy-sync/src/fmt.rs                       | 228 ++++++++++++++++++
 {embassy-util => embassy-sync}/src/lib.rs     |   6 -
 {embassy-util => embassy-sync}/src/mutex.rs   |   0
 {embassy-util => embassy-sync}/src/pipe.rs    |   4 +-
 .../src/ring_buffer.rs                        |   0
 .../src/waitqueue/mod.rs                      |   0
 .../src/waitqueue/multi_waker.rs              |   0
 .../src/waitqueue/waker.rs                    |   0
 embassy-usb-hid/Cargo.toml                    |   2 +-
 embassy-usb-ncm/Cargo.toml                    |   2 +-
 embassy-usb-serial/Cargo.toml                 |   2 +-
 embassy-usb-serial/src/lib.rs                 |   2 +-
 embassy-usb/Cargo.toml                        |   2 +-
 embassy-usb/src/lib.rs                        |   2 +-
 examples/boot/application/nrf/Cargo.toml      |   2 +-
 examples/boot/application/stm32f3/Cargo.toml  |   2 +-
 examples/boot/application/stm32f7/Cargo.toml  |   2 +-
 examples/boot/application/stm32h7/Cargo.toml  |   2 +-
 examples/boot/application/stm32l0/Cargo.toml  |   2 +-
 examples/boot/application/stm32l1/Cargo.toml  |   2 +-
 examples/boot/application/stm32l4/Cargo.toml  |   2 +-
 examples/boot/application/stm32wl/Cargo.toml  |   2 +-
 examples/nrf-rtos-trace/Cargo.toml            |   4 +-
 examples/nrf/Cargo.toml                       |   3 +-
 examples/nrf/src/bin/channel.rs               |   4 +-
 .../nrf/src/bin/channel_sender_receiver.rs    |   4 +-
 examples/nrf/src/bin/mutex.rs                 |   4 +-
 examples/nrf/src/bin/pubsub.rs                |   4 +-
 examples/nrf/src/bin/uart_split.rs            |   4 +-
 examples/nrf/src/bin/usb_ethernet.rs          |   4 +-
 examples/nrf/src/bin/usb_hid_keyboard.rs      |   4 +-
 examples/rp/Cargo.toml                        |   2 +-
 examples/std/Cargo.toml                       |   2 +-
 examples/stm32f0/Cargo.toml                   |   2 +-
 examples/stm32f1/Cargo.toml                   |   2 +-
 examples/stm32f2/Cargo.toml                   |   2 +-
 examples/stm32f3/Cargo.toml                   |   2 +-
 examples/stm32f3/src/bin/button_events.rs     |   4 +-
 examples/stm32f4/Cargo.toml                   |   2 +-
 examples/stm32f7/Cargo.toml                   |   2 +-
 examples/stm32g0/Cargo.toml                   |   2 +-
 examples/stm32g4/Cargo.toml                   |   2 +-
 examples/stm32h7/Cargo.toml                   |   2 +-
 examples/stm32h7/src/bin/signal.rs            |   2 +-
 examples/stm32h7/src/bin/usart_split.rs       |   4 +-
 examples/stm32l0/Cargo.toml                   |   2 +-
 examples/stm32l1/Cargo.toml                   |   2 +-
 examples/stm32l4/Cargo.toml                   |   2 +-
 examples/stm32l5/Cargo.toml                   |   2 +-
 examples/stm32l5/src/bin/usb_ethernet.rs      |   4 +-
 examples/stm32u5/Cargo.toml                   |   2 +-
 examples/stm32wb/Cargo.toml                   |   2 +-
 examples/stm32wl/Cargo.toml                   |   2 +-
 examples/stm32wl/src/bin/subghz.rs            |   2 +-
 examples/wasm/Cargo.toml                      |   2 +-
 tests/rp/Cargo.toml                           |   2 +-
 tests/stm32/Cargo.toml                        |   2 +-
 118 files changed, 391 insertions(+), 142 deletions(-)
 create mode 100644 embassy-futures/Cargo.toml
 rename {embassy-util => embassy-futures}/src/fmt.rs (100%)
 create mode 100644 embassy-futures/src/lib.rs
 rename {embassy-util => embassy-futures}/src/select.rs (100%)
 rename {embassy-util => embassy-futures}/src/yield_now.rs (100%)
 rename {embassy-util => embassy-sync}/Cargo.toml (85%)
 rename {embassy-util => embassy-sync}/build.rs (100%)
 rename {embassy-util => embassy-sync}/src/blocking_mutex/mod.rs (100%)
 rename {embassy-util => embassy-sync}/src/blocking_mutex/raw.rs (100%)
 rename {embassy-util => embassy-sync}/src/channel/mod.rs (100%)
 rename {embassy-util => embassy-sync}/src/channel/mpmc.rs (99%)
 rename {embassy-util => embassy-sync}/src/channel/pubsub/mod.rs (99%)
 rename {embassy-util => embassy-sync}/src/channel/pubsub/publisher.rs (100%)
 rename {embassy-util => embassy-sync}/src/channel/pubsub/subscriber.rs (100%)
 rename {embassy-util => embassy-sync}/src/channel/signal.rs (98%)
 create mode 100644 embassy-sync/src/fmt.rs
 rename {embassy-util => embassy-sync}/src/lib.rs (87%)
 rename {embassy-util => embassy-sync}/src/mutex.rs (100%)
 rename {embassy-util => embassy-sync}/src/pipe.rs (99%)
 rename {embassy-util => embassy-sync}/src/ring_buffer.rs (100%)
 rename {embassy-util => embassy-sync}/src/waitqueue/mod.rs (100%)
 rename {embassy-util => embassy-sync}/src/waitqueue/multi_waker.rs (100%)
 rename {embassy-util => embassy-sync}/src/waitqueue/waker.rs (100%)

diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml
index d76e5ced4..d2e8e316b 100644
--- a/.github/workflows/rust.yml
+++ b/.github/workflows/rust.yml
@@ -69,4 +69,4 @@ jobs:
     steps:
       - uses: actions/checkout@v2
       - name: Test
-        run: cd embassy-util && cargo test
+        run: cd embassy-sync && cargo test
diff --git a/.vscode/settings.json b/.vscode/settings.json
index d6ce75c99..5e9e51799 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -18,7 +18,7 @@
   "rust-analyzer.linkedProjects": [
     // Declare for the target you wish to develop
     //"embassy-executor/Cargo.toml",
-    //"embassy-util/Cargo.toml",
+    //"embassy-sync/Cargo.toml",
     "examples/nrf/Cargo.toml",
     // "examples/rp/Cargo.toml",
     // "examples/std/Cargo.toml",
diff --git a/embassy-boot/boot/Cargo.toml b/embassy-boot/boot/Cargo.toml
index 9c2e72be5..a42f88688 100644
--- a/embassy-boot/boot/Cargo.toml
+++ b/embassy-boot/boot/Cargo.toml
@@ -14,7 +14,7 @@ target = "thumbv7em-none-eabi"
 [dependencies]
 defmt = { version = "0.3", optional = true }
 log = { version = "0.4", optional = true  }
-embassy-util = { version = "0.1.0", path = "../../embassy-util" }
+embassy-sync = { version = "0.1.0", path = "../../embassy-sync" }
 embedded-storage = "0.3.0"
 embedded-storage-async = "0.3.0"
 
diff --git a/embassy-boot/nrf/Cargo.toml b/embassy-boot/nrf/Cargo.toml
index b06e8102c..234393e7c 100644
--- a/embassy-boot/nrf/Cargo.toml
+++ b/embassy-boot/nrf/Cargo.toml
@@ -15,7 +15,7 @@ target = "thumbv7em-none-eabi"
 [dependencies]
 defmt = { version = "0.3", optional = true }
 
-embassy-util = { path = "../../embassy-util" }
+embassy-sync = { path = "../../embassy-sync" }
 embassy-nrf = { path = "../../embassy-nrf", default-features = false, features = ["nightly"] }
 embassy-boot = { path = "../boot", default-features = false }
 cortex-m = { version = "0.7.6" }
diff --git a/embassy-boot/stm32/Cargo.toml b/embassy-boot/stm32/Cargo.toml
index d8f492531..ad4657e0d 100644
--- a/embassy-boot/stm32/Cargo.toml
+++ b/embassy-boot/stm32/Cargo.toml
@@ -17,7 +17,7 @@ defmt = { version = "0.3", optional = true }
 defmt-rtt = { version = "0.3", optional = true }
 log = { version = "0.4", optional = true }
 
-embassy-util = { path = "../../embassy-util" }
+embassy-sync = { path = "../../embassy-sync" }
 embassy-stm32 = { path = "../../embassy-stm32", default-features = false, features = ["nightly"] }
 embassy-boot = { path = "../boot", default-features = false }
 cortex-m = { version = "0.7.6" }
diff --git a/embassy-cortex-m/Cargo.toml b/embassy-cortex-m/Cargo.toml
index 1f16da31b..7efced669 100644
--- a/embassy-cortex-m/Cargo.toml
+++ b/embassy-cortex-m/Cargo.toml
@@ -35,7 +35,7 @@ prio-bits-8 = []
 defmt = { version = "0.3", optional = true }
 log = { version = "0.4.14", optional = true }
 
-embassy-util = { version = "0.1.0", path = "../embassy-util" }
+embassy-sync = { version = "0.1.0", path = "../embassy-sync" }
 embassy-executor = { version = "0.1.0", path = "../embassy-executor"}
 embassy-macros = { version = "0.1.0", path = "../embassy-macros"}
 embassy-hal-common = { version = "0.1.0", path = "../embassy-hal-common"}
diff --git a/embassy-embedded-hal/Cargo.toml b/embassy-embedded-hal/Cargo.toml
index 866666871..462680720 100644
--- a/embassy-embedded-hal/Cargo.toml
+++ b/embassy-embedded-hal/Cargo.toml
@@ -16,7 +16,7 @@ std = []
 nightly = ["embedded-hal-async", "embedded-storage-async"]
 
 [dependencies]
-embassy-util = { version = "0.1.0", path = "../embassy-util" }
+embassy-sync = { version = "0.1.0", path = "../embassy-sync" }
 embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] }
 embedded-hal-1 = { package = "embedded-hal", version = "1.0.0-alpha.8" }
 embedded-hal-async = { version = "0.1.0-alpha.1", optional = true }
diff --git a/embassy-embedded-hal/src/shared_bus/asynch/i2c.rs b/embassy-embedded-hal/src/shared_bus/asynch/i2c.rs
index dc483b826..0bc6afd98 100644
--- a/embassy-embedded-hal/src/shared_bus/asynch/i2c.rs
+++ b/embassy-embedded-hal/src/shared_bus/asynch/i2c.rs
@@ -4,8 +4,8 @@
 //!
 //! ```rust
 //! use embassy_embedded_hal::shared_bus::i2c::I2cDevice;
-//! use embassy_util::mutex::Mutex;
-//! use embassy_util::blocking_mutex::raw::ThreadModeRawMutex;
+//! use embassy_sync::mutex::Mutex;
+//! use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex;
 //!
 //! static I2C_BUS: StaticCell<Mutex::<ThreadModeRawMutex, Twim<TWISPI0>>> = StaticCell::new();
 //! let config = twim::Config::default();
@@ -24,8 +24,8 @@
 //! ```
 use core::future::Future;
 
-use embassy_util::blocking_mutex::raw::RawMutex;
-use embassy_util::mutex::Mutex;
+use embassy_sync::blocking_mutex::raw::RawMutex;
+use embassy_sync::mutex::Mutex;
 use embedded_hal_async::i2c;
 
 use crate::shared_bus::I2cDeviceError;
diff --git a/embassy-embedded-hal/src/shared_bus/asynch/spi.rs b/embassy-embedded-hal/src/shared_bus/asynch/spi.rs
index bb419d6a6..c95b59ef0 100644
--- a/embassy-embedded-hal/src/shared_bus/asynch/spi.rs
+++ b/embassy-embedded-hal/src/shared_bus/asynch/spi.rs
@@ -4,8 +4,8 @@
 //!
 //! ```rust
 //! use embassy_embedded_hal::shared_bus::spi::SpiDevice;
-//! use embassy_util::mutex::Mutex;
-//! use embassy_util::blocking_mutex::raw::ThreadModeRawMutex;
+//! use embassy_sync::mutex::Mutex;
+//! use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex;
 //!
 //! static SPI_BUS: StaticCell<Mutex<ThreadModeRawMutex, spim::Spim<SPI3>>> = StaticCell::new();
 //! let mut config = spim::Config::default();
@@ -27,8 +27,8 @@
 //! ```
 use core::future::Future;
 
-use embassy_util::blocking_mutex::raw::RawMutex;
-use embassy_util::mutex::Mutex;
+use embassy_sync::blocking_mutex::raw::RawMutex;
+use embassy_sync::mutex::Mutex;
 use embedded_hal_1::digital::blocking::OutputPin;
 use embedded_hal_1::spi::ErrorType;
 use embedded_hal_async::spi;
diff --git a/embassy-embedded-hal/src/shared_bus/blocking/i2c.rs b/embassy-embedded-hal/src/shared_bus/blocking/i2c.rs
index 837312e87..a611e2d27 100644
--- a/embassy-embedded-hal/src/shared_bus/blocking/i2c.rs
+++ b/embassy-embedded-hal/src/shared_bus/blocking/i2c.rs
@@ -4,7 +4,7 @@
 //!
 //! ```rust
 //! use embassy_embedded_hal::shared_bus::blocking::i2c::I2cDevice;
-//! use embassy_util::blocking_mutex::{NoopMutex, raw::NoopRawMutex};
+//! use embassy_sync::blocking_mutex::{NoopMutex, raw::NoopRawMutex};
 //!
 //! static I2C_BUS: StaticCell<NoopMutex<RefCell<Twim<TWISPI0>>>> = StaticCell::new();
 //! let irq = interrupt::take!(SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0);
@@ -18,8 +18,8 @@
 
 use core::cell::RefCell;
 
-use embassy_util::blocking_mutex::raw::RawMutex;
-use embassy_util::blocking_mutex::Mutex;
+use embassy_sync::blocking_mutex::raw::RawMutex;
+use embassy_sync::blocking_mutex::Mutex;
 use embedded_hal_1::i2c::blocking::{I2c, Operation};
 use embedded_hal_1::i2c::ErrorType;
 
diff --git a/embassy-embedded-hal/src/shared_bus/blocking/spi.rs b/embassy-embedded-hal/src/shared_bus/blocking/spi.rs
index a48d9183c..23845d887 100644
--- a/embassy-embedded-hal/src/shared_bus/blocking/spi.rs
+++ b/embassy-embedded-hal/src/shared_bus/blocking/spi.rs
@@ -4,7 +4,7 @@
 //!
 //! ```rust
 //! use embassy_embedded_hal::shared_bus::blocking::spi::SpiDevice;
-//! use embassy_util::blocking_mutex::{NoopMutex, raw::NoopRawMutex};
+//! use embassy_sync::blocking_mutex::{NoopMutex, raw::NoopRawMutex};
 //!
 //! static SPI_BUS: StaticCell<NoopMutex<RefCell<Spim<SPI3>>>> = StaticCell::new();
 //! let irq = interrupt::take!(SPIM3);
@@ -20,8 +20,8 @@
 
 use core::cell::RefCell;
 
-use embassy_util::blocking_mutex::raw::RawMutex;
-use embassy_util::blocking_mutex::Mutex;
+use embassy_sync::blocking_mutex::raw::RawMutex;
+use embassy_sync::blocking_mutex::Mutex;
 use embedded_hal_1::digital::blocking::OutputPin;
 use embedded_hal_1::spi;
 use embedded_hal_1::spi::blocking::SpiBusFlush;
diff --git a/embassy-futures/Cargo.toml b/embassy-futures/Cargo.toml
new file mode 100644
index 000000000..e564f5a96
--- /dev/null
+++ b/embassy-futures/Cargo.toml
@@ -0,0 +1,14 @@
+[package]
+name = "embassy-futures"
+version = "0.1.0"
+edition = "2021"
+
+[package.metadata.embassy_docs]
+src_base = "https://github.com/embassy-rs/embassy/blob/embassy-futures-v$VERSION/embassy-futures/src/"
+src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-futures/src/"
+features = ["nightly"]
+target = "thumbv7em-none-eabi"
+
+[dependencies]
+defmt = { version = "0.3", optional = true }
+log = { version = "0.4.14", optional = true }
diff --git a/embassy-util/src/fmt.rs b/embassy-futures/src/fmt.rs
similarity index 100%
rename from embassy-util/src/fmt.rs
rename to embassy-futures/src/fmt.rs
diff --git a/embassy-futures/src/lib.rs b/embassy-futures/src/lib.rs
new file mode 100644
index 000000000..48c9c8574
--- /dev/null
+++ b/embassy-futures/src/lib.rs
@@ -0,0 +1,12 @@
+#![no_std]
+#![doc = include_str!("../../README.md")]
+#![warn(missing_docs)]
+
+// This mod MUST go first, so that the others see its macros.
+pub(crate) mod fmt;
+
+mod select;
+mod yield_now;
+
+pub use select::*;
+pub use yield_now::*;
diff --git a/embassy-util/src/select.rs b/embassy-futures/src/select.rs
similarity index 100%
rename from embassy-util/src/select.rs
rename to embassy-futures/src/select.rs
diff --git a/embassy-util/src/yield_now.rs b/embassy-futures/src/yield_now.rs
similarity index 100%
rename from embassy-util/src/yield_now.rs
rename to embassy-futures/src/yield_now.rs
diff --git a/embassy-lora/Cargo.toml b/embassy-lora/Cargo.toml
index c7435ab3e..9d5e7aed2 100644
--- a/embassy-lora/Cargo.toml
+++ b/embassy-lora/Cargo.toml
@@ -25,7 +25,7 @@ defmt = { version = "0.3", optional = true }
 log = { version = "0.4.14", optional = true }
 
 embassy-time = { version = "0.1.0", path = "../embassy-time" }
-embassy-util = { version = "0.1.0", path = "../embassy-util" }
+embassy-sync = { version = "0.1.0", path = "../embassy-sync" }
 embassy-stm32 = { version = "0.1.0", path = "../embassy-stm32", default-features = false, optional = true }
 embedded-hal-1 = { package = "embedded-hal", version = "1.0.0-alpha.8" }
 embedded-hal-async = { version = "0.1.0-alpha.1" }
diff --git a/embassy-lora/src/stm32wl/mod.rs b/embassy-lora/src/stm32wl/mod.rs
index 4a4c5cfb7..374c8532f 100644
--- a/embassy-lora/src/stm32wl/mod.rs
+++ b/embassy-lora/src/stm32wl/mod.rs
@@ -12,7 +12,7 @@ use embassy_stm32::subghz::{
     Status, SubGhz, TcxoMode, TcxoTrim, Timeout, TxParams,
 };
 use embassy_stm32::Peripheral;
-use embassy_util::channel::signal::Signal;
+use embassy_sync::channel::signal::Signal;
 use lorawan_device::async_device::radio::{Bandwidth, PhyRxTx, RfConfig, RxQuality, SpreadingFactor, TxConfig};
 use lorawan_device::async_device::Timings;
 
diff --git a/embassy-net/Cargo.toml b/embassy-net/Cargo.toml
index 9f9bb2261..2143f36d3 100644
--- a/embassy-net/Cargo.toml
+++ b/embassy-net/Cargo.toml
@@ -38,7 +38,7 @@ defmt = { version = "0.3", optional = true }
 log = { version = "0.4.14", optional = true }
 
 embassy-time = { version = "0.1.0", path = "../embassy-time" }
-embassy-util = { version = "0.1.0", path = "../embassy-util" }
+embassy-sync = { version = "0.1.0", path = "../embassy-sync" }
 embedded-io = { version = "0.3.0", features = [ "async" ] }
 
 managed = { version = "0.8.0", default-features = false, features = [ "map" ] }
diff --git a/embassy-net/src/stack.rs b/embassy-net/src/stack.rs
index 4b6a7ae2a..8d2dd4bca 100644
--- a/embassy-net/src/stack.rs
+++ b/embassy-net/src/stack.rs
@@ -2,8 +2,8 @@ use core::cell::UnsafeCell;
 use core::future::Future;
 use core::task::{Context, Poll};
 
+use embassy_sync::waitqueue::WakerRegistration;
 use embassy_time::{Instant, Timer};
-use embassy_util::waitqueue::WakerRegistration;
 use futures::future::poll_fn;
 use futures::pin_mut;
 use heapless::Vec;
diff --git a/embassy-nrf/Cargo.toml b/embassy-nrf/Cargo.toml
index 0ef7f5bbd..186c73a58 100644
--- a/embassy-nrf/Cargo.toml
+++ b/embassy-nrf/Cargo.toml
@@ -18,7 +18,7 @@ flavors = [
 
 time = ["dep:embassy-time"]
 
-defmt = ["dep:defmt", "embassy-executor/defmt", "embassy-util/defmt", "embassy-usb?/defmt", "embedded-io?/defmt", "embassy-embedded-hal/defmt"]
+defmt = ["dep:defmt", "embassy-executor/defmt", "embassy-sync/defmt", "embassy-usb?/defmt", "embedded-io?/defmt", "embassy-embedded-hal/defmt"]
 
 # Enable nightly-only features
 nightly = ["embedded-hal-1", "embedded-hal-async", "embassy-usb", "embedded-storage-async", "dep:embedded-io", "embassy-embedded-hal/nightly"]
@@ -66,7 +66,7 @@ _gpio-p1 = []
 [dependencies]
 embassy-executor = { version = "0.1.0", path = "../embassy-executor", optional = true }
 embassy-time = { version = "0.1.0", path = "../embassy-time", optional = true }
-embassy-util = { version = "0.1.0", path = "../embassy-util" }
+embassy-sync = { version = "0.1.0", path = "../embassy-sync" }
 embassy-cortex-m = { version = "0.1.0", path = "../embassy-cortex-m", features = ["prio-bits-3"]}
 embassy-hal-common = {version = "0.1.0", path = "../embassy-hal-common" }
 embassy-embedded-hal = {version = "0.1.0", path = "../embassy-embedded-hal" }
diff --git a/embassy-nrf/src/buffered_uarte.rs b/embassy-nrf/src/buffered_uarte.rs
index 08dfcbcf9..62af544ae 100644
--- a/embassy-nrf/src/buffered_uarte.rs
+++ b/embassy-nrf/src/buffered_uarte.rs
@@ -21,7 +21,7 @@ use core::task::Poll;
 use embassy_cortex_m::peripheral::{PeripheralMutex, PeripheralState, StateStorage};
 use embassy_hal_common::ring_buffer::RingBuffer;
 use embassy_hal_common::{into_ref, PeripheralRef};
-use embassy_util::waitqueue::WakerRegistration;
+use embassy_sync::waitqueue::WakerRegistration;
 use futures::future::poll_fn;
 // Re-export SVD variants to allow user to directly set values
 pub use pac::uarte0::{baudrate::BAUDRATE_A as Baudrate, config::PARITY_A as Parity};
diff --git a/embassy-nrf/src/gpiote.rs b/embassy-nrf/src/gpiote.rs
index cf49b0db0..b52035705 100644
--- a/embassy-nrf/src/gpiote.rs
+++ b/embassy-nrf/src/gpiote.rs
@@ -3,7 +3,7 @@ use core::future::Future;
 use core::task::{Context, Poll};
 
 use embassy_hal_common::{impl_peripheral, Peripheral, PeripheralRef};
-use embassy_util::waitqueue::AtomicWaker;
+use embassy_sync::waitqueue::AtomicWaker;
 use futures::future::poll_fn;
 
 use crate::gpio::sealed::Pin as _;
diff --git a/embassy-nrf/src/qdec.rs b/embassy-nrf/src/qdec.rs
index 83f2916b9..762e09715 100644
--- a/embassy-nrf/src/qdec.rs
+++ b/embassy-nrf/src/qdec.rs
@@ -3,7 +3,7 @@
 use core::task::Poll;
 
 use embassy_hal_common::{into_ref, PeripheralRef};
-use embassy_util::waitqueue::AtomicWaker;
+use embassy_sync::waitqueue::AtomicWaker;
 use futures::future::poll_fn;
 
 use crate::gpio::sealed::Pin as _;
diff --git a/embassy-nrf/src/qspi.rs b/embassy-nrf/src/qspi.rs
index 6d7ebb4b1..c97cb1656 100644
--- a/embassy-nrf/src/qspi.rs
+++ b/embassy-nrf/src/qspi.rs
@@ -526,7 +526,7 @@ cfg_if::cfg_if! {
 }
 
 pub(crate) mod sealed {
-    use embassy_util::waitqueue::AtomicWaker;
+    use embassy_sync::waitqueue::AtomicWaker;
 
     use super::*;
 
diff --git a/embassy-nrf/src/rng.rs b/embassy-nrf/src/rng.rs
index 7aad561b6..42da51d0f 100644
--- a/embassy-nrf/src/rng.rs
+++ b/embassy-nrf/src/rng.rs
@@ -4,7 +4,7 @@ use core::task::Poll;
 
 use embassy_hal_common::drop::OnDrop;
 use embassy_hal_common::{into_ref, PeripheralRef};
-use embassy_util::waitqueue::AtomicWaker;
+use embassy_sync::waitqueue::AtomicWaker;
 use futures::future::poll_fn;
 
 use crate::interrupt::InterruptExt;
diff --git a/embassy-nrf/src/saadc.rs b/embassy-nrf/src/saadc.rs
index f2ef46d8d..7dc66349e 100644
--- a/embassy-nrf/src/saadc.rs
+++ b/embassy-nrf/src/saadc.rs
@@ -4,7 +4,7 @@ use core::sync::atomic::{compiler_fence, Ordering};
 use core::task::Poll;
 
 use embassy_hal_common::{impl_peripheral, into_ref, PeripheralRef};
-use embassy_util::waitqueue::AtomicWaker;
+use embassy_sync::waitqueue::AtomicWaker;
 use futures::future::poll_fn;
 use pac::{saadc, SAADC};
 use saadc::ch::config::{GAIN_A, REFSEL_A, RESP_A, TACQ_A};
diff --git a/embassy-nrf/src/spim.rs b/embassy-nrf/src/spim.rs
index 57c0c14c7..be2fc02fc 100644
--- a/embassy-nrf/src/spim.rs
+++ b/embassy-nrf/src/spim.rs
@@ -363,7 +363,7 @@ impl<'d, T: Instance> Drop for Spim<'d, T> {
 }
 
 pub(crate) mod sealed {
-    use embassy_util::waitqueue::AtomicWaker;
+    use embassy_sync::waitqueue::AtomicWaker;
 
     use super::*;
 
diff --git a/embassy-nrf/src/temp.rs b/embassy-nrf/src/temp.rs
index 1491e4268..d520fd686 100644
--- a/embassy-nrf/src/temp.rs
+++ b/embassy-nrf/src/temp.rs
@@ -4,7 +4,7 @@ use core::task::Poll;
 
 use embassy_hal_common::drop::OnDrop;
 use embassy_hal_common::{into_ref, PeripheralRef};
-use embassy_util::waitqueue::AtomicWaker;
+use embassy_sync::waitqueue::AtomicWaker;
 use fixed::types::I30F2;
 use futures::future::poll_fn;
 
diff --git a/embassy-nrf/src/time_driver.rs b/embassy-nrf/src/time_driver.rs
index b961d65a0..c32a44637 100644
--- a/embassy-nrf/src/time_driver.rs
+++ b/embassy-nrf/src/time_driver.rs
@@ -3,9 +3,9 @@ use core::sync::atomic::{compiler_fence, AtomicU32, AtomicU8, Ordering};
 use core::{mem, ptr};
 
 use critical_section::CriticalSection;
+use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
+use embassy_sync::blocking_mutex::CriticalSectionMutex as Mutex;
 use embassy_time::driver::{AlarmHandle, Driver};
-use embassy_util::blocking_mutex::raw::CriticalSectionRawMutex;
-use embassy_util::blocking_mutex::CriticalSectionMutex as Mutex;
 
 use crate::interrupt::{Interrupt, InterruptExt};
 use crate::{interrupt, pac};
diff --git a/embassy-nrf/src/timer.rs b/embassy-nrf/src/timer.rs
index b3b613db2..3de5a8962 100644
--- a/embassy-nrf/src/timer.rs
+++ b/embassy-nrf/src/timer.rs
@@ -5,7 +5,7 @@ use core::task::Poll;
 
 use embassy_hal_common::drop::OnDrop;
 use embassy_hal_common::{into_ref, PeripheralRef};
-use embassy_util::waitqueue::AtomicWaker;
+use embassy_sync::waitqueue::AtomicWaker;
 use futures::future::poll_fn;
 
 use crate::interrupt::{Interrupt, InterruptExt};
@@ -40,8 +40,8 @@ macro_rules! impl_timer {
             fn regs() -> &'static pac::timer0::RegisterBlock {
                 unsafe { &*(pac::$pac_type::ptr() as *const pac::timer0::RegisterBlock) }
             }
-            fn waker(n: usize) -> &'static ::embassy_util::waitqueue::AtomicWaker {
-                use ::embassy_util::waitqueue::AtomicWaker;
+            fn waker(n: usize) -> &'static ::embassy_sync::waitqueue::AtomicWaker {
+                use ::embassy_sync::waitqueue::AtomicWaker;
                 const NEW_AW: AtomicWaker = AtomicWaker::new();
                 static WAKERS: [AtomicWaker; $ccs] = [NEW_AW; $ccs];
                 &WAKERS[n]
diff --git a/embassy-nrf/src/twim.rs b/embassy-nrf/src/twim.rs
index 9587d1f40..850f6d0fa 100644
--- a/embassy-nrf/src/twim.rs
+++ b/embassy-nrf/src/twim.rs
@@ -13,9 +13,9 @@ use core::task::Poll;
 
 use embassy_embedded_hal::SetConfig;
 use embassy_hal_common::{into_ref, PeripheralRef};
+use embassy_sync::waitqueue::AtomicWaker;
 #[cfg(feature = "time")]
 use embassy_time::{Duration, Instant};
-use embassy_util::waitqueue::AtomicWaker;
 use futures::future::poll_fn;
 
 use crate::chip::{EASY_DMA_SIZE, FORCE_COPY_BUFFER_SIZE};
diff --git a/embassy-nrf/src/uarte.rs b/embassy-nrf/src/uarte.rs
index 0d24cf65f..4347ea558 100644
--- a/embassy-nrf/src/uarte.rs
+++ b/embassy-nrf/src/uarte.rs
@@ -932,7 +932,7 @@ impl<'d, U: Instance, T: TimerInstance> UarteRxWithIdle<'d, U, T> {
 pub(crate) mod sealed {
     use core::sync::atomic::AtomicU8;
 
-    use embassy_util::waitqueue::AtomicWaker;
+    use embassy_sync::waitqueue::AtomicWaker;
 
     use super::*;
 
diff --git a/embassy-nrf/src/usb.rs b/embassy-nrf/src/usb.rs
index 509ee313e..688326e9c 100644
--- a/embassy-nrf/src/usb.rs
+++ b/embassy-nrf/src/usb.rs
@@ -7,10 +7,10 @@ use core::task::Poll;
 
 use cortex_m::peripheral::NVIC;
 use embassy_hal_common::{into_ref, PeripheralRef};
+use embassy_sync::waitqueue::AtomicWaker;
 pub use embassy_usb;
 use embassy_usb::driver::{self, EndpointError, Event, Unsupported};
 use embassy_usb::types::{EndpointAddress, EndpointInfo, EndpointType, UsbDirection};
-use embassy_util::waitqueue::AtomicWaker;
 use futures::future::poll_fn;
 use futures::Future;
 use pac::usbd::RegisterBlock;
diff --git a/embassy-rp/Cargo.toml b/embassy-rp/Cargo.toml
index 0e53d3a35..cfd95b7b4 100644
--- a/embassy-rp/Cargo.toml
+++ b/embassy-rp/Cargo.toml
@@ -27,7 +27,7 @@ nightly = ["embassy-executor/nightly", "embedded-hal-1", "embedded-hal-async", "
 unstable-traits = ["embedded-hal-1"]
 
 [dependencies]
-embassy-util = { version = "0.1.0", path = "../embassy-util" }
+embassy-sync = { version = "0.1.0", path = "../embassy-sync" }
 embassy-executor = { version = "0.1.0", path = "../embassy-executor" }
 embassy-time = { version = "0.1.0", path = "../embassy-time", features = [ "tick-1mhz" ] }
 embassy-cortex-m = { version = "0.1.0", path = "../embassy-cortex-m", features = ["prio-bits-2"]}
diff --git a/embassy-rp/src/gpio.rs b/embassy-rp/src/gpio.rs
index 90862fa32..428855c7f 100644
--- a/embassy-rp/src/gpio.rs
+++ b/embassy-rp/src/gpio.rs
@@ -5,7 +5,7 @@ use core::task::{Context, Poll};
 
 use embassy_cortex_m::interrupt::{Interrupt, InterruptExt};
 use embassy_hal_common::{impl_peripheral, into_ref, PeripheralRef};
-use embassy_util::waitqueue::AtomicWaker;
+use embassy_sync::waitqueue::AtomicWaker;
 
 use crate::pac::common::{Reg, RW};
 use crate::pac::SIO;
diff --git a/embassy-rp/src/timer.rs b/embassy-rp/src/timer.rs
index 5bc1f66c8..5215c0c0f 100644
--- a/embassy-rp/src/timer.rs
+++ b/embassy-rp/src/timer.rs
@@ -2,9 +2,9 @@ use core::cell::Cell;
 
 use atomic_polyfill::{AtomicU8, Ordering};
 use critical_section::CriticalSection;
+use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
+use embassy_sync::blocking_mutex::Mutex;
 use embassy_time::driver::{AlarmHandle, Driver};
-use embassy_util::blocking_mutex::raw::CriticalSectionRawMutex;
-use embassy_util::blocking_mutex::Mutex;
 
 use crate::interrupt::{Interrupt, InterruptExt};
 use crate::{interrupt, pac};
diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml
index c47ea0bca..7a8e5c59b 100644
--- a/embassy-stm32/Cargo.toml
+++ b/embassy-stm32/Cargo.toml
@@ -31,7 +31,7 @@ flavors = [
 ]
 
 [dependencies]
-embassy-util = { version = "0.1.0", path = "../embassy-util" }
+embassy-sync = { version = "0.1.0", path = "../embassy-sync" }
 embassy-executor = { version = "0.1.0", path = "../embassy-executor" }
 embassy-time = { version = "0.1.0", path = "../embassy-time", optional = true }
 embassy-cortex-m = { version = "0.1.0", path = "../embassy-cortex-m", features = ["prio-bits-4"]}
@@ -72,7 +72,7 @@ quote = "1.0.15"
 stm32-metapac = { version = "0.1.0", path = "../stm32-metapac", default-features = false, features = ["metadata"]}
 
 [features]
-defmt = ["dep:defmt", "bxcan/unstable-defmt", "embassy-util/defmt", "embassy-executor/defmt", "embassy-embedded-hal/defmt", "embedded-io?/defmt", "embassy-usb?/defmt"]
+defmt = ["dep:defmt", "bxcan/unstable-defmt", "embassy-sync/defmt", "embassy-executor/defmt", "embassy-embedded-hal/defmt", "embedded-io?/defmt", "embassy-usb?/defmt"]
 sdmmc-rs = ["embedded-sdmmc"]
 net = ["embassy-net" ]
 memory-x = ["stm32-metapac/memory-x"]
diff --git a/embassy-stm32/src/dcmi.rs b/embassy-stm32/src/dcmi.rs
index bbb9a12cb..fb9dc9d08 100644
--- a/embassy-stm32/src/dcmi.rs
+++ b/embassy-stm32/src/dcmi.rs
@@ -1,7 +1,7 @@
 use core::task::Poll;
 
 use embassy_hal_common::{into_ref, PeripheralRef};
-use embassy_util::waitqueue::AtomicWaker;
+use embassy_sync::waitqueue::AtomicWaker;
 use futures::future::poll_fn;
 
 use crate::gpio::sealed::AFType;
diff --git a/embassy-stm32/src/dma/bdma.rs b/embassy-stm32/src/dma/bdma.rs
index bd2cd5b57..674255ddc 100644
--- a/embassy-stm32/src/dma/bdma.rs
+++ b/embassy-stm32/src/dma/bdma.rs
@@ -3,7 +3,7 @@
 use core::sync::atomic::{fence, Ordering};
 use core::task::Waker;
 
-use embassy_util::waitqueue::AtomicWaker;
+use embassy_sync::waitqueue::AtomicWaker;
 
 use super::{TransferOptions, Word, WordSize};
 use crate::_generated::BDMA_CHANNEL_COUNT;
diff --git a/embassy-stm32/src/dma/dma.rs b/embassy-stm32/src/dma/dma.rs
index 0c66005c7..a45b8780b 100644
--- a/embassy-stm32/src/dma/dma.rs
+++ b/embassy-stm32/src/dma/dma.rs
@@ -1,7 +1,7 @@
 use core::sync::atomic::{fence, Ordering};
 use core::task::Waker;
 
-use embassy_util::waitqueue::AtomicWaker;
+use embassy_sync::waitqueue::AtomicWaker;
 
 use super::{Burst, FlowControl, Request, TransferOptions, Word, WordSize};
 use crate::_generated::DMA_CHANNEL_COUNT;
diff --git a/embassy-stm32/src/dma/gpdma.rs b/embassy-stm32/src/dma/gpdma.rs
index 1aea6c65d..bde8c3ef3 100644
--- a/embassy-stm32/src/dma/gpdma.rs
+++ b/embassy-stm32/src/dma/gpdma.rs
@@ -1,7 +1,7 @@
 use core::sync::atomic::{fence, Ordering};
 use core::task::Waker;
 
-use embassy_util::waitqueue::AtomicWaker;
+use embassy_sync::waitqueue::AtomicWaker;
 
 use super::{Request, TransferOptions, Word, WordSize};
 use crate::_generated::GPDMA_CHANNEL_COUNT;
diff --git a/embassy-stm32/src/eth/v1/mod.rs b/embassy-stm32/src/eth/v1/mod.rs
index 37593914f..1ab0438ad 100644
--- a/embassy-stm32/src/eth/v1/mod.rs
+++ b/embassy-stm32/src/eth/v1/mod.rs
@@ -7,7 +7,7 @@ use core::task::Waker;
 use embassy_cortex_m::peripheral::{PeripheralMutex, PeripheralState, StateStorage};
 use embassy_hal_common::{into_ref, PeripheralRef};
 use embassy_net::{Device, DeviceCapabilities, LinkState, PacketBuf, MTU};
-use embassy_util::waitqueue::AtomicWaker;
+use embassy_sync::waitqueue::AtomicWaker;
 
 use crate::gpio::sealed::{AFType, Pin as __GpioPin};
 use crate::gpio::{AnyPin, Speed};
diff --git a/embassy-stm32/src/eth/v2/mod.rs b/embassy-stm32/src/eth/v2/mod.rs
index 1bc1fb72e..d67c3c5e4 100644
--- a/embassy-stm32/src/eth/v2/mod.rs
+++ b/embassy-stm32/src/eth/v2/mod.rs
@@ -5,7 +5,7 @@ use core::task::Waker;
 use embassy_cortex_m::peripheral::{PeripheralMutex, PeripheralState, StateStorage};
 use embassy_hal_common::{into_ref, PeripheralRef};
 use embassy_net::{Device, DeviceCapabilities, LinkState, PacketBuf, MTU};
-use embassy_util::waitqueue::AtomicWaker;
+use embassy_sync::waitqueue::AtomicWaker;
 
 use crate::gpio::sealed::{AFType, Pin as _};
 use crate::gpio::{AnyPin, Speed};
diff --git a/embassy-stm32/src/exti.rs b/embassy-stm32/src/exti.rs
index ecb180bbe..935149b13 100644
--- a/embassy-stm32/src/exti.rs
+++ b/embassy-stm32/src/exti.rs
@@ -4,7 +4,7 @@ use core::pin::Pin;
 use core::task::{Context, Poll};
 
 use embassy_hal_common::impl_peripheral;
-use embassy_util::waitqueue::AtomicWaker;
+use embassy_sync::waitqueue::AtomicWaker;
 
 use crate::gpio::{AnyPin, Input, Pin as GpioPin};
 use crate::pac::exti::regs::Lines;
diff --git a/embassy-stm32/src/i2c/v2.rs b/embassy-stm32/src/i2c/v2.rs
index b4303d3d4..07a3105da 100644
--- a/embassy-stm32/src/i2c/v2.rs
+++ b/embassy-stm32/src/i2c/v2.rs
@@ -5,7 +5,7 @@ use atomic_polyfill::{AtomicUsize, Ordering};
 use embassy_embedded_hal::SetConfig;
 use embassy_hal_common::drop::OnDrop;
 use embassy_hal_common::{into_ref, PeripheralRef};
-use embassy_util::waitqueue::AtomicWaker;
+use embassy_sync::waitqueue::AtomicWaker;
 use futures::future::poll_fn;
 
 use crate::dma::NoDma;
diff --git a/embassy-stm32/src/rng.rs b/embassy-stm32/src/rng.rs
index 81e28f355..520f2ab9a 100644
--- a/embassy-stm32/src/rng.rs
+++ b/embassy-stm32/src/rng.rs
@@ -3,7 +3,7 @@
 use core::task::Poll;
 
 use embassy_hal_common::{into_ref, PeripheralRef};
-use embassy_util::waitqueue::AtomicWaker;
+use embassy_sync::waitqueue::AtomicWaker;
 use futures::future::poll_fn;
 use rand_core::{CryptoRng, RngCore};
 
diff --git a/embassy-stm32/src/sdmmc/mod.rs b/embassy-stm32/src/sdmmc/mod.rs
index 3ad31ec87..67758c492 100644
--- a/embassy-stm32/src/sdmmc/mod.rs
+++ b/embassy-stm32/src/sdmmc/mod.rs
@@ -5,7 +5,7 @@ use core::task::Poll;
 
 use embassy_hal_common::drop::OnDrop;
 use embassy_hal_common::{into_ref, PeripheralRef};
-use embassy_util::waitqueue::AtomicWaker;
+use embassy_sync::waitqueue::AtomicWaker;
 use futures::future::poll_fn;
 use sdio_host::{BusWidth, CardCapacity, CardStatus, CurrentState, SDStatus, CID, CSD, OCR, SCR};
 
@@ -1514,8 +1514,8 @@ foreach_peripheral!(
                 INNER
             }
 
-            fn state() -> &'static ::embassy_util::waitqueue::AtomicWaker {
-                static WAKER: ::embassy_util::waitqueue::AtomicWaker = ::embassy_util::waitqueue::AtomicWaker::new();
+            fn state() -> &'static ::embassy_sync::waitqueue::AtomicWaker {
+                static WAKER: ::embassy_sync::waitqueue::AtomicWaker = ::embassy_sync::waitqueue::AtomicWaker::new();
                 &WAKER
             }
         }
diff --git a/embassy-stm32/src/time_driver.rs b/embassy-stm32/src/time_driver.rs
index 7f4723162..6989a43d3 100644
--- a/embassy-stm32/src/time_driver.rs
+++ b/embassy-stm32/src/time_driver.rs
@@ -4,10 +4,10 @@ use core::sync::atomic::{compiler_fence, Ordering};
 use core::{mem, ptr};
 
 use atomic_polyfill::{AtomicU32, AtomicU8};
+use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
+use embassy_sync::blocking_mutex::Mutex;
 use embassy_time::driver::{AlarmHandle, Driver};
 use embassy_time::TICKS_PER_SECOND;
-use embassy_util::blocking_mutex::raw::CriticalSectionRawMutex;
-use embassy_util::blocking_mutex::Mutex;
 use stm32_metapac::timer::regs;
 
 use crate::interrupt::{CriticalSection, InterruptExt};
diff --git a/embassy-stm32/src/usart/buffered.rs b/embassy-stm32/src/usart/buffered.rs
index ec2231e43..a7fa43894 100644
--- a/embassy-stm32/src/usart/buffered.rs
+++ b/embassy-stm32/src/usart/buffered.rs
@@ -4,7 +4,7 @@ use core::task::Poll;
 use atomic_polyfill::{compiler_fence, Ordering};
 use embassy_cortex_m::peripheral::{PeripheralMutex, PeripheralState, StateStorage};
 use embassy_hal_common::ring_buffer::RingBuffer;
-use embassy_util::waitqueue::WakerRegistration;
+use embassy_sync::waitqueue::WakerRegistration;
 use futures::future::poll_fn;
 
 use super::*;
diff --git a/embassy-stm32/src/usb/usb.rs b/embassy-stm32/src/usb/usb.rs
index 3861e42d0..db965824a 100644
--- a/embassy-stm32/src/usb/usb.rs
+++ b/embassy-stm32/src/usb/usb.rs
@@ -6,10 +6,10 @@ use core::task::Poll;
 
 use atomic_polyfill::{AtomicBool, AtomicU8};
 use embassy_hal_common::into_ref;
+use embassy_sync::waitqueue::AtomicWaker;
 use embassy_time::{block_for, Duration};
 use embassy_usb::driver::{self, EndpointAllocError, EndpointError, Event, Unsupported};
 use embassy_usb::types::{EndpointAddress, EndpointInfo, EndpointType, UsbDirection};
-use embassy_util::waitqueue::AtomicWaker;
 use futures::future::poll_fn;
 use futures::Future;
 use pac::common::{Reg, RW};
diff --git a/embassy-util/Cargo.toml b/embassy-sync/Cargo.toml
similarity index 85%
rename from embassy-util/Cargo.toml
rename to embassy-sync/Cargo.toml
index b54a58b46..0d14bba55 100644
--- a/embassy-util/Cargo.toml
+++ b/embassy-sync/Cargo.toml
@@ -1,11 +1,11 @@
 [package]
-name = "embassy-util"
+name = "embassy-sync"
 version = "0.1.0"
 edition = "2021"
 
 [package.metadata.embassy_docs]
-src_base = "https://github.com/embassy-rs/embassy/blob/embassy-util-v$VERSION/embassy-util/src/"
-src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-util/src/"
+src_base = "https://github.com/embassy-rs/embassy/blob/embassy-sync-v$VERSION/embassy-sync/src/"
+src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-sync/src/"
 features = ["nightly"]
 target = "thumbv7em-none-eabi"
 
diff --git a/embassy-util/build.rs b/embassy-sync/build.rs
similarity index 100%
rename from embassy-util/build.rs
rename to embassy-sync/build.rs
diff --git a/embassy-util/src/blocking_mutex/mod.rs b/embassy-sync/src/blocking_mutex/mod.rs
similarity index 100%
rename from embassy-util/src/blocking_mutex/mod.rs
rename to embassy-sync/src/blocking_mutex/mod.rs
diff --git a/embassy-util/src/blocking_mutex/raw.rs b/embassy-sync/src/blocking_mutex/raw.rs
similarity index 100%
rename from embassy-util/src/blocking_mutex/raw.rs
rename to embassy-sync/src/blocking_mutex/raw.rs
diff --git a/embassy-util/src/channel/mod.rs b/embassy-sync/src/channel/mod.rs
similarity index 100%
rename from embassy-util/src/channel/mod.rs
rename to embassy-sync/src/channel/mod.rs
diff --git a/embassy-util/src/channel/mpmc.rs b/embassy-sync/src/channel/mpmc.rs
similarity index 99%
rename from embassy-util/src/channel/mpmc.rs
rename to embassy-sync/src/channel/mpmc.rs
index 263f29bfc..7bebd3412 100644
--- a/embassy-util/src/channel/mpmc.rs
+++ b/embassy-sync/src/channel/mpmc.rs
@@ -373,8 +373,8 @@ where
     /// Establish a new bounded channel. For example, to create one with a NoopMutex:
     ///
     /// ```
-    /// use embassy_util::channel::mpmc::Channel;
-    /// use embassy_util::blocking_mutex::raw::NoopRawMutex;
+    /// use embassy_sync::channel::mpmc::Channel;
+    /// use embassy_sync::blocking_mutex::raw::NoopRawMutex;
     ///
     /// // Declare a bounded channel of 3 u32s.
     /// let mut channel = Channel::<NoopRawMutex, u32, 3>::new();
diff --git a/embassy-util/src/channel/pubsub/mod.rs b/embassy-sync/src/channel/pubsub/mod.rs
similarity index 99%
rename from embassy-util/src/channel/pubsub/mod.rs
rename to embassy-sync/src/channel/pubsub/mod.rs
index ecc8fbd8f..f62b4d118 100644
--- a/embassy-util/src/channel/pubsub/mod.rs
+++ b/embassy-sync/src/channel/pubsub/mod.rs
@@ -33,9 +33,9 @@ pub use subscriber::{DynSubscriber, Subscriber};
 /// ## Example
 ///
 /// ```
-/// # use embassy_util::blocking_mutex::raw::NoopRawMutex;
-/// # use embassy_util::channel::pubsub::WaitResult;
-/// # use embassy_util::channel::pubsub::PubSubChannel;
+/// # use embassy_sync::blocking_mutex::raw::NoopRawMutex;
+/// # use embassy_sync::channel::pubsub::WaitResult;
+/// # use embassy_sync::channel::pubsub::PubSubChannel;
 /// # use futures_executor::block_on;
 /// # let test = async {
 /// // Create the channel. This can be static as well
diff --git a/embassy-util/src/channel/pubsub/publisher.rs b/embassy-sync/src/channel/pubsub/publisher.rs
similarity index 100%
rename from embassy-util/src/channel/pubsub/publisher.rs
rename to embassy-sync/src/channel/pubsub/publisher.rs
diff --git a/embassy-util/src/channel/pubsub/subscriber.rs b/embassy-sync/src/channel/pubsub/subscriber.rs
similarity index 100%
rename from embassy-util/src/channel/pubsub/subscriber.rs
rename to embassy-sync/src/channel/pubsub/subscriber.rs
diff --git a/embassy-util/src/channel/signal.rs b/embassy-sync/src/channel/signal.rs
similarity index 98%
rename from embassy-util/src/channel/signal.rs
rename to embassy-sync/src/channel/signal.rs
index 05889f5a4..9279266c1 100644
--- a/embassy-util/src/channel/signal.rs
+++ b/embassy-sync/src/channel/signal.rs
@@ -19,7 +19,7 @@ use core::task::{Context, Poll, Waker};
 /// Signals are generally declared as `static`s and then borrowed as required.
 ///
 /// ```
-/// use embassy_util::channel::signal::Signal;
+/// use embassy_sync::channel::signal::Signal;
 ///
 /// enum SomeCommand {
 ///   On,
diff --git a/embassy-sync/src/fmt.rs b/embassy-sync/src/fmt.rs
new file mode 100644
index 000000000..f8bb0a035
--- /dev/null
+++ b/embassy-sync/src/fmt.rs
@@ -0,0 +1,228 @@
+#![macro_use]
+#![allow(unused_macros)]
+
+#[cfg(all(feature = "defmt", feature = "log"))]
+compile_error!("You may not enable both `defmt` and `log` features.");
+
+macro_rules! assert {
+    ($($x:tt)*) => {
+        {
+            #[cfg(not(feature = "defmt"))]
+            ::core::assert!($($x)*);
+            #[cfg(feature = "defmt")]
+            ::defmt::assert!($($x)*);
+        }
+    };
+}
+
+macro_rules! assert_eq {
+    ($($x:tt)*) => {
+        {
+            #[cfg(not(feature = "defmt"))]
+            ::core::assert_eq!($($x)*);
+            #[cfg(feature = "defmt")]
+            ::defmt::assert_eq!($($x)*);
+        }
+    };
+}
+
+macro_rules! assert_ne {
+    ($($x:tt)*) => {
+        {
+            #[cfg(not(feature = "defmt"))]
+            ::core::assert_ne!($($x)*);
+            #[cfg(feature = "defmt")]
+            ::defmt::assert_ne!($($x)*);
+        }
+    };
+}
+
+macro_rules! debug_assert {
+    ($($x:tt)*) => {
+        {
+            #[cfg(not(feature = "defmt"))]
+            ::core::debug_assert!($($x)*);
+            #[cfg(feature = "defmt")]
+            ::defmt::debug_assert!($($x)*);
+        }
+    };
+}
+
+macro_rules! debug_assert_eq {
+    ($($x:tt)*) => {
+        {
+            #[cfg(not(feature = "defmt"))]
+            ::core::debug_assert_eq!($($x)*);
+            #[cfg(feature = "defmt")]
+            ::defmt::debug_assert_eq!($($x)*);
+        }
+    };
+}
+
+macro_rules! debug_assert_ne {
+    ($($x:tt)*) => {
+        {
+            #[cfg(not(feature = "defmt"))]
+            ::core::debug_assert_ne!($($x)*);
+            #[cfg(feature = "defmt")]
+            ::defmt::debug_assert_ne!($($x)*);
+        }
+    };
+}
+
+macro_rules! todo {
+    ($($x:tt)*) => {
+        {
+            #[cfg(not(feature = "defmt"))]
+            ::core::todo!($($x)*);
+            #[cfg(feature = "defmt")]
+            ::defmt::todo!($($x)*);
+        }
+    };
+}
+
+macro_rules! unreachable {
+    ($($x:tt)*) => {
+        {
+            #[cfg(not(feature = "defmt"))]
+            ::core::unreachable!($($x)*);
+            #[cfg(feature = "defmt")]
+            ::defmt::unreachable!($($x)*);
+        }
+    };
+}
+
+macro_rules! panic {
+    ($($x:tt)*) => {
+        {
+            #[cfg(not(feature = "defmt"))]
+            ::core::panic!($($x)*);
+            #[cfg(feature = "defmt")]
+            ::defmt::panic!($($x)*);
+        }
+    };
+}
+
+macro_rules! trace {
+    ($s:literal $(, $x:expr)* $(,)?) => {
+        {
+            #[cfg(feature = "log")]
+            ::log::trace!($s $(, $x)*);
+            #[cfg(feature = "defmt")]
+            ::defmt::trace!($s $(, $x)*);
+            #[cfg(not(any(feature = "log", feature="defmt")))]
+            let _ = ($( & $x ),*);
+        }
+    };
+}
+
+macro_rules! debug {
+    ($s:literal $(, $x:expr)* $(,)?) => {
+        {
+            #[cfg(feature = "log")]
+            ::log::debug!($s $(, $x)*);
+            #[cfg(feature = "defmt")]
+            ::defmt::debug!($s $(, $x)*);
+            #[cfg(not(any(feature = "log", feature="defmt")))]
+            let _ = ($( & $x ),*);
+        }
+    };
+}
+
+macro_rules! info {
+    ($s:literal $(, $x:expr)* $(,)?) => {
+        {
+            #[cfg(feature = "log")]
+            ::log::info!($s $(, $x)*);
+            #[cfg(feature = "defmt")]
+            ::defmt::info!($s $(, $x)*);
+            #[cfg(not(any(feature = "log", feature="defmt")))]
+            let _ = ($( & $x ),*);
+        }
+    };
+}
+
+macro_rules! warn {
+    ($s:literal $(, $x:expr)* $(,)?) => {
+        {
+            #[cfg(feature = "log")]
+            ::log::warn!($s $(, $x)*);
+            #[cfg(feature = "defmt")]
+            ::defmt::warn!($s $(, $x)*);
+            #[cfg(not(any(feature = "log", feature="defmt")))]
+            let _ = ($( & $x ),*);
+        }
+    };
+}
+
+macro_rules! error {
+    ($s:literal $(, $x:expr)* $(,)?) => {
+        {
+            #[cfg(feature = "log")]
+            ::log::error!($s $(, $x)*);
+            #[cfg(feature = "defmt")]
+            ::defmt::error!($s $(, $x)*);
+            #[cfg(not(any(feature = "log", feature="defmt")))]
+            let _ = ($( & $x ),*);
+        }
+    };
+}
+
+#[cfg(feature = "defmt")]
+macro_rules! unwrap {
+    ($($x:tt)*) => {
+        ::defmt::unwrap!($($x)*)
+    };
+}
+
+#[cfg(not(feature = "defmt"))]
+macro_rules! unwrap {
+    ($arg:expr) => {
+        match $crate::fmt::Try::into_result($arg) {
+            ::core::result::Result::Ok(t) => t,
+            ::core::result::Result::Err(e) => {
+                ::core::panic!("unwrap of `{}` failed: {:?}", ::core::stringify!($arg), e);
+            }
+        }
+    };
+    ($arg:expr, $($msg:expr),+ $(,)? ) => {
+        match $crate::fmt::Try::into_result($arg) {
+            ::core::result::Result::Ok(t) => t,
+            ::core::result::Result::Err(e) => {
+                ::core::panic!("unwrap of `{}` failed: {}: {:?}", ::core::stringify!($arg), ::core::format_args!($($msg,)*), e);
+            }
+        }
+    }
+}
+
+#[cfg(feature = "defmt-timestamp-uptime")]
+defmt::timestamp! {"{=u64:us}", crate::time::Instant::now().as_micros() }
+
+#[derive(Debug, Copy, Clone, Eq, PartialEq)]
+pub struct NoneError;
+
+pub trait Try {
+    type Ok;
+    type Error;
+    fn into_result(self) -> Result<Self::Ok, Self::Error>;
+}
+
+impl<T> Try for Option<T> {
+    type Ok = T;
+    type Error = NoneError;
+
+    #[inline]
+    fn into_result(self) -> Result<T, NoneError> {
+        self.ok_or(NoneError)
+    }
+}
+
+impl<T, E> Try for Result<T, E> {
+    type Ok = T;
+    type Error = E;
+
+    #[inline]
+    fn into_result(self) -> Self {
+        self
+    }
+}
diff --git a/embassy-util/src/lib.rs b/embassy-sync/src/lib.rs
similarity index 87%
rename from embassy-util/src/lib.rs
rename to embassy-sync/src/lib.rs
index 8ec3300d9..7d8815903 100644
--- a/embassy-util/src/lib.rs
+++ b/embassy-sync/src/lib.rs
@@ -15,9 +15,3 @@ pub mod channel;
 pub mod mutex;
 pub mod pipe;
 pub mod waitqueue;
-
-mod select;
-mod yield_now;
-
-pub use select::*;
-pub use yield_now::*;
diff --git a/embassy-util/src/mutex.rs b/embassy-sync/src/mutex.rs
similarity index 100%
rename from embassy-util/src/mutex.rs
rename to embassy-sync/src/mutex.rs
diff --git a/embassy-util/src/pipe.rs b/embassy-sync/src/pipe.rs
similarity index 99%
rename from embassy-util/src/pipe.rs
rename to embassy-sync/src/pipe.rs
index d85b843e4..7d64b648e 100644
--- a/embassy-util/src/pipe.rs
+++ b/embassy-sync/src/pipe.rs
@@ -241,8 +241,8 @@ where
     /// Establish a new bounded pipe. For example, to create one with a NoopMutex:
     ///
     /// ```
-    /// use embassy_util::pipe::Pipe;
-    /// use embassy_util::blocking_mutex::raw::NoopRawMutex;
+    /// use embassy_sync::pipe::Pipe;
+    /// use embassy_sync::blocking_mutex::raw::NoopRawMutex;
     ///
     /// // Declare a bounded pipe, with a buffer of 256 bytes.
     /// let mut pipe = Pipe::<NoopRawMutex, 256>::new();
diff --git a/embassy-util/src/ring_buffer.rs b/embassy-sync/src/ring_buffer.rs
similarity index 100%
rename from embassy-util/src/ring_buffer.rs
rename to embassy-sync/src/ring_buffer.rs
diff --git a/embassy-util/src/waitqueue/mod.rs b/embassy-sync/src/waitqueue/mod.rs
similarity index 100%
rename from embassy-util/src/waitqueue/mod.rs
rename to embassy-sync/src/waitqueue/mod.rs
diff --git a/embassy-util/src/waitqueue/multi_waker.rs b/embassy-sync/src/waitqueue/multi_waker.rs
similarity index 100%
rename from embassy-util/src/waitqueue/multi_waker.rs
rename to embassy-sync/src/waitqueue/multi_waker.rs
diff --git a/embassy-util/src/waitqueue/waker.rs b/embassy-sync/src/waitqueue/waker.rs
similarity index 100%
rename from embassy-util/src/waitqueue/waker.rs
rename to embassy-sync/src/waitqueue/waker.rs
diff --git a/embassy-usb-hid/Cargo.toml b/embassy-usb-hid/Cargo.toml
index 5e9cfebf7..730351485 100644
--- a/embassy-usb-hid/Cargo.toml
+++ b/embassy-usb-hid/Cargo.toml
@@ -14,7 +14,7 @@ default = ["usbd-hid"]
 usbd-hid = ["dep:usbd-hid", "ssmarshal"]
 
 [dependencies]
-embassy-util = { version = "0.1.0", path = "../embassy-util" }
+embassy-sync = { version = "0.1.0", path = "../embassy-sync" }
 embassy-usb = { version = "0.1.0", path = "../embassy-usb" }
 
 defmt = { version = "0.3", optional = true }
diff --git a/embassy-usb-ncm/Cargo.toml b/embassy-usb-ncm/Cargo.toml
index 47c1f36bd..15d3db96f 100644
--- a/embassy-usb-ncm/Cargo.toml
+++ b/embassy-usb-ncm/Cargo.toml
@@ -10,7 +10,7 @@ features = ["defmt"]
 target = "thumbv7em-none-eabi"
 
 [dependencies]
-embassy-util = { version = "0.1.0", path = "../embassy-util" }
+embassy-sync = { version = "0.1.0", path = "../embassy-sync" }
 embassy-usb = { version = "0.1.0", path = "../embassy-usb" }
 
 defmt = { version = "0.3", optional = true }
diff --git a/embassy-usb-serial/Cargo.toml b/embassy-usb-serial/Cargo.toml
index 633610471..9788588e9 100644
--- a/embassy-usb-serial/Cargo.toml
+++ b/embassy-usb-serial/Cargo.toml
@@ -10,7 +10,7 @@ features = ["defmt"]
 target = "thumbv7em-none-eabi"
 
 [dependencies]
-embassy-util = { version = "0.1.0", path = "../embassy-util" }
+embassy-sync = { version = "0.1.0", path = "../embassy-sync" }
 embassy-usb = { version = "0.1.0", path = "../embassy-usb" }
 
 defmt = { version = "0.3", optional = true }
diff --git a/embassy-usb-serial/src/lib.rs b/embassy-usb-serial/src/lib.rs
index e561be9df..f3de2ec1b 100644
--- a/embassy-usb-serial/src/lib.rs
+++ b/embassy-usb-serial/src/lib.rs
@@ -9,11 +9,11 @@ use core::cell::Cell;
 use core::mem::{self, MaybeUninit};
 use core::sync::atomic::{AtomicBool, Ordering};
 
+use embassy_sync::blocking_mutex::CriticalSectionMutex;
 use embassy_usb::control::{self, ControlHandler, InResponse, OutResponse, Request};
 use embassy_usb::driver::{Driver, Endpoint, EndpointError, EndpointIn, EndpointOut};
 use embassy_usb::types::*;
 use embassy_usb::Builder;
-use embassy_util::blocking_mutex::CriticalSectionMutex;
 
 /// This should be used as `device_class` when building the `UsbDevice`.
 pub const USB_CLASS_CDC: u8 = 0x02;
diff --git a/embassy-usb/Cargo.toml b/embassy-usb/Cargo.toml
index 6adbd399b..8cad4d314 100644
--- a/embassy-usb/Cargo.toml
+++ b/embassy-usb/Cargo.toml
@@ -10,7 +10,7 @@ features = ["defmt"]
 target = "thumbv7em-none-eabi"
 
 [dependencies]
-embassy-util = { version = "0.1.0", path = "../embassy-util" }
+embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
 
 defmt = { version = "0.3", optional = true }
 log = { version = "0.4.14", optional = true }
diff --git a/embassy-usb/src/lib.rs b/embassy-usb/src/lib.rs
index 3f6e13472..5a3f8ba88 100644
--- a/embassy-usb/src/lib.rs
+++ b/embassy-usb/src/lib.rs
@@ -12,7 +12,7 @@ mod descriptor_reader;
 pub mod driver;
 pub mod types;
 
-use embassy_util::{select, Either};
+use embassy_futures::{select, Either};
 use heapless::Vec;
 
 pub use self::builder::{Builder, Config};
diff --git a/examples/boot/application/nrf/Cargo.toml b/examples/boot/application/nrf/Cargo.toml
index ef9346639..b9ff92578 100644
--- a/examples/boot/application/nrf/Cargo.toml
+++ b/examples/boot/application/nrf/Cargo.toml
@@ -4,7 +4,7 @@ name = "embassy-boot-nrf-examples"
 version = "0.1.0"
 
 [dependencies]
-embassy-util = { version = "0.1.0", path = "../../../../embassy-util" }
+embassy-sync = { version = "0.1.0", path = "../../../../embassy-sync" }
 embassy-executor = { version = "0.1.0", path = "../../../../embassy-executor", features = ["nightly", "integrated-timers"] }
 embassy-time = { version = "0.1.0", path = "../../../../embassy-time", features = ["nightly"] }
 embassy-nrf = { version = "0.1.0", path = "../../../../embassy-nrf", features = ["time-driver-rtc1", "gpiote", "nightly", "nrf52840"] }
diff --git a/examples/boot/application/stm32f3/Cargo.toml b/examples/boot/application/stm32f3/Cargo.toml
index 27eafa653..f143d1e8d 100644
--- a/examples/boot/application/stm32f3/Cargo.toml
+++ b/examples/boot/application/stm32f3/Cargo.toml
@@ -4,7 +4,7 @@ name = "embassy-boot-stm32f3-examples"
 version = "0.1.0"
 
 [dependencies]
-embassy-util = { version = "0.1.0", path = "../../../../embassy-util", features = ["defmt"] }
+embassy-sync = { version = "0.1.0", path = "../../../../embassy-sync", features = ["defmt"] }
 embassy-executor = { version = "0.1.0", path = "../../../../embassy-executor", features = ["nightly", "integrated-timers"] }
 embassy-time = { version = "0.1.0", path = "../../../../embassy-time", features = ["nightly", "tick-32768hz"] }
 embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["unstable-traits", "nightly", "stm32f303re", "time-driver-any", "exti"]  }
diff --git a/examples/boot/application/stm32f7/Cargo.toml b/examples/boot/application/stm32f7/Cargo.toml
index 7de0b82d7..29c87eee1 100644
--- a/examples/boot/application/stm32f7/Cargo.toml
+++ b/examples/boot/application/stm32f7/Cargo.toml
@@ -4,7 +4,7 @@ name = "embassy-boot-stm32f7-examples"
 version = "0.1.0"
 
 [dependencies]
-embassy-util = { version = "0.1.0", path = "../../../../embassy-util", features = ["defmt"] }
+embassy-sync = { version = "0.1.0", path = "../../../../embassy-sync", features = ["defmt"] }
 embassy-executor = { version = "0.1.0", path = "../../../../embassy-executor", features = ["nightly", "integrated-timers"] }
 embassy-time = { version = "0.1.0", path = "../../../../embassy-time", features = ["nightly", "tick-32768hz"] }
 embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["unstable-traits", "nightly", "stm32f767zi", "time-driver-any", "exti"]  }
diff --git a/examples/boot/application/stm32h7/Cargo.toml b/examples/boot/application/stm32h7/Cargo.toml
index 65d34c70b..5669527fe 100644
--- a/examples/boot/application/stm32h7/Cargo.toml
+++ b/examples/boot/application/stm32h7/Cargo.toml
@@ -4,7 +4,7 @@ name = "embassy-boot-stm32h7-examples"
 version = "0.1.0"
 
 [dependencies]
-embassy-util = { version = "0.1.0", path = "../../../../embassy-util", features = ["defmt"] }
+embassy-sync = { version = "0.1.0", path = "../../../../embassy-sync", features = ["defmt"] }
 embassy-executor = { version = "0.1.0", path = "../../../../embassy-executor", features = ["nightly", "integrated-timers"] }
 embassy-time = { version = "0.1.0", path = "../../../../embassy-time", features = ["nightly", "tick-32768hz"] }
 embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["unstable-traits", "nightly", "stm32h743zi", "time-driver-any", "exti"]  }
diff --git a/examples/boot/application/stm32l0/Cargo.toml b/examples/boot/application/stm32l0/Cargo.toml
index 8f37869e3..48624d5ec 100644
--- a/examples/boot/application/stm32l0/Cargo.toml
+++ b/examples/boot/application/stm32l0/Cargo.toml
@@ -4,7 +4,7 @@ name = "embassy-boot-stm32l0-examples"
 version = "0.1.0"
 
 [dependencies]
-embassy-util = { version = "0.1.0", path = "../../../../embassy-util", features = ["defmt"] }
+embassy-sync = { version = "0.1.0", path = "../../../../embassy-sync", features = ["defmt"] }
 embassy-executor = { version = "0.1.0", path = "../../../../embassy-executor", features = ["nightly", "integrated-timers"] }
 embassy-time = { version = "0.1.0", path = "../../../../embassy-time", features = ["nightly", "tick-32768hz"] }
 embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["unstable-traits", "nightly", "stm32l072cz", "time-driver-any", "exti", "memory-x"]  }
diff --git a/examples/boot/application/stm32l1/Cargo.toml b/examples/boot/application/stm32l1/Cargo.toml
index 6abf1986d..00b638ca5 100644
--- a/examples/boot/application/stm32l1/Cargo.toml
+++ b/examples/boot/application/stm32l1/Cargo.toml
@@ -4,7 +4,7 @@ name = "embassy-boot-stm32l1-examples"
 version = "0.1.0"
 
 [dependencies]
-embassy-util = { version = "0.1.0", path = "../../../../embassy-util", features = ["defmt"] }
+embassy-sync = { version = "0.1.0", path = "../../../../embassy-sync", features = ["defmt"] }
 embassy-executor = { version = "0.1.0", path = "../../../../embassy-executor", features = ["nightly", "integrated-timers"] }
 embassy-time = { version = "0.1.0", path = "../../../../embassy-time", features = ["nightly", "tick-32768hz"] }
 embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["unstable-traits", "nightly", "stm32l151cb-a", "time-driver-any", "exti"]  }
diff --git a/examples/boot/application/stm32l4/Cargo.toml b/examples/boot/application/stm32l4/Cargo.toml
index 6f2d12ff1..51ba730d5 100644
--- a/examples/boot/application/stm32l4/Cargo.toml
+++ b/examples/boot/application/stm32l4/Cargo.toml
@@ -4,7 +4,7 @@ name = "embassy-boot-stm32l4-examples"
 version = "0.1.0"
 
 [dependencies]
-embassy-util = { version = "0.1.0", path = "../../../../embassy-util", features = ["defmt"] }
+embassy-sync = { version = "0.1.0", path = "../../../../embassy-sync", features = ["defmt"] }
 embassy-executor = { version = "0.1.0", path = "../../../../embassy-executor", features = ["nightly", "integrated-timers"] }
 embassy-time = { version = "0.1.0", path = "../../../../embassy-time", features = ["nightly", "tick-32768hz"] }
 embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["unstable-traits", "nightly", "stm32l475vg", "time-driver-any", "exti"]  }
diff --git a/examples/boot/application/stm32wl/Cargo.toml b/examples/boot/application/stm32wl/Cargo.toml
index be97d4ebb..182acf694 100644
--- a/examples/boot/application/stm32wl/Cargo.toml
+++ b/examples/boot/application/stm32wl/Cargo.toml
@@ -4,7 +4,7 @@ name = "embassy-boot-stm32wl-examples"
 version = "0.1.0"
 
 [dependencies]
-embassy-util = { version = "0.1.0", path = "../../../../embassy-util", features = ["defmt"] }
+embassy-sync = { version = "0.1.0", path = "../../../../embassy-sync", features = ["defmt"] }
 embassy-executor = { version = "0.1.0", path = "../../../../embassy-executor", features = ["nightly", "integrated-timers"] }
 embassy-time = { version = "0.1.0", path = "../../../../embassy-time", features = ["nightly", "tick-32768hz"] }
 embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["unstable-traits", "nightly", "stm32wl55jc-cm4", "time-driver-any", "exti"]  }
diff --git a/examples/nrf-rtos-trace/Cargo.toml b/examples/nrf-rtos-trace/Cargo.toml
index b0907f92c..87c9f33f5 100644
--- a/examples/nrf-rtos-trace/Cargo.toml
+++ b/examples/nrf-rtos-trace/Cargo.toml
@@ -8,14 +8,14 @@ default = ["log", "nightly"]
 nightly = ["embassy-executor/nightly", "embassy-nrf/nightly", "embassy-nrf/unstable-traits"]
 log = [
     "dep:log",
-    "embassy-util/log",
+    "embassy-sync/log",
     "embassy-executor/log",
     "embassy-time/log",
     "embassy-nrf/log",
 ]
 
 [dependencies]
-embassy-util = { version = "0.1.0", path = "../../embassy-util" }
+embassy-sync = { version = "0.1.0", path = "../../embassy-sync" }
 embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features=["rtos-trace", "rtos-trace-interrupt", "integrated-timers"] }
 embassy-time = { version = "0.1.0", path = "../../embassy-time" }
 embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac"] }
diff --git a/examples/nrf/Cargo.toml b/examples/nrf/Cargo.toml
index 17f29b8fb..b0af0c86e 100644
--- a/examples/nrf/Cargo.toml
+++ b/examples/nrf/Cargo.toml
@@ -8,7 +8,8 @@ default = ["nightly"]
 nightly = ["embassy-executor/nightly", "embassy-nrf/nightly", "embassy-nrf/unstable-traits", "embassy-usb", "embassy-usb-serial", "embassy-usb-hid", "embassy-usb-ncm", "embedded-io/async", "embassy-net"]
 
 [dependencies]
-embassy-util = { version = "0.1.0", path = "../../embassy-util", features = ["defmt"] }
+embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
+embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] }
 embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["defmt", "integrated-timers"] }
 embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] }
 embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac"] }
diff --git a/examples/nrf/src/bin/channel.rs b/examples/nrf/src/bin/channel.rs
index 195200988..8371fd0af 100644
--- a/examples/nrf/src/bin/channel.rs
+++ b/examples/nrf/src/bin/channel.rs
@@ -5,9 +5,9 @@
 use defmt::unwrap;
 use embassy_executor::Spawner;
 use embassy_nrf::gpio::{Level, Output, OutputDrive};
+use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex;
+use embassy_sync::channel::mpmc::Channel;
 use embassy_time::{Duration, Timer};
-use embassy_util::blocking_mutex::raw::ThreadModeRawMutex;
-use embassy_util::channel::mpmc::Channel;
 use {defmt_rtt as _, panic_probe as _};
 
 enum LedState {
diff --git a/examples/nrf/src/bin/channel_sender_receiver.rs b/examples/nrf/src/bin/channel_sender_receiver.rs
index d250b6a5c..55d1fccb2 100644
--- a/examples/nrf/src/bin/channel_sender_receiver.rs
+++ b/examples/nrf/src/bin/channel_sender_receiver.rs
@@ -5,9 +5,9 @@
 use defmt::unwrap;
 use embassy_executor::Spawner;
 use embassy_nrf::gpio::{AnyPin, Level, Output, OutputDrive, Pin};
+use embassy_sync::blocking_mutex::raw::NoopRawMutex;
+use embassy_sync::channel::mpmc::{Channel, Receiver, Sender};
 use embassy_time::{Duration, Timer};
-use embassy_util::blocking_mutex::raw::NoopRawMutex;
-use embassy_util::channel::mpmc::{Channel, Receiver, Sender};
 use static_cell::StaticCell;
 use {defmt_rtt as _, panic_probe as _};
 
diff --git a/examples/nrf/src/bin/mutex.rs b/examples/nrf/src/bin/mutex.rs
index 876297883..c402c6ba1 100644
--- a/examples/nrf/src/bin/mutex.rs
+++ b/examples/nrf/src/bin/mutex.rs
@@ -4,9 +4,9 @@
 
 use defmt::{info, unwrap};
 use embassy_executor::Spawner;
+use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex;
+use embassy_sync::mutex::Mutex;
 use embassy_time::{Duration, Timer};
-use embassy_util::blocking_mutex::raw::ThreadModeRawMutex;
-use embassy_util::mutex::Mutex;
 use {defmt_rtt as _, panic_probe as _};
 
 static MUTEX: Mutex<ThreadModeRawMutex, u32> = Mutex::new(0);
diff --git a/examples/nrf/src/bin/pubsub.rs b/examples/nrf/src/bin/pubsub.rs
index 1d90217f2..64fed641b 100644
--- a/examples/nrf/src/bin/pubsub.rs
+++ b/examples/nrf/src/bin/pubsub.rs
@@ -4,9 +4,9 @@
 
 use defmt::unwrap;
 use embassy_executor::Spawner;
+use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex;
+use embassy_sync::channel::pubsub::{DynSubscriber, PubSubChannel, Subscriber};
 use embassy_time::{Duration, Timer};
-use embassy_util::blocking_mutex::raw::ThreadModeRawMutex;
-use embassy_util::channel::pubsub::{DynSubscriber, PubSubChannel, Subscriber};
 use {defmt_rtt as _, panic_probe as _};
 
 /// Create the message bus. It has a queue of 4, supports 3 subscribers and 1 publisher
diff --git a/examples/nrf/src/bin/uart_split.rs b/examples/nrf/src/bin/uart_split.rs
index dab8e475d..88b9c0a81 100644
--- a/examples/nrf/src/bin/uart_split.rs
+++ b/examples/nrf/src/bin/uart_split.rs
@@ -7,8 +7,8 @@ use embassy_executor::Spawner;
 use embassy_nrf::peripherals::UARTE0;
 use embassy_nrf::uarte::UarteRx;
 use embassy_nrf::{interrupt, uarte};
-use embassy_util::blocking_mutex::raw::ThreadModeRawMutex;
-use embassy_util::channel::mpmc::Channel;
+use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex;
+use embassy_sync::channel::mpmc::Channel;
 use {defmt_rtt as _, panic_probe as _};
 
 static CHANNEL: Channel<ThreadModeRawMutex, [u8; 8], 1> = Channel::new();
diff --git a/examples/nrf/src/bin/usb_ethernet.rs b/examples/nrf/src/bin/usb_ethernet.rs
index d427f7563..0200d8807 100644
--- a/examples/nrf/src/bin/usb_ethernet.rs
+++ b/examples/nrf/src/bin/usb_ethernet.rs
@@ -14,10 +14,10 @@ use embassy_net::{PacketBox, PacketBoxExt, PacketBuf, Stack, StackResources};
 use embassy_nrf::rng::Rng;
 use embassy_nrf::usb::{Driver, PowerUsb};
 use embassy_nrf::{interrupt, pac, peripherals};
+use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex;
+use embassy_sync::channel::mpmc::Channel;
 use embassy_usb::{Builder, Config, UsbDevice};
 use embassy_usb_ncm::{CdcNcmClass, Receiver, Sender, State};
-use embassy_util::blocking_mutex::raw::ThreadModeRawMutex;
-use embassy_util::channel::mpmc::Channel;
 use embedded_io::asynch::{Read, Write};
 use static_cell::StaticCell;
 use {defmt_rtt as _, panic_probe as _};
diff --git a/examples/nrf/src/bin/usb_hid_keyboard.rs b/examples/nrf/src/bin/usb_hid_keyboard.rs
index cf0078eec..d7c6dafdf 100644
--- a/examples/nrf/src/bin/usb_hid_keyboard.rs
+++ b/examples/nrf/src/bin/usb_hid_keyboard.rs
@@ -8,14 +8,14 @@ use core::sync::atomic::{AtomicBool, Ordering};
 
 use defmt::*;
 use embassy_executor::Spawner;
+use embassy_futures::{select, Either};
 use embassy_nrf::gpio::{Input, Pin, Pull};
 use embassy_nrf::usb::{Driver, PowerUsb};
 use embassy_nrf::{interrupt, pac};
+use embassy_sync::channel::signal::Signal;
 use embassy_usb::control::OutResponse;
 use embassy_usb::{Builder, Config, DeviceStateHandler};
 use embassy_usb_hid::{HidReaderWriter, ReportId, RequestHandler, State};
-use embassy_util::channel::signal::Signal;
-use embassy_util::{select, Either};
 use futures::future::join;
 use usbd_hid::descriptor::{KeyboardReport, SerializedDescriptor};
 use {defmt_rtt as _, panic_probe as _};
diff --git a/examples/rp/Cargo.toml b/examples/rp/Cargo.toml
index c2dcf429a..d804a660b 100644
--- a/examples/rp/Cargo.toml
+++ b/examples/rp/Cargo.toml
@@ -5,7 +5,7 @@ version = "0.1.0"
 
 
 [dependencies]
-embassy-util = { version = "0.1.0", path = "../../embassy-util", features = ["defmt"] }
+embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] }
 embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["defmt", "integrated-timers"] }
 embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] }
 embassy-rp = { version = "0.1.0", path = "../../embassy-rp", features = ["defmt", "unstable-traits", "nightly", "unstable-pac"] }
diff --git a/examples/std/Cargo.toml b/examples/std/Cargo.toml
index 164a2b42d..c7cec6b19 100644
--- a/examples/std/Cargo.toml
+++ b/examples/std/Cargo.toml
@@ -4,7 +4,7 @@ name = "embassy-std-examples"
 version = "0.1.0"
 
 [dependencies]
-embassy-util = { version = "0.1.0", path = "../../embassy-util", features = ["log"] }
+embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["log"] }
 embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["log", "std", "nightly", "integrated-timers"] }
 embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["log", "std", "nightly"] }
 embassy-net = { version = "0.1.0", path = "../../embassy-net", features=[ "std", "log", "medium-ethernet", "tcp", "udp", "dhcpv4", "pool-16"] }
diff --git a/examples/stm32f0/Cargo.toml b/examples/stm32f0/Cargo.toml
index 8476200d4..cd2995d2c 100644
--- a/examples/stm32f0/Cargo.toml
+++ b/examples/stm32f0/Cargo.toml
@@ -11,7 +11,7 @@ cortex-m-rt = "0.7.0"
 defmt = "0.3"
 defmt-rtt = "0.3"
 panic-probe = "0.3"
-embassy-util = { version = "0.1.0", path = "../../embassy-util", features = ["defmt"] }
+embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] }
 embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["defmt", "integrated-timers"] }
 embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-32768hz"] }
 embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "memory-x", "stm32f030f4", "time-driver-any"] }
diff --git a/examples/stm32f1/Cargo.toml b/examples/stm32f1/Cargo.toml
index fbc96400c..8660e743d 100644
--- a/examples/stm32f1/Cargo.toml
+++ b/examples/stm32f1/Cargo.toml
@@ -4,7 +4,7 @@ name = "embassy-stm32f1-examples"
 version = "0.1.0"
 
 [dependencies]
-embassy-util = { version = "0.1.0", path = "../../embassy-util", features = ["defmt"] }
+embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] }
 embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["defmt", "integrated-timers"] }
 embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-32768hz"] }
 embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32f103c8", "unstable-pac", "memory-x", "time-driver-any"]  }
diff --git a/examples/stm32f2/Cargo.toml b/examples/stm32f2/Cargo.toml
index 27894df50..b4bff4d85 100644
--- a/examples/stm32f2/Cargo.toml
+++ b/examples/stm32f2/Cargo.toml
@@ -4,7 +4,7 @@ name = "embassy-stm32f2-examples"
 version = "0.1.0"
 
 [dependencies]
-embassy-util = { version = "0.1.0", path = "../../embassy-util", features = ["defmt"] }
+embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] }
 embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["defmt", "integrated-timers"] }
 embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-32768hz"] }
 embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32f207zg", "unstable-pac", "memory-x", "time-driver-any", "exti"]  }
diff --git a/examples/stm32f3/Cargo.toml b/examples/stm32f3/Cargo.toml
index 4e6b0ea1e..d152b145f 100644
--- a/examples/stm32f3/Cargo.toml
+++ b/examples/stm32f3/Cargo.toml
@@ -4,7 +4,7 @@ name = "embassy-stm32f3-examples"
 version = "0.1.0"
 
 [dependencies]
-embassy-util = { version = "0.1.0", path = "../../embassy-util", features = ["defmt"] }
+embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] }
 embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["defmt", "integrated-timers"] }
 embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-32768hz"] }
 embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32f303ze", "unstable-pac", "memory-x", "time-driver-any", "exti"]  }
diff --git a/examples/stm32f3/src/bin/button_events.rs b/examples/stm32f3/src/bin/button_events.rs
index 61fc6dcab..edf34b4d1 100644
--- a/examples/stm32f3/src/bin/button_events.rs
+++ b/examples/stm32f3/src/bin/button_events.rs
@@ -15,9 +15,9 @@ use embassy_executor::Spawner;
 use embassy_stm32::exti::ExtiInput;
 use embassy_stm32::gpio::{AnyPin, Input, Level, Output, Pin, Pull, Speed};
 use embassy_stm32::peripherals::PA0;
+use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex;
+use embassy_sync::channel::mpmc::Channel;
 use embassy_time::{with_timeout, Duration, Timer};
-use embassy_util::blocking_mutex::raw::ThreadModeRawMutex;
-use embassy_util::channel::mpmc::Channel;
 use {defmt_rtt as _, panic_probe as _};
 
 struct Leds<'a> {
diff --git a/examples/stm32f4/Cargo.toml b/examples/stm32f4/Cargo.toml
index f93a1d0f9..9bfdda92d 100644
--- a/examples/stm32f4/Cargo.toml
+++ b/examples/stm32f4/Cargo.toml
@@ -5,7 +5,7 @@ version = "0.1.0"
 
 
 [dependencies]
-embassy-util = { version = "0.1.0", path = "../../embassy-util", features = ["defmt"] }
+embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] }
 embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["defmt", "integrated-timers"] }
 embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "unstable-traits", "tick-32768hz"] }
 embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "unstable-traits", "defmt", "stm32f429zi", "unstable-pac", "memory-x", "time-driver-any", "exti"]  }
diff --git a/examples/stm32f7/Cargo.toml b/examples/stm32f7/Cargo.toml
index e286d2310..a446fe3fb 100644
--- a/examples/stm32f7/Cargo.toml
+++ b/examples/stm32f7/Cargo.toml
@@ -4,7 +4,7 @@ name = "embassy-stm32f7-examples"
 version = "0.1.0"
 
 [dependencies]
-embassy-util = { version = "0.1.0", path = "../../embassy-util", features = ["defmt"] }
+embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] }
 embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["defmt", "integrated-timers"] }
 embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-32768hz"] }
 embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "net", "stm32f767zi", "unstable-pac", "time-driver-any", "exti"]  }
diff --git a/examples/stm32g0/Cargo.toml b/examples/stm32g0/Cargo.toml
index 5c80d43eb..30f2b86f8 100644
--- a/examples/stm32g0/Cargo.toml
+++ b/examples/stm32g0/Cargo.toml
@@ -4,7 +4,7 @@ name = "embassy-stm32g0-examples"
 version = "0.1.0"
 
 [dependencies]
-embassy-util = { version = "0.1.0", path = "../../embassy-util", features = ["defmt"] }
+embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] }
 embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["defmt", "integrated-timers"] }
 embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-32768hz"] }
 embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "time-driver-any", "stm32g071rb", "memory-x", "unstable-pac", "exti"]  }
diff --git a/examples/stm32g4/Cargo.toml b/examples/stm32g4/Cargo.toml
index 74c645cf5..f81df0b70 100644
--- a/examples/stm32g4/Cargo.toml
+++ b/examples/stm32g4/Cargo.toml
@@ -4,7 +4,7 @@ name = "embassy-stm32g4-examples"
 version = "0.1.0"
 
 [dependencies]
-embassy-util = { version = "0.1.0", path = "../../embassy-util", features = ["defmt"] }
+embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] }
 embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["defmt", "integrated-timers"] }
 embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-32768hz"] }
 embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "time-driver-any", "stm32g491re", "memory-x", "unstable-pac", "exti"]  }
diff --git a/examples/stm32h7/Cargo.toml b/examples/stm32h7/Cargo.toml
index fc5f74f99..0f76f3226 100644
--- a/examples/stm32h7/Cargo.toml
+++ b/examples/stm32h7/Cargo.toml
@@ -4,7 +4,7 @@ name = "embassy-stm32h7-examples"
 version = "0.1.0"
 
 [dependencies]
-embassy-util = { version = "0.1.0", path = "../../embassy-util", features = ["defmt"] }
+embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] }
 embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["defmt", "integrated-timers"] }
 embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "unstable-traits", "tick-32768hz"] }
 embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32h743bi", "net", "time-driver-any", "exti", "unstable-pac", "unstable-traits"] }
diff --git a/examples/stm32h7/src/bin/signal.rs b/examples/stm32h7/src/bin/signal.rs
index be2ac268e..ae41b07a9 100644
--- a/examples/stm32h7/src/bin/signal.rs
+++ b/examples/stm32h7/src/bin/signal.rs
@@ -4,8 +4,8 @@
 
 use defmt::{info, unwrap};
 use embassy_executor::Spawner;
+use embassy_sync::channel::signal::Signal;
 use embassy_time::{Duration, Timer};
-use embassy_util::channel::signal::Signal;
 use {defmt_rtt as _, panic_probe as _};
 
 static SIGNAL: Signal<u32> = Signal::new();
diff --git a/examples/stm32h7/src/bin/usart_split.rs b/examples/stm32h7/src/bin/usart_split.rs
index 64080ec45..55630dd39 100644
--- a/examples/stm32h7/src/bin/usart_split.rs
+++ b/examples/stm32h7/src/bin/usart_split.rs
@@ -7,8 +7,8 @@ use embassy_executor::Spawner;
 use embassy_stm32::dma::NoDma;
 use embassy_stm32::peripherals::{DMA1_CH1, UART7};
 use embassy_stm32::usart::{Config, Uart, UartRx};
-use embassy_util::blocking_mutex::raw::ThreadModeRawMutex;
-use embassy_util::channel::mpmc::Channel;
+use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex;
+use embassy_sync::channel::mpmc::Channel;
 use {defmt_rtt as _, panic_probe as _};
 
 #[embassy_executor::task]
diff --git a/examples/stm32l0/Cargo.toml b/examples/stm32l0/Cargo.toml
index 72365a640..11751a21d 100644
--- a/examples/stm32l0/Cargo.toml
+++ b/examples/stm32l0/Cargo.toml
@@ -8,7 +8,7 @@ default = ["nightly"]
 nightly = ["embassy-stm32/nightly", "embassy-lora", "lorawan-device", "lorawan", "embedded-io/async"]
 
 [dependencies]
-embassy-util = { version = "0.1.0", path = "../../embassy-util", features = ["defmt"] }
+embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] }
 embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["defmt", "integrated-timers"] }
 embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-32768hz"] }
 embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32l072cz", "time-driver-any", "exti", "unstable-traits", "memory-x"]  }
diff --git a/examples/stm32l1/Cargo.toml b/examples/stm32l1/Cargo.toml
index 43f844b67..18b35b305 100644
--- a/examples/stm32l1/Cargo.toml
+++ b/examples/stm32l1/Cargo.toml
@@ -4,7 +4,7 @@ name = "embassy-stm32l1-examples"
 version = "0.1.0"
 
 [dependencies]
-embassy-util = { version = "0.1.0", path = "../../embassy-util", features = ["defmt"] }
+embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] }
 embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["defmt", "integrated-timers"] }
 embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-32768hz"] }
 embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32l151cb-a", "time-driver-any", "memory-x"]  }
diff --git a/examples/stm32l4/Cargo.toml b/examples/stm32l4/Cargo.toml
index eaffa253e..cb7238e4c 100644
--- a/examples/stm32l4/Cargo.toml
+++ b/examples/stm32l4/Cargo.toml
@@ -6,7 +6,7 @@ version = "0.1.0"
 [features]
 
 [dependencies]
-embassy-util = { version = "0.1.0", path = "../../embassy-util", features = ["defmt"] }
+embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] }
 embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["defmt", "integrated-timers"] }
 embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-32768hz"] }
 embassy-embedded-hal = { version = "0.1.0", path = "../../embassy-embedded-hal" }
diff --git a/examples/stm32l5/Cargo.toml b/examples/stm32l5/Cargo.toml
index d8e78088a..624c73c26 100644
--- a/examples/stm32l5/Cargo.toml
+++ b/examples/stm32l5/Cargo.toml
@@ -6,7 +6,7 @@ version = "0.1.0"
 [features]
 
 [dependencies]
-embassy-util = { version = "0.1.0", path = "../../embassy-util", features = ["defmt"] }
+embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] }
 embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["defmt", "integrated-timers"] }
 embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-32768hz"] }
 embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "unstable-pac", "stm32l552ze", "time-driver-any", "exti", "unstable-traits", "memory-x"]  }
diff --git a/examples/stm32l5/src/bin/usb_ethernet.rs b/examples/stm32l5/src/bin/usb_ethernet.rs
index 959195518..b21d8629f 100644
--- a/examples/stm32l5/src/bin/usb_ethernet.rs
+++ b/examples/stm32l5/src/bin/usb_ethernet.rs
@@ -15,10 +15,10 @@ use embassy_stm32::rng::Rng;
 use embassy_stm32::time::Hertz;
 use embassy_stm32::usb::Driver;
 use embassy_stm32::{interrupt, Config};
+use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex;
+use embassy_sync::channel::mpmc::Channel;
 use embassy_usb::{Builder, UsbDevice};
 use embassy_usb_ncm::{CdcNcmClass, Receiver, Sender, State};
-use embassy_util::blocking_mutex::raw::ThreadModeRawMutex;
-use embassy_util::channel::mpmc::Channel;
 use embedded_io::asynch::{Read, Write};
 use rand_core::RngCore;
 use static_cell::StaticCell;
diff --git a/examples/stm32u5/Cargo.toml b/examples/stm32u5/Cargo.toml
index 48833664a..ff0ec9f42 100644
--- a/examples/stm32u5/Cargo.toml
+++ b/examples/stm32u5/Cargo.toml
@@ -4,7 +4,7 @@ name = "embassy-stm32u5-examples"
 version = "0.1.0"
 
 [dependencies]
-embassy-util = { version = "0.1.0", path = "../../embassy-util", features = ["defmt"] }
+embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] }
 embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["defmt", "integrated-timers"] }
 embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-32768hz"] }
 embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "unstable-pac", "stm32u585ai", "time-driver-any", "memory-x" ]  }
diff --git a/examples/stm32wb/Cargo.toml b/examples/stm32wb/Cargo.toml
index b46300764..3b10da0ad 100644
--- a/examples/stm32wb/Cargo.toml
+++ b/examples/stm32wb/Cargo.toml
@@ -4,7 +4,7 @@ name = "embassy-stm32wb-examples"
 version = "0.1.0"
 
 [dependencies]
-embassy-util = { version = "0.1.0", path = "../../embassy-util", features = ["defmt"] }
+embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] }
 embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["defmt", "integrated-timers"] }
 embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-32768hz"] }
 embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32wb55cc", "time-driver-any", "exti"]  }
diff --git a/examples/stm32wl/Cargo.toml b/examples/stm32wl/Cargo.toml
index ae33478af..5f6679f4b 100644
--- a/examples/stm32wl/Cargo.toml
+++ b/examples/stm32wl/Cargo.toml
@@ -4,7 +4,7 @@ name = "embassy-stm32wl-examples"
 version = "0.1.0"
 
 [dependencies]
-embassy-util = { version = "0.1.0", path = "../../embassy-util", features = ["defmt"] }
+embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] }
 embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["defmt", "integrated-timers"] }
 embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-32768hz"] }
 embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32wl55jc-cm4", "time-driver-any", "memory-x", "subghz", "unstable-pac", "exti"]  }
diff --git a/examples/stm32wl/src/bin/subghz.rs b/examples/stm32wl/src/bin/subghz.rs
index d16e3f5e4..6d54e8503 100644
--- a/examples/stm32wl/src/bin/subghz.rs
+++ b/examples/stm32wl/src/bin/subghz.rs
@@ -13,7 +13,7 @@ use embassy_stm32::gpio::{Input, Level, Output, Pull, Speed};
 use embassy_stm32::interrupt;
 use embassy_stm32::interrupt::{Interrupt, InterruptExt};
 use embassy_stm32::subghz::*;
-use embassy_util::channel::signal::Signal;
+use embassy_sync::channel::signal::Signal;
 use {defmt_rtt as _, panic_probe as _};
 
 const PING_DATA: &str = "PING";
diff --git a/examples/wasm/Cargo.toml b/examples/wasm/Cargo.toml
index c7f980366..194e8f4b8 100644
--- a/examples/wasm/Cargo.toml
+++ b/examples/wasm/Cargo.toml
@@ -7,7 +7,7 @@ version = "0.1.0"
 crate-type = ["cdylib"]
 
 [dependencies]
-embassy-util = { version = "0.1.0", path = "../../embassy-util", features = ["log"] }
+embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["log"] }
 embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["log", "wasm", "nightly", "integrated-timers"] }
 embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["log", "wasm", "nightly"] }
 
diff --git a/tests/rp/Cargo.toml b/tests/rp/Cargo.toml
index 8740cc488..4d6877ccd 100644
--- a/tests/rp/Cargo.toml
+++ b/tests/rp/Cargo.toml
@@ -4,7 +4,7 @@ name = "embassy-rp-tests"
 version = "0.1.0"
 
 [dependencies]
-embassy-util = { version = "0.1.0", path = "../../embassy-util", features = ["defmt"] }
+embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] }
 embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["defmt", "integrated-timers"] }
 embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt"] }
 embassy-rp = { version = "0.1.0", path = "../../embassy-rp", features = ["nightly", "defmt", "unstable-pac", "unstable-traits"]  }
diff --git a/tests/stm32/Cargo.toml b/tests/stm32/Cargo.toml
index 1d12995a2..f1441d00c 100644
--- a/tests/stm32/Cargo.toml
+++ b/tests/stm32/Cargo.toml
@@ -13,7 +13,7 @@ stm32wb55rg = ["embassy-stm32/stm32wb55rg"]     # Nucleo
 stm32u585ai = ["embassy-stm32/stm32u585ai"]     # IoT board
 
 [dependencies]
-embassy-util = { version = "0.1.0", path = "../../embassy-util", features = ["defmt"] }
+embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] }
 embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["defmt", "integrated-timers"] }
 embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "tick-32768hz"] }
 embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "unstable-pac", "memory-x", "time-driver-tim2"]  }

From 5677b13a86beca58aa57ecfd7cea0db7ceb189fa Mon Sep 17 00:00:00 2001
From: Dario Nieuwenhuis <dirbaio@dirbaio.net>
Date: Mon, 22 Aug 2022 22:00:06 +0200
Subject: [PATCH 21/21] sync: flatten module structure.

---
 embassy-lora/src/stm32wl/mod.rs                     | 2 +-
 embassy-sync/src/{channel/mpmc.rs => channel.rs}    | 2 +-
 embassy-sync/src/channel/mod.rs                     | 5 -----
 embassy-sync/src/lib.rs                             | 2 ++
 embassy-sync/src/{channel => }/pubsub/mod.rs        | 4 ++--
 embassy-sync/src/{channel => }/pubsub/publisher.rs  | 0
 embassy-sync/src/{channel => }/pubsub/subscriber.rs | 0
 embassy-sync/src/{channel => }/signal.rs            | 2 +-
 examples/nrf/src/bin/channel.rs                     | 2 +-
 examples/nrf/src/bin/channel_sender_receiver.rs     | 2 +-
 examples/nrf/src/bin/pubsub.rs                      | 2 +-
 examples/nrf/src/bin/uart_split.rs                  | 2 +-
 examples/nrf/src/bin/usb_ethernet.rs                | 2 +-
 examples/nrf/src/bin/usb_hid_keyboard.rs            | 2 +-
 examples/stm32f3/src/bin/button_events.rs           | 2 +-
 examples/stm32h7/src/bin/signal.rs                  | 2 +-
 examples/stm32h7/src/bin/usart_split.rs             | 2 +-
 examples/stm32l5/src/bin/usb_ethernet.rs            | 2 +-
 examples/stm32wl/src/bin/subghz.rs                  | 2 +-
 19 files changed, 18 insertions(+), 21 deletions(-)
 rename embassy-sync/src/{channel/mpmc.rs => channel.rs} (99%)
 delete mode 100644 embassy-sync/src/channel/mod.rs
 rename embassy-sync/src/{channel => }/pubsub/mod.rs (99%)
 rename embassy-sync/src/{channel => }/pubsub/publisher.rs (100%)
 rename embassy-sync/src/{channel => }/pubsub/subscriber.rs (100%)
 rename embassy-sync/src/{channel => }/signal.rs (98%)

diff --git a/embassy-lora/src/stm32wl/mod.rs b/embassy-lora/src/stm32wl/mod.rs
index 374c8532f..7822d0153 100644
--- a/embassy-lora/src/stm32wl/mod.rs
+++ b/embassy-lora/src/stm32wl/mod.rs
@@ -12,7 +12,7 @@ use embassy_stm32::subghz::{
     Status, SubGhz, TcxoMode, TcxoTrim, Timeout, TxParams,
 };
 use embassy_stm32::Peripheral;
-use embassy_sync::channel::signal::Signal;
+use embassy_sync::signal::Signal;
 use lorawan_device::async_device::radio::{Bandwidth, PhyRxTx, RfConfig, RxQuality, SpreadingFactor, TxConfig};
 use lorawan_device::async_device::Timings;
 
diff --git a/embassy-sync/src/channel/mpmc.rs b/embassy-sync/src/channel.rs
similarity index 99%
rename from embassy-sync/src/channel/mpmc.rs
rename to embassy-sync/src/channel.rs
index 7bebd3412..76f42d0e7 100644
--- a/embassy-sync/src/channel/mpmc.rs
+++ b/embassy-sync/src/channel.rs
@@ -373,7 +373,7 @@ where
     /// Establish a new bounded channel. For example, to create one with a NoopMutex:
     ///
     /// ```
-    /// use embassy_sync::channel::mpmc::Channel;
+    /// use embassy_sync::channel::Channel;
     /// use embassy_sync::blocking_mutex::raw::NoopRawMutex;
     ///
     /// // Declare a bounded channel of 3 u32s.
diff --git a/embassy-sync/src/channel/mod.rs b/embassy-sync/src/channel/mod.rs
deleted file mode 100644
index 5df1f5c5c..000000000
--- a/embassy-sync/src/channel/mod.rs
+++ /dev/null
@@ -1,5 +0,0 @@
-//! Async channels
-
-pub mod mpmc;
-pub mod pubsub;
-pub mod signal;
diff --git a/embassy-sync/src/lib.rs b/embassy-sync/src/lib.rs
index 7d8815903..8e81e5cbe 100644
--- a/embassy-sync/src/lib.rs
+++ b/embassy-sync/src/lib.rs
@@ -14,4 +14,6 @@ pub mod blocking_mutex;
 pub mod channel;
 pub mod mutex;
 pub mod pipe;
+pub mod pubsub;
+pub mod signal;
 pub mod waitqueue;
diff --git a/embassy-sync/src/channel/pubsub/mod.rs b/embassy-sync/src/pubsub/mod.rs
similarity index 99%
rename from embassy-sync/src/channel/pubsub/mod.rs
rename to embassy-sync/src/pubsub/mod.rs
index f62b4d118..62a9e4763 100644
--- a/embassy-sync/src/channel/pubsub/mod.rs
+++ b/embassy-sync/src/pubsub/mod.rs
@@ -34,8 +34,8 @@ pub use subscriber::{DynSubscriber, Subscriber};
 ///
 /// ```
 /// # use embassy_sync::blocking_mutex::raw::NoopRawMutex;
-/// # use embassy_sync::channel::pubsub::WaitResult;
-/// # use embassy_sync::channel::pubsub::PubSubChannel;
+/// # use embassy_sync::pubsub::WaitResult;
+/// # use embassy_sync::pubsub::PubSubChannel;
 /// # use futures_executor::block_on;
 /// # let test = async {
 /// // Create the channel. This can be static as well
diff --git a/embassy-sync/src/channel/pubsub/publisher.rs b/embassy-sync/src/pubsub/publisher.rs
similarity index 100%
rename from embassy-sync/src/channel/pubsub/publisher.rs
rename to embassy-sync/src/pubsub/publisher.rs
diff --git a/embassy-sync/src/channel/pubsub/subscriber.rs b/embassy-sync/src/pubsub/subscriber.rs
similarity index 100%
rename from embassy-sync/src/channel/pubsub/subscriber.rs
rename to embassy-sync/src/pubsub/subscriber.rs
diff --git a/embassy-sync/src/channel/signal.rs b/embassy-sync/src/signal.rs
similarity index 98%
rename from embassy-sync/src/channel/signal.rs
rename to embassy-sync/src/signal.rs
index 9279266c1..3f665e388 100644
--- a/embassy-sync/src/channel/signal.rs
+++ b/embassy-sync/src/signal.rs
@@ -19,7 +19,7 @@ use core::task::{Context, Poll, Waker};
 /// Signals are generally declared as `static`s and then borrowed as required.
 ///
 /// ```
-/// use embassy_sync::channel::signal::Signal;
+/// use embassy_sync::signal::Signal;
 ///
 /// enum SomeCommand {
 ///   On,
diff --git a/examples/nrf/src/bin/channel.rs b/examples/nrf/src/bin/channel.rs
index 8371fd0af..d782a79e7 100644
--- a/examples/nrf/src/bin/channel.rs
+++ b/examples/nrf/src/bin/channel.rs
@@ -6,7 +6,7 @@ use defmt::unwrap;
 use embassy_executor::Spawner;
 use embassy_nrf::gpio::{Level, Output, OutputDrive};
 use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex;
-use embassy_sync::channel::mpmc::Channel;
+use embassy_sync::channel::Channel;
 use embassy_time::{Duration, Timer};
 use {defmt_rtt as _, panic_probe as _};
 
diff --git a/examples/nrf/src/bin/channel_sender_receiver.rs b/examples/nrf/src/bin/channel_sender_receiver.rs
index 55d1fccb2..fcccdaed5 100644
--- a/examples/nrf/src/bin/channel_sender_receiver.rs
+++ b/examples/nrf/src/bin/channel_sender_receiver.rs
@@ -6,7 +6,7 @@ use defmt::unwrap;
 use embassy_executor::Spawner;
 use embassy_nrf::gpio::{AnyPin, Level, Output, OutputDrive, Pin};
 use embassy_sync::blocking_mutex::raw::NoopRawMutex;
-use embassy_sync::channel::mpmc::{Channel, Receiver, Sender};
+use embassy_sync::channel::{Channel, Receiver, Sender};
 use embassy_time::{Duration, Timer};
 use static_cell::StaticCell;
 use {defmt_rtt as _, panic_probe as _};
diff --git a/examples/nrf/src/bin/pubsub.rs b/examples/nrf/src/bin/pubsub.rs
index 64fed641b..688e6d075 100644
--- a/examples/nrf/src/bin/pubsub.rs
+++ b/examples/nrf/src/bin/pubsub.rs
@@ -5,7 +5,7 @@
 use defmt::unwrap;
 use embassy_executor::Spawner;
 use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex;
-use embassy_sync::channel::pubsub::{DynSubscriber, PubSubChannel, Subscriber};
+use embassy_sync::pubsub::{DynSubscriber, PubSubChannel, Subscriber};
 use embassy_time::{Duration, Timer};
 use {defmt_rtt as _, panic_probe as _};
 
diff --git a/examples/nrf/src/bin/uart_split.rs b/examples/nrf/src/bin/uart_split.rs
index 88b9c0a81..1adaf53fd 100644
--- a/examples/nrf/src/bin/uart_split.rs
+++ b/examples/nrf/src/bin/uart_split.rs
@@ -8,7 +8,7 @@ use embassy_nrf::peripherals::UARTE0;
 use embassy_nrf::uarte::UarteRx;
 use embassy_nrf::{interrupt, uarte};
 use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex;
-use embassy_sync::channel::mpmc::Channel;
+use embassy_sync::channel::Channel;
 use {defmt_rtt as _, panic_probe as _};
 
 static CHANNEL: Channel<ThreadModeRawMutex, [u8; 8], 1> = Channel::new();
diff --git a/examples/nrf/src/bin/usb_ethernet.rs b/examples/nrf/src/bin/usb_ethernet.rs
index 0200d8807..ca6c7e0d1 100644
--- a/examples/nrf/src/bin/usb_ethernet.rs
+++ b/examples/nrf/src/bin/usb_ethernet.rs
@@ -15,7 +15,7 @@ use embassy_nrf::rng::Rng;
 use embassy_nrf::usb::{Driver, PowerUsb};
 use embassy_nrf::{interrupt, pac, peripherals};
 use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex;
-use embassy_sync::channel::mpmc::Channel;
+use embassy_sync::channel::Channel;
 use embassy_usb::{Builder, Config, UsbDevice};
 use embassy_usb_ncm::{CdcNcmClass, Receiver, Sender, State};
 use embedded_io::asynch::{Read, Write};
diff --git a/examples/nrf/src/bin/usb_hid_keyboard.rs b/examples/nrf/src/bin/usb_hid_keyboard.rs
index d7c6dafdf..ba2159c72 100644
--- a/examples/nrf/src/bin/usb_hid_keyboard.rs
+++ b/examples/nrf/src/bin/usb_hid_keyboard.rs
@@ -12,7 +12,7 @@ use embassy_futures::{select, Either};
 use embassy_nrf::gpio::{Input, Pin, Pull};
 use embassy_nrf::usb::{Driver, PowerUsb};
 use embassy_nrf::{interrupt, pac};
-use embassy_sync::channel::signal::Signal;
+use embassy_sync::signal::Signal;
 use embassy_usb::control::OutResponse;
 use embassy_usb::{Builder, Config, DeviceStateHandler};
 use embassy_usb_hid::{HidReaderWriter, ReportId, RequestHandler, State};
diff --git a/examples/stm32f3/src/bin/button_events.rs b/examples/stm32f3/src/bin/button_events.rs
index edf34b4d1..02c475f66 100644
--- a/examples/stm32f3/src/bin/button_events.rs
+++ b/examples/stm32f3/src/bin/button_events.rs
@@ -16,7 +16,7 @@ use embassy_stm32::exti::ExtiInput;
 use embassy_stm32::gpio::{AnyPin, Input, Level, Output, Pin, Pull, Speed};
 use embassy_stm32::peripherals::PA0;
 use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex;
-use embassy_sync::channel::mpmc::Channel;
+use embassy_sync::channel::Channel;
 use embassy_time::{with_timeout, Duration, Timer};
 use {defmt_rtt as _, panic_probe as _};
 
diff --git a/examples/stm32h7/src/bin/signal.rs b/examples/stm32h7/src/bin/signal.rs
index ae41b07a9..cc3e4e3ca 100644
--- a/examples/stm32h7/src/bin/signal.rs
+++ b/examples/stm32h7/src/bin/signal.rs
@@ -4,7 +4,7 @@
 
 use defmt::{info, unwrap};
 use embassy_executor::Spawner;
-use embassy_sync::channel::signal::Signal;
+use embassy_sync::signal::Signal;
 use embassy_time::{Duration, Timer};
 use {defmt_rtt as _, panic_probe as _};
 
diff --git a/examples/stm32h7/src/bin/usart_split.rs b/examples/stm32h7/src/bin/usart_split.rs
index 55630dd39..df2b600f8 100644
--- a/examples/stm32h7/src/bin/usart_split.rs
+++ b/examples/stm32h7/src/bin/usart_split.rs
@@ -8,7 +8,7 @@ use embassy_stm32::dma::NoDma;
 use embassy_stm32::peripherals::{DMA1_CH1, UART7};
 use embassy_stm32::usart::{Config, Uart, UartRx};
 use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex;
-use embassy_sync::channel::mpmc::Channel;
+use embassy_sync::channel::Channel;
 use {defmt_rtt as _, panic_probe as _};
 
 #[embassy_executor::task]
diff --git a/examples/stm32l5/src/bin/usb_ethernet.rs b/examples/stm32l5/src/bin/usb_ethernet.rs
index b21d8629f..3286f5c4d 100644
--- a/examples/stm32l5/src/bin/usb_ethernet.rs
+++ b/examples/stm32l5/src/bin/usb_ethernet.rs
@@ -16,7 +16,7 @@ use embassy_stm32::time::Hertz;
 use embassy_stm32::usb::Driver;
 use embassy_stm32::{interrupt, Config};
 use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex;
-use embassy_sync::channel::mpmc::Channel;
+use embassy_sync::channel::Channel;
 use embassy_usb::{Builder, UsbDevice};
 use embassy_usb_ncm::{CdcNcmClass, Receiver, Sender, State};
 use embedded_io::asynch::{Read, Write};
diff --git a/examples/stm32wl/src/bin/subghz.rs b/examples/stm32wl/src/bin/subghz.rs
index 6d54e8503..c5e9bb597 100644
--- a/examples/stm32wl/src/bin/subghz.rs
+++ b/examples/stm32wl/src/bin/subghz.rs
@@ -13,7 +13,7 @@ use embassy_stm32::gpio::{Input, Level, Output, Pull, Speed};
 use embassy_stm32::interrupt;
 use embassy_stm32::interrupt::{Interrupt, InterruptExt};
 use embassy_stm32::subghz::*;
-use embassy_sync::channel::signal::Signal;
+use embassy_sync::signal::Signal;
 use {defmt_rtt as _, panic_probe as _};
 
 const PING_DATA: &str = "PING";