aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMehmet Ali Anil <[email protected]>2023-03-07 10:46:59 +0100
committerMehmet Ali Anil <[email protected]>2023-03-07 23:16:54 +0100
commit935633c90b817b15c6c2cf180e107992ad5dd9a6 (patch)
tree5e4c33aa5992a7eb941a0920b0c080a624cd15a5
parentbc0cb43307c2a46330ce253505203dbc607bcc6c (diff)
parent18fe398673f55b07159d01a230910bb9689c1525 (diff)
Merge upstream
-rw-r--r--README.md4
-rwxr-xr-xci.sh1
-rw-r--r--embassy-boot/boot/src/lib.rs60
-rw-r--r--embassy-cortex-m/src/executor.rs99
-rw-r--r--embassy-cortex-m/src/interrupt.rs36
-rw-r--r--embassy-futures/src/yield_now.rs1
-rw-r--r--embassy-hal-common/src/atomic_ring_buffer.rs245
-rw-r--r--embassy-macros/src/macros/cortex_m_interrupt_declare.rs4
-rw-r--r--embassy-macros/src/macros/cortex_m_interrupt_take.rs2
-rw-r--r--embassy-net/src/lib.rs16
-rw-r--r--embassy-nrf/src/buffered_uarte.rs828
-rw-r--r--embassy-nrf/src/chips/nrf52805.rs4
-rw-r--r--embassy-nrf/src/chips/nrf52810.rs6
-rw-r--r--embassy-nrf/src/chips/nrf52811.rs6
-rw-r--r--embassy-nrf/src/chips/nrf52820.rs4
-rw-r--r--embassy-nrf/src/chips/nrf52832.rs9
-rw-r--r--embassy-nrf/src/chips/nrf52833.rs6
-rw-r--r--embassy-nrf/src/chips/nrf52840.rs6
-rw-r--r--embassy-nrf/src/chips/nrf5340_app.rs21
-rw-r--r--embassy-nrf/src/chips/nrf5340_net.rs5
-rw-r--r--embassy-nrf/src/chips/nrf9160.rs2
-rw-r--r--embassy-nrf/src/gpiote.rs1
-rw-r--r--embassy-nrf/src/i2s.rs77
-rw-r--r--embassy-nrf/src/lib.rs44
-rw-r--r--embassy-nrf/src/pdm.rs131
-rw-r--r--embassy-nrf/src/ppi/dppi.rs2
-rw-r--r--embassy-nrf/src/ppi/mod.rs104
-rw-r--r--embassy-nrf/src/ppi/ppi.rs2
-rw-r--r--embassy-nrf/src/qdec.rs112
-rw-r--r--embassy-nrf/src/qspi.rs296
-rw-r--r--embassy-nrf/src/rng.rs193
-rw-r--r--embassy-nrf/src/saadc.rs62
-rw-r--r--embassy-nrf/src/spim.rs59
-rw-r--r--embassy-nrf/src/spis.rs85
-rw-r--r--embassy-nrf/src/temp.rs35
-rw-r--r--embassy-nrf/src/timer.rs143
-rw-r--r--embassy-nrf/src/twim.rs47
-rw-r--r--embassy-nrf/src/twis.rs55
-rw-r--r--embassy-nrf/src/uarte.rs90
-rw-r--r--embassy-nrf/src/usb/mod.rs (renamed from embassy-nrf/src/usb.rs)234
-rw-r--r--embassy-nrf/src/usb/vbus_detect.rs177
-rw-r--r--embassy-rp/src/adc.rs11
-rw-r--r--embassy-rp/src/dma.rs1
-rw-r--r--embassy-rp/src/gpio.rs19
-rw-r--r--embassy-rp/src/pio.rs3
-rw-r--r--embassy-rp/src/uart/mod.rs49
-rw-r--r--embassy-stm32/src/dma/mod.rs1
-rw-r--r--embassy-stm32/src/eth/mod.rs8
-rw-r--r--embassy-stm32/src/exti.rs1
-rw-r--r--embassy-stm32/src/spi/mod.rs6
-rw-r--r--embassy-sync/src/channel.rs4
-rw-r--r--embassy-sync/src/pipe.rs2
-rw-r--r--embassy-time/src/timer.rs17
-rw-r--r--embassy-usb/src/class/cdc_acm.rs100
-rw-r--r--examples/nrf52840/Cargo.toml7
-rw-r--r--examples/nrf52840/src/bin/awaitable_timer.rs26
-rw-r--r--examples/nrf52840/src/bin/buffered_uart.rs23
-rw-r--r--examples/nrf52840/src/bin/i2s_effect.rs15
-rw-r--r--examples/nrf52840/src/bin/i2s_monitor.rs9
-rw-r--r--examples/nrf52840/src/bin/i2s_waveform.rs9
-rw-r--r--examples/nrf52840/src/bin/lora_p2p_report.rs9
-rw-r--r--examples/nrf52840/src/bin/lora_p2p_sense.rs9
-rw-r--r--examples/nrf52840/src/bin/multiprio.rs32
-rw-r--r--examples/nrf52840/src/bin/pdm.rs10
-rw-r--r--examples/nrf52840/src/bin/qdec.rs9
-rw-r--r--examples/nrf52840/src/bin/qspi.rs24
-rw-r--r--examples/nrf52840/src/bin/qspi_lowpower.rs14
-rw-r--r--examples/nrf52840/src/bin/rng.rs8
-rw-r--r--examples/nrf52840/src/bin/saadc.rs8
-rw-r--r--examples/nrf52840/src/bin/saadc_continuous.rs8
-rw-r--r--examples/nrf52840/src/bin/spim.rs9
-rw-r--r--examples/nrf52840/src/bin/spis.rs9
-rw-r--r--examples/nrf52840/src/bin/temp.rs9
-rw-r--r--examples/nrf52840/src/bin/twim.rs9
-rw-r--r--examples/nrf52840/src/bin/twim_lowpower.rs9
-rw-r--r--examples/nrf52840/src/bin/twis.rs12
-rw-r--r--examples/nrf52840/src/bin/uart.rs9
-rw-r--r--examples/nrf52840/src/bin/uart_idle.rs10
-rw-r--r--examples/nrf52840/src/bin/uart_split.rs9
-rw-r--r--examples/nrf52840/src/bin/usb_ethernet.rs41
-rw-r--r--examples/nrf52840/src/bin/usb_hid_keyboard.rs16
-rw-r--r--examples/nrf52840/src/bin/usb_hid_mouse.rs16
-rw-r--r--examples/nrf52840/src/bin/usb_serial.rs16
-rw-r--r--examples/nrf52840/src/bin/usb_serial_multitask.rs51
-rw-r--r--examples/nrf52840/src/bin/usb_serial_winusb.rs14
-rw-r--r--examples/nrf5340/Cargo.toml23
-rw-r--r--examples/nrf5340/src/bin/uart.rs10
-rw-r--r--examples/std/src/bin/net.rs2
-rw-r--r--examples/std/src/bin/net_dns.rs2
-rw-r--r--examples/std/src/bin/net_udp.rs2
-rw-r--r--examples/stm32f0/Cargo.toml2
-rw-r--r--examples/stm32f0/src/bin/multiprio.rs (renamed from examples/stm32f0/src/bin/priority.rs)32
-rw-r--r--examples/stm32f3/src/bin/multiprio.rs36
-rw-r--r--examples/stm32f4/Cargo.toml6
-rw-r--r--examples/stm32f4/src/bin/multiprio.rs36
-rw-r--r--examples/stm32f4/src/bin/usb_ethernet.rs11
-rw-r--r--examples/stm32l4/Cargo.toml2
-rw-r--r--examples/stm32l5/Cargo.toml2
-rw-r--r--tests/nrf/.cargo/config.toml9
-rw-r--r--tests/nrf/Cargo.toml20
-rw-r--r--tests/nrf/build.rs16
-rw-r--r--tests/nrf/link_ram.x254
-rw-r--r--tests/nrf/memory.x5
-rw-r--r--tests/nrf/src/bin/buffered_uart.rs78
-rw-r--r--tests/nrf/src/bin/buffered_uart_spam.rs91
105 files changed, 3053 insertions, 1581 deletions
diff --git a/README.md b/README.md
index 938f2f4a6..33f38dafe 100644
--- a/README.md
+++ b/README.md
@@ -14,6 +14,10 @@ Rust's <a href="https://rust-lang.github.io/async-book/">async/await</a> allows
14- **Hardware Abstraction Layers** - HALs implement safe, idiomatic Rust APIs to use the hardware capabilities, so raw register manipulation is not needed. The Embassy project maintains HALs for select hardware, but you can still use HALs from other projects with Embassy. 14- **Hardware Abstraction Layers** - HALs implement safe, idiomatic Rust APIs to use the hardware capabilities, so raw register manipulation is not needed. The Embassy project maintains HALs for select hardware, but you can still use HALs from other projects with Embassy.
15 - <a href="https://docs.embassy.dev/embassy-stm32/">embassy-stm32</a>, for all STM32 microcontroller families. 15 - <a href="https://docs.embassy.dev/embassy-stm32/">embassy-stm32</a>, for all STM32 microcontroller families.
16 - <a href="https://docs.embassy.dev/embassy-nrf/">embassy-nrf</a>, for the Nordic Semiconductor nRF52, nRF53, nRF91 series. 16 - <a href="https://docs.embassy.dev/embassy-nrf/">embassy-nrf</a>, for the Nordic Semiconductor nRF52, nRF53, nRF91 series.
17 - <a href="https://docs.embassy.dev/embassy-rp/">embassy-rp</a>, for the Raspberry Pi RP2040 microcontroller.
18 - <a href="https://github.com/esp-rs">esp-rs</a>, for the Espressif Systems ESP32 series of chips.
19 - Embassy HAL support for Espressif chips is being developed in the [esp-rs/esp-hal](https://github.com/esp-rs/esp-hal) repository.
20 - Async WiFi, Bluetooth and ESP-NOW is being developed in the [esp-rs/esp-wifi](https://github.com/esp-rs/esp-wifi) repository.
17 21
18- **Time that Just Works** - 22- **Time that Just Works** -
19No more messing with hardware timers. <a href="https://docs.embassy.dev/embassy-time">embassy_time</a> provides Instant, Duration and Timer types that are globally available and never overflow. 23No more messing with hardware timers. <a href="https://docs.embassy.dev/embassy-time">embassy_time</a> provides Instant, Duration and Timer types that are globally available and never overflow.
diff --git a/ci.sh b/ci.sh
index 417937d07..bbcb26bdb 100755
--- a/ci.sh
+++ b/ci.sh
@@ -133,6 +133,7 @@ cargo batch \
133 --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32wb55rg --out-dir out/tests/nucleo-stm32wb55rg \ 133 --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32wb55rg --out-dir out/tests/nucleo-stm32wb55rg \
134 --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32u585ai --out-dir out/tests/iot-stm32u585ai \ 134 --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32u585ai --out-dir out/tests/iot-stm32u585ai \
135 --- build --release --manifest-path tests/rp/Cargo.toml --target thumbv6m-none-eabi --out-dir out/tests/rpi-pico \ 135 --- build --release --manifest-path tests/rp/Cargo.toml --target thumbv6m-none-eabi --out-dir out/tests/rpi-pico \
136 --- build --release --manifest-path tests/nrf/Cargo.toml --target thumbv7em-none-eabi --out-dir out/tests/nrf52840-dk \
136 $BUILD_EXTRA 137 $BUILD_EXTRA
137 138
138 139
diff --git a/embassy-boot/boot/src/lib.rs b/embassy-boot/boot/src/lib.rs
index b5dad5046..4dd1ebe06 100644
--- a/embassy-boot/boot/src/lib.rs
+++ b/embassy-boot/boot/src/lib.rs
@@ -1,4 +1,5 @@
1#![feature(type_alias_impl_trait)] 1#![feature(async_fn_in_trait)]
2#![allow(incomplete_features)]
2#![no_std] 3#![no_std]
3#![warn(missing_docs)] 4#![warn(missing_docs)]
4#![doc = include_str!("../README.md")] 5#![doc = include_str!("../README.md")]
@@ -1196,8 +1197,6 @@ impl FirmwareWriter {
1196#[cfg(test)] 1197#[cfg(test)]
1197mod tests { 1198mod tests {
1198 use core::convert::Infallible; 1199 use core::convert::Infallible;
1199 use core::future::Future;
1200
1201 use embedded_storage::nor_flash::ErrorType; 1200 use embedded_storage::nor_flash::ErrorType;
1202 use embedded_storage_async::nor_flash::ReadNorFlash as AsyncReadNorFlash; 1201 use embedded_storage_async::nor_flash::ReadNorFlash as AsyncReadNorFlash;
1203 use futures::executor::block_on; 1202 use futures::executor::block_on;
@@ -1424,7 +1423,7 @@ mod tests {
1424 } 1423 }
1425 1424
1426 #[test] 1425 #[test]
1427 #[cfg(feature = "_verify")] 1426 #[cfg(feature="_verify")]
1428 fn test_verify() { 1427 fn test_verify() {
1429 // The following key setup is based on: 1428 // The following key setup is based on:
1430 // https://docs.rs/ed25519-dalek/latest/ed25519_dalek/#example 1429 // https://docs.rs/ed25519-dalek/latest/ed25519_dalek/#example
@@ -1535,13 +1534,10 @@ mod tests {
1535 { 1534 {
1536 const READ_SIZE: usize = 1; 1535 const READ_SIZE: usize = 1;
1537 1536
1538 type ReadFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a; 1537 async fn read(&mut self, offset: u32, buf: &mut [u8]) -> Result<(), Self::Error> {
1539 fn read<'a>(&'a mut self, offset: u32, buf: &'a mut [u8]) -> Self::ReadFuture<'a> {
1540 async move {
1541 let len = buf.len(); 1538 let len = buf.len();
1542 buf[..].copy_from_slice(&self.0[offset as usize..offset as usize + len]); 1539 buf[..].copy_from_slice(&self.0[offset as usize..offset as usize + len]);
1543 Ok(()) 1540 Ok(())
1544 }
1545 } 1541 }
1546 1542
1547 fn capacity(&self) -> usize { 1543 fn capacity(&self) -> usize {
@@ -1555,38 +1551,32 @@ mod tests {
1555 const WRITE_SIZE: usize = WRITE_SIZE; 1551 const WRITE_SIZE: usize = WRITE_SIZE;
1556 const ERASE_SIZE: usize = ERASE_SIZE; 1552 const ERASE_SIZE: usize = ERASE_SIZE;
1557 1553
1558 type EraseFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a; 1554 async fn erase(&mut self, from: u32, to: u32) -> Result<(), Self::Error> {
1559 fn erase(&mut self, from: u32, to: u32) -> Self::EraseFuture<'_> { 1555 let from = from as usize;
1560 async move { 1556 let to = to as usize;
1561 let from = from as usize; 1557 assert!(from % ERASE_SIZE == 0);
1562 let to = to as usize; 1558 assert!(to % ERASE_SIZE == 0);
1563 assert!(from % ERASE_SIZE == 0); 1559 for i in from..to {
1564 assert!(to % ERASE_SIZE == 0); 1560 self.0[i] = 0xFF;
1565 for i in from..to {
1566 self.0[i] = 0xFF;
1567 }
1568 Ok(())
1569 } 1561 }
1562 Ok(())
1570 } 1563 }
1571 1564
1572 type WriteFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a; 1565 async fn write(&mut self, offset: u32, data: &[u8]) -> Result<(), Self::Error> {
1573 fn write<'a>(&'a mut self, offset: u32, data: &'a [u8]) -> Self::WriteFuture<'a> {
1574 info!("Writing {} bytes to 0x{:x}", data.len(), offset); 1566 info!("Writing {} bytes to 0x{:x}", data.len(), offset);
1575 async move { 1567 assert!(data.len() % WRITE_SIZE == 0);
1576 assert!(data.len() % WRITE_SIZE == 0); 1568 assert!(offset as usize % WRITE_SIZE == 0);
1577 assert!(offset as usize % WRITE_SIZE == 0); 1569 assert!(
1578 assert!( 1570 offset as usize + data.len() <= SIZE,
1579 offset as usize + data.len() <= SIZE, 1571 "OFFSET: {}, LEN: {}, FLASH SIZE: {}",
1580 "OFFSET: {}, LEN: {}, FLASH SIZE: {}", 1572 offset,
1581 offset, 1573 data.len(),
1582 data.len(), 1574 SIZE
1583 SIZE 1575 );
1584 );
1585
1586 self.0[offset as usize..offset as usize + data.len()].copy_from_slice(data);
1587 1576
1588 Ok(()) 1577 self.0[offset as usize..offset as usize + data.len()].copy_from_slice(data);
1589 } 1578
1579 Ok(())
1590 } 1580 }
1591 } 1581 }
1592} 1582}
diff --git a/embassy-cortex-m/src/executor.rs b/embassy-cortex-m/src/executor.rs
index 0d1745d8a..558539e73 100644
--- a/embassy-cortex-m/src/executor.rs
+++ b/embassy-cortex-m/src/executor.rs
@@ -1,18 +1,22 @@
1//! Executor specific to cortex-m devices. 1//! Executor specific to cortex-m devices.
2use core::marker::PhantomData;
3 2
3use core::cell::UnsafeCell;
4use core::mem::MaybeUninit;
5
6use atomic_polyfill::{AtomicBool, Ordering};
7use cortex_m::interrupt::InterruptNumber;
8use cortex_m::peripheral::NVIC;
4pub use embassy_executor::*; 9pub use embassy_executor::*;
5 10
6use crate::interrupt::{Interrupt, InterruptExt}; 11#[derive(Clone, Copy)]
12struct N(u16);
13unsafe impl cortex_m::interrupt::InterruptNumber for N {
14 fn number(self) -> u16 {
15 self.0
16 }
17}
7 18
8fn pend_by_number(n: u16) { 19fn pend_by_number(n: u16) {
9 #[derive(Clone, Copy)]
10 struct N(u16);
11 unsafe impl cortex_m::interrupt::InterruptNumber for N {
12 fn number(self) -> u16 {
13 self.0
14 }
15 }
16 cortex_m::peripheral::NVIC::pend(N(n)) 20 cortex_m::peripheral::NVIC::pend(N(n))
17} 21}
18 22
@@ -37,26 +41,37 @@ fn pend_by_number(n: u16) {
37/// 41///
38/// It is somewhat more complex to use, it's recommended to use the thread-mode 42/// It is somewhat more complex to use, it's recommended to use the thread-mode
39/// [`Executor`] instead, if it works for your use case. 43/// [`Executor`] instead, if it works for your use case.
40pub struct InterruptExecutor<I: Interrupt> { 44pub struct InterruptExecutor {
41 irq: I, 45 started: AtomicBool,
42 inner: raw::Executor, 46 executor: UnsafeCell<MaybeUninit<raw::Executor>>,
43 not_send: PhantomData<*mut ()>,
44} 47}
45 48
46impl<I: Interrupt> InterruptExecutor<I> { 49unsafe impl Send for InterruptExecutor {}
47 /// Create a new Executor. 50unsafe impl Sync for InterruptExecutor {}
48 pub fn new(irq: I) -> Self { 51
49 let ctx = irq.number() as *mut (); 52impl InterruptExecutor {
53 /// Create a new, not started `InterruptExecutor`.
54 #[inline]
55 pub const fn new() -> Self {
50 Self { 56 Self {
51 irq, 57 started: AtomicBool::new(false),
52 inner: raw::Executor::new(|ctx| pend_by_number(ctx as u16), ctx), 58 executor: UnsafeCell::new(MaybeUninit::uninit()),
53 not_send: PhantomData,
54 } 59 }
55 } 60 }
56 61
62 /// Executor interrupt callback.
63 ///
64 /// # Safety
65 ///
66 /// You MUST call this from the interrupt handler, and from nowhere else.
67 pub unsafe fn on_interrupt(&'static self) {
68 let executor = unsafe { (&*self.executor.get()).assume_init_ref() };
69 executor.poll();
70 }
71
57 /// Start the executor. 72 /// Start the executor.
58 /// 73 ///
59 /// This initializes the executor, configures and enables the interrupt, and returns. 74 /// This initializes the executor, enables the interrupt, and returns.
60 /// The executor keeps running in the background through the interrupt. 75 /// The executor keeps running in the background through the interrupt.
61 /// 76 ///
62 /// This returns a [`SendSpawner`] you can use to spawn tasks on it. A [`SendSpawner`] 77 /// This returns a [`SendSpawner`] you can use to spawn tasks on it. A [`SendSpawner`]
@@ -67,23 +82,35 @@ impl<I: Interrupt> InterruptExecutor<I> {
67 /// To obtain a [`Spawner`](embassy_executor::Spawner) for this executor, use [`Spawner::for_current_executor()`](embassy_executor::Spawner::for_current_executor()) from 82 /// To obtain a [`Spawner`](embassy_executor::Spawner) for this executor, use [`Spawner::for_current_executor()`](embassy_executor::Spawner::for_current_executor()) from
68 /// a task running in it. 83 /// a task running in it.
69 /// 84 ///
70 /// This function requires `&'static mut self`. This means you have to store the 85 /// # Interrupt requirements
71 /// Executor instance in a place where it'll live forever and grants you mutable 86 ///
72 /// access. There's a few ways to do this: 87 /// You must write the interrupt handler yourself, and make it call [`on_interrupt()`](Self::on_interrupt).
88 ///
89 /// This method already enables (unmasks) the interrupt, you must NOT do it yourself.
90 ///
91 /// You must set the interrupt priority before calling this method. You MUST NOT
92 /// do it after.
73 /// 93 ///
74 /// - a [StaticCell](https://docs.rs/static_cell/latest/static_cell/) (safe) 94 pub fn start(&'static self, irq: impl InterruptNumber) -> SendSpawner {
75 /// - a `static mut` (unsafe) 95 if self
76 /// - a local variable in a function you know never returns (like `fn main() -> !`), upgrading its lifetime with `transmute`. (unsafe) 96 .started
77 pub fn start(&'static mut self) -> SendSpawner { 97 .compare_exchange(false, true, Ordering::Acquire, Ordering::Relaxed)
78 self.irq.disable(); 98 .is_err()
99 {
100 panic!("InterruptExecutor::start() called multiple times on the same executor.");
101 }
102
103 unsafe {
104 (&mut *self.executor.get()).as_mut_ptr().write(raw::Executor::new(
105 |ctx| pend_by_number(ctx as u16),
106 irq.number() as *mut (),
107 ))
108 }
109
110 let executor = unsafe { (&*self.executor.get()).assume_init_ref() };
79 111
80 self.irq.set_handler(|ctx| unsafe { 112 unsafe { NVIC::unmask(irq) }
81 let executor = &*(ctx as *const raw::Executor);
82 executor.poll();
83 });
84 self.irq.set_handler_context(&self.inner as *const _ as _);
85 self.irq.enable();
86 113
87 self.inner.spawner().make_send() 114 executor.spawner().make_send()
88 } 115 }
89} 116}
diff --git a/embassy-cortex-m/src/interrupt.rs b/embassy-cortex-m/src/interrupt.rs
index 1df8671b9..3a82726df 100644
--- a/embassy-cortex-m/src/interrupt.rs
+++ b/embassy-cortex-m/src/interrupt.rs
@@ -13,14 +13,44 @@ pub mod _export {
13 pub use embassy_macros::{cortex_m_interrupt as interrupt, cortex_m_interrupt_declare as declare}; 13 pub use embassy_macros::{cortex_m_interrupt as interrupt, cortex_m_interrupt_declare as declare};
14} 14}
15 15
16/// Interrupt handler trait.
17///
18/// Drivers that need to handle interrupts implement this trait.
19/// The user must ensure `on_interrupt()` is called every time the interrupt fires.
20/// Drivers must use use [`Binding`] to assert at compile time that the user has done so.
21pub trait Handler<I: Interrupt> {
22 /// Interrupt handler function.
23 ///
24 /// Must be called every time the `I` interrupt fires, synchronously from
25 /// the interrupt handler context.
26 ///
27 /// # Safety
28 ///
29 /// This function must ONLY be called from the interrupt handler for `I`.
30 unsafe fn on_interrupt();
31}
32
33/// Compile-time assertion that an interrupt has been bound to a handler.
34///
35/// For the vast majority of cases, you should use the `bind_interrupts!`
36/// macro instead of writing `unsafe impl`s of this trait.
37///
38/// # Safety
39///
40/// By implementing this trait, you are asserting that you have arranged for `H::on_interrupt()`
41/// to be called every time the `I` interrupt fires.
42///
43/// This allows drivers to check bindings at compile-time.
44pub unsafe trait Binding<I: Interrupt, H: Handler<I>> {}
45
16/// Implementation detail, do not use outside embassy crates. 46/// Implementation detail, do not use outside embassy crates.
17#[doc(hidden)] 47#[doc(hidden)]
18pub struct Handler { 48pub struct DynHandler {
19 pub func: AtomicPtr<()>, 49 pub func: AtomicPtr<()>,
20 pub ctx: AtomicPtr<()>, 50 pub ctx: AtomicPtr<()>,
21} 51}
22 52
23impl Handler { 53impl DynHandler {
24 pub const fn new() -> Self { 54 pub const fn new() -> Self {
25 Self { 55 Self {
26 func: AtomicPtr::new(ptr::null_mut()), 56 func: AtomicPtr::new(ptr::null_mut()),
@@ -51,7 +81,7 @@ pub unsafe trait Interrupt: Peripheral<P = Self> {
51 81
52 /// Implementation detail, do not use outside embassy crates. 82 /// Implementation detail, do not use outside embassy crates.
53 #[doc(hidden)] 83 #[doc(hidden)]
54 unsafe fn __handler(&self) -> &'static Handler; 84 unsafe fn __handler(&self) -> &'static DynHandler;
55} 85}
56 86
57/// Represents additional behavior for all interrupts. 87/// Represents additional behavior for all interrupts.
diff --git a/embassy-futures/src/yield_now.rs b/embassy-futures/src/yield_now.rs
index 13b103778..bb3c67d17 100644
--- a/embassy-futures/src/yield_now.rs
+++ b/embassy-futures/src/yield_now.rs
@@ -24,6 +24,7 @@ pub fn yield_now() -> impl Future<Output = ()> {
24 YieldNowFuture { yielded: false } 24 YieldNowFuture { yielded: false }
25} 25}
26 26
27#[must_use = "futures do nothing unless you `.await` or poll them"]
27struct YieldNowFuture { 28struct YieldNowFuture {
28 yielded: bool, 29 yielded: bool,
29} 30}
diff --git a/embassy-hal-common/src/atomic_ring_buffer.rs b/embassy-hal-common/src/atomic_ring_buffer.rs
index 4c944d763..afd3ce1de 100644
--- a/embassy-hal-common/src/atomic_ring_buffer.rs
+++ b/embassy-hal-common/src/atomic_ring_buffer.rs
@@ -14,10 +14,18 @@ use core::sync::atomic::{AtomicPtr, AtomicUsize, Ordering};
14/// One concurrent writer and one concurrent reader are supported, even at 14/// One concurrent writer and one concurrent reader are supported, even at
15/// different execution priorities (like main and irq). 15/// different execution priorities (like main and irq).
16pub struct RingBuffer { 16pub struct RingBuffer {
17 buf: AtomicPtr<u8>, 17 pub buf: AtomicPtr<u8>,
18 len: AtomicUsize, 18 pub len: AtomicUsize,
19 start: AtomicUsize, 19
20 end: AtomicUsize, 20 // start and end wrap at len*2, not at len.
21 // This allows distinguishing "full" and "empty".
22 // full is when start+len == end (modulo len*2)
23 // empty is when start == end
24 //
25 // This avoids having to consider the ringbuffer "full" at len-1 instead of len.
26 // The usual solution is adding a "full" flag, but that can't be made atomic
27 pub start: AtomicUsize,
28 pub end: AtomicUsize,
21} 29}
22 30
23pub struct Reader<'a>(&'a RingBuffer); 31pub struct Reader<'a>(&'a RingBuffer);
@@ -90,7 +98,7 @@ impl RingBuffer {
90 let start = self.start.load(Ordering::Relaxed); 98 let start = self.start.load(Ordering::Relaxed);
91 let end = self.end.load(Ordering::Relaxed); 99 let end = self.end.load(Ordering::Relaxed);
92 100
93 len == 0 || self.wrap(end + 1) == start 101 self.wrap(start + len) == end
94 } 102 }
95 103
96 pub fn is_empty(&self) -> bool { 104 pub fn is_empty(&self) -> bool {
@@ -100,15 +108,13 @@ impl RingBuffer {
100 start == end 108 start == end
101 } 109 }
102 110
103 fn wrap(&self, n: usize) -> usize { 111 fn wrap(&self, mut n: usize) -> usize {
104 let len = self.len.load(Ordering::Relaxed); 112 let len = self.len.load(Ordering::Relaxed);
105 113
106 assert!(n <= len); 114 if n >= len * 2 {
107 if n == len { 115 n -= len * 2
108 0
109 } else {
110 n
111 } 116 }
117 n
112 } 118 }
113} 119}
114 120
@@ -147,6 +153,14 @@ impl<'a> Writer<'a> {
147 unsafe { slice::from_raw_parts_mut(data, len) } 153 unsafe { slice::from_raw_parts_mut(data, len) }
148 } 154 }
149 155
156 /// Get up to two buffers where data can be pushed to.
157 ///
158 /// Equivalent to [`Self::push_bufs`] but returns slices.
159 pub fn push_slices(&mut self) -> [&mut [u8]; 2] {
160 let [(d0, l0), (d1, l1)] = self.push_bufs();
161 unsafe { [slice::from_raw_parts_mut(d0, l0), slice::from_raw_parts_mut(d1, l1)] }
162 }
163
150 /// Get a buffer where data can be pushed to. 164 /// Get a buffer where data can be pushed to.
151 /// 165 ///
152 /// Write data to the start of the buffer, then call `push_done` with 166 /// Write data to the start of the buffer, then call `push_done` with
@@ -161,21 +175,69 @@ impl<'a> Writer<'a> {
161 pub fn push_buf(&mut self) -> (*mut u8, usize) { 175 pub fn push_buf(&mut self) -> (*mut u8, usize) {
162 // Ordering: popping writes `start` last, so we read `start` first. 176 // Ordering: popping writes `start` last, so we read `start` first.
163 // Read it with Acquire ordering, so that the next accesses can't be reordered up past it. 177 // Read it with Acquire ordering, so that the next accesses can't be reordered up past it.
164 let start = self.0.start.load(Ordering::Acquire); 178 let mut start = self.0.start.load(Ordering::Acquire);
165 let buf = self.0.buf.load(Ordering::Relaxed); 179 let buf = self.0.buf.load(Ordering::Relaxed);
166 let len = self.0.len.load(Ordering::Relaxed); 180 let len = self.0.len.load(Ordering::Relaxed);
167 let end = self.0.end.load(Ordering::Relaxed); 181 let mut end = self.0.end.load(Ordering::Relaxed);
168 182
169 let n = if start <= end { 183 let empty = start == end;
170 len - end - (start == 0 && len != 0) as usize 184
171 } else { 185 if start >= len {
172 start - end - 1 186 start -= len
173 }; 187 }
188 if end >= len {
189 end -= len
190 }
191
192 if start == end && !empty {
193 // full
194 return (buf, 0);
195 }
196 let n = if start > end { start - end } else { len - end };
174 197
175 trace!(" ringbuf: push_buf {:?}..{:?}", end, end + n); 198 trace!(" ringbuf: push_buf {:?}..{:?}", end, end + n);
176 (unsafe { buf.add(end) }, n) 199 (unsafe { buf.add(end) }, n)
177 } 200 }
178 201
202 /// Get up to two buffers where data can be pushed to.
203 ///
204 /// Write data starting at the beginning of the first buffer, then call
205 /// `push_done` with however many bytes you've pushed.
206 ///
207 /// The buffers are suitable to DMA to.
208 ///
209 /// If the ringbuf is full, both buffers will be zero length.
210 /// If there is only area available, the second buffer will be zero length.
211 ///
212 /// The buffer stays valid as long as no other `Writer` method is called
213 /// and `init`/`deinit` aren't called on the ringbuf.
214 pub fn push_bufs(&mut self) -> [(*mut u8, usize); 2] {
215 // Ordering: as per push_buf()
216 let mut start = self.0.start.load(Ordering::Acquire);
217 let buf = self.0.buf.load(Ordering::Relaxed);
218 let len = self.0.len.load(Ordering::Relaxed);
219 let mut end = self.0.end.load(Ordering::Relaxed);
220
221 let empty = start == end;
222
223 if start >= len {
224 start -= len
225 }
226 if end >= len {
227 end -= len
228 }
229
230 if start == end && !empty {
231 // full
232 return [(buf, 0), (buf, 0)];
233 }
234 let n0 = if start > end { start - end } else { len - end };
235 let n1 = if start <= end { start } else { 0 };
236
237 trace!(" ringbuf: push_bufs [{:?}..{:?}, {:?}..{:?}]", end, end + n0, 0, n1);
238 [(unsafe { buf.add(end) }, n0), (buf, n1)]
239 }
240
179 pub fn push_done(&mut self, n: usize) { 241 pub fn push_done(&mut self, n: usize) {
180 trace!(" ringbuf: push {:?}", n); 242 trace!(" ringbuf: push {:?}", n);
181 let end = self.0.end.load(Ordering::Relaxed); 243 let end = self.0.end.load(Ordering::Relaxed);
@@ -239,12 +301,23 @@ impl<'a> Reader<'a> {
239 // Ordering: pushing writes `end` last, so we read `end` first. 301 // Ordering: pushing writes `end` last, so we read `end` first.
240 // Read it with Acquire ordering, so that the next accesses can't be reordered up past it. 302 // Read it with Acquire ordering, so that the next accesses can't be reordered up past it.
241 // This is needed to guarantee we "see" the data written by the writer. 303 // This is needed to guarantee we "see" the data written by the writer.
242 let end = self.0.end.load(Ordering::Acquire); 304 let mut end = self.0.end.load(Ordering::Acquire);
243 let buf = self.0.buf.load(Ordering::Relaxed); 305 let buf = self.0.buf.load(Ordering::Relaxed);
244 let len = self.0.len.load(Ordering::Relaxed); 306 let len = self.0.len.load(Ordering::Relaxed);
245 let start = self.0.start.load(Ordering::Relaxed); 307 let mut start = self.0.start.load(Ordering::Relaxed);
308
309 if start == end {
310 return (buf, 0);
311 }
312
313 if start >= len {
314 start -= len
315 }
316 if end >= len {
317 end -= len
318 }
246 319
247 let n = if end < start { len - start } else { end - start }; 320 let n = if end > start { end - start } else { len - start };
248 321
249 trace!(" ringbuf: pop_buf {:?}..{:?}", start, start + n); 322 trace!(" ringbuf: pop_buf {:?}..{:?}", start, start + n);
250 (unsafe { buf.add(start) }, n) 323 (unsafe { buf.add(start) }, n)
@@ -280,12 +353,12 @@ mod tests {
280 assert_eq!(rb.is_full(), false); 353 assert_eq!(rb.is_full(), false);
281 354
282 rb.writer().push(|buf| { 355 rb.writer().push(|buf| {
283 // If capacity is 4, we can fill it up to 3. 356 assert_eq!(4, buf.len());
284 assert_eq!(3, buf.len());
285 buf[0] = 1; 357 buf[0] = 1;
286 buf[1] = 2; 358 buf[1] = 2;
287 buf[2] = 3; 359 buf[2] = 3;
288 3 360 buf[3] = 4;
361 4
289 }); 362 });
290 363
291 assert_eq!(rb.is_empty(), false); 364 assert_eq!(rb.is_empty(), false);
@@ -301,7 +374,7 @@ mod tests {
301 assert_eq!(rb.is_full(), true); 374 assert_eq!(rb.is_full(), true);
302 375
303 rb.reader().pop(|buf| { 376 rb.reader().pop(|buf| {
304 assert_eq!(3, buf.len()); 377 assert_eq!(4, buf.len());
305 assert_eq!(1, buf[0]); 378 assert_eq!(1, buf[0]);
306 1 379 1
307 }); 380 });
@@ -310,7 +383,7 @@ mod tests {
310 assert_eq!(rb.is_full(), false); 383 assert_eq!(rb.is_full(), false);
311 384
312 rb.reader().pop(|buf| { 385 rb.reader().pop(|buf| {
313 assert_eq!(2, buf.len()); 386 assert_eq!(3, buf.len());
314 0 387 0
315 }); 388 });
316 389
@@ -318,11 +391,16 @@ mod tests {
318 assert_eq!(rb.is_full(), false); 391 assert_eq!(rb.is_full(), false);
319 392
320 rb.reader().pop(|buf| { 393 rb.reader().pop(|buf| {
321 assert_eq!(2, buf.len()); 394 assert_eq!(3, buf.len());
322 assert_eq!(2, buf[0]); 395 assert_eq!(2, buf[0]);
323 assert_eq!(3, buf[1]); 396 assert_eq!(3, buf[1]);
324 2 397 2
325 }); 398 });
399 rb.reader().pop(|buf| {
400 assert_eq!(1, buf.len());
401 assert_eq!(4, buf[0]);
402 1
403 });
326 404
327 assert_eq!(rb.is_empty(), true); 405 assert_eq!(rb.is_empty(), true);
328 assert_eq!(rb.is_full(), false); 406 assert_eq!(rb.is_full(), false);
@@ -333,19 +411,28 @@ mod tests {
333 }); 411 });
334 412
335 rb.writer().push(|buf| { 413 rb.writer().push(|buf| {
336 assert_eq!(1, buf.len()); 414 assert_eq!(4, buf.len());
337 buf[0] = 10; 415 buf[0] = 10;
338 1 416 1
339 }); 417 });
340 418
341 rb.writer().push(|buf| { 419 rb.writer().push(|buf| {
342 assert_eq!(2, buf.len()); 420 assert_eq!(3, buf.len());
343 buf[0] = 11; 421 buf[0] = 11;
344 buf[1] = 12; 422 buf[1] = 12;
345 2 423 2
346 }); 424 });
347 425
348 assert_eq!(rb.is_empty(), false); 426 assert_eq!(rb.is_empty(), false);
427 assert_eq!(rb.is_full(), false);
428
429 rb.writer().push(|buf| {
430 assert_eq!(1, buf.len());
431 buf[0] = 13;
432 1
433 });
434
435 assert_eq!(rb.is_empty(), false);
349 assert_eq!(rb.is_full(), true); 436 assert_eq!(rb.is_full(), true);
350 } 437 }
351 } 438 }
@@ -368,4 +455,104 @@ mod tests {
368 }); 455 });
369 } 456 }
370 } 457 }
458
459 #[test]
460 fn push_slices() {
461 init();
462
463 let mut b = [0; 4];
464 let rb = RingBuffer::new();
465 unsafe {
466 rb.init(b.as_mut_ptr(), 4);
467
468 /* push 3 -> [1 2 3 x] */
469 let mut w = rb.writer();
470 let ps = w.push_slices();
471 assert_eq!(4, ps[0].len());
472 assert_eq!(0, ps[1].len());
473 ps[0][0] = 1;
474 ps[0][1] = 2;
475 ps[0][2] = 3;
476 w.push_done(3);
477 drop(w);
478
479 /* pop 2 -> [x x 3 x] */
480 rb.reader().pop(|buf| {
481 assert_eq!(3, buf.len());
482 assert_eq!(1, buf[0]);
483 assert_eq!(2, buf[1]);
484 assert_eq!(3, buf[2]);
485 2
486 });
487
488 /* push 3 -> [5 6 3 4] */
489 let mut w = rb.writer();
490 let ps = w.push_slices();
491 assert_eq!(1, ps[0].len());
492 assert_eq!(2, ps[1].len());
493 ps[0][0] = 4;
494 ps[1][0] = 5;
495 ps[1][1] = 6;
496 w.push_done(3);
497 drop(w);
498
499 /* buf is now full */
500 let mut w = rb.writer();
501 let ps = w.push_slices();
502 assert_eq!(0, ps[0].len());
503 assert_eq!(0, ps[1].len());
504
505 /* pop 2 -> [5 6 x x] */
506 rb.reader().pop(|buf| {
507 assert_eq!(2, buf.len());
508 assert_eq!(3, buf[0]);
509 assert_eq!(4, buf[1]);
510 2
511 });
512
513 /* should now have one push slice again */
514 let mut w = rb.writer();
515 let ps = w.push_slices();
516 assert_eq!(2, ps[0].len());
517 assert_eq!(0, ps[1].len());
518 drop(w);
519
520 /* pop 2 -> [x x x x] */
521 rb.reader().pop(|buf| {
522 assert_eq!(2, buf.len());
523 assert_eq!(5, buf[0]);
524 assert_eq!(6, buf[1]);
525 2
526 });
527
528 /* should now have two push slices */
529 let mut w = rb.writer();
530 let ps = w.push_slices();
531 assert_eq!(2, ps[0].len());
532 assert_eq!(2, ps[1].len());
533 drop(w);
534
535 /* make sure we exercise all wrap around cases properly */
536 for _ in 0..10 {
537 /* should be empty, push 1 */
538 let mut w = rb.writer();
539 let ps = w.push_slices();
540 assert_eq!(4, ps[0].len() + ps[1].len());
541 w.push_done(1);
542 drop(w);
543
544 /* should have 1 element */
545 let mut w = rb.writer();
546 let ps = w.push_slices();
547 assert_eq!(3, ps[0].len() + ps[1].len());
548 drop(w);
549
550 /* pop 1 */
551 rb.reader().pop(|buf| {
552 assert_eq!(1, buf.len());
553 1
554 });
555 }
556 }
557 }
371} 558}
diff --git a/embassy-macros/src/macros/cortex_m_interrupt_declare.rs b/embassy-macros/src/macros/cortex_m_interrupt_declare.rs
index ebbb47cd7..699883efa 100644
--- a/embassy-macros/src/macros/cortex_m_interrupt_declare.rs
+++ b/embassy-macros/src/macros/cortex_m_interrupt_declare.rs
@@ -21,9 +21,9 @@ pub fn run(name: syn::Ident) -> Result<TokenStream, TokenStream> {
21 unsafe fn steal() -> Self { 21 unsafe fn steal() -> Self {
22 Self(()) 22 Self(())
23 } 23 }
24 unsafe fn __handler(&self) -> &'static ::embassy_cortex_m::interrupt::Handler { 24 unsafe fn __handler(&self) -> &'static ::embassy_cortex_m::interrupt::DynHandler {
25 #[export_name = #name_handler] 25 #[export_name = #name_handler]
26 static HANDLER: ::embassy_cortex_m::interrupt::Handler = ::embassy_cortex_m::interrupt::Handler::new(); 26 static HANDLER: ::embassy_cortex_m::interrupt::DynHandler = ::embassy_cortex_m::interrupt::DynHandler::new();
27 &HANDLER 27 &HANDLER
28 } 28 }
29 } 29 }
diff --git a/embassy-macros/src/macros/cortex_m_interrupt_take.rs b/embassy-macros/src/macros/cortex_m_interrupt_take.rs
index d30189ce3..e2ebf98c7 100644
--- a/embassy-macros/src/macros/cortex_m_interrupt_take.rs
+++ b/embassy-macros/src/macros/cortex_m_interrupt_take.rs
@@ -30,7 +30,7 @@ pub fn run(name: syn::Ident) -> Result<TokenStream, TokenStream> {
30 pub unsafe extern "C" fn trampoline() { 30 pub unsafe extern "C" fn trampoline() {
31 extern "C" { 31 extern "C" {
32 #[link_name = #name_handler] 32 #[link_name = #name_handler]
33 static HANDLER: interrupt::Handler; 33 static HANDLER: interrupt::DynHandler;
34 } 34 }
35 35
36 let func = HANDLER.func.load(interrupt::_export::atomic::Ordering::Relaxed); 36 let func = HANDLER.func.load(interrupt::_export::atomic::Ordering::Relaxed);
diff --git a/embassy-net/src/lib.rs b/embassy-net/src/lib.rs
index bda5f9e14..4ec1b5a77 100644
--- a/embassy-net/src/lib.rs
+++ b/embassy-net/src/lib.rs
@@ -236,6 +236,22 @@ impl<D: Driver + 'static> Stack<D> {
236 /// Make a query for a given name and return the corresponding IP addresses. 236 /// Make a query for a given name and return the corresponding IP addresses.
237 #[cfg(feature = "dns")] 237 #[cfg(feature = "dns")]
238 pub async fn dns_query(&self, name: &str, qtype: dns::DnsQueryType) -> Result<Vec<IpAddress, 1>, dns::Error> { 238 pub async fn dns_query(&self, name: &str, qtype: dns::DnsQueryType) -> Result<Vec<IpAddress, 1>, dns::Error> {
239 // For A and AAAA queries we try detect whether `name` is just an IP address
240 match qtype {
241 dns::DnsQueryType::A => {
242 if let Ok(ip) = name.parse().map(IpAddress::Ipv4) {
243 return Ok([ip].into_iter().collect());
244 }
245 }
246 #[cfg(feature = "proto-ipv6")]
247 dns::DnsQueryType::Aaaa => {
248 if let Ok(ip) = name.parse().map(IpAddress::Ipv6) {
249 return Ok([ip].into_iter().collect());
250 }
251 }
252 _ => {}
253 }
254
239 let query = poll_fn(|cx| { 255 let query = poll_fn(|cx| {
240 self.with_mut(|s, i| { 256 self.with_mut(|s, i| {
241 let socket = s.sockets.get_mut::<dns::Socket>(i.dns_socket); 257 let socket = s.sockets.get_mut::<dns::Socket>(i.dns_socket);
diff --git a/embassy-nrf/src/buffered_uarte.rs b/embassy-nrf/src/buffered_uarte.rs
index 112f084c1..75f93f904 100644
--- a/embassy-nrf/src/buffered_uarte.rs
+++ b/embassy-nrf/src/buffered_uarte.rs
@@ -1,10 +1,5 @@
1//! Async buffered UART driver. 1//! Async buffered UART driver.
2//! 2//!
3//! WARNING!!! The functionality provided here is intended to be used only
4//! in situations where hardware flow control are available i.e. CTS and RTS.
5//! This is a problem that should be addressed at a later stage and can be
6//! fully explained at <https://github.com/embassy-rs/embassy/issues/536>.
7//!
8//! Note that discarding a future from a read or write operation may lead to losing 3//! Note that discarding a future from a read or write operation may lead to losing
9//! data. For example, when using `futures_util::future::select` and completion occurs 4//! data. For example, when using `futures_util::future::select` and completion occurs
10//! on the "other" future, you should capture the incomplete future and continue to use 5//! on the "other" future, you should capture the incomplete future and continue to use
@@ -13,83 +8,236 @@
13//! 8//!
14//! Please also see [crate::uarte] to understand when [BufferedUarte] should be used. 9//! Please also see [crate::uarte] to understand when [BufferedUarte] should be used.
15 10
16use core::cell::RefCell;
17use core::cmp::min; 11use core::cmp::min;
18use core::future::poll_fn; 12use core::future::poll_fn;
19use core::sync::atomic::{compiler_fence, Ordering}; 13use core::marker::PhantomData;
14use core::slice;
15use core::sync::atomic::{compiler_fence, AtomicU8, AtomicUsize, Ordering};
20use core::task::Poll; 16use core::task::Poll;
21 17
22use embassy_cortex_m::peripheral::{PeripheralMutex, PeripheralState, StateStorage}; 18use embassy_cortex_m::interrupt::Interrupt;
23use embassy_hal_common::ring_buffer::RingBuffer; 19use embassy_hal_common::atomic_ring_buffer::RingBuffer;
24use embassy_hal_common::{into_ref, PeripheralRef}; 20use embassy_hal_common::{into_ref, PeripheralRef};
25use embassy_sync::waitqueue::WakerRegistration; 21use embassy_sync::waitqueue::AtomicWaker;
26// Re-export SVD variants to allow user to directly set values 22// Re-export SVD variants to allow user to directly set values
27pub use pac::uarte0::{baudrate::BAUDRATE_A as Baudrate, config::PARITY_A as Parity}; 23pub use pac::uarte0::{baudrate::BAUDRATE_A as Baudrate, config::PARITY_A as Parity};
28 24
29use crate::gpio::{self, Pin as GpioPin}; 25use crate::gpio::sealed::Pin;
30use crate::interrupt::InterruptExt; 26use crate::gpio::{self, AnyPin, Pin as GpioPin, PselBits};
31use crate::ppi::{AnyConfigurableChannel, ConfigurableChannel, Event, Ppi, Task}; 27use crate::interrupt::{self, InterruptExt};
32use crate::timer::{Frequency, Instance as TimerInstance, Timer}; 28use crate::ppi::{
29 self, AnyConfigurableChannel, AnyGroup, Channel, ConfigurableChannel, Event, Group, Ppi, PpiGroup, Task,
30};
31use crate::timer::{Instance as TimerInstance, Timer};
33use crate::uarte::{apply_workaround_for_enable_anomaly, Config, Instance as UarteInstance}; 32use crate::uarte::{apply_workaround_for_enable_anomaly, Config, Instance as UarteInstance};
34use crate::{pac, Peripheral}; 33use crate::{pac, Peripheral};
35 34
36#[derive(Copy, Clone, Debug, PartialEq)] 35mod sealed {
37enum RxState { 36 use super::*;
38 Idle, 37
39 Receiving, 38 pub struct State {
39 pub tx_waker: AtomicWaker,
40 pub tx_buf: RingBuffer,
41 pub tx_count: AtomicUsize,
42
43 pub rx_waker: AtomicWaker,
44 pub rx_buf: RingBuffer,
45 pub rx_bufs: AtomicU8,
46 pub rx_ppi_ch: AtomicU8,
47 }
40} 48}
41 49
42#[derive(Copy, Clone, Debug, PartialEq)] 50/// UART error.
43enum TxState { 51#[derive(Debug, Clone, Copy, PartialEq, Eq)]
44 Idle, 52#[cfg_attr(feature = "defmt", derive(defmt::Format))]
45 Transmitting(usize), 53#[non_exhaustive]
54pub enum Error {
55 // No errors for now
46} 56}
47 57
48/// A type for storing the state of the UARTE peripheral that can be stored in a static. 58pub(crate) use sealed::State;
49pub struct State<'d, U: UarteInstance, T: TimerInstance>(StateStorage<StateInner<'d, U, T>>); 59
50impl<'d, U: UarteInstance, T: TimerInstance> State<'d, U, T> { 60impl State {
51 /// Create an instance for storing UARTE peripheral state. 61 pub(crate) const fn new() -> Self {
52 pub fn new() -> Self { 62 Self {
53 Self(StateStorage::new()) 63 tx_waker: AtomicWaker::new(),
64 tx_buf: RingBuffer::new(),
65 tx_count: AtomicUsize::new(0),
66
67 rx_waker: AtomicWaker::new(),
68 rx_buf: RingBuffer::new(),
69 rx_bufs: AtomicU8::new(0),
70 rx_ppi_ch: AtomicU8::new(0),
71 }
54 } 72 }
55} 73}
56 74
57struct StateInner<'d, U: UarteInstance, T: TimerInstance> { 75/// Interrupt handler.
58 _peri: PeripheralRef<'d, U>, 76pub struct InterruptHandler<U: UarteInstance> {
59 timer: Timer<'d, T>, 77 _phantom: PhantomData<U>,
60 _ppi_ch1: Ppi<'d, AnyConfigurableChannel, 1, 2>, 78}
61 _ppi_ch2: Ppi<'d, AnyConfigurableChannel, 1, 1>, 79
80impl<U: UarteInstance> interrupt::Handler<U::Interrupt> for InterruptHandler<U> {
81 unsafe fn on_interrupt() {
82 //trace!("irq: start");
83 let r = U::regs();
84 let s = U::buffered_state();
85
86 let buf_len = s.rx_buf.len();
87 let half_len = buf_len / 2;
88 let mut tx = unsafe { s.tx_buf.reader() };
89 let mut rx = unsafe { s.rx_buf.writer() };
90
91 if r.events_error.read().bits() != 0 {
92 r.events_error.reset();
93 let errs = r.errorsrc.read();
94 r.errorsrc.write(|w| unsafe { w.bits(errs.bits()) });
95
96 if errs.overrun().bit() {
97 panic!("BufferedUarte overrun");
98 }
99 }
100
101 // Received some bytes, wake task.
102 if r.inten.read().rxdrdy().bit_is_set() && r.events_rxdrdy.read().bits() != 0 {
103 r.intenclr.write(|w| w.rxdrdy().clear());
104 r.events_rxdrdy.reset();
105 s.rx_waker.wake();
106 }
107
108 // If not RXing, start.
109 if s.rx_bufs.load(Ordering::Relaxed) == 0 {
110 let (ptr, len) = rx.push_buf();
111 if len >= half_len {
112 //trace!(" irq_rx: starting {:?}", half_len);
113 s.rx_bufs.store(1, Ordering::Relaxed);
114
115 // Set up the DMA read
116 r.rxd.ptr.write(|w| unsafe { w.ptr().bits(ptr as u32) });
117 r.rxd.maxcnt.write(|w| unsafe { w.maxcnt().bits(half_len as _) });
118
119 // Start UARTE Receive transaction
120 r.tasks_startrx.write(|w| unsafe { w.bits(1) });
121 rx.push_done(half_len);
122 r.intenset.write(|w| w.rxstarted().set());
123 }
124 }
125
126 if r.events_rxstarted.read().bits() != 0 {
127 //trace!(" irq_rx: rxstarted");
128 let (ptr, len) = rx.push_buf();
129 if len >= half_len {
130 //trace!(" irq_rx: starting second {:?}", half_len);
62 131
63 rx: RingBuffer<'d>, 132 // Set up the DMA read
64 rx_state: RxState, 133 r.rxd.ptr.write(|w| unsafe { w.ptr().bits(ptr as u32) });
65 rx_waker: WakerRegistration, 134 r.rxd.maxcnt.write(|w| unsafe { w.maxcnt().bits(half_len as _) });
66 135
67 tx: RingBuffer<'d>, 136 let chn = s.rx_ppi_ch.load(Ordering::Relaxed);
68 tx_state: TxState, 137
69 tx_waker: WakerRegistration, 138 ppi::regs().chenset.write(|w| unsafe { w.bits(1 << chn) });
139
140 rx.push_done(half_len);
141
142 r.events_rxstarted.reset();
143 } else {
144 //trace!(" irq_rx: rxstarted no buf");
145 r.intenclr.write(|w| w.rxstarted().clear());
146 }
147 }
148
149 // =============================
150
151 // TX end
152 if r.events_endtx.read().bits() != 0 {
153 r.events_endtx.reset();
154
155 let n = s.tx_count.load(Ordering::Relaxed);
156 //trace!(" irq_tx: endtx {:?}", n);
157 tx.pop_done(n);
158 s.tx_waker.wake();
159 s.tx_count.store(0, Ordering::Relaxed);
160 }
161
162 // If not TXing, start.
163 if s.tx_count.load(Ordering::Relaxed) == 0 {
164 let (ptr, len) = tx.pop_buf();
165 if len != 0 {
166 //trace!(" irq_tx: starting {:?}", len);
167 s.tx_count.store(len, Ordering::Relaxed);
168
169 // Set up the DMA write
170 r.txd.ptr.write(|w| unsafe { w.ptr().bits(ptr as u32) });
171 r.txd.maxcnt.write(|w| unsafe { w.maxcnt().bits(len as _) });
172
173 // Start UARTE Transmit transaction
174 r.tasks_starttx.write(|w| unsafe { w.bits(1) });
175 }
176 }
177
178 //trace!("irq: end");
179 }
70} 180}
71 181
72/// Buffered UARTE driver. 182/// Buffered UARTE driver.
73pub struct BufferedUarte<'d, U: UarteInstance, T: TimerInstance> { 183pub struct BufferedUarte<'d, U: UarteInstance, T: TimerInstance> {
74 inner: RefCell<PeripheralMutex<'d, StateInner<'d, U, T>>>, 184 _peri: PeripheralRef<'d, U>,
185 timer: Timer<'d, T>,
186 _ppi_ch1: Ppi<'d, AnyConfigurableChannel, 1, 1>,
187 _ppi_ch2: Ppi<'d, AnyConfigurableChannel, 1, 2>,
188 _ppi_group: PpiGroup<'d, AnyGroup>,
75} 189}
76 190
77impl<'d, U: UarteInstance, T: TimerInstance> Unpin for BufferedUarte<'d, U, T> {} 191impl<'d, U: UarteInstance, T: TimerInstance> Unpin for BufferedUarte<'d, U, T> {}
78 192
79impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> { 193impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> {
80 /// Create a new instance of a BufferedUarte. 194 /// Create a new BufferedUarte without hardware flow control.
81 /// 195 ///
82 /// See the [module documentation](crate::buffered_uarte) for more details about the intended use. 196 /// # Panics
83 /// 197 ///
84 /// 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 198 /// Panics if `rx_buffer.len()` is odd.
85 /// can return early if there is no data to receive.
86 pub fn new( 199 pub fn new(
87 state: &'d mut State<'d, U, T>, 200 uarte: impl Peripheral<P = U> + 'd,
88 peri: impl Peripheral<P = U> + 'd,
89 timer: impl Peripheral<P = T> + 'd, 201 timer: impl Peripheral<P = T> + 'd,
90 ppi_ch1: impl Peripheral<P = impl ConfigurableChannel + 'd> + 'd, 202 ppi_ch1: impl Peripheral<P = impl ConfigurableChannel> + 'd,
91 ppi_ch2: impl Peripheral<P = impl ConfigurableChannel + 'd> + 'd, 203 ppi_ch2: impl Peripheral<P = impl ConfigurableChannel> + 'd,
92 irq: impl Peripheral<P = U::Interrupt> + 'd, 204 ppi_group: impl Peripheral<P = impl Group> + 'd,
205 _irq: impl interrupt::Binding<U::Interrupt, InterruptHandler<U>> + 'd,
206 rxd: impl Peripheral<P = impl GpioPin> + 'd,
207 txd: impl Peripheral<P = impl GpioPin> + 'd,
208 config: Config,
209 rx_buffer: &'d mut [u8],
210 tx_buffer: &'d mut [u8],
211 ) -> Self {
212 into_ref!(rxd, txd, ppi_ch1, ppi_ch2, ppi_group);
213 Self::new_inner(
214 uarte,
215 timer,
216 ppi_ch1.map_into(),
217 ppi_ch2.map_into(),
218 ppi_group.map_into(),
219 rxd.map_into(),
220 txd.map_into(),
221 None,
222 None,
223 config,
224 rx_buffer,
225 tx_buffer,
226 )
227 }
228
229 /// Create a new BufferedUarte with hardware flow control (RTS/CTS)
230 ///
231 /// # Panics
232 ///
233 /// Panics if `rx_buffer.len()` is odd.
234 pub fn new_with_rtscts(
235 uarte: impl Peripheral<P = U> + 'd,
236 timer: impl Peripheral<P = T> + 'd,
237 ppi_ch1: impl Peripheral<P = impl ConfigurableChannel> + 'd,
238 ppi_ch2: impl Peripheral<P = impl ConfigurableChannel> + 'd,
239 ppi_group: impl Peripheral<P = impl Group> + 'd,
240 _irq: impl interrupt::Binding<U::Interrupt, InterruptHandler<U>> + 'd,
93 rxd: impl Peripheral<P = impl GpioPin> + 'd, 241 rxd: impl Peripheral<P = impl GpioPin> + 'd,
94 txd: impl Peripheral<P = impl GpioPin> + 'd, 242 txd: impl Peripheral<P = impl GpioPin> + 'd,
95 cts: impl Peripheral<P = impl GpioPin> + 'd, 243 cts: impl Peripheral<P = impl GpioPin> + 'd,
@@ -98,11 +246,42 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> {
98 rx_buffer: &'d mut [u8], 246 rx_buffer: &'d mut [u8],
99 tx_buffer: &'d mut [u8], 247 tx_buffer: &'d mut [u8],
100 ) -> Self { 248 ) -> Self {
101 into_ref!(peri, ppi_ch1, ppi_ch2, irq, rxd, txd, cts, rts); 249 into_ref!(rxd, txd, cts, rts, ppi_ch1, ppi_ch2, ppi_group);
250 Self::new_inner(
251 uarte,
252 timer,
253 ppi_ch1.map_into(),
254 ppi_ch2.map_into(),
255 ppi_group.map_into(),
256 rxd.map_into(),
257 txd.map_into(),
258 Some(cts.map_into()),
259 Some(rts.map_into()),
260 config,
261 rx_buffer,
262 tx_buffer,
263 )
264 }
265
266 fn new_inner(
267 peri: impl Peripheral<P = U> + 'd,
268 timer: impl Peripheral<P = T> + 'd,
269 ppi_ch1: PeripheralRef<'d, AnyConfigurableChannel>,
270 ppi_ch2: PeripheralRef<'d, AnyConfigurableChannel>,
271 ppi_group: PeripheralRef<'d, AnyGroup>,
272 rxd: PeripheralRef<'d, AnyPin>,
273 txd: PeripheralRef<'d, AnyPin>,
274 cts: Option<PeripheralRef<'d, AnyPin>>,
275 rts: Option<PeripheralRef<'d, AnyPin>>,
276 config: Config,
277 rx_buffer: &'d mut [u8],
278 tx_buffer: &'d mut [u8],
279 ) -> Self {
280 into_ref!(peri, timer);
102 281
103 let r = U::regs(); 282 assert!(rx_buffer.len() % 2 == 0);
104 283
105 let mut timer = Timer::new(timer); 284 let r = U::regs();
106 285
107 rxd.conf().write(|w| w.input().connect().drive().h0h1()); 286 rxd.conf().write(|w| w.input().connect().drive().h0h1());
108 r.psel.rxd.write(|w| unsafe { w.bits(rxd.psel_bits()) }); 287 r.psel.rxd.write(|w| unsafe { w.bits(rxd.psel_bits()) });
@@ -111,92 +290,98 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> {
111 txd.conf().write(|w| w.dir().output().drive().h0h1()); 290 txd.conf().write(|w| w.dir().output().drive().h0h1());
112 r.psel.txd.write(|w| unsafe { w.bits(txd.psel_bits()) }); 291 r.psel.txd.write(|w| unsafe { w.bits(txd.psel_bits()) });
113 292
114 cts.conf().write(|w| w.input().connect().drive().h0h1()); 293 if let Some(pin) = &cts {
294 pin.conf().write(|w| w.input().connect().drive().h0h1());
295 }
115 r.psel.cts.write(|w| unsafe { w.bits(cts.psel_bits()) }); 296 r.psel.cts.write(|w| unsafe { w.bits(cts.psel_bits()) });
116 297
117 rts.set_high(); 298 if let Some(pin) = &rts {
118 rts.conf().write(|w| w.dir().output().drive().h0h1()); 299 pin.set_high();
300 pin.conf().write(|w| w.dir().output().drive().h0h1());
301 }
119 r.psel.rts.write(|w| unsafe { w.bits(rts.psel_bits()) }); 302 r.psel.rts.write(|w| unsafe { w.bits(rts.psel_bits()) });
120 303
121 r.baudrate.write(|w| w.baudrate().variant(config.baudrate)); 304 // Initialize state
122 r.config.write(|w| w.parity().variant(config.parity)); 305 let s = U::buffered_state();
306 s.tx_count.store(0, Ordering::Relaxed);
307 s.rx_bufs.store(0, Ordering::Relaxed);
308 let len = tx_buffer.len();
309 unsafe { s.tx_buf.init(tx_buffer.as_mut_ptr(), len) };
310 let len = rx_buffer.len();
311 unsafe { s.rx_buf.init(rx_buffer.as_mut_ptr(), len) };
123 312
124 // Configure 313 // Configure
125 r.config.write(|w| { 314 r.config.write(|w| {
126 w.hwfc().bit(true); 315 w.hwfc().bit(false);
127 w.parity().variant(config.parity); 316 w.parity().variant(config.parity);
128 w 317 w
129 }); 318 });
130 r.baudrate.write(|w| w.baudrate().variant(config.baudrate)); 319 r.baudrate.write(|w| w.baudrate().variant(config.baudrate));
131 320
132 // Enable interrupts 321 // clear errors
133 r.intenset.write(|w| w.endrx().set().endtx().set()); 322 let errors = r.errorsrc.read().bits();
323 r.errorsrc.write(|w| unsafe { w.bits(errors) });
134 324
135 // Disable the irq, let the Registration enable it when everything is set up. 325 r.events_rxstarted.reset();
136 irq.disable(); 326 r.events_txstarted.reset();
137 irq.pend(); 327 r.events_error.reset();
328 r.events_endrx.reset();
329 r.events_endtx.reset();
330
331 // Enable interrupts
332 r.intenclr.write(|w| unsafe { w.bits(!0) });
333 r.intenset.write(|w| {
334 w.endtx().set();
335 w.rxstarted().set();
336 w.error().set();
337 w
338 });
138 339
139 // Enable UARTE instance 340 // Enable UARTE instance
140 apply_workaround_for_enable_anomaly(&r); 341 apply_workaround_for_enable_anomaly(&r);
141 r.enable.write(|w| w.enable().enabled()); 342 r.enable.write(|w| w.enable().enabled());
142 343
143 // BAUDRATE register values are `baudrate * 2^32 / 16000000` 344 // Configure byte counter.
144 // source: https://devzone.nordicsemi.com/f/nordic-q-a/391/uart-baudrate-register-values 345 let mut timer = Timer::new_counter(timer);
145 // 346 timer.cc(1).write(rx_buffer.len() as u32 * 2);
146 // We want to stop RX if line is idle for 2 bytes worth of time 347 timer.cc(1).short_compare_clear();
147 // That is 20 bits (each byte is 1 start bit + 8 data bits + 1 stop bit) 348 timer.clear();
148 // This gives us the amount of 16M ticks for 20 bits. 349 timer.start();
149 let timeout = 0x8000_0000 / (config.baudrate as u32 / 40);
150
151 timer.set_frequency(Frequency::F16MHz);
152 timer.cc(0).write(timeout);
153 timer.cc(0).short_compare_clear();
154 timer.cc(0).short_compare_stop();
155 350
156 let mut ppi_ch1 = Ppi::new_one_to_two( 351 let mut ppi_ch1 = Ppi::new_one_to_one(ppi_ch1, Event::from_reg(&r.events_rxdrdy), timer.task_count());
157 ppi_ch1.map_into(),
158 Event::from_reg(&r.events_rxdrdy),
159 timer.task_clear(),
160 timer.task_start(),
161 );
162 ppi_ch1.enable(); 352 ppi_ch1.enable();
163 353
164 let mut ppi_ch2 = Ppi::new_one_to_one( 354 s.rx_ppi_ch.store(ppi_ch2.number() as u8, Ordering::Relaxed);
165 ppi_ch2.map_into(), 355 let mut ppi_group = PpiGroup::new(ppi_group);
166 timer.cc(0).event_compare(), 356 let mut ppi_ch2 = Ppi::new_one_to_two(
167 Task::from_reg(&r.tasks_stoprx), 357 ppi_ch2,
358 Event::from_reg(&r.events_endrx),
359 Task::from_reg(&r.tasks_startrx),
360 ppi_group.task_disable_all(),
168 ); 361 );
169 ppi_ch2.enable(); 362 ppi_ch2.disable();
363 ppi_group.add_channel(&ppi_ch2);
364
365 unsafe { U::Interrupt::steal() }.pend();
366 unsafe { U::Interrupt::steal() }.enable();
170 367
171 Self { 368 Self {
172 inner: RefCell::new(PeripheralMutex::new(irq, &mut state.0, move || StateInner { 369 _peri: peri,
173 _peri: peri, 370 timer,
174 timer, 371 _ppi_ch1: ppi_ch1,
175 _ppi_ch1: ppi_ch1, 372 _ppi_ch2: ppi_ch2,
176 _ppi_ch2: ppi_ch2, 373 _ppi_group: ppi_group,
177
178 rx: RingBuffer::new(rx_buffer),
179 rx_state: RxState::Idle,
180 rx_waker: WakerRegistration::new(),
181
182 tx: RingBuffer::new(tx_buffer),
183 tx_state: TxState::Idle,
184 tx_waker: WakerRegistration::new(),
185 })),
186 } 374 }
187 } 375 }
188 376
377 fn pend_irq() {
378 unsafe { <U::Interrupt as Interrupt>::steal() }.pend()
379 }
380
189 /// Adjust the baud rate to the provided value. 381 /// Adjust the baud rate to the provided value.
190 pub fn set_baudrate(&mut self, baudrate: Baudrate) { 382 pub fn set_baudrate(&mut self, baudrate: Baudrate) {
191 self.inner.borrow_mut().with(|state| { 383 let r = U::regs();
192 let r = U::regs(); 384 r.baudrate.write(|w| w.baudrate().variant(baudrate));
193
194 let timeout = 0x8000_0000 / (baudrate as u32 / 40);
195 state.timer.cc(0).write(timeout);
196 state.timer.clear();
197
198 r.baudrate.write(|w| w.baudrate().variant(baudrate));
199 });
200 } 385 }
201 386
202 /// Split the UART in reader and writer parts. 387 /// Split the UART in reader and writer parts.
@@ -206,120 +391,142 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> {
206 (BufferedUarteRx { inner: self }, BufferedUarteTx { inner: self }) 391 (BufferedUarteRx { inner: self }, BufferedUarteTx { inner: self })
207 } 392 }
208 393
209 async fn inner_read<'a>(&'a self, buf: &'a mut [u8]) -> Result<usize, core::convert::Infallible> { 394 async fn inner_read(&self, buf: &mut [u8]) -> Result<usize, Error> {
395 let data = self.inner_fill_buf().await?;
396 let n = data.len().min(buf.len());
397 buf[..n].copy_from_slice(&data[..n]);
398 self.inner_consume(n);
399 Ok(n)
400 }
401
402 async fn inner_write<'a>(&'a self, buf: &'a [u8]) -> Result<usize, Error> {
210 poll_fn(move |cx| { 403 poll_fn(move |cx| {
211 let mut do_pend = false; 404 //trace!("poll_write: {:?}", buf.len());
212 let mut inner = self.inner.borrow_mut(); 405 let s = U::buffered_state();
213 let res = inner.with(|state| { 406 let mut tx = unsafe { s.tx_buf.writer() };
214 compiler_fence(Ordering::SeqCst); 407
215 trace!("poll_read"); 408 let tx_buf = tx.push_slice();
216 409 if tx_buf.is_empty() {
217 // We have data ready in buffer? Return it. 410 //trace!("poll_write: pending");
218 let data = state.rx.pop_buf(); 411 s.tx_waker.register(cx.waker());
219 if !data.is_empty() { 412 return Poll::Pending;
220 trace!(" got {:?} {:?}", data.as_ptr() as u32, data.len());
221 let len = data.len().min(buf.len());
222 buf[..len].copy_from_slice(&data[..len]);
223 state.rx.pop(len);
224 do_pend = true;
225 return Poll::Ready(Ok(len));
226 }
227
228 trace!(" empty");
229 state.rx_waker.register(cx.waker());
230 Poll::Pending
231 });
232 if do_pend {
233 inner.pend();
234 } 413 }
235 414
236 res 415 let n = min(tx_buf.len(), buf.len());
416 tx_buf[..n].copy_from_slice(&buf[..n]);
417 tx.push_done(n);
418
419 //trace!("poll_write: queued {:?}", n);
420
421 compiler_fence(Ordering::SeqCst);
422 Self::pend_irq();
423
424 Poll::Ready(Ok(n))
237 }) 425 })
238 .await 426 .await
239 } 427 }
240 428
241 async fn inner_write<'a>(&'a self, buf: &'a [u8]) -> Result<usize, core::convert::Infallible> { 429 async fn inner_flush<'a>(&'a self) -> Result<(), Error> {
242 poll_fn(move |cx| { 430 poll_fn(move |cx| {
243 let mut inner = self.inner.borrow_mut(); 431 //trace!("poll_flush");
244 let res = inner.with(|state| { 432 let s = U::buffered_state();
245 trace!("poll_write: {:?}", buf.len()); 433 if !s.tx_buf.is_empty() {
434 //trace!("poll_flush: pending");
435 s.tx_waker.register(cx.waker());
436 return Poll::Pending;
437 }
246 438
247 let tx_buf = state.tx.push_buf(); 439 Poll::Ready(Ok(()))
248 if tx_buf.is_empty() { 440 })
249 trace!("poll_write: pending"); 441 .await
250 state.tx_waker.register(cx.waker()); 442 }
251 return Poll::Pending;
252 }
253 443
254 let n = min(tx_buf.len(), buf.len()); 444 async fn inner_fill_buf<'a>(&'a self) -> Result<&'a [u8], Error> {
255 tx_buf[..n].copy_from_slice(&buf[..n]); 445 poll_fn(move |cx| {
256 state.tx.push(n); 446 compiler_fence(Ordering::SeqCst);
447 //trace!("poll_read");
257 448
258 trace!("poll_write: queued {:?}", n); 449 let r = U::regs();
450 let s = U::buffered_state();
451
452 // Read the RXDRDY counter.
453 T::regs().tasks_capture[0].write(|w| unsafe { w.bits(1) });
454 let mut end = T::regs().cc[0].read().bits() as usize;
455 //trace!(" rxdrdy count = {:?}", end);
456
457 // We've set a compare channel that resets the counter to 0 when it reaches `len*2`.
458 // However, it's unclear if that's instant, or there's a small window where you can
459 // still read `len()*2`.
460 // This could happen if in one clock cycle the counter is updated, and in the next the
461 // clear takes effect. The docs are very sparse, they just say "Task delays: After TIMER
462 // is started, the CLEAR, COUNT, and STOP tasks are guaranteed to take effect within one
463 // clock cycle of the PCLK16M." :shrug:
464 // So, we wrap the counter ourselves, just in case.
465 if end > s.rx_buf.len() * 2 {
466 end = 0
467 }
259 468
260 compiler_fence(Ordering::SeqCst); 469 // This logic mirrors `atomic_ring_buffer::Reader::pop_buf()`
470 let mut start = s.rx_buf.start.load(Ordering::Relaxed);
471 let len = s.rx_buf.len();
472 if start == end {
473 //trace!(" empty");
474 s.rx_waker.register(cx.waker());
475 r.intenset.write(|w| w.rxdrdy().set_bit());
476 return Poll::Pending;
477 }
261 478
262 Poll::Ready(Ok(n)) 479 if start >= len {
263 }); 480 start -= len
481 }
482 if end >= len {
483 end -= len
484 }
264 485
265 inner.pend(); 486 let n = if end > start { end - start } else { len - start };
487 assert!(n != 0);
488 //trace!(" uarte ringbuf: pop_buf {:?}..{:?}", start, start + n);
266 489
267 res 490 let buf = s.rx_buf.buf.load(Ordering::Relaxed);
491 Poll::Ready(Ok(unsafe { slice::from_raw_parts(buf.add(start), n) }))
268 }) 492 })
269 .await 493 .await
270 } 494 }
271 495
272 async fn inner_flush<'a>(&'a self) -> Result<(), core::convert::Infallible> { 496 fn inner_consume(&self, amt: usize) {
273 poll_fn(move |cx| { 497 if amt == 0 {
274 self.inner.borrow_mut().with(|state| { 498 return;
275 trace!("poll_flush"); 499 }
276 500
277 if !state.tx.is_empty() { 501 let s = U::buffered_state();
278 trace!("poll_flush: pending"); 502 let mut rx = unsafe { s.rx_buf.reader() };
279 state.tx_waker.register(cx.waker()); 503 rx.pop_done(amt);
280 return Poll::Pending; 504 U::regs().intenset.write(|w| w.rxstarted().set());
281 } 505 }
282 506
283 Poll::Ready(Ok(())) 507 /// Pull some bytes from this source into the specified buffer, returning how many bytes were read.
284 }) 508 pub async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Error> {
285 }) 509 self.inner_read(buf).await
286 .await
287 } 510 }
288 511
289 async fn inner_fill_buf<'a>(&'a self) -> Result<&'a [u8], core::convert::Infallible> { 512 /// Return the contents of the internal buffer, filling it with more data from the inner reader if it is empty.
290 poll_fn(move |cx| { 513 pub async fn fill_buf(&mut self) -> Result<&[u8], Error> {
291 self.inner.borrow_mut().with(|state| { 514 self.inner_fill_buf().await
292 compiler_fence(Ordering::SeqCst);
293 trace!("fill_buf");
294
295 // We have data ready in buffer? Return it.
296 let buf = state.rx.pop_buf();
297 if !buf.is_empty() {
298 trace!(" got {:?} {:?}", buf.as_ptr() as u32, buf.len());
299 let buf: &[u8] = buf;
300 // Safety: buffer lives as long as uart
301 let buf: &[u8] = unsafe { core::mem::transmute(buf) };
302 return Poll::Ready(Ok(buf));
303 }
304
305 trace!(" empty");
306 state.rx_waker.register(cx.waker());
307 Poll::<Result<&[u8], core::convert::Infallible>>::Pending
308 })
309 })
310 .await
311 } 515 }
312 516
313 fn inner_consume(&self, amt: usize) { 517 /// Tell this buffer that `amt` bytes have been consumed from the buffer, so they should no longer be returned in calls to `fill_buf`.
314 let mut inner = self.inner.borrow_mut(); 518 pub fn consume(&mut self, amt: usize) {
315 let signal = inner.with(|state| { 519 self.inner_consume(amt)
316 let full = state.rx.is_full(); 520 }
317 state.rx.pop(amt); 521
318 full 522 /// Write a buffer into this writer, returning how many bytes were written.
319 }); 523 pub async fn write(&mut self, buf: &[u8]) -> Result<usize, Error> {
320 if signal { 524 self.inner_write(buf).await
321 inner.pend(); 525 }
322 } 526
527 /// Flush this output stream, ensuring that all intermediately buffered contents reach their destination.
528 pub async fn flush(&mut self) -> Result<(), Error> {
529 self.inner_flush().await
323 } 530 }
324} 531}
325 532
@@ -328,76 +535,116 @@ pub struct BufferedUarteTx<'u, 'd, U: UarteInstance, T: TimerInstance> {
328 inner: &'u BufferedUarte<'d, U, T>, 535 inner: &'u BufferedUarte<'d, U, T>,
329} 536}
330 537
538impl<'u, 'd, U: UarteInstance, T: TimerInstance> BufferedUarteTx<'u, 'd, U, T> {
539 /// Write a buffer into this writer, returning how many bytes were written.
540 pub async fn write(&mut self, buf: &[u8]) -> Result<usize, Error> {
541 self.inner.inner_write(buf).await
542 }
543
544 /// Flush this output stream, ensuring that all intermediately buffered contents reach their destination.
545 pub async fn flush(&mut self) -> Result<(), Error> {
546 self.inner.inner_flush().await
547 }
548}
549
331/// Writer part of the buffered UARTE driver. 550/// Writer part of the buffered UARTE driver.
332pub struct BufferedUarteRx<'u, 'd, U: UarteInstance, T: TimerInstance> { 551pub struct BufferedUarteRx<'u, 'd, U: UarteInstance, T: TimerInstance> {
333 inner: &'u BufferedUarte<'d, U, T>, 552 inner: &'u BufferedUarte<'d, U, T>,
334} 553}
335 554
336impl<'d, U: UarteInstance, T: TimerInstance> embedded_io::Io for BufferedUarte<'d, U, T> { 555impl<'u, 'd, U: UarteInstance, T: TimerInstance> BufferedUarteRx<'u, 'd, U, T> {
337 type Error = core::convert::Infallible; 556 /// Pull some bytes from this source into the specified buffer, returning how many bytes were read.
338} 557 pub async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Error> {
558 self.inner.inner_read(buf).await
559 }
339 560
340impl<'u, 'd, U: UarteInstance, T: TimerInstance> embedded_io::Io for BufferedUarteRx<'u, 'd, U, T> { 561 /// Return the contents of the internal buffer, filling it with more data from the inner reader if it is empty.
341 type Error = core::convert::Infallible; 562 pub async fn fill_buf(&mut self) -> Result<&[u8], Error> {
342} 563 self.inner.inner_fill_buf().await
564 }
343 565
344impl<'u, 'd, U: UarteInstance, T: TimerInstance> embedded_io::Io for BufferedUarteTx<'u, 'd, U, T> { 566 /// Tell this buffer that `amt` bytes have been consumed from the buffer, so they should no longer be returned in calls to `fill_buf`.
345 type Error = core::convert::Infallible; 567 pub fn consume(&mut self, amt: usize) {
568 self.inner.inner_consume(amt)
569 }
346} 570}
347 571
348impl<'d, U: UarteInstance, T: TimerInstance> embedded_io::asynch::Read for BufferedUarte<'d, U, T> { 572#[cfg(feature = "nightly")]
349 async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> { 573mod _embedded_io {
350 self.inner_read(buf).await 574 use super::*;
575
576 impl embedded_io::Error for Error {
577 fn kind(&self) -> embedded_io::ErrorKind {
578 match *self {}
579 }
351 } 580 }
352}
353 581
354impl<'u, 'd: 'u, U: UarteInstance, T: TimerInstance> embedded_io::asynch::Read for BufferedUarteRx<'u, 'd, U, T> { 582 impl<'d, U: UarteInstance, T: TimerInstance> embedded_io::Io for BufferedUarte<'d, U, T> {
355 async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> { 583 type Error = Error;
356 self.inner.inner_read(buf).await
357 } 584 }
358}
359 585
360impl<'d, U: UarteInstance, T: TimerInstance> embedded_io::asynch::BufRead for BufferedUarte<'d, U, T> { 586 impl<'u, 'd, U: UarteInstance, T: TimerInstance> embedded_io::Io for BufferedUarteRx<'u, 'd, U, T> {
361 async fn fill_buf(&mut self) -> Result<&[u8], Self::Error> { 587 type Error = Error;
362 self.inner_fill_buf().await
363 } 588 }
364 589
365 fn consume(&mut self, amt: usize) { 590 impl<'u, 'd, U: UarteInstance, T: TimerInstance> embedded_io::Io for BufferedUarteTx<'u, 'd, U, T> {
366 self.inner_consume(amt) 591 type Error = Error;
367 } 592 }
368}
369 593
370impl<'u, 'd: 'u, U: UarteInstance, T: TimerInstance> embedded_io::asynch::BufRead for BufferedUarteRx<'u, 'd, U, T> { 594 impl<'d, U: UarteInstance, T: TimerInstance> embedded_io::asynch::Read for BufferedUarte<'d, U, T> {
371 async fn fill_buf(&mut self) -> Result<&[u8], Self::Error> { 595 async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
372 self.inner.inner_fill_buf().await 596 self.inner_read(buf).await
597 }
373 } 598 }
374 599
375 fn consume(&mut self, amt: usize) { 600 impl<'u, 'd: 'u, U: UarteInstance, T: TimerInstance> embedded_io::asynch::Read for BufferedUarteRx<'u, 'd, U, T> {
376 self.inner.inner_consume(amt) 601 async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
602 self.inner.inner_read(buf).await
603 }
377 } 604 }
378}
379 605
380impl<'d, U: UarteInstance, T: TimerInstance> embedded_io::asynch::Write for BufferedUarte<'d, U, T> { 606 impl<'d, U: UarteInstance, T: TimerInstance> embedded_io::asynch::BufRead for BufferedUarte<'d, U, T> {
381 async fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> { 607 async fn fill_buf(&mut self) -> Result<&[u8], Self::Error> {
382 self.inner_write(buf).await 608 self.inner_fill_buf().await
609 }
610
611 fn consume(&mut self, amt: usize) {
612 self.inner_consume(amt)
613 }
383 } 614 }
384 615
385 async fn flush(&mut self) -> Result<(), Self::Error> { 616 impl<'u, 'd: 'u, U: UarteInstance, T: TimerInstance> embedded_io::asynch::BufRead for BufferedUarteRx<'u, 'd, U, T> {
386 self.inner_flush().await 617 async fn fill_buf(&mut self) -> Result<&[u8], Self::Error> {
618 self.inner.inner_fill_buf().await
619 }
620
621 fn consume(&mut self, amt: usize) {
622 self.inner.inner_consume(amt)
623 }
387 } 624 }
388}
389 625
390impl<'u, 'd: 'u, U: UarteInstance, T: TimerInstance> embedded_io::asynch::Write for BufferedUarteTx<'u, 'd, U, T> { 626 impl<'d, U: UarteInstance, T: TimerInstance> embedded_io::asynch::Write for BufferedUarte<'d, U, T> {
391 async fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> { 627 async fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
392 self.inner.inner_write(buf).await 628 self.inner_write(buf).await
629 }
630
631 async fn flush(&mut self) -> Result<(), Self::Error> {
632 self.inner_flush().await
633 }
393 } 634 }
394 635
395 async fn flush(&mut self) -> Result<(), Self::Error> { 636 impl<'u, 'd: 'u, U: UarteInstance, T: TimerInstance> embedded_io::asynch::Write for BufferedUarteTx<'u, 'd, U, T> {
396 self.inner.inner_flush().await 637 async fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
638 self.inner.inner_write(buf).await
639 }
640
641 async fn flush(&mut self) -> Result<(), Self::Error> {
642 self.inner.inner_flush().await
643 }
397 } 644 }
398} 645}
399 646
400impl<'a, U: UarteInstance, T: TimerInstance> Drop for StateInner<'a, U, T> { 647impl<'a, U: UarteInstance, T: TimerInstance> Drop for BufferedUarte<'a, U, T> {
401 fn drop(&mut self) { 648 fn drop(&mut self) {
402 let r = U::regs(); 649 let r = U::regs();
403 650
@@ -418,108 +665,11 @@ impl<'a, U: UarteInstance, T: TimerInstance> Drop for StateInner<'a, U, T> {
418 gpio::deconfigure_pin(r.psel.txd.read().bits()); 665 gpio::deconfigure_pin(r.psel.txd.read().bits());
419 gpio::deconfigure_pin(r.psel.rts.read().bits()); 666 gpio::deconfigure_pin(r.psel.rts.read().bits());
420 gpio::deconfigure_pin(r.psel.cts.read().bits()); 667 gpio::deconfigure_pin(r.psel.cts.read().bits());
421 }
422}
423 668
424impl<'a, U: UarteInstance, T: TimerInstance> PeripheralState for StateInner<'a, U, T> { 669 let s = U::buffered_state();
425 type Interrupt = U::Interrupt; 670 unsafe {
426 fn on_interrupt(&mut self) { 671 s.rx_buf.deinit();
427 trace!("irq: start"); 672 s.tx_buf.deinit();
428 let r = U::regs();
429
430 loop {
431 match self.rx_state {
432 RxState::Idle => {
433 trace!(" irq_rx: in state idle");
434
435 let buf = self.rx.push_buf();
436 if !buf.is_empty() {
437 trace!(" irq_rx: starting {:?}", buf.len());
438 self.rx_state = RxState::Receiving;
439
440 // Set up the DMA read
441 r.rxd.ptr.write(|w|
442 // The PTR field is a full 32 bits wide and accepts the full range
443 // of values.
444 unsafe { w.ptr().bits(buf.as_ptr() as u32) });
445 r.rxd.maxcnt.write(|w|
446 // We're giving it the length of the buffer, so no danger of
447 // accessing invalid memory. We have verified that the length of the
448 // buffer fits in an `u8`, so the cast to `u8` is also fine.
449 //
450 // The MAXCNT field is at least 8 bits wide and accepts the full
451 // range of values.
452 unsafe { w.maxcnt().bits(buf.len() as _) });
453 trace!(" irq_rx: buf {:?} {:?}", buf.as_ptr() as u32, buf.len());
454
455 // Start UARTE Receive transaction
456 r.tasks_startrx.write(|w| unsafe { w.bits(1) });
457 }
458 break;
459 }
460 RxState::Receiving => {
461 trace!(" irq_rx: in state receiving");
462 if r.events_endrx.read().bits() != 0 {
463 self.timer.stop();
464
465 let n: usize = r.rxd.amount.read().amount().bits() as usize;
466 trace!(" irq_rx: endrx {:?}", n);
467 self.rx.push(n);
468
469 r.events_endrx.reset();
470
471 self.rx_waker.wake();
472 self.rx_state = RxState::Idle;
473 } else {
474 break;
475 }
476 }
477 }
478 }
479
480 loop {
481 match self.tx_state {
482 TxState::Idle => {
483 trace!(" irq_tx: in state Idle");
484 let buf = self.tx.pop_buf();
485 if !buf.is_empty() {
486 trace!(" irq_tx: starting {:?}", buf.len());
487 self.tx_state = TxState::Transmitting(buf.len());
488
489 // Set up the DMA write
490 r.txd.ptr.write(|w|
491 // The PTR field is a full 32 bits wide and accepts the full range
492 // of values.
493 unsafe { w.ptr().bits(buf.as_ptr() as u32) });
494 r.txd.maxcnt.write(|w|
495 // We're giving it the length of the buffer, so no danger of
496 // accessing invalid memory. We have verified that the length of the
497 // buffer fits in an `u8`, so the cast to `u8` is also fine.
498 //
499 // The MAXCNT field is 8 bits wide and accepts the full range of
500 // values.
501 unsafe { w.maxcnt().bits(buf.len() as _) });
502
503 // Start UARTE Transmit transaction
504 r.tasks_starttx.write(|w| unsafe { w.bits(1) });
505 }
506 break;
507 }
508 TxState::Transmitting(n) => {
509 trace!(" irq_tx: in state Transmitting");
510 if r.events_endtx.read().bits() != 0 {
511 r.events_endtx.reset();
512
513 trace!(" irq_tx: endtx {:?}", n);
514 self.tx.pop(n);
515 self.tx_waker.wake();
516 self.tx_state = TxState::Idle;
517 } else {
518 break;
519 }
520 }
521 }
522 } 673 }
523 trace!("irq: end");
524 } 674 }
525} 675}
diff --git a/embassy-nrf/src/chips/nrf52805.rs b/embassy-nrf/src/chips/nrf52805.rs
index 3c74a2a63..e406c081b 100644
--- a/embassy-nrf/src/chips/nrf52805.rs
+++ b/embassy-nrf/src/chips/nrf52805.rs
@@ -140,6 +140,10 @@ impl_twim!(TWI0, TWIM0, TWIM0_TWIS0_TWI0);
140 140
141impl_twis!(TWI0, TWIS0, TWIM0_TWIS0_TWI0); 141impl_twis!(TWI0, TWIS0, TWIM0_TWIS0_TWI0);
142 142
143impl_qdec!(QDEC, QDEC, QDEC);
144
145impl_rng!(RNG, RNG, RNG);
146
143impl_timer!(TIMER0, TIMER0, TIMER0); 147impl_timer!(TIMER0, TIMER0, TIMER0);
144impl_timer!(TIMER1, TIMER1, TIMER1); 148impl_timer!(TIMER1, TIMER1, TIMER1);
145impl_timer!(TIMER2, TIMER2, TIMER2); 149impl_timer!(TIMER2, TIMER2, TIMER2);
diff --git a/embassy-nrf/src/chips/nrf52810.rs b/embassy-nrf/src/chips/nrf52810.rs
index 6b5c134b8..153795e54 100644
--- a/embassy-nrf/src/chips/nrf52810.rs
+++ b/embassy-nrf/src/chips/nrf52810.rs
@@ -148,6 +148,12 @@ impl_twis!(TWI0, TWIS0, TWIM0_TWIS0_TWI0);
148 148
149impl_pwm!(PWM0, PWM0, PWM0); 149impl_pwm!(PWM0, PWM0, PWM0);
150 150
151impl_pdm!(PDM, PDM, PDM);
152
153impl_qdec!(QDEC, QDEC, QDEC);
154
155impl_rng!(RNG, RNG, RNG);
156
151impl_timer!(TIMER0, TIMER0, TIMER0); 157impl_timer!(TIMER0, TIMER0, TIMER0);
152impl_timer!(TIMER1, TIMER1, TIMER1); 158impl_timer!(TIMER1, TIMER1, TIMER1);
153impl_timer!(TIMER2, TIMER2, TIMER2); 159impl_timer!(TIMER2, TIMER2, TIMER2);
diff --git a/embassy-nrf/src/chips/nrf52811.rs b/embassy-nrf/src/chips/nrf52811.rs
index c5de9a447..a7a7cf58c 100644
--- a/embassy-nrf/src/chips/nrf52811.rs
+++ b/embassy-nrf/src/chips/nrf52811.rs
@@ -150,6 +150,12 @@ impl_twis!(TWISPI0, TWIS0, TWIM0_TWIS0_TWI0_SPIM0_SPIS0_SPI0);
150 150
151impl_pwm!(PWM0, PWM0, PWM0); 151impl_pwm!(PWM0, PWM0, PWM0);
152 152
153impl_pdm!(PDM, PDM, PDM);
154
155impl_qdec!(QDEC, QDEC, QDEC);
156
157impl_rng!(RNG, RNG, RNG);
158
153impl_timer!(TIMER0, TIMER0, TIMER0); 159impl_timer!(TIMER0, TIMER0, TIMER0);
154impl_timer!(TIMER1, TIMER1, TIMER1); 160impl_timer!(TIMER1, TIMER1, TIMER1);
155impl_timer!(TIMER2, TIMER2, TIMER2); 161impl_timer!(TIMER2, TIMER2, TIMER2);
diff --git a/embassy-nrf/src/chips/nrf52820.rs b/embassy-nrf/src/chips/nrf52820.rs
index 81b07f32c..14a1b8cc9 100644
--- a/embassy-nrf/src/chips/nrf52820.rs
+++ b/embassy-nrf/src/chips/nrf52820.rs
@@ -153,6 +153,10 @@ impl_timer!(TIMER1, TIMER1, TIMER1);
153impl_timer!(TIMER2, TIMER2, TIMER2); 153impl_timer!(TIMER2, TIMER2, TIMER2);
154impl_timer!(TIMER3, TIMER3, TIMER3, extended); 154impl_timer!(TIMER3, TIMER3, TIMER3, extended);
155 155
156impl_qdec!(QDEC, QDEC, QDEC);
157
158impl_rng!(RNG, RNG, RNG);
159
156impl_pin!(P0_00, 0, 0); 160impl_pin!(P0_00, 0, 0);
157impl_pin!(P0_01, 0, 1); 161impl_pin!(P0_01, 0, 1);
158impl_pin!(P0_02, 0, 2); 162impl_pin!(P0_02, 0, 2);
diff --git a/embassy-nrf/src/chips/nrf52832.rs b/embassy-nrf/src/chips/nrf52832.rs
index c2b23fc5b..83ecd0deb 100644
--- a/embassy-nrf/src/chips/nrf52832.rs
+++ b/embassy-nrf/src/chips/nrf52832.rs
@@ -146,6 +146,9 @@ embassy_hal_common::peripherals! {
146 146
147 // I2S 147 // I2S
148 I2S, 148 I2S,
149
150 // PDM
151 PDM,
149} 152}
150 153
151impl_uarte!(UARTE0, UARTE0, UARTE0_UART0); 154impl_uarte!(UARTE0, UARTE0, UARTE0_UART0);
@@ -168,6 +171,12 @@ impl_pwm!(PWM0, PWM0, PWM0);
168impl_pwm!(PWM1, PWM1, PWM1); 171impl_pwm!(PWM1, PWM1, PWM1);
169impl_pwm!(PWM2, PWM2, PWM2); 172impl_pwm!(PWM2, PWM2, PWM2);
170 173
174impl_pdm!(PDM, PDM, PDM);
175
176impl_qdec!(QDEC, QDEC, QDEC);
177
178impl_rng!(RNG, RNG, RNG);
179
171impl_timer!(TIMER0, TIMER0, TIMER0); 180impl_timer!(TIMER0, TIMER0, TIMER0);
172impl_timer!(TIMER1, TIMER1, TIMER1); 181impl_timer!(TIMER1, TIMER1, TIMER1);
173impl_timer!(TIMER2, TIMER2, TIMER2); 182impl_timer!(TIMER2, TIMER2, TIMER2);
diff --git a/embassy-nrf/src/chips/nrf52833.rs b/embassy-nrf/src/chips/nrf52833.rs
index 95f71ade7..5e5db04de 100644
--- a/embassy-nrf/src/chips/nrf52833.rs
+++ b/embassy-nrf/src/chips/nrf52833.rs
@@ -197,6 +197,12 @@ impl_pwm!(PWM1, PWM1, PWM1);
197impl_pwm!(PWM2, PWM2, PWM2); 197impl_pwm!(PWM2, PWM2, PWM2);
198impl_pwm!(PWM3, PWM3, PWM3); 198impl_pwm!(PWM3, PWM3, PWM3);
199 199
200impl_pdm!(PDM, PDM, PDM);
201
202impl_qdec!(QDEC, QDEC, QDEC);
203
204impl_rng!(RNG, RNG, RNG);
205
200impl_timer!(TIMER0, TIMER0, TIMER0); 206impl_timer!(TIMER0, TIMER0, TIMER0);
201impl_timer!(TIMER1, TIMER1, TIMER1); 207impl_timer!(TIMER1, TIMER1, TIMER1);
202impl_timer!(TIMER2, TIMER2, TIMER2); 208impl_timer!(TIMER2, TIMER2, TIMER2);
diff --git a/embassy-nrf/src/chips/nrf52840.rs b/embassy-nrf/src/chips/nrf52840.rs
index 5e7479e88..f6d33f85c 100644
--- a/embassy-nrf/src/chips/nrf52840.rs
+++ b/embassy-nrf/src/chips/nrf52840.rs
@@ -208,6 +208,12 @@ impl_timer!(TIMER4, TIMER4, TIMER4, extended);
208 208
209impl_qspi!(QSPI, QSPI, QSPI); 209impl_qspi!(QSPI, QSPI, QSPI);
210 210
211impl_pdm!(PDM, PDM, PDM);
212
213impl_qdec!(QDEC, QDEC, QDEC);
214
215impl_rng!(RNG, RNG, RNG);
216
211impl_pin!(P0_00, 0, 0); 217impl_pin!(P0_00, 0, 0);
212impl_pin!(P0_01, 0, 1); 218impl_pin!(P0_01, 0, 1);
213impl_pin!(P0_02, 0, 2); 219impl_pin!(P0_02, 0, 2);
diff --git a/embassy-nrf/src/chips/nrf5340_app.rs b/embassy-nrf/src/chips/nrf5340_app.rs
index 2e1c7f384..34f96800f 100644
--- a/embassy-nrf/src/chips/nrf5340_app.rs
+++ b/embassy-nrf/src/chips/nrf5340_app.rs
@@ -34,10 +34,10 @@ pub mod pac {
34 nvmc_ns as nvmc, 34 nvmc_ns as nvmc,
35 oscillators_ns as oscillators, 35 oscillators_ns as oscillators,
36 p0_ns as p0, 36 p0_ns as p0,
37 pdm0_ns as pdm0, 37 pdm0_ns as pdm,
38 power_ns as power, 38 power_ns as power,
39 pwm0_ns as pwm0, 39 pwm0_ns as pwm0,
40 qdec0_ns as qdec0, 40 qdec0_ns as qdec,
41 qspi_ns as qspi, 41 qspi_ns as qspi,
42 regulators_ns as regulators, 42 regulators_ns as regulators,
43 reset_ns as reset, 43 reset_ns as reset,
@@ -250,6 +250,16 @@ embassy_hal_common::peripherals! {
250 TIMER1, 250 TIMER1,
251 TIMER2, 251 TIMER2,
252 252
253 // QSPI
254 QSPI,
255
256 // PDM
257 PDM0,
258
259 // QDEC
260 QDEC0,
261 QDEC1,
262
253 // GPIOTE 263 // GPIOTE
254 GPIOTE_CH0, 264 GPIOTE_CH0,
255 GPIOTE_CH1, 265 GPIOTE_CH1,
@@ -393,6 +403,13 @@ impl_timer!(TIMER0, TIMER0, TIMER0);
393impl_timer!(TIMER1, TIMER1, TIMER1); 403impl_timer!(TIMER1, TIMER1, TIMER1);
394impl_timer!(TIMER2, TIMER2, TIMER2); 404impl_timer!(TIMER2, TIMER2, TIMER2);
395 405
406impl_qspi!(QSPI, QSPI, QSPI);
407
408impl_pdm!(PDM0, PDM0, PDM0);
409
410impl_qdec!(QDEC0, QDEC0, QDEC0);
411impl_qdec!(QDEC1, QDEC1, QDEC1);
412
396impl_pin!(P0_00, 0, 0); 413impl_pin!(P0_00, 0, 0);
397impl_pin!(P0_01, 0, 1); 414impl_pin!(P0_01, 0, 1);
398#[cfg(feature = "nfc-pins-as-gpio")] 415#[cfg(feature = "nfc-pins-as-gpio")]
diff --git a/embassy-nrf/src/chips/nrf5340_net.rs b/embassy-nrf/src/chips/nrf5340_net.rs
index d7ba6c16c..1e59528cb 100644
--- a/embassy-nrf/src/chips/nrf5340_net.rs
+++ b/embassy-nrf/src/chips/nrf5340_net.rs
@@ -127,6 +127,9 @@ embassy_hal_common::peripherals! {
127 // SAADC 127 // SAADC
128 SAADC, 128 SAADC,
129 129
130 // RNG
131 RNG,
132
130 // PWM 133 // PWM
131 PWM0, 134 PWM0,
132 PWM1, 135 PWM1,
@@ -252,6 +255,8 @@ impl_timer!(TIMER0, TIMER0, TIMER0);
252impl_timer!(TIMER1, TIMER1, TIMER1); 255impl_timer!(TIMER1, TIMER1, TIMER1);
253impl_timer!(TIMER2, TIMER2, TIMER2); 256impl_timer!(TIMER2, TIMER2, TIMER2);
254 257
258impl_rng!(RNG, RNG, RNG);
259
255impl_pin!(P0_00, 0, 0); 260impl_pin!(P0_00, 0, 0);
256impl_pin!(P0_01, 0, 1); 261impl_pin!(P0_01, 0, 1);
257impl_pin!(P0_02, 0, 2); 262impl_pin!(P0_02, 0, 2);
diff --git a/embassy-nrf/src/chips/nrf9160.rs b/embassy-nrf/src/chips/nrf9160.rs
index 385bd133d..d2b45114f 100644
--- a/embassy-nrf/src/chips/nrf9160.rs
+++ b/embassy-nrf/src/chips/nrf9160.rs
@@ -301,6 +301,8 @@ impl_pwm!(PWM1, PWM1, PWM1);
301impl_pwm!(PWM2, PWM2, PWM2); 301impl_pwm!(PWM2, PWM2, PWM2);
302impl_pwm!(PWM3, PWM3, PWM3); 302impl_pwm!(PWM3, PWM3, PWM3);
303 303
304impl_pdm!(PDM, PDM, PDM);
305
304impl_timer!(TIMER0, TIMER0, TIMER0); 306impl_timer!(TIMER0, TIMER0, TIMER0);
305impl_timer!(TIMER1, TIMER1, TIMER1); 307impl_timer!(TIMER1, TIMER1, TIMER1);
306impl_timer!(TIMER2, TIMER2, TIMER2); 308impl_timer!(TIMER2, TIMER2, TIMER2);
diff --git a/embassy-nrf/src/gpiote.rs b/embassy-nrf/src/gpiote.rs
index e1816eb9b..66c682b43 100644
--- a/embassy-nrf/src/gpiote.rs
+++ b/embassy-nrf/src/gpiote.rs
@@ -315,6 +315,7 @@ impl<'d, C: Channel, T: GpioPin> OutputChannel<'d, C, T> {
315 315
316// ======================= 316// =======================
317 317
318#[must_use = "futures do nothing unless you `.await` or poll them"]
318pub(crate) struct PortInputFuture<'a> { 319pub(crate) struct PortInputFuture<'a> {
319 pin: PeripheralRef<'a, AnyPin>, 320 pin: PeripheralRef<'a, AnyPin>,
320} 321}
diff --git a/embassy-nrf/src/i2s.rs b/embassy-nrf/src/i2s.rs
index 770df7c89..8a1188ce4 100644
--- a/embassy-nrf/src/i2s.rs
+++ b/embassy-nrf/src/i2s.rs
@@ -14,7 +14,7 @@ use embassy_hal_common::drop::OnDrop;
14use embassy_hal_common::{into_ref, PeripheralRef}; 14use embassy_hal_common::{into_ref, PeripheralRef};
15 15
16use crate::gpio::{AnyPin, Pin as GpioPin}; 16use crate::gpio::{AnyPin, Pin as GpioPin};
17use crate::interrupt::Interrupt; 17use crate::interrupt::{self, Interrupt};
18use crate::pac::i2s::RegisterBlock; 18use crate::pac::i2s::RegisterBlock;
19use crate::util::{slice_in_ram_or, slice_ptr_parts}; 19use crate::util::{slice_in_ram_or, slice_ptr_parts};
20use crate::{Peripheral, EASY_DMA_SIZE}; 20use crate::{Peripheral, EASY_DMA_SIZE};
@@ -363,10 +363,39 @@ impl From<Channels> for u8 {
363 } 363 }
364} 364}
365 365
366/// Interrupt handler.
367pub struct InterruptHandler<T: Instance> {
368 _phantom: PhantomData<T>,
369}
370
371impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> {
372 unsafe fn on_interrupt() {
373 let device = Device::<T>::new();
374 let s = T::state();
375
376 if device.is_tx_ptr_updated() {
377 trace!("TX INT");
378 s.tx_waker.wake();
379 device.disable_tx_ptr_interrupt();
380 }
381
382 if device.is_rx_ptr_updated() {
383 trace!("RX INT");
384 s.rx_waker.wake();
385 device.disable_rx_ptr_interrupt();
386 }
387
388 if device.is_stopped() {
389 trace!("STOPPED INT");
390 s.stop_waker.wake();
391 device.disable_stopped_interrupt();
392 }
393 }
394}
395
366/// I2S driver. 396/// I2S driver.
367pub struct I2S<'d, T: Instance> { 397pub struct I2S<'d, T: Instance> {
368 i2s: PeripheralRef<'d, T>, 398 i2s: PeripheralRef<'d, T>,
369 irq: PeripheralRef<'d, T::Interrupt>,
370 mck: Option<PeripheralRef<'d, AnyPin>>, 399 mck: Option<PeripheralRef<'d, AnyPin>>,
371 sck: PeripheralRef<'d, AnyPin>, 400 sck: PeripheralRef<'d, AnyPin>,
372 lrck: PeripheralRef<'d, AnyPin>, 401 lrck: PeripheralRef<'d, AnyPin>,
@@ -378,19 +407,18 @@ pub struct I2S<'d, T: Instance> {
378 407
379impl<'d, T: Instance> I2S<'d, T> { 408impl<'d, T: Instance> I2S<'d, T> {
380 /// Create a new I2S in master mode 409 /// Create a new I2S in master mode
381 pub fn master( 410 pub fn new_master(
382 i2s: impl Peripheral<P = T> + 'd, 411 i2s: impl Peripheral<P = T> + 'd,
383 irq: impl Peripheral<P = T::Interrupt> + 'd, 412 _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
384 mck: impl Peripheral<P = impl GpioPin> + 'd, 413 mck: impl Peripheral<P = impl GpioPin> + 'd,
385 sck: impl Peripheral<P = impl GpioPin> + 'd, 414 sck: impl Peripheral<P = impl GpioPin> + 'd,
386 lrck: impl Peripheral<P = impl GpioPin> + 'd, 415 lrck: impl Peripheral<P = impl GpioPin> + 'd,
387 master_clock: MasterClock, 416 master_clock: MasterClock,
388 config: Config, 417 config: Config,
389 ) -> Self { 418 ) -> Self {
390 into_ref!(i2s, irq, mck, sck, lrck); 419 into_ref!(i2s, mck, sck, lrck);
391 Self { 420 Self {
392 i2s, 421 i2s,
393 irq,
394 mck: Some(mck.map_into()), 422 mck: Some(mck.map_into()),
395 sck: sck.map_into(), 423 sck: sck.map_into(),
396 lrck: lrck.map_into(), 424 lrck: lrck.map_into(),
@@ -402,17 +430,16 @@ impl<'d, T: Instance> I2S<'d, T> {
402 } 430 }
403 431
404 /// Create a new I2S in slave mode 432 /// Create a new I2S in slave mode
405 pub fn slave( 433 pub fn new_slave(
406 i2s: impl Peripheral<P = T> + 'd, 434 i2s: impl Peripheral<P = T> + 'd,
407 irq: impl Peripheral<P = T::Interrupt> + 'd, 435 _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
408 sck: impl Peripheral<P = impl GpioPin> + 'd, 436 sck: impl Peripheral<P = impl GpioPin> + 'd,
409 lrck: impl Peripheral<P = impl GpioPin> + 'd, 437 lrck: impl Peripheral<P = impl GpioPin> + 'd,
410 config: Config, 438 config: Config,
411 ) -> Self { 439 ) -> Self {
412 into_ref!(i2s, irq, sck, lrck); 440 into_ref!(i2s, sck, lrck);
413 Self { 441 Self {
414 i2s, 442 i2s,
415 irq,
416 mck: None, 443 mck: None,
417 sck: sck.map_into(), 444 sck: sck.map_into(),
418 lrck: lrck.map_into(), 445 lrck: lrck.map_into(),
@@ -537,9 +564,8 @@ impl<'d, T: Instance> I2S<'d, T> {
537 } 564 }
538 565
539 fn setup_interrupt(&self) { 566 fn setup_interrupt(&self) {
540 self.irq.set_handler(Self::on_interrupt); 567 unsafe { T::Interrupt::steal() }.unpend();
541 self.irq.unpend(); 568 unsafe { T::Interrupt::steal() }.enable();
542 self.irq.enable();
543 569
544 let device = Device::<T>::new(); 570 let device = Device::<T>::new();
545 device.disable_tx_ptr_interrupt(); 571 device.disable_tx_ptr_interrupt();
@@ -555,29 +581,6 @@ impl<'d, T: Instance> I2S<'d, T> {
555 device.enable_stopped_interrupt(); 581 device.enable_stopped_interrupt();
556 } 582 }
557 583
558 fn on_interrupt(_: *mut ()) {
559 let device = Device::<T>::new();
560 let s = T::state();
561
562 if device.is_tx_ptr_updated() {
563 trace!("TX INT");
564 s.tx_waker.wake();
565 device.disable_tx_ptr_interrupt();
566 }
567
568 if device.is_rx_ptr_updated() {
569 trace!("RX INT");
570 s.rx_waker.wake();
571 device.disable_rx_ptr_interrupt();
572 }
573
574 if device.is_stopped() {
575 trace!("STOPPED INT");
576 s.stop_waker.wake();
577 device.disable_stopped_interrupt();
578 }
579 }
580
581 async fn stop() { 584 async fn stop() {
582 compiler_fence(Ordering::SeqCst); 585 compiler_fence(Ordering::SeqCst);
583 586
@@ -1168,7 +1171,7 @@ pub(crate) mod sealed {
1168 } 1171 }
1169} 1172}
1170 1173
1171/// I2S peripehral instance. 1174/// I2S peripheral instance.
1172pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static + Send { 1175pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static + Send {
1173 /// Interrupt for this peripheral. 1176 /// Interrupt for this peripheral.
1174 type Interrupt: Interrupt; 1177 type Interrupt: Interrupt;
diff --git a/embassy-nrf/src/lib.rs b/embassy-nrf/src/lib.rs
index a9683df44..cb629902a 100644
--- a/embassy-nrf/src/lib.rs
+++ b/embassy-nrf/src/lib.rs
@@ -37,7 +37,6 @@ pub(crate) mod util;
37#[cfg(feature = "_time-driver")] 37#[cfg(feature = "_time-driver")]
38mod time_driver; 38mod time_driver;
39 39
40#[cfg(feature = "nightly")]
41pub mod buffered_uarte; 40pub mod buffered_uarte;
42pub mod gpio; 41pub mod gpio;
43#[cfg(feature = "gpiote")] 42#[cfg(feature = "gpiote")]
@@ -48,19 +47,21 @@ pub mod nvmc;
48#[cfg(any( 47#[cfg(any(
49 feature = "nrf52810", 48 feature = "nrf52810",
50 feature = "nrf52811", 49 feature = "nrf52811",
50 feature = "nrf52832",
51 feature = "nrf52833", 51 feature = "nrf52833",
52 feature = "nrf52840", 52 feature = "nrf52840",
53 feature = "_nrf5340-app",
53 feature = "_nrf9160" 54 feature = "_nrf9160"
54))] 55))]
55pub mod pdm; 56pub mod pdm;
56pub mod ppi; 57pub mod ppi;
57#[cfg(not(any(feature = "nrf52805", feature = "nrf52820", feature = "_nrf5340-net")))] 58#[cfg(not(any(feature = "nrf52805", feature = "nrf52820", feature = "_nrf5340-net")))]
58pub mod pwm; 59pub mod pwm;
59#[cfg(not(any(feature = "nrf51", feature = "_nrf9160", feature = "_nrf5340")))] 60#[cfg(not(any(feature = "nrf51", feature = "_nrf9160", feature = "_nrf5340-net")))]
60pub mod qdec; 61pub mod qdec;
61#[cfg(feature = "nrf52840")] 62#[cfg(any(feature = "nrf52840", feature = "_nrf5340-app"))]
62pub mod qspi; 63pub mod qspi;
63#[cfg(not(any(feature = "_nrf5340", feature = "_nrf9160")))] 64#[cfg(not(any(feature = "_nrf5340-app", feature = "_nrf9160")))]
64pub mod rng; 65pub mod rng;
65#[cfg(not(any(feature = "nrf52820", feature = "_nrf5340-net")))] 66#[cfg(not(any(feature = "nrf52820", feature = "_nrf5340-net")))]
66pub mod saadc; 67pub mod saadc;
@@ -96,14 +97,39 @@ pub mod wdt;
96#[cfg_attr(feature = "_nrf9160", path = "chips/nrf9160.rs")] 97#[cfg_attr(feature = "_nrf9160", path = "chips/nrf9160.rs")]
97mod chip; 98mod chip;
98 99
99pub use chip::EASY_DMA_SIZE;
100
101pub mod interrupt { 100pub mod interrupt {
102 //! nRF interrupts for cortex-m devices. 101 //! Interrupt definitions and macros to bind them.
103 pub use cortex_m::interrupt::{CriticalSection, Mutex}; 102 pub use cortex_m::interrupt::{CriticalSection, Mutex};
104 pub use embassy_cortex_m::interrupt::*; 103 pub use embassy_cortex_m::interrupt::{Binding, Handler, Interrupt, InterruptExt, Priority};
105 104
106 pub use crate::chip::irqs::*; 105 pub use crate::chip::irqs::*;
106
107 /// Macro to bind interrupts to handlers.
108 ///
109 /// This defines the right interrupt handlers, and creates a unit struct (like `struct Irqs;`)
110 /// and implements the right [`Binding`]s for it. You can pass this struct to drivers to
111 /// prove at compile-time that the right interrupts have been bound.
112 // developer note: this macro can't be in `embassy-cortex-m` due to the use of `$crate`.
113 #[macro_export]
114 macro_rules! bind_interrupts {
115 ($vis:vis struct $name:ident { $($irq:ident => $($handler:ty),*;)* }) => {
116 $vis struct $name;
117
118 $(
119 #[allow(non_snake_case)]
120 #[no_mangle]
121 unsafe extern "C" fn $irq() {
122 $(
123 <$handler as $crate::interrupt::Handler<$crate::interrupt::$irq>>::on_interrupt();
124 )*
125 }
126
127 $(
128 unsafe impl $crate::interrupt::Binding<$crate::interrupt::$irq, $handler> for $name {}
129 )*
130 )*
131 };
132 }
107} 133}
108 134
109// Reexports 135// Reexports
@@ -112,7 +138,7 @@ pub mod interrupt {
112pub use chip::pac; 138pub use chip::pac;
113#[cfg(not(feature = "unstable-pac"))] 139#[cfg(not(feature = "unstable-pac"))]
114pub(crate) use chip::pac; 140pub(crate) use chip::pac;
115pub use chip::{peripherals, Peripherals}; 141pub use chip::{peripherals, Peripherals, EASY_DMA_SIZE};
116pub use embassy_cortex_m::executor; 142pub use embassy_cortex_m::executor;
117pub use embassy_cortex_m::interrupt::_export::interrupt; 143pub use embassy_cortex_m::interrupt::_export::interrupt;
118pub use embassy_hal_common::{into_ref, Peripheral, PeripheralRef}; 144pub use embassy_hal_common::{into_ref, Peripheral, PeripheralRef};
diff --git a/embassy-nrf/src/pdm.rs b/embassy-nrf/src/pdm.rs
index 54feca4c1..8815bb316 100644
--- a/embassy-nrf/src/pdm.rs
+++ b/embassy-nrf/src/pdm.rs
@@ -1,25 +1,37 @@
1//! Pulse Density Modulation (PDM) mirophone driver. 1//! Pulse Density Modulation (PDM) mirophone driver.
2 2
3#![macro_use]
4
3use core::marker::PhantomData; 5use core::marker::PhantomData;
4use core::sync::atomic::{compiler_fence, Ordering}; 6use core::sync::atomic::{compiler_fence, Ordering};
5use core::task::Poll; 7use core::task::Poll;
6 8
9use embassy_cortex_m::interrupt::Interrupt;
7use embassy_hal_common::drop::OnDrop; 10use embassy_hal_common::drop::OnDrop;
8use embassy_hal_common::{into_ref, PeripheralRef}; 11use embassy_hal_common::{into_ref, PeripheralRef};
9use embassy_sync::waitqueue::AtomicWaker;
10use futures::future::poll_fn; 12use futures::future::poll_fn;
11 13
12use crate::chip::EASY_DMA_SIZE; 14use crate::chip::EASY_DMA_SIZE;
13use crate::gpio::sealed::Pin; 15use crate::gpio::sealed::Pin;
14use crate::gpio::{AnyPin, Pin as GpioPin}; 16use crate::gpio::{AnyPin, Pin as GpioPin};
15use crate::interrupt::{self, InterruptExt}; 17use crate::interrupt::{self, InterruptExt};
16use crate::peripherals::PDM; 18use crate::Peripheral;
17use crate::{pac, Peripheral}; 19
20/// Interrupt handler.
21pub struct InterruptHandler<T: Instance> {
22 _phantom: PhantomData<T>,
23}
24
25impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> {
26 unsafe fn on_interrupt() {
27 T::regs().intenclr.write(|w| w.end().clear());
28 T::state().waker.wake();
29 }
30}
18 31
19/// PDM microphone interface 32/// PDM microphone interface
20pub struct Pdm<'d> { 33pub struct Pdm<'d, T: Instance> {
21 irq: PeripheralRef<'d, interrupt::PDM>, 34 _peri: PeripheralRef<'d, T>,
22 phantom: PhantomData<&'d PDM>,
23} 35}
24 36
25/// PDM error. 37/// PDM error.
@@ -35,32 +47,30 @@ pub enum Error {
35 NotRunning, 47 NotRunning,
36} 48}
37 49
38static WAKER: AtomicWaker = AtomicWaker::new();
39static DUMMY_BUFFER: [i16; 1] = [0; 1]; 50static DUMMY_BUFFER: [i16; 1] = [0; 1];
40 51
41impl<'d> Pdm<'d> { 52impl<'d, T: Instance> Pdm<'d, T> {
42 /// Create PDM driver 53 /// Create PDM driver
43 pub fn new( 54 pub fn new(
44 pdm: impl Peripheral<P = PDM> + 'd, 55 pdm: impl Peripheral<P = T> + 'd,
45 irq: impl Peripheral<P = interrupt::PDM> + 'd, 56 _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
46 clk: impl Peripheral<P = impl GpioPin> + 'd, 57 clk: impl Peripheral<P = impl GpioPin> + 'd,
47 din: impl Peripheral<P = impl GpioPin> + 'd, 58 din: impl Peripheral<P = impl GpioPin> + 'd,
48 config: Config, 59 config: Config,
49 ) -> Self { 60 ) -> Self {
50 into_ref!(clk, din); 61 into_ref!(pdm, clk, din);
51 Self::new_inner(pdm, irq, clk.map_into(), din.map_into(), config) 62 Self::new_inner(pdm, clk.map_into(), din.map_into(), config)
52 } 63 }
53 64
54 fn new_inner( 65 fn new_inner(
55 _pdm: impl Peripheral<P = PDM> + 'd, 66 pdm: PeripheralRef<'d, T>,
56 irq: impl Peripheral<P = interrupt::PDM> + 'd,
57 clk: PeripheralRef<'d, AnyPin>, 67 clk: PeripheralRef<'d, AnyPin>,
58 din: PeripheralRef<'d, AnyPin>, 68 din: PeripheralRef<'d, AnyPin>,
59 config: Config, 69 config: Config,
60 ) -> Self { 70 ) -> Self {
61 into_ref!(irq); 71 into_ref!(pdm);
62 72
63 let r = Self::regs(); 73 let r = T::regs();
64 74
65 // setup gpio pins 75 // setup gpio pins
66 din.conf().write(|w| w.input().set_bit()); 76 din.conf().write(|w| w.input().set_bit());
@@ -84,26 +94,18 @@ impl<'d> Pdm<'d> {
84 r.gainr.write(|w| w.gainr().default_gain()); 94 r.gainr.write(|w| w.gainr().default_gain());
85 95
86 // IRQ 96 // IRQ
87 irq.disable(); 97 unsafe { T::Interrupt::steal() }.unpend();
88 irq.set_handler(|_| { 98 unsafe { T::Interrupt::steal() }.enable();
89 let r = Self::regs();
90 r.intenclr.write(|w| w.end().clear());
91 WAKER.wake();
92 });
93 irq.enable();
94 99
95 r.enable.write(|w| w.enable().set_bit()); 100 r.enable.write(|w| w.enable().set_bit());
96 101
97 Self { 102 Self { _peri: pdm }
98 phantom: PhantomData,
99 irq,
100 }
101 } 103 }
102 104
103 /// Start sampling microphon data into a dummy buffer 105 /// Start sampling microphon data into a dummy buffer
104 /// Usefull to start the microphon and keep it active between recording samples 106 /// Usefull to start the microphon and keep it active between recording samples
105 pub async fn start(&mut self) { 107 pub async fn start(&mut self) {
106 let r = Self::regs(); 108 let r = T::regs();
107 109
108 // start dummy sampling because microphon needs some setup time 110 // start dummy sampling because microphon needs some setup time
109 r.sample 111 r.sample
@@ -113,13 +115,13 @@ impl<'d> Pdm<'d> {
113 .maxcnt 115 .maxcnt
114 .write(|w| unsafe { w.buffsize().bits(DUMMY_BUFFER.len() as _) }); 116 .write(|w| unsafe { w.buffsize().bits(DUMMY_BUFFER.len() as _) });
115 117
116 r.tasks_start.write(|w| w.tasks_start().set_bit()); 118 r.tasks_start.write(|w| unsafe { w.bits(1) });
117 } 119 }
118 120
119 /// Stop sampling microphon data inta a dummy buffer 121 /// Stop sampling microphon data inta a dummy buffer
120 pub async fn stop(&mut self) { 122 pub async fn stop(&mut self) {
121 let r = Self::regs(); 123 let r = T::regs();
122 r.tasks_stop.write(|w| w.tasks_stop().set_bit()); 124 r.tasks_stop.write(|w| unsafe { w.bits(1) });
123 r.events_started.reset(); 125 r.events_started.reset();
124 } 126 }
125 127
@@ -132,9 +134,9 @@ impl<'d> Pdm<'d> {
132 return Err(Error::BufferTooLong); 134 return Err(Error::BufferTooLong);
133 } 135 }
134 136
135 let r = Self::regs(); 137 let r = T::regs();
136 138
137 if r.events_started.read().events_started().bit_is_clear() { 139 if r.events_started.read().bits() == 0 {
138 return Err(Error::NotRunning); 140 return Err(Error::NotRunning);
139 } 141 }
140 142
@@ -179,7 +181,7 @@ impl<'d> Pdm<'d> {
179 } 181 }
180 182
181 async fn wait_for_sample() { 183 async fn wait_for_sample() {
182 let r = Self::regs(); 184 let r = T::regs();
183 185
184 r.events_end.reset(); 186 r.events_end.reset();
185 r.intenset.write(|w| w.end().set()); 187 r.intenset.write(|w| w.end().set());
@@ -187,8 +189,8 @@ impl<'d> Pdm<'d> {
187 compiler_fence(Ordering::SeqCst); 189 compiler_fence(Ordering::SeqCst);
188 190
189 poll_fn(|cx| { 191 poll_fn(|cx| {
190 WAKER.register(cx.waker()); 192 T::state().waker.register(cx.waker());
191 if r.events_end.read().events_end().bit_is_set() { 193 if r.events_end.read().bits() != 0 {
192 return Poll::Ready(()); 194 return Poll::Ready(());
193 } 195 }
194 Poll::Pending 196 Poll::Pending
@@ -197,10 +199,6 @@ impl<'d> Pdm<'d> {
197 199
198 compiler_fence(Ordering::SeqCst); 200 compiler_fence(Ordering::SeqCst);
199 } 201 }
200
201 fn regs() -> &'static pac::pdm::RegisterBlock {
202 unsafe { &*pac::PDM::ptr() }
203 }
204} 202}
205 203
206/// PDM microphone driver Config 204/// PDM microphone driver Config
@@ -238,13 +236,11 @@ pub enum Edge {
238 LeftFalling, 236 LeftFalling,
239} 237}
240 238
241impl<'d> Drop for Pdm<'d> { 239impl<'d, T: Instance> Drop for Pdm<'d, T> {
242 fn drop(&mut self) { 240 fn drop(&mut self) {
243 let r = Self::regs(); 241 let r = T::regs();
244 242
245 r.tasks_stop.write(|w| w.tasks_stop().set_bit()); 243 r.tasks_stop.write(|w| unsafe { w.bits(1) });
246
247 self.irq.disable();
248 244
249 r.enable.write(|w| w.enable().disabled()); 245 r.enable.write(|w| w.enable().disabled());
250 246
@@ -252,3 +248,48 @@ impl<'d> Drop for Pdm<'d> {
252 r.psel.clk.reset(); 248 r.psel.clk.reset();
253 } 249 }
254} 250}
251
252pub(crate) mod sealed {
253 use embassy_sync::waitqueue::AtomicWaker;
254
255 /// Peripheral static state
256 pub struct State {
257 pub waker: AtomicWaker,
258 }
259
260 impl State {
261 pub const fn new() -> Self {
262 Self {
263 waker: AtomicWaker::new(),
264 }
265 }
266 }
267
268 pub trait Instance {
269 fn regs() -> &'static crate::pac::pdm::RegisterBlock;
270 fn state() -> &'static State;
271 }
272}
273
274/// PDM peripheral instance.
275pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static + Send {
276 /// Interrupt for this peripheral.
277 type Interrupt: Interrupt;
278}
279
280macro_rules! impl_pdm {
281 ($type:ident, $pac_type:ident, $irq:ident) => {
282 impl crate::pdm::sealed::Instance for peripherals::$type {
283 fn regs() -> &'static crate::pac::pdm::RegisterBlock {
284 unsafe { &*pac::$pac_type::ptr() }
285 }
286 fn state() -> &'static crate::pdm::sealed::State {
287 static STATE: crate::pdm::sealed::State = crate::pdm::sealed::State::new();
288 &STATE
289 }
290 }
291 impl crate::pdm::Instance for peripherals::$type {
292 type Interrupt = crate::interrupt::$irq;
293 }
294 };
295}
diff --git a/embassy-nrf/src/ppi/dppi.rs b/embassy-nrf/src/ppi/dppi.rs
index 0908cd7be..3a1e7f170 100644
--- a/embassy-nrf/src/ppi/dppi.rs
+++ b/embassy-nrf/src/ppi/dppi.rs
@@ -6,7 +6,7 @@ use crate::{pac, Peripheral};
6const DPPI_ENABLE_BIT: u32 = 0x8000_0000; 6const DPPI_ENABLE_BIT: u32 = 0x8000_0000;
7const DPPI_CHANNEL_MASK: u32 = 0x0000_00FF; 7const DPPI_CHANNEL_MASK: u32 = 0x0000_00FF;
8 8
9fn regs() -> &'static pac::dppic::RegisterBlock { 9pub(crate) fn regs() -> &'static pac::dppic::RegisterBlock {
10 unsafe { &*pac::DPPIC::ptr() } 10 unsafe { &*pac::DPPIC::ptr() }
11} 11}
12 12
diff --git a/embassy-nrf/src/ppi/mod.rs b/embassy-nrf/src/ppi/mod.rs
index b76eccf0b..7c18da6ee 100644
--- a/embassy-nrf/src/ppi/mod.rs
+++ b/embassy-nrf/src/ppi/mod.rs
@@ -17,16 +17,16 @@
17 17
18use core::ptr::NonNull; 18use core::ptr::NonNull;
19 19
20use embassy_hal_common::{impl_peripheral, PeripheralRef}; 20use embassy_hal_common::{impl_peripheral, into_ref, PeripheralRef};
21 21
22use crate::{peripherals, Peripheral}; 22use crate::{peripherals, Peripheral};
23 23
24#[cfg(feature = "_dppi")] 24#[cfg_attr(feature = "_dppi", path = "dppi.rs")]
25mod dppi; 25#[cfg_attr(feature = "_ppi", path = "ppi.rs")]
26#[cfg(feature = "_ppi")] 26mod _version;
27mod ppi; 27pub(crate) use _version::*;
28 28
29/// An instance of the Programmable peripheral interconnect on nRF devices. 29/// PPI channel driver.
30pub struct Ppi<'d, C: Channel, const EVENT_COUNT: usize, const TASK_COUNT: usize> { 30pub struct Ppi<'d, C: Channel, const EVENT_COUNT: usize, const TASK_COUNT: usize> {
31 ch: PeripheralRef<'d, C>, 31 ch: PeripheralRef<'d, C>,
32 #[cfg(feature = "_dppi")] 32 #[cfg(feature = "_dppi")]
@@ -35,6 +35,88 @@ pub struct Ppi<'d, C: Channel, const EVENT_COUNT: usize, const TASK_COUNT: usize
35 tasks: [Task; TASK_COUNT], 35 tasks: [Task; TASK_COUNT],
36} 36}
37 37
38/// PPI channel group driver.
39pub struct PpiGroup<'d, G: Group> {
40 g: PeripheralRef<'d, G>,
41}
42
43impl<'d, G: Group> PpiGroup<'d, G> {
44 /// Create a new PPI group driver.
45 ///
46 /// The group is initialized as containing no channels.
47 pub fn new(g: impl Peripheral<P = G> + 'd) -> Self {
48 into_ref!(g);
49
50 let r = regs();
51 let n = g.number();
52 r.chg[n].write(|w| unsafe { w.bits(0) });
53
54 Self { g }
55 }
56
57 /// Add a PPI channel to this group.
58 ///
59 /// If the channel is already in the group, this is a no-op.
60 pub fn add_channel<C: Channel, const EVENT_COUNT: usize, const TASK_COUNT: usize>(
61 &mut self,
62 ch: &Ppi<'_, C, EVENT_COUNT, TASK_COUNT>,
63 ) {
64 let r = regs();
65 let ng = self.g.number();
66 let nc = ch.ch.number();
67 r.chg[ng].modify(|r, w| unsafe { w.bits(r.bits() | 1 << nc) });
68 }
69
70 /// Remove a PPI channel from this group.
71 ///
72 /// If the channel is already not in the group, this is a no-op.
73 pub fn remove_channel<C: Channel, const EVENT_COUNT: usize, const TASK_COUNT: usize>(
74 &mut self,
75 ch: &Ppi<'_, C, EVENT_COUNT, TASK_COUNT>,
76 ) {
77 let r = regs();
78 let ng = self.g.number();
79 let nc = ch.ch.number();
80 r.chg[ng].modify(|r, w| unsafe { w.bits(r.bits() & !(1 << nc)) });
81 }
82
83 /// Enable all the channels in this group.
84 pub fn enable_all(&mut self) {
85 let n = self.g.number();
86 regs().tasks_chg[n].en.write(|w| unsafe { w.bits(1) });
87 }
88
89 /// Disable all the channels in this group.
90 pub fn disable_all(&mut self) {
91 let n = self.g.number();
92 regs().tasks_chg[n].dis.write(|w| unsafe { w.bits(1) });
93 }
94
95 /// Get a reference to the "enable all" task.
96 ///
97 /// When triggered, it will enable all the channels in this group.
98 pub fn task_enable_all(&self) -> Task {
99 let n = self.g.number();
100 Task::from_reg(&regs().tasks_chg[n].en)
101 }
102
103 /// Get a reference to the "disable all" task.
104 ///
105 /// When triggered, it will disable all the channels in this group.
106 pub fn task_disable_all(&self) -> Task {
107 let n = self.g.number();
108 Task::from_reg(&regs().tasks_chg[n].dis)
109 }
110}
111
112impl<'d, G: Group> Drop for PpiGroup<'d, G> {
113 fn drop(&mut self) {
114 let r = regs();
115 let n = self.g.number();
116 r.chg[n].write(|w| unsafe { w.bits(0) });
117 }
118}
119
38#[cfg(feature = "_dppi")] 120#[cfg(feature = "_dppi")]
39const REGISTER_DPPI_CONFIG_OFFSET: usize = 0x80 / core::mem::size_of::<u32>(); 121const REGISTER_DPPI_CONFIG_OFFSET: usize = 0x80 / core::mem::size_of::<u32>();
40 122
@@ -112,7 +194,7 @@ pub(crate) mod sealed {
112} 194}
113 195
114/// Interface for PPI channels. 196/// Interface for PPI channels.
115pub trait Channel: sealed::Channel + Peripheral<P = Self> + Sized { 197pub trait Channel: sealed::Channel + Peripheral<P = Self> + Sized + 'static {
116 /// Returns the number of the channel 198 /// Returns the number of the channel
117 fn number(&self) -> usize; 199 fn number(&self) -> usize;
118} 200}
@@ -130,7 +212,7 @@ pub trait StaticChannel: Channel + Into<AnyStaticChannel> {
130} 212}
131 213
132/// Interface for a group of PPI channels. 214/// Interface for a group of PPI channels.
133pub trait Group: sealed::Group + Sized { 215pub trait Group: sealed::Group + Peripheral<P = Self> + Into<AnyGroup> + Sized + 'static {
134 /// Returns the number of the group. 216 /// Returns the number of the group.
135 fn number(&self) -> usize; 217 fn number(&self) -> usize;
136 /// Convert into a type erased group. 218 /// Convert into a type erased group.
@@ -248,6 +330,12 @@ macro_rules! impl_group {
248 $number 330 $number
249 } 331 }
250 } 332 }
333
334 impl From<peripherals::$type> for crate::ppi::AnyGroup {
335 fn from(val: peripherals::$type) -> Self {
336 crate::ppi::Group::degrade(val)
337 }
338 }
251 }; 339 };
252} 340}
253 341
diff --git a/embassy-nrf/src/ppi/ppi.rs b/embassy-nrf/src/ppi/ppi.rs
index a96ab50b7..f1eeaee1e 100644
--- a/embassy-nrf/src/ppi/ppi.rs
+++ b/embassy-nrf/src/ppi/ppi.rs
@@ -14,7 +14,7 @@ impl Event {
14 } 14 }
15} 15}
16 16
17fn regs() -> &'static pac::ppi::RegisterBlock { 17pub(crate) fn regs() -> &'static pac::ppi::RegisterBlock {
18 unsafe { &*pac::PPI::ptr() } 18 unsafe { &*pac::PPI::ptr() }
19} 19}
20 20
diff --git a/embassy-nrf/src/qdec.rs b/embassy-nrf/src/qdec.rs
index c01babca3..4d2a09198 100644
--- a/embassy-nrf/src/qdec.rs
+++ b/embassy-nrf/src/qdec.rs
@@ -1,20 +1,22 @@
1//! Quadrature decoder (QDEC) driver. 1//! Quadrature decoder (QDEC) driver.
2 2
3#![macro_use]
4
3use core::future::poll_fn; 5use core::future::poll_fn;
6use core::marker::PhantomData;
4use core::task::Poll; 7use core::task::Poll;
5 8
9use embassy_cortex_m::interrupt::Interrupt;
6use embassy_hal_common::{into_ref, PeripheralRef}; 10use embassy_hal_common::{into_ref, PeripheralRef};
7use embassy_sync::waitqueue::AtomicWaker;
8 11
9use crate::gpio::sealed::Pin as _; 12use crate::gpio::sealed::Pin as _;
10use crate::gpio::{AnyPin, Pin as GpioPin}; 13use crate::gpio::{AnyPin, Pin as GpioPin};
11use crate::interrupt::InterruptExt; 14use crate::interrupt::InterruptExt;
12use crate::peripherals::QDEC; 15use crate::{interrupt, Peripheral};
13use crate::{interrupt, pac, Peripheral};
14 16
15/// Quadrature decoder driver. 17/// Quadrature decoder driver.
16pub struct Qdec<'d> { 18pub struct Qdec<'d, T: Instance> {
17 _p: PeripheralRef<'d, QDEC>, 19 _p: PeripheralRef<'d, T>,
18} 20}
19 21
20/// QDEC config 22/// QDEC config
@@ -44,44 +46,52 @@ impl Default for Config {
44 } 46 }
45} 47}
46 48
47static WAKER: AtomicWaker = AtomicWaker::new(); 49/// Interrupt handler.
50pub struct InterruptHandler<T: Instance> {
51 _phantom: PhantomData<T>,
52}
48 53
49impl<'d> Qdec<'d> { 54impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> {
55 unsafe fn on_interrupt() {
56 T::regs().intenclr.write(|w| w.reportrdy().clear());
57 T::state().waker.wake();
58 }
59}
60
61impl<'d, T: Instance> Qdec<'d, T> {
50 /// Create a new QDEC. 62 /// Create a new QDEC.
51 pub fn new( 63 pub fn new(
52 qdec: impl Peripheral<P = QDEC> + 'd, 64 qdec: impl Peripheral<P = T> + 'd,
53 irq: impl Peripheral<P = interrupt::QDEC> + 'd, 65 _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
54 a: impl Peripheral<P = impl GpioPin> + 'd, 66 a: impl Peripheral<P = impl GpioPin> + 'd,
55 b: impl Peripheral<P = impl GpioPin> + 'd, 67 b: impl Peripheral<P = impl GpioPin> + 'd,
56 config: Config, 68 config: Config,
57 ) -> Self { 69 ) -> Self {
58 into_ref!(a, b); 70 into_ref!(qdec, a, b);
59 Self::new_inner(qdec, irq, a.map_into(), b.map_into(), None, config) 71 Self::new_inner(qdec, a.map_into(), b.map_into(), None, config)
60 } 72 }
61 73
62 /// Create a new QDEC, with a pin for LED output. 74 /// Create a new QDEC, with a pin for LED output.
63 pub fn new_with_led( 75 pub fn new_with_led(
64 qdec: impl Peripheral<P = QDEC> + 'd, 76 qdec: impl Peripheral<P = T> + 'd,
65 irq: impl Peripheral<P = interrupt::QDEC> + 'd, 77 _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
66 a: impl Peripheral<P = impl GpioPin> + 'd, 78 a: impl Peripheral<P = impl GpioPin> + 'd,
67 b: impl Peripheral<P = impl GpioPin> + 'd, 79 b: impl Peripheral<P = impl GpioPin> + 'd,
68 led: impl Peripheral<P = impl GpioPin> + 'd, 80 led: impl Peripheral<P = impl GpioPin> + 'd,
69 config: Config, 81 config: Config,
70 ) -> Self { 82 ) -> Self {
71 into_ref!(a, b, led); 83 into_ref!(qdec, a, b, led);
72 Self::new_inner(qdec, irq, a.map_into(), b.map_into(), Some(led.map_into()), config) 84 Self::new_inner(qdec, a.map_into(), b.map_into(), Some(led.map_into()), config)
73 } 85 }
74 86
75 fn new_inner( 87 fn new_inner(
76 p: impl Peripheral<P = QDEC> + 'd, 88 p: PeripheralRef<'d, T>,
77 irq: impl Peripheral<P = interrupt::QDEC> + 'd,
78 a: PeripheralRef<'d, AnyPin>, 89 a: PeripheralRef<'d, AnyPin>,
79 b: PeripheralRef<'d, AnyPin>, 90 b: PeripheralRef<'d, AnyPin>,
80 led: Option<PeripheralRef<'d, AnyPin>>, 91 led: Option<PeripheralRef<'d, AnyPin>>,
81 config: Config, 92 config: Config,
82 ) -> Self { 93 ) -> Self {
83 into_ref!(p, irq); 94 let r = T::regs();
84 let r = Self::regs();
85 95
86 // Select pins. 96 // Select pins.
87 a.conf().write(|w| w.input().connect().pull().pullup()); 97 a.conf().write(|w| w.input().connect().pull().pullup());
@@ -124,20 +134,15 @@ impl<'d> Qdec<'d> {
124 SamplePeriod::_131ms => w.sampleper()._131ms(), 134 SamplePeriod::_131ms => w.sampleper()._131ms(),
125 }); 135 });
126 136
137 unsafe { T::Interrupt::steal() }.unpend();
138 unsafe { T::Interrupt::steal() }.enable();
139
127 // Enable peripheral 140 // Enable peripheral
128 r.enable.write(|w| w.enable().set_bit()); 141 r.enable.write(|w| w.enable().set_bit());
129 142
130 // Start sampling 143 // Start sampling
131 unsafe { r.tasks_start.write(|w| w.bits(1)) }; 144 unsafe { r.tasks_start.write(|w| w.bits(1)) };
132 145
133 irq.disable();
134 irq.set_handler(|_| {
135 let r = Self::regs();
136 r.intenclr.write(|w| w.reportrdy().clear());
137 WAKER.wake();
138 });
139 irq.enable();
140
141 Self { _p: p } 146 Self { _p: p }
142 } 147 }
143 148
@@ -155,12 +160,12 @@ impl<'d> Qdec<'d> {
155 /// let delta = q.read().await; 160 /// let delta = q.read().await;
156 /// ``` 161 /// ```
157 pub async fn read(&mut self) -> i16 { 162 pub async fn read(&mut self) -> i16 {
158 let t = Self::regs(); 163 let t = T::regs();
159 t.intenset.write(|w| w.reportrdy().set()); 164 t.intenset.write(|w| w.reportrdy().set());
160 unsafe { t.tasks_readclracc.write(|w| w.bits(1)) }; 165 unsafe { t.tasks_readclracc.write(|w| w.bits(1)) };
161 166
162 let value = poll_fn(|cx| { 167 let value = poll_fn(|cx| {
163 WAKER.register(cx.waker()); 168 T::state().waker.register(cx.waker());
164 if t.events_reportrdy.read().bits() == 0 { 169 if t.events_reportrdy.read().bits() == 0 {
165 return Poll::Pending; 170 return Poll::Pending;
166 } else { 171 } else {
@@ -172,10 +177,6 @@ impl<'d> Qdec<'d> {
172 .await; 177 .await;
173 value 178 value
174 } 179 }
175
176 fn regs() -> &'static pac::qdec::RegisterBlock {
177 unsafe { &*pac::QDEC::ptr() }
178 }
179} 180}
180 181
181/// Sample period 182/// Sample period
@@ -236,3 +237,48 @@ pub enum LedPolarity {
236 /// Active low (a low output turns on the LED). 237 /// Active low (a low output turns on the LED).
237 ActiveLow, 238 ActiveLow,
238} 239}
240
241pub(crate) mod sealed {
242 use embassy_sync::waitqueue::AtomicWaker;
243
244 /// Peripheral static state
245 pub struct State {
246 pub waker: AtomicWaker,
247 }
248
249 impl State {
250 pub const fn new() -> Self {
251 Self {
252 waker: AtomicWaker::new(),
253 }
254 }
255 }
256
257 pub trait Instance {
258 fn regs() -> &'static crate::pac::qdec::RegisterBlock;
259 fn state() -> &'static State;
260 }
261}
262
263/// qdec peripheral instance.
264pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static + Send {
265 /// Interrupt for this peripheral.
266 type Interrupt: Interrupt;
267}
268
269macro_rules! impl_qdec {
270 ($type:ident, $pac_type:ident, $irq:ident) => {
271 impl crate::qdec::sealed::Instance for peripherals::$type {
272 fn regs() -> &'static crate::pac::qdec::RegisterBlock {
273 unsafe { &*pac::$pac_type::ptr() }
274 }
275 fn state() -> &'static crate::qdec::sealed::State {
276 static STATE: crate::qdec::sealed::State = crate::qdec::sealed::State::new();
277 &STATE
278 }
279 }
280 impl crate::qdec::Instance for peripherals::$type {
281 type Interrupt = crate::interrupt::$irq;
282 }
283 };
284}
diff --git a/embassy-nrf/src/qspi.rs b/embassy-nrf/src/qspi.rs
index 1b379002b..2e16c2ff5 100644
--- a/embassy-nrf/src/qspi.rs
+++ b/embassy-nrf/src/qspi.rs
@@ -3,19 +3,21 @@
3#![macro_use] 3#![macro_use]
4 4
5use core::future::poll_fn; 5use core::future::poll_fn;
6use core::marker::PhantomData;
6use core::ptr; 7use core::ptr;
7use core::task::Poll; 8use core::task::Poll;
8 9
9use embassy_hal_common::drop::OnDrop; 10use embassy_hal_common::drop::OnDrop;
10use embassy_hal_common::{into_ref, PeripheralRef}; 11use embassy_hal_common::{into_ref, PeripheralRef};
12use embedded_storage::nor_flash::{ErrorType, NorFlash, NorFlashError, NorFlashErrorKind, ReadNorFlash};
11 13
12use crate::gpio::{self, Pin as GpioPin}; 14use crate::gpio::{self, Pin as GpioPin};
13use crate::interrupt::{Interrupt, InterruptExt}; 15use crate::interrupt::{self, Interrupt, InterruptExt};
14pub use crate::pac::qspi::ifconfig0::{ 16pub use crate::pac::qspi::ifconfig0::{
15 ADDRMODE_A as AddressMode, PPSIZE_A as WritePageSize, READOC_A as ReadOpcode, WRITEOC_A as WriteOpcode, 17 ADDRMODE_A as AddressMode, PPSIZE_A as WritePageSize, READOC_A as ReadOpcode, WRITEOC_A as WriteOpcode,
16}; 18};
17pub use crate::pac::qspi::ifconfig1::SPIMODE_A as SpiMode; 19pub use crate::pac::qspi::ifconfig1::SPIMODE_A as SpiMode;
18use crate::{pac, Peripheral}; 20use crate::Peripheral;
19 21
20/// Deep power-down config. 22/// Deep power-down config.
21pub struct DeepPowerDownConfig { 23pub struct DeepPowerDownConfig {
@@ -82,6 +84,8 @@ pub struct Config {
82 pub spi_mode: SpiMode, 84 pub spi_mode: SpiMode,
83 /// Addressing mode (24-bit or 32-bit) 85 /// Addressing mode (24-bit or 32-bit)
84 pub address_mode: AddressMode, 86 pub address_mode: AddressMode,
87 /// Flash memory capacity in bytes. This is the value reported by the `embedded-storage` traits.
88 pub capacity: u32,
85} 89}
86 90
87impl Default for Config { 91impl Default for Config {
@@ -96,6 +100,7 @@ impl Default for Config {
96 sck_delay: 80, 100 sck_delay: 80,
97 spi_mode: SpiMode::MODE0, 101 spi_mode: SpiMode::MODE0,
98 address_mode: AddressMode::_24BIT, 102 address_mode: AddressMode::_24BIT,
103 capacity: 0,
99 } 104 }
100 } 105 }
101} 106}
@@ -110,17 +115,35 @@ pub enum Error {
110 // TODO add "not in data memory" error and check for it 115 // TODO add "not in data memory" error and check for it
111} 116}
112 117
118/// Interrupt handler.
119pub struct InterruptHandler<T: Instance> {
120 _phantom: PhantomData<T>,
121}
122
123impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> {
124 unsafe fn on_interrupt() {
125 let r = T::regs();
126 let s = T::state();
127
128 if r.events_ready.read().bits() != 0 {
129 s.waker.wake();
130 r.intenclr.write(|w| w.ready().clear());
131 }
132 }
133}
134
113/// QSPI flash driver. 135/// QSPI flash driver.
114pub struct Qspi<'d, T: Instance, const FLASH_SIZE: usize> { 136pub struct Qspi<'d, T: Instance> {
115 irq: PeripheralRef<'d, T::Interrupt>, 137 _peri: PeripheralRef<'d, T>,
116 dpm_enabled: bool, 138 dpm_enabled: bool,
139 capacity: u32,
117} 140}
118 141
119impl<'d, T: Instance, const FLASH_SIZE: usize> Qspi<'d, T, FLASH_SIZE> { 142impl<'d, T: Instance> Qspi<'d, T> {
120 /// Create a new QSPI driver. 143 /// Create a new QSPI driver.
121 pub fn new( 144 pub fn new(
122 _qspi: impl Peripheral<P = T> + 'd, 145 qspi: impl Peripheral<P = T> + 'd,
123 irq: impl Peripheral<P = T::Interrupt> + 'd, 146 _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
124 sck: impl Peripheral<P = impl GpioPin> + 'd, 147 sck: impl Peripheral<P = impl GpioPin> + 'd,
125 csn: impl Peripheral<P = impl GpioPin> + 'd, 148 csn: impl Peripheral<P = impl GpioPin> + 'd,
126 io0: impl Peripheral<P = impl GpioPin> + 'd, 149 io0: impl Peripheral<P = impl GpioPin> + 'd,
@@ -128,30 +151,31 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> Qspi<'d, T, FLASH_SIZE> {
128 io2: impl Peripheral<P = impl GpioPin> + 'd, 151 io2: impl Peripheral<P = impl GpioPin> + 'd,
129 io3: impl Peripheral<P = impl GpioPin> + 'd, 152 io3: impl Peripheral<P = impl GpioPin> + 'd,
130 config: Config, 153 config: Config,
131 ) -> Qspi<'d, T, FLASH_SIZE> { 154 ) -> Self {
132 into_ref!(irq, sck, csn, io0, io1, io2, io3); 155 into_ref!(qspi, sck, csn, io0, io1, io2, io3);
133 156
134 let r = T::regs(); 157 let r = T::regs();
135 158
136 sck.set_high(); 159 macro_rules! config_pin {
137 csn.set_high(); 160 ($pin:ident) => {
138 io0.set_high(); 161 $pin.set_high();
139 io1.set_high(); 162 $pin.conf().write(|w| {
140 io2.set_high(); 163 w.dir().output();
141 io3.set_high(); 164 w.drive().h0h1();
142 sck.conf().write(|w| w.dir().output().drive().h0h1()); 165 #[cfg(feature = "_nrf5340-s")]
143 csn.conf().write(|w| w.dir().output().drive().h0h1()); 166 w.mcusel().peripheral();
144 io0.conf().write(|w| w.dir().output().drive().h0h1()); 167 w
145 io1.conf().write(|w| w.dir().output().drive().h0h1()); 168 });
146 io2.conf().write(|w| w.dir().output().drive().h0h1()); 169 r.psel.$pin.write(|w| unsafe { w.bits($pin.psel_bits()) });
147 io3.conf().write(|w| w.dir().output().drive().h0h1()); 170 };
148 171 }
149 r.psel.sck.write(|w| unsafe { w.bits(sck.psel_bits()) }); 172
150 r.psel.csn.write(|w| unsafe { w.bits(csn.psel_bits()) }); 173 config_pin!(sck);
151 r.psel.io0.write(|w| unsafe { w.bits(io0.psel_bits()) }); 174 config_pin!(csn);
152 r.psel.io1.write(|w| unsafe { w.bits(io1.psel_bits()) }); 175 config_pin!(io0);
153 r.psel.io2.write(|w| unsafe { w.bits(io2.psel_bits()) }); 176 config_pin!(io1);
154 r.psel.io3.write(|w| unsafe { w.bits(io3.psel_bits()) }); 177 config_pin!(io2);
178 config_pin!(io3);
155 179
156 r.ifconfig0.write(|w| { 180 r.ifconfig0.write(|w| {
157 w.addrmode().variant(config.address_mode); 181 w.addrmode().variant(config.address_mode);
@@ -183,16 +207,16 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> Qspi<'d, T, FLASH_SIZE> {
183 w 207 w
184 }); 208 });
185 209
186 irq.set_handler(Self::on_interrupt); 210 unsafe { T::Interrupt::steal() }.unpend();
187 irq.unpend(); 211 unsafe { T::Interrupt::steal() }.enable();
188 irq.enable();
189 212
190 // Enable it 213 // Enable it
191 r.enable.write(|w| w.enable().enabled()); 214 r.enable.write(|w| w.enable().enabled());
192 215
193 let res = Self { 216 let res = Self {
217 _peri: qspi,
194 dpm_enabled: config.deep_power_down.is_some(), 218 dpm_enabled: config.deep_power_down.is_some(),
195 irq, 219 capacity: config.capacity,
196 }; 220 };
197 221
198 r.events_ready.reset(); 222 r.events_ready.reset();
@@ -205,16 +229,6 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> Qspi<'d, T, FLASH_SIZE> {
205 res 229 res
206 } 230 }
207 231
208 fn on_interrupt(_: *mut ()) {
209 let r = T::regs();
210 let s = T::state();
211
212 if r.events_ready.read().bits() != 0 {
213 s.ready_waker.wake();
214 r.intenclr.write(|w| w.ready().clear());
215 }
216 }
217
218 /// Do a custom QSPI instruction. 232 /// Do a custom QSPI instruction.
219 pub async fn custom_instruction(&mut self, opcode: u8, req: &[u8], resp: &mut [u8]) -> Result<(), Error> { 233 pub async fn custom_instruction(&mut self, opcode: u8, req: &[u8], resp: &mut [u8]) -> Result<(), Error> {
220 let ondrop = OnDrop::new(Self::blocking_wait_ready); 234 let ondrop = OnDrop::new(Self::blocking_wait_ready);
@@ -303,7 +317,7 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> Qspi<'d, T, FLASH_SIZE> {
303 poll_fn(move |cx| { 317 poll_fn(move |cx| {
304 let r = T::regs(); 318 let r = T::regs();
305 let s = T::state(); 319 let s = T::state();
306 s.ready_waker.register(cx.waker()); 320 s.waker.register(cx.waker());
307 if r.events_ready.read().bits() != 0 { 321 if r.events_ready.read().bits() != 0 {
308 return Poll::Ready(()); 322 return Poll::Ready(());
309 } 323 }
@@ -321,17 +335,15 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> Qspi<'d, T, FLASH_SIZE> {
321 } 335 }
322 } 336 }
323 337
324 fn start_read(&mut self, address: usize, data: &mut [u8]) -> Result<(), Error> { 338 fn start_read(&mut self, address: u32, data: &mut [u8]) -> Result<(), Error> {
339 // TODO: Return these as errors instead.
325 assert_eq!(data.as_ptr() as u32 % 4, 0); 340 assert_eq!(data.as_ptr() as u32 % 4, 0);
326 assert_eq!(data.len() as u32 % 4, 0); 341 assert_eq!(data.len() as u32 % 4, 0);
327 assert_eq!(address as u32 % 4, 0); 342 assert_eq!(address % 4, 0);
328 if address > FLASH_SIZE {
329 return Err(Error::OutOfBounds);
330 }
331 343
332 let r = T::regs(); 344 let r = T::regs();
333 345
334 r.read.src.write(|w| unsafe { w.src().bits(address as u32) }); 346 r.read.src.write(|w| unsafe { w.src().bits(address) });
335 r.read.dst.write(|w| unsafe { w.dst().bits(data.as_ptr() as u32) }); 347 r.read.dst.write(|w| unsafe { w.dst().bits(data.as_ptr() as u32) });
336 r.read.cnt.write(|w| unsafe { w.cnt().bits(data.len() as u32) }); 348 r.read.cnt.write(|w| unsafe { w.cnt().bits(data.len() as u32) });
337 349
@@ -342,18 +354,15 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> Qspi<'d, T, FLASH_SIZE> {
342 Ok(()) 354 Ok(())
343 } 355 }
344 356
345 fn start_write(&mut self, address: usize, data: &[u8]) -> Result<(), Error> { 357 fn start_write(&mut self, address: u32, data: &[u8]) -> Result<(), Error> {
358 // TODO: Return these as errors instead.
346 assert_eq!(data.as_ptr() as u32 % 4, 0); 359 assert_eq!(data.as_ptr() as u32 % 4, 0);
347 assert_eq!(data.len() as u32 % 4, 0); 360 assert_eq!(data.len() as u32 % 4, 0);
348 assert_eq!(address as u32 % 4, 0); 361 assert_eq!(address % 4, 0);
349
350 if address > FLASH_SIZE {
351 return Err(Error::OutOfBounds);
352 }
353 362
354 let r = T::regs(); 363 let r = T::regs();
355 r.write.src.write(|w| unsafe { w.src().bits(data.as_ptr() as u32) }); 364 r.write.src.write(|w| unsafe { w.src().bits(data.as_ptr() as u32) });
356 r.write.dst.write(|w| unsafe { w.dst().bits(address as u32) }); 365 r.write.dst.write(|w| unsafe { w.dst().bits(address) });
357 r.write.cnt.write(|w| unsafe { w.cnt().bits(data.len() as u32) }); 366 r.write.cnt.write(|w| unsafe { w.cnt().bits(data.len() as u32) });
358 367
359 r.events_ready.reset(); 368 r.events_ready.reset();
@@ -363,14 +372,12 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> Qspi<'d, T, FLASH_SIZE> {
363 Ok(()) 372 Ok(())
364 } 373 }
365 374
366 fn start_erase(&mut self, address: usize) -> Result<(), Error> { 375 fn start_erase(&mut self, address: u32) -> Result<(), Error> {
367 assert_eq!(address as u32 % 4096, 0); 376 // TODO: Return these as errors instead.
368 if address > FLASH_SIZE { 377 assert_eq!(address % 4096, 0);
369 return Err(Error::OutOfBounds);
370 }
371 378
372 let r = T::regs(); 379 let r = T::regs();
373 r.erase.ptr.write(|w| unsafe { w.ptr().bits(address as u32) }); 380 r.erase.ptr.write(|w| unsafe { w.ptr().bits(address) });
374 r.erase.len.write(|w| w.len()._4kb()); 381 r.erase.len.write(|w| w.len()._4kb());
375 382
376 r.events_ready.reset(); 383 r.events_ready.reset();
@@ -380,8 +387,12 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> Qspi<'d, T, FLASH_SIZE> {
380 Ok(()) 387 Ok(())
381 } 388 }
382 389
383 /// Read data from the flash memory. 390 /// Raw QSPI read.
384 pub async fn read(&mut self, address: usize, data: &mut [u8]) -> Result<(), Error> { 391 ///
392 /// The difference with `read` is that this does not do bounds checks
393 /// against the flash capacity. It is intended for use when QSPI is used as
394 /// a raw bus, not with flash memory.
395 pub async fn read_raw(&mut self, address: u32, data: &mut [u8]) -> Result<(), Error> {
385 let ondrop = OnDrop::new(Self::blocking_wait_ready); 396 let ondrop = OnDrop::new(Self::blocking_wait_ready);
386 397
387 self.start_read(address, data)?; 398 self.start_read(address, data)?;
@@ -392,8 +403,12 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> Qspi<'d, T, FLASH_SIZE> {
392 Ok(()) 403 Ok(())
393 } 404 }
394 405
395 /// Write data to the flash memory. 406 /// Raw QSPI write.
396 pub async fn write(&mut self, address: usize, data: &[u8]) -> Result<(), Error> { 407 ///
408 /// The difference with `write` is that this does not do bounds checks
409 /// against the flash capacity. It is intended for use when QSPI is used as
410 /// a raw bus, not with flash memory.
411 pub async fn write_raw(&mut self, address: u32, data: &[u8]) -> Result<(), Error> {
397 let ondrop = OnDrop::new(Self::blocking_wait_ready); 412 let ondrop = OnDrop::new(Self::blocking_wait_ready);
398 413
399 self.start_write(address, data)?; 414 self.start_write(address, data)?;
@@ -404,8 +419,46 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> Qspi<'d, T, FLASH_SIZE> {
404 Ok(()) 419 Ok(())
405 } 420 }
406 421
422 /// Raw QSPI read, blocking version.
423 ///
424 /// The difference with `blocking_read` is that this does not do bounds checks
425 /// against the flash capacity. It is intended for use when QSPI is used as
426 /// a raw bus, not with flash memory.
427 pub fn blocking_read_raw(&mut self, address: u32, data: &mut [u8]) -> Result<(), Error> {
428 self.start_read(address, data)?;
429 Self::blocking_wait_ready();
430 Ok(())
431 }
432
433 /// Raw QSPI write, blocking version.
434 ///
435 /// The difference with `blocking_write` is that this does not do bounds checks
436 /// against the flash capacity. It is intended for use when QSPI is used as
437 /// a raw bus, not with flash memory.
438 pub fn blocking_write_raw(&mut self, address: u32, data: &[u8]) -> Result<(), Error> {
439 self.start_write(address, data)?;
440 Self::blocking_wait_ready();
441 Ok(())
442 }
443
444 /// Read data from the flash memory.
445 pub async fn read(&mut self, address: u32, data: &mut [u8]) -> Result<(), Error> {
446 self.bounds_check(address, data.len())?;
447 self.read_raw(address, data).await
448 }
449
450 /// Write data to the flash memory.
451 pub async fn write(&mut self, address: u32, data: &[u8]) -> Result<(), Error> {
452 self.bounds_check(address, data.len())?;
453 self.write_raw(address, data).await
454 }
455
407 /// Erase a sector on the flash memory. 456 /// Erase a sector on the flash memory.
408 pub async fn erase(&mut self, address: usize) -> Result<(), Error> { 457 pub async fn erase(&mut self, address: u32) -> Result<(), Error> {
458 if address >= self.capacity {
459 return Err(Error::OutOfBounds);
460 }
461
409 let ondrop = OnDrop::new(Self::blocking_wait_ready); 462 let ondrop = OnDrop::new(Self::blocking_wait_ready);
410 463
411 self.start_erase(address)?; 464 self.start_erase(address)?;
@@ -417,28 +470,39 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> Qspi<'d, T, FLASH_SIZE> {
417 } 470 }
418 471
419 /// Read data from the flash memory, blocking version. 472 /// Read data from the flash memory, blocking version.
420 pub fn blocking_read(&mut self, address: usize, data: &mut [u8]) -> Result<(), Error> { 473 pub fn blocking_read(&mut self, address: u32, data: &mut [u8]) -> Result<(), Error> {
421 self.start_read(address, data)?; 474 self.bounds_check(address, data.len())?;
422 Self::blocking_wait_ready(); 475 self.blocking_read_raw(address, data)
423 Ok(())
424 } 476 }
425 477
426 /// Write data to the flash memory, blocking version. 478 /// Write data to the flash memory, blocking version.
427 pub fn blocking_write(&mut self, address: usize, data: &[u8]) -> Result<(), Error> { 479 pub fn blocking_write(&mut self, address: u32, data: &[u8]) -> Result<(), Error> {
428 self.start_write(address, data)?; 480 self.bounds_check(address, data.len())?;
429 Self::blocking_wait_ready(); 481 self.blocking_write_raw(address, data)
430 Ok(())
431 } 482 }
432 483
433 /// Erase a sector on the flash memory, blocking version. 484 /// Erase a sector on the flash memory, blocking version.
434 pub fn blocking_erase(&mut self, address: usize) -> Result<(), Error> { 485 pub fn blocking_erase(&mut self, address: u32) -> Result<(), Error> {
486 if address >= self.capacity {
487 return Err(Error::OutOfBounds);
488 }
489
435 self.start_erase(address)?; 490 self.start_erase(address)?;
436 Self::blocking_wait_ready(); 491 Self::blocking_wait_ready();
437 Ok(()) 492 Ok(())
438 } 493 }
494
495 fn bounds_check(&self, address: u32, len: usize) -> Result<(), Error> {
496 let len_u32: u32 = len.try_into().map_err(|_| Error::OutOfBounds)?;
497 let end_address = address.checked_add(len_u32).ok_or(Error::OutOfBounds)?;
498 if end_address > self.capacity {
499 return Err(Error::OutOfBounds);
500 }
501 Ok(())
502 }
439} 503}
440 504
441impl<'d, T: Instance, const FLASH_SIZE: usize> Drop for Qspi<'d, T, FLASH_SIZE> { 505impl<'d, T: Instance> Drop for Qspi<'d, T> {
442 fn drop(&mut self) { 506 fn drop(&mut self) {
443 let r = T::regs(); 507 let r = T::regs();
444 508
@@ -468,8 +532,6 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> Drop for Qspi<'d, T, FLASH_SIZE>
468 532
469 r.enable.write(|w| w.enable().disabled()); 533 r.enable.write(|w| w.enable().disabled());
470 534
471 self.irq.disable();
472
473 // Note: we do NOT deconfigure CSN here. If DPM is in use and we disconnect CSN, 535 // Note: we do NOT deconfigure CSN here. If DPM is in use and we disconnect CSN,
474 // leaving it floating, the flash chip might read it as zero which would cause it to 536 // leaving it floating, the flash chip might read it as zero which would cause it to
475 // spuriously exit DPM. 537 // spuriously exit DPM.
@@ -483,9 +545,7 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> Drop for Qspi<'d, T, FLASH_SIZE>
483 } 545 }
484} 546}
485 547
486use embedded_storage::nor_flash::{ErrorType, NorFlash, NorFlashError, NorFlashErrorKind, ReadNorFlash}; 548impl<'d, T: Instance> ErrorType for Qspi<'d, T> {
487
488impl<'d, T: Instance, const FLASH_SIZE: usize> ErrorType for Qspi<'d, T, FLASH_SIZE> {
489 type Error = Error; 549 type Error = Error;
490} 550}
491 551
@@ -495,66 +555,66 @@ impl NorFlashError for Error {
495 } 555 }
496} 556}
497 557
498impl<'d, T: Instance, const FLASH_SIZE: usize> ReadNorFlash for Qspi<'d, T, FLASH_SIZE> { 558impl<'d, T: Instance> ReadNorFlash for Qspi<'d, T> {
499 const READ_SIZE: usize = 4; 559 const READ_SIZE: usize = 4;
500 560
501 fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> { 561 fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> {
502 self.blocking_read(offset as usize, bytes)?; 562 self.blocking_read(offset, bytes)?;
503 Ok(()) 563 Ok(())
504 } 564 }
505 565
506 fn capacity(&self) -> usize { 566 fn capacity(&self) -> usize {
507 FLASH_SIZE 567 self.capacity as usize
508 } 568 }
509} 569}
510 570
511impl<'d, T: Instance, const FLASH_SIZE: usize> NorFlash for Qspi<'d, T, FLASH_SIZE> { 571impl<'d, T: Instance> NorFlash for Qspi<'d, T> {
512 const WRITE_SIZE: usize = 4; 572 const WRITE_SIZE: usize = 4;
513 const ERASE_SIZE: usize = 4096; 573 const ERASE_SIZE: usize = 4096;
514 574
515 fn erase(&mut self, from: u32, to: u32) -> Result<(), Self::Error> { 575 fn erase(&mut self, from: u32, to: u32) -> Result<(), Self::Error> {
516 for address in (from as usize..to as usize).step_by(<Self as NorFlash>::ERASE_SIZE) { 576 for address in (from..to).step_by(<Self as NorFlash>::ERASE_SIZE) {
517 self.blocking_erase(address)?; 577 self.blocking_erase(address)?;
518 } 578 }
519 Ok(()) 579 Ok(())
520 } 580 }
521 581
522 fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Self::Error> { 582 fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Self::Error> {
523 self.blocking_write(offset as usize, bytes)?; 583 self.blocking_write(offset, bytes)?;
524 Ok(()) 584 Ok(())
525 } 585 }
526} 586}
527 587
528cfg_if::cfg_if! { 588#[cfg(feature = "nightly")]
529 if #[cfg(feature = "nightly")] 589mod _eh1 {
530 { 590 use embedded_storage_async::nor_flash::{NorFlash as AsyncNorFlash, ReadNorFlash as AsyncReadNorFlash};
531 use embedded_storage_async::nor_flash::{NorFlash as AsyncNorFlash, ReadNorFlash as AsyncReadNorFlash};
532 591
533 impl<'d, T: Instance, const FLASH_SIZE: usize> AsyncNorFlash for Qspi<'d, T, FLASH_SIZE> { 592 use super::*;
534 const WRITE_SIZE: usize = <Self as NorFlash>::WRITE_SIZE;
535 const ERASE_SIZE: usize = <Self as NorFlash>::ERASE_SIZE;
536 593
537 async fn write(&mut self, offset: u32, data: &[u8]) -> Result<(), Self::Error> { 594 impl<'d, T: Instance> AsyncNorFlash for Qspi<'d, T> {
538 self.write(offset as usize, data).await 595 const WRITE_SIZE: usize = <Self as NorFlash>::WRITE_SIZE;
539 } 596 const ERASE_SIZE: usize = <Self as NorFlash>::ERASE_SIZE;
540 597
541 async fn erase(&mut self, from: u32, to: u32) -> Result<(), Self::Error> { 598 async fn write(&mut self, offset: u32, data: &[u8]) -> Result<(), Self::Error> {
542 for address in (from as usize..to as usize).step_by(<Self as AsyncNorFlash>::ERASE_SIZE) { 599 self.write(offset, data).await
543 self.erase(address).await?
544 }
545 Ok(())
546 }
547 } 600 }
548 601
549 impl<'d, T: Instance, const FLASH_SIZE: usize> AsyncReadNorFlash for Qspi<'d, T, FLASH_SIZE> { 602 async fn erase(&mut self, from: u32, to: u32) -> Result<(), Self::Error> {
550 const READ_SIZE: usize = 4; 603 for address in (from..to).step_by(<Self as AsyncNorFlash>::ERASE_SIZE) {
551 async fn read(&mut self, address: u32, data: &mut [u8]) -> Result<(), Self::Error> { 604 self.erase(address).await?
552 self.read(address as usize, data).await
553 } 605 }
606 Ok(())
607 }
608 }
554 609
555 fn capacity(&self) -> usize { 610 impl<'d, T: Instance> AsyncReadNorFlash for Qspi<'d, T> {
556 FLASH_SIZE 611 const READ_SIZE: usize = 4;
557 } 612 async fn read(&mut self, address: u32, data: &mut [u8]) -> Result<(), Self::Error> {
613 self.read(address, data).await
614 }
615
616 fn capacity(&self) -> usize {
617 self.capacity as usize
558 } 618 }
559 } 619 }
560} 620}
@@ -562,27 +622,27 @@ cfg_if::cfg_if! {
562pub(crate) mod sealed { 622pub(crate) mod sealed {
563 use embassy_sync::waitqueue::AtomicWaker; 623 use embassy_sync::waitqueue::AtomicWaker;
564 624
565 use super::*; 625 /// Peripheral static state
566
567 pub struct State { 626 pub struct State {
568 pub ready_waker: AtomicWaker, 627 pub waker: AtomicWaker,
569 } 628 }
629
570 impl State { 630 impl State {
571 pub const fn new() -> Self { 631 pub const fn new() -> Self {
572 Self { 632 Self {
573 ready_waker: AtomicWaker::new(), 633 waker: AtomicWaker::new(),
574 } 634 }
575 } 635 }
576 } 636 }
577 637
578 pub trait Instance { 638 pub trait Instance {
579 fn regs() -> &'static pac::qspi::RegisterBlock; 639 fn regs() -> &'static crate::pac::qspi::RegisterBlock;
580 fn state() -> &'static State; 640 fn state() -> &'static State;
581 } 641 }
582} 642}
583 643
584/// QSPI peripheral instance. 644/// QSPI peripheral instance.
585pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static { 645pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static + Send {
586 /// Interrupt for this peripheral. 646 /// Interrupt for this peripheral.
587 type Interrupt: Interrupt; 647 type Interrupt: Interrupt;
588} 648}
@@ -590,7 +650,7 @@ pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static {
590macro_rules! impl_qspi { 650macro_rules! impl_qspi {
591 ($type:ident, $pac_type:ident, $irq:ident) => { 651 ($type:ident, $pac_type:ident, $irq:ident) => {
592 impl crate::qspi::sealed::Instance for peripherals::$type { 652 impl crate::qspi::sealed::Instance for peripherals::$type {
593 fn regs() -> &'static pac::qspi::RegisterBlock { 653 fn regs() -> &'static crate::pac::qspi::RegisterBlock {
594 unsafe { &*pac::$pac_type::ptr() } 654 unsafe { &*pac::$pac_type::ptr() }
595 } 655 }
596 fn state() -> &'static crate::qspi::sealed::State { 656 fn state() -> &'static crate::qspi::sealed::State {
diff --git a/embassy-nrf/src/rng.rs b/embassy-nrf/src/rng.rs
index b0b3a8eb8..a5602248d 100644
--- a/embassy-nrf/src/rng.rs
+++ b/embassy-nrf/src/rng.rs
@@ -1,83 +1,48 @@
1//! Random Number Generator (RNG) driver. 1//! Random Number Generator (RNG) driver.
2 2
3#![macro_use]
4
3use core::future::poll_fn; 5use core::future::poll_fn;
6use core::marker::PhantomData;
4use core::ptr; 7use core::ptr;
5use core::sync::atomic::{AtomicPtr, Ordering}; 8use core::sync::atomic::{AtomicPtr, Ordering};
6use core::task::Poll; 9use core::task::Poll;
7 10
11use embassy_cortex_m::interrupt::Interrupt;
8use embassy_hal_common::drop::OnDrop; 12use embassy_hal_common::drop::OnDrop;
9use embassy_hal_common::{into_ref, PeripheralRef}; 13use embassy_hal_common::{into_ref, PeripheralRef};
10use embassy_sync::waitqueue::AtomicWaker; 14use embassy_sync::waitqueue::AtomicWaker;
11 15
12use crate::interrupt::InterruptExt; 16use crate::interrupt::InterruptExt;
13use crate::peripherals::RNG; 17use crate::{interrupt, Peripheral};
14use crate::{interrupt, pac, Peripheral};
15
16impl RNG {
17 fn regs() -> &'static pac::rng::RegisterBlock {
18 unsafe { &*pac::RNG::ptr() }
19 }
20}
21
22static STATE: State = State {
23 ptr: AtomicPtr::new(ptr::null_mut()),
24 end: AtomicPtr::new(ptr::null_mut()),
25 waker: AtomicWaker::new(),
26};
27 18
28struct State { 19/// Interrupt handler.
29 ptr: AtomicPtr<u8>, 20pub struct InterruptHandler<T: Instance> {
30 end: AtomicPtr<u8>, 21 _phantom: PhantomData<T>,
31 waker: AtomicWaker,
32} 22}
33 23
34/// A wrapper around an nRF RNG peripheral. 24impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> {
35/// 25 unsafe fn on_interrupt() {
36/// It has a non-blocking API, and a blocking api through `rand`. 26 let s = T::state();
37pub struct Rng<'d> { 27 let r = T::regs();
38 irq: PeripheralRef<'d, interrupt::RNG>,
39}
40
41impl<'d> Rng<'d> {
42 /// Creates a new RNG driver from the `RNG` peripheral and interrupt.
43 ///
44 /// SAFETY: The future returned from `fill_bytes` must not have its lifetime end without running its destructor,
45 /// e.g. using `mem::forget`.
46 ///
47 /// The synchronous API is safe.
48 pub fn new(_rng: impl Peripheral<P = RNG> + 'd, irq: impl Peripheral<P = interrupt::RNG> + 'd) -> Self {
49 into_ref!(irq);
50
51 let this = Self { irq };
52 28
53 this.stop();
54 this.disable_irq();
55
56 this.irq.set_handler(Self::on_interrupt);
57 this.irq.unpend();
58 this.irq.enable();
59
60 this
61 }
62
63 fn on_interrupt(_: *mut ()) {
64 // Clear the event. 29 // Clear the event.
65 RNG::regs().events_valrdy.reset(); 30 r.events_valrdy.reset();
66 31
67 // Mutate the slice within a critical section, 32 // Mutate the slice within a critical section,
68 // so that the future isn't dropped in between us loading the pointer and actually dereferencing it. 33 // so that the future isn't dropped in between us loading the pointer and actually dereferencing it.
69 let (ptr, end) = critical_section::with(|_| { 34 let (ptr, end) = critical_section::with(|_| {
70 let ptr = STATE.ptr.load(Ordering::Relaxed); 35 let ptr = s.ptr.load(Ordering::Relaxed);
71 // We need to make sure we haven't already filled the whole slice, 36 // We need to make sure we haven't already filled the whole slice,
72 // in case the interrupt fired again before the executor got back to the future. 37 // in case the interrupt fired again before the executor got back to the future.
73 let end = STATE.end.load(Ordering::Relaxed); 38 let end = s.end.load(Ordering::Relaxed);
74 if !ptr.is_null() && ptr != end { 39 if !ptr.is_null() && ptr != end {
75 // If the future was dropped, the pointer would have been set to null, 40 // If the future was dropped, the pointer would have been set to null,
76 // so we're still good to mutate the slice. 41 // so we're still good to mutate the slice.
77 // The safety contract of `Rng::new` means that the future can't have been dropped 42 // The safety contract of `Rng::new` means that the future can't have been dropped
78 // without calling its destructor. 43 // without calling its destructor.
79 unsafe { 44 unsafe {
80 *ptr = RNG::regs().value.read().value().bits(); 45 *ptr = r.value.read().value().bits();
81 } 46 }
82 } 47 }
83 (ptr, end) 48 (ptr, end)
@@ -90,15 +55,15 @@ impl<'d> Rng<'d> {
90 } 55 }
91 56
92 let new_ptr = unsafe { ptr.add(1) }; 57 let new_ptr = unsafe { ptr.add(1) };
93 match STATE 58 match s
94 .ptr 59 .ptr
95 .compare_exchange(ptr, new_ptr, Ordering::Relaxed, Ordering::Relaxed) 60 .compare_exchange(ptr, new_ptr, Ordering::Relaxed, Ordering::Relaxed)
96 { 61 {
97 Ok(_) => { 62 Ok(_) => {
98 let end = STATE.end.load(Ordering::Relaxed); 63 let end = s.end.load(Ordering::Relaxed);
99 // It doesn't matter if `end` was changed under our feet, because then this will just be false. 64 // It doesn't matter if `end` was changed under our feet, because then this will just be false.
100 if new_ptr == end { 65 if new_ptr == end {
101 STATE.waker.wake(); 66 s.waker.wake();
102 } 67 }
103 } 68 }
104 Err(_) => { 69 Err(_) => {
@@ -107,21 +72,53 @@ impl<'d> Rng<'d> {
107 } 72 }
108 } 73 }
109 } 74 }
75}
76
77/// A wrapper around an nRF RNG peripheral.
78///
79/// It has a non-blocking API, and a blocking api through `rand`.
80pub struct Rng<'d, T: Instance> {
81 _peri: PeripheralRef<'d, T>,
82}
83
84impl<'d, T: Instance> Rng<'d, T> {
85 /// Creates a new RNG driver from the `RNG` peripheral and interrupt.
86 ///
87 /// SAFETY: The future returned from `fill_bytes` must not have its lifetime end without running its destructor,
88 /// e.g. using `mem::forget`.
89 ///
90 /// The synchronous API is safe.
91 pub fn new(
92 rng: impl Peripheral<P = T> + 'd,
93 _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
94 ) -> Self {
95 into_ref!(rng);
96
97 let this = Self { _peri: rng };
98
99 this.stop();
100 this.disable_irq();
101
102 unsafe { T::Interrupt::steal() }.unpend();
103 unsafe { T::Interrupt::steal() }.enable();
104
105 this
106 }
110 107
111 fn stop(&self) { 108 fn stop(&self) {
112 RNG::regs().tasks_stop.write(|w| unsafe { w.bits(1) }) 109 T::regs().tasks_stop.write(|w| unsafe { w.bits(1) })
113 } 110 }
114 111
115 fn start(&self) { 112 fn start(&self) {
116 RNG::regs().tasks_start.write(|w| unsafe { w.bits(1) }) 113 T::regs().tasks_start.write(|w| unsafe { w.bits(1) })
117 } 114 }
118 115
119 fn enable_irq(&self) { 116 fn enable_irq(&self) {
120 RNG::regs().intenset.write(|w| w.valrdy().set()); 117 T::regs().intenset.write(|w| w.valrdy().set());
121 } 118 }
122 119
123 fn disable_irq(&self) { 120 fn disable_irq(&self) {
124 RNG::regs().intenclr.write(|w| w.valrdy().clear()); 121 T::regs().intenclr.write(|w| w.valrdy().clear());
125 } 122 }
126 123
127 /// Enable or disable the RNG's bias correction. 124 /// Enable or disable the RNG's bias correction.
@@ -131,7 +128,7 @@ impl<'d> Rng<'d> {
131 /// 128 ///
132 /// Defaults to disabled. 129 /// Defaults to disabled.
133 pub fn set_bias_correction(&self, enable: bool) { 130 pub fn set_bias_correction(&self, enable: bool) {
134 RNG::regs().config.write(|w| w.dercen().bit(enable)) 131 T::regs().config.write(|w| w.dercen().bit(enable))
135 } 132 }
136 133
137 /// Fill the buffer with random bytes. 134 /// Fill the buffer with random bytes.
@@ -140,11 +137,13 @@ impl<'d> Rng<'d> {
140 return; // Nothing to fill 137 return; // Nothing to fill
141 } 138 }
142 139
140 let s = T::state();
141
143 let range = dest.as_mut_ptr_range(); 142 let range = dest.as_mut_ptr_range();
144 // Even if we've preempted the interrupt, it can't preempt us again, 143 // Even if we've preempted the interrupt, it can't preempt us again,
145 // so we don't need to worry about the order we write these in. 144 // so we don't need to worry about the order we write these in.
146 STATE.ptr.store(range.start, Ordering::Relaxed); 145 s.ptr.store(range.start, Ordering::Relaxed);
147 STATE.end.store(range.end, Ordering::Relaxed); 146 s.end.store(range.end, Ordering::Relaxed);
148 147
149 self.enable_irq(); 148 self.enable_irq();
150 self.start(); 149 self.start();
@@ -154,16 +153,16 @@ impl<'d> Rng<'d> {
154 self.disable_irq(); 153 self.disable_irq();
155 154
156 // The interrupt is now disabled and can't preempt us anymore, so the order doesn't matter here. 155 // The interrupt is now disabled and can't preempt us anymore, so the order doesn't matter here.
157 STATE.ptr.store(ptr::null_mut(), Ordering::Relaxed); 156 s.ptr.store(ptr::null_mut(), Ordering::Relaxed);
158 STATE.end.store(ptr::null_mut(), Ordering::Relaxed); 157 s.end.store(ptr::null_mut(), Ordering::Relaxed);
159 }); 158 });
160 159
161 poll_fn(|cx| { 160 poll_fn(|cx| {
162 STATE.waker.register(cx.waker()); 161 s.waker.register(cx.waker());
163 162
164 // The interrupt will never modify `end`, so load it first and then get the most up-to-date `ptr`. 163 // The interrupt will never modify `end`, so load it first and then get the most up-to-date `ptr`.
165 let end = STATE.end.load(Ordering::Relaxed); 164 let end = s.end.load(Ordering::Relaxed);
166 let ptr = STATE.ptr.load(Ordering::Relaxed); 165 let ptr = s.ptr.load(Ordering::Relaxed);
167 166
168 if ptr == end { 167 if ptr == end {
169 // We're done. 168 // We're done.
@@ -183,7 +182,7 @@ impl<'d> Rng<'d> {
183 self.start(); 182 self.start();
184 183
185 for byte in dest.iter_mut() { 184 for byte in dest.iter_mut() {
186 let regs = RNG::regs(); 185 let regs = T::regs();
187 while regs.events_valrdy.read().bits() == 0 {} 186 while regs.events_valrdy.read().bits() == 0 {}
188 regs.events_valrdy.reset(); 187 regs.events_valrdy.reset();
189 *byte = regs.value.read().value().bits(); 188 *byte = regs.value.read().value().bits();
@@ -193,13 +192,16 @@ impl<'d> Rng<'d> {
193 } 192 }
194} 193}
195 194
196impl<'d> Drop for Rng<'d> { 195impl<'d, T: Instance> Drop for Rng<'d, T> {
197 fn drop(&mut self) { 196 fn drop(&mut self) {
198 self.irq.disable() 197 self.stop();
198 let s = T::state();
199 s.ptr.store(ptr::null_mut(), Ordering::Relaxed);
200 s.end.store(ptr::null_mut(), Ordering::Relaxed);
199 } 201 }
200} 202}
201 203
202impl<'d> rand_core::RngCore for Rng<'d> { 204impl<'d, T: Instance> rand_core::RngCore for Rng<'d, T> {
203 fn fill_bytes(&mut self, dest: &mut [u8]) { 205 fn fill_bytes(&mut self, dest: &mut [u8]) {
204 self.blocking_fill_bytes(dest); 206 self.blocking_fill_bytes(dest);
205 } 207 }
@@ -223,4 +225,53 @@ impl<'d> rand_core::RngCore for Rng<'d> {
223 } 225 }
224} 226}
225 227
226impl<'d> rand_core::CryptoRng for Rng<'d> {} 228impl<'d, T: Instance> rand_core::CryptoRng for Rng<'d, T> {}
229
230pub(crate) mod sealed {
231 use super::*;
232
233 /// Peripheral static state
234 pub struct State {
235 pub ptr: AtomicPtr<u8>,
236 pub end: AtomicPtr<u8>,
237 pub waker: AtomicWaker,
238 }
239
240 impl State {
241 pub const fn new() -> Self {
242 Self {
243 ptr: AtomicPtr::new(ptr::null_mut()),
244 end: AtomicPtr::new(ptr::null_mut()),
245 waker: AtomicWaker::new(),
246 }
247 }
248 }
249
250 pub trait Instance {
251 fn regs() -> &'static crate::pac::rng::RegisterBlock;
252 fn state() -> &'static State;
253 }
254}
255
256/// RNG peripheral instance.
257pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static + Send {
258 /// Interrupt for this peripheral.
259 type Interrupt: Interrupt;
260}
261
262macro_rules! impl_rng {
263 ($type:ident, $pac_type:ident, $irq:ident) => {
264 impl crate::rng::sealed::Instance for peripherals::$type {
265 fn regs() -> &'static crate::pac::rng::RegisterBlock {
266 unsafe { &*pac::$pac_type::ptr() }
267 }
268 fn state() -> &'static crate::rng::sealed::State {
269 static STATE: crate::rng::sealed::State = crate::rng::sealed::State::new();
270 &STATE
271 }
272 }
273 impl crate::rng::Instance for peripherals::$type {
274 type Interrupt = crate::interrupt::$irq;
275 }
276 };
277}
diff --git a/embassy-nrf/src/saadc.rs b/embassy-nrf/src/saadc.rs
index 2d01a3dda..af952f03d 100644
--- a/embassy-nrf/src/saadc.rs
+++ b/embassy-nrf/src/saadc.rs
@@ -6,6 +6,7 @@ use core::future::poll_fn;
6use core::sync::atomic::{compiler_fence, Ordering}; 6use core::sync::atomic::{compiler_fence, Ordering};
7use core::task::Poll; 7use core::task::Poll;
8 8
9use embassy_cortex_m::interrupt::{Interrupt, InterruptExt};
9use embassy_hal_common::drop::OnDrop; 10use embassy_hal_common::drop::OnDrop;
10use embassy_hal_common::{impl_peripheral, into_ref, PeripheralRef}; 11use embassy_hal_common::{impl_peripheral, into_ref, PeripheralRef};
11use embassy_sync::waitqueue::AtomicWaker; 12use embassy_sync::waitqueue::AtomicWaker;
@@ -17,7 +18,6 @@ use saadc::oversample::OVERSAMPLE_A;
17use saadc::resolution::VAL_A; 18use saadc::resolution::VAL_A;
18 19
19use self::sealed::Input as _; 20use self::sealed::Input as _;
20use crate::interrupt::InterruptExt;
21use crate::ppi::{ConfigurableChannel, Event, Ppi, Task}; 21use crate::ppi::{ConfigurableChannel, Event, Ppi, Task};
22use crate::timer::{Frequency, Instance as TimerInstance, Timer}; 22use crate::timer::{Frequency, Instance as TimerInstance, Timer};
23use crate::{interrupt, pac, peripherals, Peripheral}; 23use crate::{interrupt, pac, peripherals, Peripheral};
@@ -28,9 +28,30 @@ use crate::{interrupt, pac, peripherals, Peripheral};
28#[non_exhaustive] 28#[non_exhaustive]
29pub enum Error {} 29pub enum Error {}
30 30
31/// One-shot and continuous SAADC. 31/// Interrupt handler.
32pub struct Saadc<'d, const N: usize> { 32pub struct InterruptHandler {
33 _p: PeripheralRef<'d, peripherals::SAADC>, 33 _private: (),
34}
35
36impl interrupt::Handler<interrupt::SAADC> for InterruptHandler {
37 unsafe fn on_interrupt() {
38 let r = unsafe { &*SAADC::ptr() };
39
40 if r.events_calibratedone.read().bits() != 0 {
41 r.intenclr.write(|w| w.calibratedone().clear());
42 WAKER.wake();
43 }
44
45 if r.events_end.read().bits() != 0 {
46 r.intenclr.write(|w| w.end().clear());
47 WAKER.wake();
48 }
49
50 if r.events_started.read().bits() != 0 {
51 r.intenclr.write(|w| w.started().clear());
52 WAKER.wake();
53 }
54 }
34} 55}
35 56
36static WAKER: AtomicWaker = AtomicWaker::new(); 57static WAKER: AtomicWaker = AtomicWaker::new();
@@ -114,15 +135,20 @@ pub enum CallbackResult {
114 Stop, 135 Stop,
115} 136}
116 137
138/// One-shot and continuous SAADC.
139pub struct Saadc<'d, const N: usize> {
140 _p: PeripheralRef<'d, peripherals::SAADC>,
141}
142
117impl<'d, const N: usize> Saadc<'d, N> { 143impl<'d, const N: usize> Saadc<'d, N> {
118 /// Create a new SAADC driver. 144 /// Create a new SAADC driver.
119 pub fn new( 145 pub fn new(
120 saadc: impl Peripheral<P = peripherals::SAADC> + 'd, 146 saadc: impl Peripheral<P = peripherals::SAADC> + 'd,
121 irq: impl Peripheral<P = interrupt::SAADC> + 'd, 147 _irq: impl interrupt::Binding<interrupt::SAADC, InterruptHandler> + 'd,
122 config: Config, 148 config: Config,
123 channel_configs: [ChannelConfig; N], 149 channel_configs: [ChannelConfig; N],
124 ) -> Self { 150 ) -> Self {
125 into_ref!(saadc, irq); 151 into_ref!(saadc);
126 152
127 let r = unsafe { &*SAADC::ptr() }; 153 let r = unsafe { &*SAADC::ptr() };
128 154
@@ -163,32 +189,12 @@ impl<'d, const N: usize> Saadc<'d, N> {
163 // Disable all events interrupts 189 // Disable all events interrupts
164 r.intenclr.write(|w| unsafe { w.bits(0x003F_FFFF) }); 190 r.intenclr.write(|w| unsafe { w.bits(0x003F_FFFF) });
165 191
166 irq.set_handler(Self::on_interrupt); 192 unsafe { interrupt::SAADC::steal() }.unpend();
167 irq.unpend(); 193 unsafe { interrupt::SAADC::steal() }.enable();
168 irq.enable();
169 194
170 Self { _p: saadc } 195 Self { _p: saadc }
171 } 196 }
172 197
173 fn on_interrupt(_ctx: *mut ()) {
174 let r = Self::regs();
175
176 if r.events_calibratedone.read().bits() != 0 {
177 r.intenclr.write(|w| w.calibratedone().clear());
178 WAKER.wake();
179 }
180
181 if r.events_end.read().bits() != 0 {
182 r.intenclr.write(|w| w.end().clear());
183 WAKER.wake();
184 }
185
186 if r.events_started.read().bits() != 0 {
187 r.intenclr.write(|w| w.started().clear());
188 WAKER.wake();
189 }
190 }
191
192 fn regs() -> &'static saadc::RegisterBlock { 198 fn regs() -> &'static saadc::RegisterBlock {
193 unsafe { &*SAADC::ptr() } 199 unsafe { &*SAADC::ptr() }
194 } 200 }
diff --git a/embassy-nrf/src/spim.rs b/embassy-nrf/src/spim.rs
index 17e435787..89cbdfee9 100644
--- a/embassy-nrf/src/spim.rs
+++ b/embassy-nrf/src/spim.rs
@@ -3,6 +3,7 @@
3#![macro_use] 3#![macro_use]
4 4
5use core::future::poll_fn; 5use core::future::poll_fn;
6use core::marker::PhantomData;
6use core::sync::atomic::{compiler_fence, Ordering}; 7use core::sync::atomic::{compiler_fence, Ordering};
7use core::task::Poll; 8use core::task::Poll;
8 9
@@ -14,7 +15,7 @@ pub use pac::spim0::frequency::FREQUENCY_A as Frequency;
14use crate::chip::FORCE_COPY_BUFFER_SIZE; 15use crate::chip::FORCE_COPY_BUFFER_SIZE;
15use crate::gpio::sealed::Pin as _; 16use crate::gpio::sealed::Pin as _;
16use crate::gpio::{self, AnyPin, Pin as GpioPin, PselBits}; 17use crate::gpio::{self, AnyPin, Pin as GpioPin, PselBits};
17use crate::interrupt::{Interrupt, InterruptExt}; 18use crate::interrupt::{self, Interrupt, InterruptExt};
18use crate::util::{slice_in_ram_or, slice_ptr_parts, slice_ptr_parts_mut}; 19use crate::util::{slice_in_ram_or, slice_ptr_parts, slice_ptr_parts_mut};
19use crate::{pac, Peripheral}; 20use crate::{pac, Peripheral};
20 21
@@ -31,11 +32,6 @@ pub enum Error {
31 BufferNotInRAM, 32 BufferNotInRAM,
32} 33}
33 34
34/// SPIM driver.
35pub struct Spim<'d, T: Instance> {
36 _p: PeripheralRef<'d, T>,
37}
38
39/// SPIM configuration. 35/// SPIM configuration.
40#[non_exhaustive] 36#[non_exhaustive]
41pub struct Config { 37pub struct Config {
@@ -62,11 +58,33 @@ impl Default for Config {
62 } 58 }
63} 59}
64 60
61/// Interrupt handler.
62pub struct InterruptHandler<T: Instance> {
63 _phantom: PhantomData<T>,
64}
65
66impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> {
67 unsafe fn on_interrupt() {
68 let r = T::regs();
69 let s = T::state();
70
71 if r.events_end.read().bits() != 0 {
72 s.end_waker.wake();
73 r.intenclr.write(|w| w.end().clear());
74 }
75 }
76}
77
78/// SPIM driver.
79pub struct Spim<'d, T: Instance> {
80 _p: PeripheralRef<'d, T>,
81}
82
65impl<'d, T: Instance> Spim<'d, T> { 83impl<'d, T: Instance> Spim<'d, T> {
66 /// Create a new SPIM driver. 84 /// Create a new SPIM driver.
67 pub fn new( 85 pub fn new(
68 spim: impl Peripheral<P = T> + 'd, 86 spim: impl Peripheral<P = T> + 'd,
69 irq: impl Peripheral<P = T::Interrupt> + 'd, 87 _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
70 sck: impl Peripheral<P = impl GpioPin> + 'd, 88 sck: impl Peripheral<P = impl GpioPin> + 'd,
71 miso: impl Peripheral<P = impl GpioPin> + 'd, 89 miso: impl Peripheral<P = impl GpioPin> + 'd,
72 mosi: impl Peripheral<P = impl GpioPin> + 'd, 90 mosi: impl Peripheral<P = impl GpioPin> + 'd,
@@ -75,7 +93,6 @@ impl<'d, T: Instance> Spim<'d, T> {
75 into_ref!(sck, miso, mosi); 93 into_ref!(sck, miso, mosi);
76 Self::new_inner( 94 Self::new_inner(
77 spim, 95 spim,
78 irq,
79 sck.map_into(), 96 sck.map_into(),
80 Some(miso.map_into()), 97 Some(miso.map_into()),
81 Some(mosi.map_into()), 98 Some(mosi.map_into()),
@@ -86,36 +103,35 @@ impl<'d, T: Instance> Spim<'d, T> {
86 /// Create a new SPIM driver, capable of TX only (MOSI only). 103 /// Create a new SPIM driver, capable of TX only (MOSI only).
87 pub fn new_txonly( 104 pub fn new_txonly(
88 spim: impl Peripheral<P = T> + 'd, 105 spim: impl Peripheral<P = T> + 'd,
89 irq: impl Peripheral<P = T::Interrupt> + 'd, 106 _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
90 sck: impl Peripheral<P = impl GpioPin> + 'd, 107 sck: impl Peripheral<P = impl GpioPin> + 'd,
91 mosi: impl Peripheral<P = impl GpioPin> + 'd, 108 mosi: impl Peripheral<P = impl GpioPin> + 'd,
92 config: Config, 109 config: Config,
93 ) -> Self { 110 ) -> Self {
94 into_ref!(sck, mosi); 111 into_ref!(sck, mosi);
95 Self::new_inner(spim, irq, sck.map_into(), None, Some(mosi.map_into()), config) 112 Self::new_inner(spim, sck.map_into(), None, Some(mosi.map_into()), config)
96 } 113 }
97 114
98 /// Create a new SPIM driver, capable of RX only (MISO only). 115 /// Create a new SPIM driver, capable of RX only (MISO only).
99 pub fn new_rxonly( 116 pub fn new_rxonly(
100 spim: impl Peripheral<P = T> + 'd, 117 spim: impl Peripheral<P = T> + 'd,
101 irq: impl Peripheral<P = T::Interrupt> + 'd, 118 _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
102 sck: impl Peripheral<P = impl GpioPin> + 'd, 119 sck: impl Peripheral<P = impl GpioPin> + 'd,
103 miso: impl Peripheral<P = impl GpioPin> + 'd, 120 miso: impl Peripheral<P = impl GpioPin> + 'd,
104 config: Config, 121 config: Config,
105 ) -> Self { 122 ) -> Self {
106 into_ref!(sck, miso); 123 into_ref!(sck, miso);
107 Self::new_inner(spim, irq, sck.map_into(), Some(miso.map_into()), None, config) 124 Self::new_inner(spim, sck.map_into(), Some(miso.map_into()), None, config)
108 } 125 }
109 126
110 fn new_inner( 127 fn new_inner(
111 spim: impl Peripheral<P = T> + 'd, 128 spim: impl Peripheral<P = T> + 'd,
112 irq: impl Peripheral<P = T::Interrupt> + 'd,
113 sck: PeripheralRef<'d, AnyPin>, 129 sck: PeripheralRef<'d, AnyPin>,
114 miso: Option<PeripheralRef<'d, AnyPin>>, 130 miso: Option<PeripheralRef<'d, AnyPin>>,
115 mosi: Option<PeripheralRef<'d, AnyPin>>, 131 mosi: Option<PeripheralRef<'d, AnyPin>>,
116 config: Config, 132 config: Config,
117 ) -> Self { 133 ) -> Self {
118 into_ref!(spim, irq); 134 into_ref!(spim);
119 135
120 let r = T::regs(); 136 let r = T::regs();
121 137
@@ -191,23 +207,12 @@ impl<'d, T: Instance> Spim<'d, T> {
191 // Disable all events interrupts 207 // Disable all events interrupts
192 r.intenclr.write(|w| unsafe { w.bits(0xFFFF_FFFF) }); 208 r.intenclr.write(|w| unsafe { w.bits(0xFFFF_FFFF) });
193 209
194 irq.set_handler(Self::on_interrupt); 210 unsafe { T::Interrupt::steal() }.unpend();
195 irq.unpend(); 211 unsafe { T::Interrupt::steal() }.enable();
196 irq.enable();
197 212
198 Self { _p: spim } 213 Self { _p: spim }
199 } 214 }
200 215
201 fn on_interrupt(_: *mut ()) {
202 let r = T::regs();
203 let s = T::state();
204
205 if r.events_end.read().bits() != 0 {
206 s.end_waker.wake();
207 r.intenclr.write(|w| w.end().clear());
208 }
209 }
210
211 fn prepare(&mut self, rx: *mut [u8], tx: *const [u8]) -> Result<(), Error> { 216 fn prepare(&mut self, rx: *mut [u8], tx: *const [u8]) -> Result<(), Error> {
212 slice_in_ram_or(tx, Error::BufferNotInRAM)?; 217 slice_in_ram_or(tx, Error::BufferNotInRAM)?;
213 // NOTE: RAM slice check for rx is not necessary, as a mutable 218 // NOTE: RAM slice check for rx is not necessary, as a mutable
diff --git a/embassy-nrf/src/spis.rs b/embassy-nrf/src/spis.rs
index 1b7436477..55b5e060e 100644
--- a/embassy-nrf/src/spis.rs
+++ b/embassy-nrf/src/spis.rs
@@ -2,6 +2,7 @@
2 2
3#![macro_use] 3#![macro_use]
4use core::future::poll_fn; 4use core::future::poll_fn;
5use core::marker::PhantomData;
5use core::sync::atomic::{compiler_fence, Ordering}; 6use core::sync::atomic::{compiler_fence, Ordering};
6use core::task::Poll; 7use core::task::Poll;
7 8
@@ -12,7 +13,7 @@ pub use embedded_hal_02::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MO
12use crate::chip::FORCE_COPY_BUFFER_SIZE; 13use crate::chip::FORCE_COPY_BUFFER_SIZE;
13use crate::gpio::sealed::Pin as _; 14use crate::gpio::sealed::Pin as _;
14use crate::gpio::{self, AnyPin, Pin as GpioPin}; 15use crate::gpio::{self, AnyPin, Pin as GpioPin};
15use crate::interrupt::{Interrupt, InterruptExt}; 16use crate::interrupt::{self, Interrupt, InterruptExt};
16use crate::util::{slice_in_ram_or, slice_ptr_parts, slice_ptr_parts_mut}; 17use crate::util::{slice_in_ram_or, slice_ptr_parts, slice_ptr_parts_mut};
17use crate::{pac, Peripheral}; 18use crate::{pac, Peripheral};
18 19
@@ -29,11 +30,6 @@ pub enum Error {
29 BufferNotInRAM, 30 BufferNotInRAM,
30} 31}
31 32
32/// SPIS driver.
33pub struct Spis<'d, T: Instance> {
34 _p: PeripheralRef<'d, T>,
35}
36
37/// SPIS configuration. 33/// SPIS configuration.
38#[non_exhaustive] 34#[non_exhaustive]
39pub struct Config { 35pub struct Config {
@@ -67,11 +63,38 @@ impl Default for Config {
67 } 63 }
68} 64}
69 65
66/// Interrupt handler.
67pub struct InterruptHandler<T: Instance> {
68 _phantom: PhantomData<T>,
69}
70
71impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> {
72 unsafe fn on_interrupt() {
73 let r = T::regs();
74 let s = T::state();
75
76 if r.events_end.read().bits() != 0 {
77 s.waker.wake();
78 r.intenclr.write(|w| w.end().clear());
79 }
80
81 if r.events_acquired.read().bits() != 0 {
82 s.waker.wake();
83 r.intenclr.write(|w| w.acquired().clear());
84 }
85 }
86}
87
88/// SPIS driver.
89pub struct Spis<'d, T: Instance> {
90 _p: PeripheralRef<'d, T>,
91}
92
70impl<'d, T: Instance> Spis<'d, T> { 93impl<'d, T: Instance> Spis<'d, T> {
71 /// Create a new SPIS driver. 94 /// Create a new SPIS driver.
72 pub fn new( 95 pub fn new(
73 spis: impl Peripheral<P = T> + 'd, 96 spis: impl Peripheral<P = T> + 'd,
74 irq: impl Peripheral<P = T::Interrupt> + 'd, 97 _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
75 cs: impl Peripheral<P = impl GpioPin> + 'd, 98 cs: impl Peripheral<P = impl GpioPin> + 'd,
76 sck: impl Peripheral<P = impl GpioPin> + 'd, 99 sck: impl Peripheral<P = impl GpioPin> + 'd,
77 miso: impl Peripheral<P = impl GpioPin> + 'd, 100 miso: impl Peripheral<P = impl GpioPin> + 'd,
@@ -81,7 +104,6 @@ impl<'d, T: Instance> Spis<'d, T> {
81 into_ref!(cs, sck, miso, mosi); 104 into_ref!(cs, sck, miso, mosi);
82 Self::new_inner( 105 Self::new_inner(
83 spis, 106 spis,
84 irq,
85 cs.map_into(), 107 cs.map_into(),
86 sck.map_into(), 108 sck.map_into(),
87 Some(miso.map_into()), 109 Some(miso.map_into()),
@@ -93,48 +115,31 @@ impl<'d, T: Instance> Spis<'d, T> {
93 /// Create a new SPIS driver, capable of TX only (MISO only). 115 /// Create a new SPIS driver, capable of TX only (MISO only).
94 pub fn new_txonly( 116 pub fn new_txonly(
95 spis: impl Peripheral<P = T> + 'd, 117 spis: impl Peripheral<P = T> + 'd,
96 irq: impl Peripheral<P = T::Interrupt> + 'd, 118 _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
97 cs: impl Peripheral<P = impl GpioPin> + 'd, 119 cs: impl Peripheral<P = impl GpioPin> + 'd,
98 sck: impl Peripheral<P = impl GpioPin> + 'd, 120 sck: impl Peripheral<P = impl GpioPin> + 'd,
99 miso: impl Peripheral<P = impl GpioPin> + 'd, 121 miso: impl Peripheral<P = impl GpioPin> + 'd,
100 config: Config, 122 config: Config,
101 ) -> Self { 123 ) -> Self {
102 into_ref!(cs, sck, miso); 124 into_ref!(cs, sck, miso);
103 Self::new_inner( 125 Self::new_inner(spis, cs.map_into(), sck.map_into(), Some(miso.map_into()), None, config)
104 spis,
105 irq,
106 cs.map_into(),
107 sck.map_into(),
108 Some(miso.map_into()),
109 None,
110 config,
111 )
112 } 126 }
113 127
114 /// Create a new SPIS driver, capable of RX only (MOSI only). 128 /// Create a new SPIS driver, capable of RX only (MOSI only).
115 pub fn new_rxonly( 129 pub fn new_rxonly(
116 spis: impl Peripheral<P = T> + 'd, 130 spis: impl Peripheral<P = T> + 'd,
117 irq: impl Peripheral<P = T::Interrupt> + 'd, 131 _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
118 cs: impl Peripheral<P = impl GpioPin> + 'd, 132 cs: impl Peripheral<P = impl GpioPin> + 'd,
119 sck: impl Peripheral<P = impl GpioPin> + 'd, 133 sck: impl Peripheral<P = impl GpioPin> + 'd,
120 mosi: impl Peripheral<P = impl GpioPin> + 'd, 134 mosi: impl Peripheral<P = impl GpioPin> + 'd,
121 config: Config, 135 config: Config,
122 ) -> Self { 136 ) -> Self {
123 into_ref!(cs, sck, mosi); 137 into_ref!(cs, sck, mosi);
124 Self::new_inner( 138 Self::new_inner(spis, cs.map_into(), sck.map_into(), None, Some(mosi.map_into()), config)
125 spis,
126 irq,
127 cs.map_into(),
128 sck.map_into(),
129 None,
130 Some(mosi.map_into()),
131 config,
132 )
133 } 139 }
134 140
135 fn new_inner( 141 fn new_inner(
136 spis: impl Peripheral<P = T> + 'd, 142 spis: impl Peripheral<P = T> + 'd,
137 irq: impl Peripheral<P = T::Interrupt> + 'd,
138 cs: PeripheralRef<'d, AnyPin>, 143 cs: PeripheralRef<'d, AnyPin>,
139 sck: PeripheralRef<'d, AnyPin>, 144 sck: PeripheralRef<'d, AnyPin>,
140 miso: Option<PeripheralRef<'d, AnyPin>>, 145 miso: Option<PeripheralRef<'d, AnyPin>>,
@@ -143,7 +148,7 @@ impl<'d, T: Instance> Spis<'d, T> {
143 ) -> Self { 148 ) -> Self {
144 compiler_fence(Ordering::SeqCst); 149 compiler_fence(Ordering::SeqCst);
145 150
146 into_ref!(spis, irq, cs, sck); 151 into_ref!(spis, cs, sck);
147 152
148 let r = T::regs(); 153 let r = T::regs();
149 154
@@ -209,28 +214,12 @@ impl<'d, T: Instance> Spis<'d, T> {
209 // Disable all events interrupts. 214 // Disable all events interrupts.
210 r.intenclr.write(|w| unsafe { w.bits(0xFFFF_FFFF) }); 215 r.intenclr.write(|w| unsafe { w.bits(0xFFFF_FFFF) });
211 216
212 irq.set_handler(Self::on_interrupt); 217 unsafe { T::Interrupt::steal() }.unpend();
213 irq.unpend(); 218 unsafe { T::Interrupt::steal() }.enable();
214 irq.enable();
215 219
216 Self { _p: spis } 220 Self { _p: spis }
217 } 221 }
218 222
219 fn on_interrupt(_: *mut ()) {
220 let r = T::regs();
221 let s = T::state();
222
223 if r.events_end.read().bits() != 0 {
224 s.waker.wake();
225 r.intenclr.write(|w| w.end().clear());
226 }
227
228 if r.events_acquired.read().bits() != 0 {
229 s.waker.wake();
230 r.intenclr.write(|w| w.acquired().clear());
231 }
232 }
233
234 fn prepare(&mut self, rx: *mut [u8], tx: *const [u8]) -> Result<(), Error> { 223 fn prepare(&mut self, rx: *mut [u8], tx: *const [u8]) -> Result<(), Error> {
235 slice_in_ram_or(tx, Error::BufferNotInRAM)?; 224 slice_in_ram_or(tx, Error::BufferNotInRAM)?;
236 // NOTE: RAM slice check for rx is not necessary, as a mutable 225 // NOTE: RAM slice check for rx is not necessary, as a mutable
diff --git a/embassy-nrf/src/temp.rs b/embassy-nrf/src/temp.rs
index 5298faabc..3a75ec629 100644
--- a/embassy-nrf/src/temp.rs
+++ b/embassy-nrf/src/temp.rs
@@ -3,6 +3,7 @@
3use core::future::poll_fn; 3use core::future::poll_fn;
4use core::task::Poll; 4use core::task::Poll;
5 5
6use embassy_cortex_m::interrupt::Interrupt;
6use embassy_hal_common::drop::OnDrop; 7use embassy_hal_common::drop::OnDrop;
7use embassy_hal_common::{into_ref, PeripheralRef}; 8use embassy_hal_common::{into_ref, PeripheralRef};
8use embassy_sync::waitqueue::AtomicWaker; 9use embassy_sync::waitqueue::AtomicWaker;
@@ -12,27 +13,39 @@ use crate::interrupt::InterruptExt;
12use crate::peripherals::TEMP; 13use crate::peripherals::TEMP;
13use crate::{interrupt, pac, Peripheral}; 14use crate::{interrupt, pac, Peripheral};
14 15
16/// Interrupt handler.
17pub struct InterruptHandler {
18 _private: (),
19}
20
21impl interrupt::Handler<interrupt::TEMP> for InterruptHandler {
22 unsafe fn on_interrupt() {
23 let r = unsafe { &*pac::TEMP::PTR };
24 r.intenclr.write(|w| w.datardy().clear());
25 WAKER.wake();
26 }
27}
28
15/// Builtin temperature sensor driver. 29/// Builtin temperature sensor driver.
16pub struct Temp<'d> { 30pub struct Temp<'d> {
17 _irq: PeripheralRef<'d, interrupt::TEMP>, 31 _peri: PeripheralRef<'d, TEMP>,
18} 32}
19 33
20static WAKER: AtomicWaker = AtomicWaker::new(); 34static WAKER: AtomicWaker = AtomicWaker::new();
21 35
22impl<'d> Temp<'d> { 36impl<'d> Temp<'d> {
23 /// Create a new temperature sensor driver. 37 /// Create a new temperature sensor driver.
24 pub fn new(_t: impl Peripheral<P = TEMP> + 'd, irq: impl Peripheral<P = interrupt::TEMP> + 'd) -> Self { 38 pub fn new(
25 into_ref!(_t, irq); 39 _peri: impl Peripheral<P = TEMP> + 'd,
40 _irq: impl interrupt::Binding<interrupt::TEMP, InterruptHandler> + 'd,
41 ) -> Self {
42 into_ref!(_peri);
26 43
27 // Enable interrupt that signals temperature values 44 // Enable interrupt that signals temperature values
28 irq.disable(); 45 unsafe { interrupt::TEMP::steal() }.unpend();
29 irq.set_handler(|_| { 46 unsafe { interrupt::TEMP::steal() }.enable();
30 let t = Self::regs(); 47
31 t.intenclr.write(|w| w.datardy().clear()); 48 Self { _peri }
32 WAKER.wake();
33 });
34 irq.enable();
35 Self { _irq: irq }
36 } 49 }
37 50
38 /// Perform an asynchronous temperature measurement. The returned future 51 /// Perform an asynchronous temperature measurement. The returned future
diff --git a/embassy-nrf/src/timer.rs b/embassy-nrf/src/timer.rs
index d1ae57237..a9487a9fd 100644
--- a/embassy-nrf/src/timer.rs
+++ b/embassy-nrf/src/timer.rs
@@ -6,15 +6,9 @@
6 6
7#![macro_use] 7#![macro_use]
8 8
9use core::future::poll_fn;
10use core::marker::PhantomData;
11use core::task::Poll;
12
13use embassy_hal_common::drop::OnDrop;
14use embassy_hal_common::{into_ref, PeripheralRef}; 9use embassy_hal_common::{into_ref, PeripheralRef};
15use embassy_sync::waitqueue::AtomicWaker;
16 10
17use crate::interrupt::{Interrupt, InterruptExt}; 11use crate::interrupt::Interrupt;
18use crate::ppi::{Event, Task}; 12use crate::ppi::{Event, Task};
19use crate::{pac, Peripheral}; 13use crate::{pac, Peripheral};
20 14
@@ -26,8 +20,6 @@ pub(crate) mod sealed {
26 /// The number of CC registers this instance has. 20 /// The number of CC registers this instance has.
27 const CCS: usize; 21 const CCS: usize;
28 fn regs() -> &'static pac::timer0::RegisterBlock; 22 fn regs() -> &'static pac::timer0::RegisterBlock;
29 /// Storage for the waker for CC register `n`.
30 fn waker(n: usize) -> &'static AtomicWaker;
31 } 23 }
32 pub trait ExtendedInstance {} 24 pub trait ExtendedInstance {}
33 25
@@ -50,12 +42,6 @@ macro_rules! impl_timer {
50 fn regs() -> &'static pac::timer0::RegisterBlock { 42 fn regs() -> &'static pac::timer0::RegisterBlock {
51 unsafe { &*(pac::$pac_type::ptr() as *const pac::timer0::RegisterBlock) } 43 unsafe { &*(pac::$pac_type::ptr() as *const pac::timer0::RegisterBlock) }
52 } 44 }
53 fn waker(n: usize) -> &'static ::embassy_sync::waitqueue::AtomicWaker {
54 use ::embassy_sync::waitqueue::AtomicWaker;
55 const NEW_AW: AtomicWaker = AtomicWaker::new();
56 static WAKERS: [AtomicWaker; $ccs] = [NEW_AW; $ccs];
57 &WAKERS[n]
58 }
59 } 45 }
60 impl crate::timer::Instance for peripherals::$type { 46 impl crate::timer::Instance for peripherals::$type {
61 type Interrupt = crate::interrupt::$irq; 47 type Interrupt = crate::interrupt::$irq;
@@ -99,73 +85,49 @@ pub enum Frequency {
99/// nRF Timer driver. 85/// nRF Timer driver.
100/// 86///
101/// The timer has an internal counter, which is incremented for every tick of the timer. 87/// The timer has an internal counter, which is incremented for every tick of the timer.
102/// The counter is 32-bit, so it wraps back to 0 at 4294967296. 88/// The counter is 32-bit, so it wraps back to 0 when it reaches 2^32.
103/// 89///
104/// It has either 4 or 6 Capture/Compare registers, which can be used to capture the current state of the counter 90/// It has either 4 or 6 Capture/Compare registers, which can be used to capture the current state of the counter
105/// or trigger an event when the counter reaches a certain value. 91/// or trigger an event when the counter reaches a certain value.
106 92
107pub trait TimerType: sealed::TimerType {}
108
109/// Marker type indicating the timer driver can await expiration (it owns the timer interrupt).
110pub enum Awaitable {}
111
112/// Marker type indicating the timer driver cannot await expiration (it does not own the timer interrupt).
113pub enum NotAwaitable {}
114
115impl sealed::TimerType for Awaitable {}
116impl sealed::TimerType for NotAwaitable {}
117impl TimerType for Awaitable {}
118impl TimerType for NotAwaitable {}
119
120/// Timer driver. 93/// Timer driver.
121pub struct Timer<'d, T: Instance, I: TimerType = NotAwaitable> { 94pub struct Timer<'d, T: Instance> {
122 _p: PeripheralRef<'d, T>, 95 _p: PeripheralRef<'d, T>,
123 _i: PhantomData<I>,
124} 96}
125 97
126impl<'d, T: Instance> Timer<'d, T, Awaitable> { 98impl<'d, T: Instance> Timer<'d, T> {
127 /// Create a new async-capable timer driver. 99 /// Create a new `Timer` driver.
128 pub fn new_awaitable(timer: impl Peripheral<P = T> + 'd, irq: impl Peripheral<P = T::Interrupt> + 'd) -> Self {
129 into_ref!(irq);
130
131 irq.set_handler(Self::on_interrupt);
132 irq.unpend();
133 irq.enable();
134
135 Self::new_inner(timer)
136 }
137}
138
139impl<'d, T: Instance> Timer<'d, T, NotAwaitable> {
140 /// Create a `Timer` driver without an interrupt, meaning `Cc::wait` won't work.
141 /// 100 ///
142 /// This can be useful for triggering tasks via PPI 101 /// This can be useful for triggering tasks via PPI
143 /// `Uarte` uses this internally. 102 /// `Uarte` uses this internally.
144 pub fn new(timer: impl Peripheral<P = T> + 'd) -> Self { 103 pub fn new(timer: impl Peripheral<P = T> + 'd) -> Self {
145 Self::new_inner(timer) 104 Self::new_inner(timer, false)
146 } 105 }
147}
148 106
149impl<'d, T: Instance, I: TimerType> Timer<'d, T, I> { 107 /// Create a new `Timer` driver in counter mode.
150 /// Create a `Timer` without an interrupt, meaning `Cc::wait` won't work.
151 /// 108 ///
152 /// This is used by the public constructors. 109 /// This can be useful for triggering tasks via PPI
153 fn new_inner(timer: impl Peripheral<P = T> + 'd) -> Self { 110 /// `Uarte` uses this internally.
111 pub fn new_counter(timer: impl Peripheral<P = T> + 'd) -> Self {
112 Self::new_inner(timer, true)
113 }
114
115 fn new_inner(timer: impl Peripheral<P = T> + 'd, is_counter: bool) -> Self {
154 into_ref!(timer); 116 into_ref!(timer);
155 117
156 let regs = T::regs(); 118 let regs = T::regs();
157 119
158 let mut this = Self { 120 let mut this = Self { _p: timer };
159 _p: timer,
160 _i: PhantomData,
161 };
162 121
163 // Stop the timer before doing anything else, 122 // Stop the timer before doing anything else,
164 // since changing BITMODE while running can cause 'unpredictable behaviour' according to the specification. 123 // since changing BITMODE while running can cause 'unpredictable behaviour' according to the specification.
165 this.stop(); 124 this.stop();
166 125
167 // Set the instance to timer mode. 126 if is_counter {
168 regs.mode.write(|w| w.mode().timer()); 127 regs.mode.write(|w| w.mode().counter());
128 } else {
129 regs.mode.write(|w| w.mode().timer());
130 }
169 131
170 // Make the counter's max value as high as possible. 132 // Make the counter's max value as high as possible.
171 // TODO: is there a reason someone would want to set this lower? 133 // TODO: is there a reason someone would want to set this lower?
@@ -225,6 +187,14 @@ impl<'d, T: Instance, I: TimerType> Timer<'d, T, I> {
225 Task::from_reg(&T::regs().tasks_clear) 187 Task::from_reg(&T::regs().tasks_clear)
226 } 188 }
227 189
190 /// Returns the COUNT task, for use with PPI.
191 ///
192 /// When triggered, this task increments the timer's counter by 1.
193 /// Only works in counter mode.
194 pub fn task_count(&self) -> Task {
195 Task::from_reg(&T::regs().tasks_count)
196 }
197
228 /// Change the timer's frequency. 198 /// Change the timer's frequency.
229 /// 199 ///
230 /// This will stop the timer if it isn't already stopped, 200 /// This will stop the timer if it isn't already stopped,
@@ -239,31 +209,17 @@ impl<'d, T: Instance, I: TimerType> Timer<'d, T, I> {
239 .write(|w| unsafe { w.prescaler().bits(frequency as u8) }) 209 .write(|w| unsafe { w.prescaler().bits(frequency as u8) })
240 } 210 }
241 211
242 fn on_interrupt(_: *mut ()) {
243 let regs = T::regs();
244 for n in 0..T::CCS {
245 if regs.events_compare[n].read().bits() != 0 {
246 // Clear the interrupt, otherwise the interrupt will be repeatedly raised as soon as the interrupt handler exits.
247 // We can't clear the event, because it's used to poll whether the future is done or still pending.
248 regs.intenclr
249 .modify(|r, w| unsafe { w.bits(r.bits() | (1 << (16 + n))) });
250 T::waker(n).wake();
251 }
252 }
253 }
254
255 /// Returns this timer's `n`th CC register. 212 /// Returns this timer's `n`th CC register.
256 /// 213 ///
257 /// # Panics 214 /// # Panics
258 /// Panics if `n` >= the number of CC registers this timer has (4 for a normal timer, 6 for an extended timer). 215 /// Panics if `n` >= the number of CC registers this timer has (4 for a normal timer, 6 for an extended timer).
259 pub fn cc(&mut self, n: usize) -> Cc<T, I> { 216 pub fn cc(&mut self, n: usize) -> Cc<T> {
260 if n >= T::CCS { 217 if n >= T::CCS {
261 panic!("Cannot get CC register {} of timer with {} CC registers.", n, T::CCS); 218 panic!("Cannot get CC register {} of timer with {} CC registers.", n, T::CCS);
262 } 219 }
263 Cc { 220 Cc {
264 n, 221 n,
265 _p: self._p.reborrow(), 222 _p: self._p.reborrow(),
266 _i: PhantomData,
267 } 223 }
268 } 224 }
269} 225}
@@ -275,49 +231,12 @@ impl<'d, T: Instance, I: TimerType> Timer<'d, T, I> {
275/// 231///
276/// The timer will fire the register's COMPARE event when its counter reaches the value stored in the register. 232/// The timer will fire the register's COMPARE event when its counter reaches the value stored in the register.
277/// When the register's CAPTURE task is triggered, the timer will store the current value of its counter in the register 233/// When the register's CAPTURE task is triggered, the timer will store the current value of its counter in the register
278pub struct Cc<'d, T: Instance, I: TimerType = NotAwaitable> { 234pub struct Cc<'d, T: Instance> {
279 n: usize, 235 n: usize,
280 _p: PeripheralRef<'d, T>, 236 _p: PeripheralRef<'d, T>,
281 _i: PhantomData<I>,
282}
283
284impl<'d, T: Instance> Cc<'d, T, Awaitable> {
285 /// Wait until the timer's counter reaches the value stored in this register.
286 ///
287 /// This requires a mutable reference so that this task's waker cannot be overwritten by a second call to `wait`.
288 pub async fn wait(&mut self) {
289 let regs = T::regs();
290
291 // Enable the interrupt for this CC's COMPARE event.
292 regs.intenset
293 .modify(|r, w| unsafe { w.bits(r.bits() | (1 << (16 + self.n))) });
294
295 // Disable the interrupt if the future is dropped.
296 let on_drop = OnDrop::new(|| {
297 regs.intenclr
298 .modify(|r, w| unsafe { w.bits(r.bits() | (1 << (16 + self.n))) });
299 });
300
301 poll_fn(|cx| {
302 T::waker(self.n).register(cx.waker());
303
304 if regs.events_compare[self.n].read().bits() != 0 {
305 // Reset the register for next time
306 regs.events_compare[self.n].reset();
307 Poll::Ready(())
308 } else {
309 Poll::Pending
310 }
311 })
312 .await;
313
314 // The interrupt was already disabled in the interrupt handler, so there's no need to disable it again.
315 on_drop.defuse();
316 }
317} 237}
318impl<'d, T: Instance> Cc<'d, T, NotAwaitable> {}
319 238
320impl<'d, T: Instance, I: TimerType> Cc<'d, T, I> { 239impl<'d, T: Instance> Cc<'d, T> {
321 /// Get the current value stored in the register. 240 /// Get the current value stored in the register.
322 pub fn read(&self) -> u32 { 241 pub fn read(&self) -> u32 {
323 T::regs().cc[self.n].read().cc().bits() 242 T::regs().cc[self.n].read().cc().bits()
diff --git a/embassy-nrf/src/twim.rs b/embassy-nrf/src/twim.rs
index 0dcb2b0da..ef4c929a3 100644
--- a/embassy-nrf/src/twim.rs
+++ b/embassy-nrf/src/twim.rs
@@ -3,6 +3,7 @@
3#![macro_use] 3#![macro_use]
4 4
5use core::future::{poll_fn, Future}; 5use core::future::{poll_fn, Future};
6use core::marker::PhantomData;
6use core::sync::atomic::compiler_fence; 7use core::sync::atomic::compiler_fence;
7use core::sync::atomic::Ordering::SeqCst; 8use core::sync::atomic::Ordering::SeqCst;
8use core::task::Poll; 9use core::task::Poll;
@@ -15,7 +16,7 @@ use embassy_time::{Duration, Instant};
15 16
16use crate::chip::{EASY_DMA_SIZE, FORCE_COPY_BUFFER_SIZE}; 17use crate::chip::{EASY_DMA_SIZE, FORCE_COPY_BUFFER_SIZE};
17use crate::gpio::Pin as GpioPin; 18use crate::gpio::Pin as GpioPin;
18use crate::interrupt::{Interrupt, InterruptExt}; 19use crate::interrupt::{self, Interrupt, InterruptExt};
19use crate::util::{slice_in_ram, slice_in_ram_or}; 20use crate::util::{slice_in_ram, slice_in_ram_or};
20use crate::{gpio, pac, Peripheral}; 21use crate::{gpio, pac, Peripheral};
21 22
@@ -92,6 +93,27 @@ pub enum Error {
92 Timeout, 93 Timeout,
93} 94}
94 95
96/// Interrupt handler.
97pub struct InterruptHandler<T: Instance> {
98 _phantom: PhantomData<T>,
99}
100
101impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> {
102 unsafe fn on_interrupt() {
103 let r = T::regs();
104 let s = T::state();
105
106 if r.events_stopped.read().bits() != 0 {
107 s.end_waker.wake();
108 r.intenclr.write(|w| w.stopped().clear());
109 }
110 if r.events_error.read().bits() != 0 {
111 s.end_waker.wake();
112 r.intenclr.write(|w| w.error().clear());
113 }
114 }
115}
116
95/// TWI driver. 117/// TWI driver.
96pub struct Twim<'d, T: Instance> { 118pub struct Twim<'d, T: Instance> {
97 _p: PeripheralRef<'d, T>, 119 _p: PeripheralRef<'d, T>,
@@ -101,12 +123,12 @@ impl<'d, T: Instance> Twim<'d, T> {
101 /// Create a new TWI driver. 123 /// Create a new TWI driver.
102 pub fn new( 124 pub fn new(
103 twim: impl Peripheral<P = T> + 'd, 125 twim: impl Peripheral<P = T> + 'd,
104 irq: impl Peripheral<P = T::Interrupt> + 'd, 126 _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
105 sda: impl Peripheral<P = impl GpioPin> + 'd, 127 sda: impl Peripheral<P = impl GpioPin> + 'd,
106 scl: impl Peripheral<P = impl GpioPin> + 'd, 128 scl: impl Peripheral<P = impl GpioPin> + 'd,
107 config: Config, 129 config: Config,
108 ) -> Self { 130 ) -> Self {
109 into_ref!(twim, irq, sda, scl); 131 into_ref!(twim, sda, scl);
110 132
111 let r = T::regs(); 133 let r = T::regs();
112 134
@@ -152,27 +174,12 @@ impl<'d, T: Instance> Twim<'d, T> {
152 // Disable all events interrupts 174 // Disable all events interrupts
153 r.intenclr.write(|w| unsafe { w.bits(0xFFFF_FFFF) }); 175 r.intenclr.write(|w| unsafe { w.bits(0xFFFF_FFFF) });
154 176
155 irq.set_handler(Self::on_interrupt); 177 unsafe { T::Interrupt::steal() }.unpend();
156 irq.unpend(); 178 unsafe { T::Interrupt::steal() }.enable();
157 irq.enable();
158 179
159 Self { _p: twim } 180 Self { _p: twim }
160 } 181 }
161 182
162 fn on_interrupt(_: *mut ()) {
163 let r = T::regs();
164 let s = T::state();
165
166 if r.events_stopped.read().bits() != 0 {
167 s.end_waker.wake();
168 r.intenclr.write(|w| w.stopped().clear());
169 }
170 if r.events_error.read().bits() != 0 {
171 s.end_waker.wake();
172 r.intenclr.write(|w| w.error().clear());
173 }
174 }
175
176 /// Set TX buffer, checking that it is in RAM and has suitable length. 183 /// Set TX buffer, checking that it is in RAM and has suitable length.
177 unsafe fn set_tx_buffer(&mut self, buffer: &[u8]) -> Result<(), Error> { 184 unsafe fn set_tx_buffer(&mut self, buffer: &[u8]) -> Result<(), Error> {
178 slice_in_ram_or(buffer, Error::BufferNotInRAM)?; 185 slice_in_ram_or(buffer, Error::BufferNotInRAM)?;
diff --git a/embassy-nrf/src/twis.rs b/embassy-nrf/src/twis.rs
index c514d9f2f..bfa30b044 100644
--- a/embassy-nrf/src/twis.rs
+++ b/embassy-nrf/src/twis.rs
@@ -3,6 +3,7 @@
3#![macro_use] 3#![macro_use]
4 4
5use core::future::{poll_fn, Future}; 5use core::future::{poll_fn, Future};
6use core::marker::PhantomData;
6use core::sync::atomic::compiler_fence; 7use core::sync::atomic::compiler_fence;
7use core::sync::atomic::Ordering::SeqCst; 8use core::sync::atomic::Ordering::SeqCst;
8use core::task::Poll; 9use core::task::Poll;
@@ -14,7 +15,7 @@ use embassy_time::{Duration, Instant};
14 15
15use crate::chip::{EASY_DMA_SIZE, FORCE_COPY_BUFFER_SIZE}; 16use crate::chip::{EASY_DMA_SIZE, FORCE_COPY_BUFFER_SIZE};
16use crate::gpio::Pin as GpioPin; 17use crate::gpio::Pin as GpioPin;
17use crate::interrupt::{Interrupt, InterruptExt}; 18use crate::interrupt::{self, Interrupt, InterruptExt};
18use crate::util::slice_in_ram_or; 19use crate::util::slice_in_ram_or;
19use crate::{gpio, pac, Peripheral}; 20use crate::{gpio, pac, Peripheral};
20 21
@@ -108,6 +109,31 @@ pub enum Command {
108 Write(usize), 109 Write(usize),
109} 110}
110 111
112/// Interrupt handler.
113pub struct InterruptHandler<T: Instance> {
114 _phantom: PhantomData<T>,
115}
116
117impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> {
118 unsafe fn on_interrupt() {
119 let r = T::regs();
120 let s = T::state();
121
122 if r.events_read.read().bits() != 0 || r.events_write.read().bits() != 0 {
123 s.waker.wake();
124 r.intenclr.modify(|_r, w| w.read().clear().write().clear());
125 }
126 if r.events_stopped.read().bits() != 0 {
127 s.waker.wake();
128 r.intenclr.modify(|_r, w| w.stopped().clear());
129 }
130 if r.events_error.read().bits() != 0 {
131 s.waker.wake();
132 r.intenclr.modify(|_r, w| w.error().clear());
133 }
134 }
135}
136
111/// TWIS driver. 137/// TWIS driver.
112pub struct Twis<'d, T: Instance> { 138pub struct Twis<'d, T: Instance> {
113 _p: PeripheralRef<'d, T>, 139 _p: PeripheralRef<'d, T>,
@@ -117,12 +143,12 @@ impl<'d, T: Instance> Twis<'d, T> {
117 /// Create a new TWIS driver. 143 /// Create a new TWIS driver.
118 pub fn new( 144 pub fn new(
119 twis: impl Peripheral<P = T> + 'd, 145 twis: impl Peripheral<P = T> + 'd,
120 irq: impl Peripheral<P = T::Interrupt> + 'd, 146 _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
121 sda: impl Peripheral<P = impl GpioPin> + 'd, 147 sda: impl Peripheral<P = impl GpioPin> + 'd,
122 scl: impl Peripheral<P = impl GpioPin> + 'd, 148 scl: impl Peripheral<P = impl GpioPin> + 'd,
123 config: Config, 149 config: Config,
124 ) -> Self { 150 ) -> Self {
125 into_ref!(twis, irq, sda, scl); 151 into_ref!(twis, sda, scl);
126 152
127 let r = T::regs(); 153 let r = T::regs();
128 154
@@ -178,31 +204,12 @@ impl<'d, T: Instance> Twis<'d, T> {
178 // Generate suspend on read event 204 // Generate suspend on read event
179 r.shorts.write(|w| w.read_suspend().enabled()); 205 r.shorts.write(|w| w.read_suspend().enabled());
180 206
181 irq.set_handler(Self::on_interrupt); 207 unsafe { T::Interrupt::steal() }.unpend();
182 irq.unpend(); 208 unsafe { T::Interrupt::steal() }.enable();
183 irq.enable();
184 209
185 Self { _p: twis } 210 Self { _p: twis }
186 } 211 }
187 212
188 fn on_interrupt(_: *mut ()) {
189 let r = T::regs();
190 let s = T::state();
191
192 if r.events_read.read().bits() != 0 || r.events_write.read().bits() != 0 {
193 s.waker.wake();
194 r.intenclr.modify(|_r, w| w.read().clear().write().clear());
195 }
196 if r.events_stopped.read().bits() != 0 {
197 s.waker.wake();
198 r.intenclr.modify(|_r, w| w.stopped().clear());
199 }
200 if r.events_error.read().bits() != 0 {
201 s.waker.wake();
202 r.intenclr.modify(|_r, w| w.error().clear());
203 }
204 }
205
206 /// Set TX buffer, checking that it is in RAM and has suitable length. 213 /// Set TX buffer, checking that it is in RAM and has suitable length.
207 unsafe fn set_tx_buffer(&mut self, buffer: &[u8]) -> Result<(), Error> { 214 unsafe fn set_tx_buffer(&mut self, buffer: &[u8]) -> Result<(), Error> {
208 slice_in_ram_or(buffer, Error::BufferNotInRAM)?; 215 slice_in_ram_or(buffer, Error::BufferNotInRAM)?;
diff --git a/embassy-nrf/src/uarte.rs b/embassy-nrf/src/uarte.rs
index 48457744b..3934d1b55 100644
--- a/embassy-nrf/src/uarte.rs
+++ b/embassy-nrf/src/uarte.rs
@@ -14,6 +14,7 @@
14#![macro_use] 14#![macro_use]
15 15
16use core::future::poll_fn; 16use core::future::poll_fn;
17use core::marker::PhantomData;
17use core::sync::atomic::{compiler_fence, Ordering}; 18use core::sync::atomic::{compiler_fence, Ordering};
18use core::task::Poll; 19use core::task::Poll;
19 20
@@ -26,7 +27,7 @@ pub use pac::uarte0::{baudrate::BAUDRATE_A as Baudrate, config::PARITY_A as Pari
26use crate::chip::{EASY_DMA_SIZE, FORCE_COPY_BUFFER_SIZE}; 27use crate::chip::{EASY_DMA_SIZE, FORCE_COPY_BUFFER_SIZE};
27use crate::gpio::sealed::Pin as _; 28use crate::gpio::sealed::Pin as _;
28use crate::gpio::{self, AnyPin, Pin as GpioPin, PselBits}; 29use crate::gpio::{self, AnyPin, Pin as GpioPin, PselBits};
29use crate::interrupt::{Interrupt, InterruptExt}; 30use crate::interrupt::{self, Interrupt, InterruptExt};
30use crate::ppi::{AnyConfigurableChannel, ConfigurableChannel, Event, Ppi, Task}; 31use crate::ppi::{AnyConfigurableChannel, ConfigurableChannel, Event, Ppi, Task};
31use crate::timer::{Frequency, Instance as TimerInstance, Timer}; 32use crate::timer::{Frequency, Instance as TimerInstance, Timer};
32use crate::util::slice_in_ram_or; 33use crate::util::slice_in_ram_or;
@@ -62,6 +63,27 @@ pub enum Error {
62 BufferNotInRAM, 63 BufferNotInRAM,
63} 64}
64 65
66/// Interrupt handler.
67pub struct InterruptHandler<T: Instance> {
68 _phantom: PhantomData<T>,
69}
70
71impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> {
72 unsafe fn on_interrupt() {
73 let r = T::regs();
74 let s = T::state();
75
76 if r.events_endrx.read().bits() != 0 {
77 s.endrx_waker.wake();
78 r.intenclr.write(|w| w.endrx().clear());
79 }
80 if r.events_endtx.read().bits() != 0 {
81 s.endtx_waker.wake();
82 r.intenclr.write(|w| w.endtx().clear());
83 }
84 }
85}
86
65/// UARTE driver. 87/// UARTE driver.
66pub struct Uarte<'d, T: Instance> { 88pub struct Uarte<'d, T: Instance> {
67 tx: UarteTx<'d, T>, 89 tx: UarteTx<'d, T>,
@@ -86,19 +108,19 @@ impl<'d, T: Instance> Uarte<'d, T> {
86 /// Create a new UARTE without hardware flow control 108 /// Create a new UARTE without hardware flow control
87 pub fn new( 109 pub fn new(
88 uarte: impl Peripheral<P = T> + 'd, 110 uarte: impl Peripheral<P = T> + 'd,
89 irq: impl Peripheral<P = T::Interrupt> + 'd, 111 _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
90 rxd: impl Peripheral<P = impl GpioPin> + 'd, 112 rxd: impl Peripheral<P = impl GpioPin> + 'd,
91 txd: impl Peripheral<P = impl GpioPin> + 'd, 113 txd: impl Peripheral<P = impl GpioPin> + 'd,
92 config: Config, 114 config: Config,
93 ) -> Self { 115 ) -> Self {
94 into_ref!(rxd, txd); 116 into_ref!(rxd, txd);
95 Self::new_inner(uarte, irq, rxd.map_into(), txd.map_into(), None, None, config) 117 Self::new_inner(uarte, rxd.map_into(), txd.map_into(), None, None, config)
96 } 118 }
97 119
98 /// Create a new UARTE with hardware flow control (RTS/CTS) 120 /// Create a new UARTE with hardware flow control (RTS/CTS)
99 pub fn new_with_rtscts( 121 pub fn new_with_rtscts(
100 uarte: impl Peripheral<P = T> + 'd, 122 uarte: impl Peripheral<P = T> + 'd,
101 irq: impl Peripheral<P = T::Interrupt> + 'd, 123 _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
102 rxd: impl Peripheral<P = impl GpioPin> + 'd, 124 rxd: impl Peripheral<P = impl GpioPin> + 'd,
103 txd: impl Peripheral<P = impl GpioPin> + 'd, 125 txd: impl Peripheral<P = impl GpioPin> + 'd,
104 cts: impl Peripheral<P = impl GpioPin> + 'd, 126 cts: impl Peripheral<P = impl GpioPin> + 'd,
@@ -108,7 +130,6 @@ impl<'d, T: Instance> Uarte<'d, T> {
108 into_ref!(rxd, txd, cts, rts); 130 into_ref!(rxd, txd, cts, rts);
109 Self::new_inner( 131 Self::new_inner(
110 uarte, 132 uarte,
111 irq,
112 rxd.map_into(), 133 rxd.map_into(),
113 txd.map_into(), 134 txd.map_into(),
114 Some(cts.map_into()), 135 Some(cts.map_into()),
@@ -119,14 +140,13 @@ impl<'d, T: Instance> Uarte<'d, T> {
119 140
120 fn new_inner( 141 fn new_inner(
121 uarte: impl Peripheral<P = T> + 'd, 142 uarte: impl Peripheral<P = T> + 'd,
122 irq: impl Peripheral<P = T::Interrupt> + 'd,
123 rxd: PeripheralRef<'d, AnyPin>, 143 rxd: PeripheralRef<'d, AnyPin>,
124 txd: PeripheralRef<'d, AnyPin>, 144 txd: PeripheralRef<'d, AnyPin>,
125 cts: Option<PeripheralRef<'d, AnyPin>>, 145 cts: Option<PeripheralRef<'d, AnyPin>>,
126 rts: Option<PeripheralRef<'d, AnyPin>>, 146 rts: Option<PeripheralRef<'d, AnyPin>>,
127 config: Config, 147 config: Config,
128 ) -> Self { 148 ) -> Self {
129 into_ref!(uarte, irq); 149 into_ref!(uarte);
130 150
131 let r = T::regs(); 151 let r = T::regs();
132 152
@@ -148,9 +168,8 @@ impl<'d, T: Instance> Uarte<'d, T> {
148 } 168 }
149 r.psel.rts.write(|w| unsafe { w.bits(rts.psel_bits()) }); 169 r.psel.rts.write(|w| unsafe { w.bits(rts.psel_bits()) });
150 170
151 irq.set_handler(Self::on_interrupt); 171 unsafe { T::Interrupt::steal() }.unpend();
152 irq.unpend(); 172 unsafe { T::Interrupt::steal() }.enable();
153 irq.enable();
154 173
155 let hardware_flow_control = match (rts.is_some(), cts.is_some()) { 174 let hardware_flow_control = match (rts.is_some(), cts.is_some()) {
156 (false, false) => false, 175 (false, false) => false,
@@ -238,20 +257,6 @@ impl<'d, T: Instance> Uarte<'d, T> {
238 Event::from_reg(&r.events_endtx) 257 Event::from_reg(&r.events_endtx)
239 } 258 }
240 259
241 fn on_interrupt(_: *mut ()) {
242 let r = T::regs();
243 let s = T::state();
244
245 if r.events_endrx.read().bits() != 0 {
246 s.endrx_waker.wake();
247 r.intenclr.write(|w| w.endrx().clear());
248 }
249 if r.events_endtx.read().bits() != 0 {
250 s.endtx_waker.wake();
251 r.intenclr.write(|w| w.endtx().clear());
252 }
253 }
254
255 /// Read bytes until the buffer is filled. 260 /// Read bytes until the buffer is filled.
256 pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> { 261 pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> {
257 self.rx.read(buffer).await 262 self.rx.read(buffer).await
@@ -308,34 +313,33 @@ impl<'d, T: Instance> UarteTx<'d, T> {
308 /// Create a new tx-only UARTE without hardware flow control 313 /// Create a new tx-only UARTE without hardware flow control
309 pub fn new( 314 pub fn new(
310 uarte: impl Peripheral<P = T> + 'd, 315 uarte: impl Peripheral<P = T> + 'd,
311 irq: impl Peripheral<P = T::Interrupt> + 'd, 316 _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
312 txd: impl Peripheral<P = impl GpioPin> + 'd, 317 txd: impl Peripheral<P = impl GpioPin> + 'd,
313 config: Config, 318 config: Config,
314 ) -> Self { 319 ) -> Self {
315 into_ref!(txd); 320 into_ref!(txd);
316 Self::new_inner(uarte, irq, txd.map_into(), None, config) 321 Self::new_inner(uarte, txd.map_into(), None, config)
317 } 322 }
318 323
319 /// Create a new tx-only UARTE with hardware flow control (RTS/CTS) 324 /// Create a new tx-only UARTE with hardware flow control (RTS/CTS)
320 pub fn new_with_rtscts( 325 pub fn new_with_rtscts(
321 uarte: impl Peripheral<P = T> + 'd, 326 uarte: impl Peripheral<P = T> + 'd,
322 irq: impl Peripheral<P = T::Interrupt> + 'd, 327 _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
323 txd: impl Peripheral<P = impl GpioPin> + 'd, 328 txd: impl Peripheral<P = impl GpioPin> + 'd,
324 cts: impl Peripheral<P = impl GpioPin> + 'd, 329 cts: impl Peripheral<P = impl GpioPin> + 'd,
325 config: Config, 330 config: Config,
326 ) -> Self { 331 ) -> Self {
327 into_ref!(txd, cts); 332 into_ref!(txd, cts);
328 Self::new_inner(uarte, irq, txd.map_into(), Some(cts.map_into()), config) 333 Self::new_inner(uarte, txd.map_into(), Some(cts.map_into()), config)
329 } 334 }
330 335
331 fn new_inner( 336 fn new_inner(
332 uarte: impl Peripheral<P = T> + 'd, 337 uarte: impl Peripheral<P = T> + 'd,
333 irq: impl Peripheral<P = T::Interrupt> + 'd,
334 txd: PeripheralRef<'d, AnyPin>, 338 txd: PeripheralRef<'d, AnyPin>,
335 cts: Option<PeripheralRef<'d, AnyPin>>, 339 cts: Option<PeripheralRef<'d, AnyPin>>,
336 config: Config, 340 config: Config,
337 ) -> Self { 341 ) -> Self {
338 into_ref!(uarte, irq); 342 into_ref!(uarte);
339 343
340 let r = T::regs(); 344 let r = T::regs();
341 345
@@ -354,9 +358,8 @@ impl<'d, T: Instance> UarteTx<'d, T> {
354 let hardware_flow_control = cts.is_some(); 358 let hardware_flow_control = cts.is_some();
355 configure(r, config, hardware_flow_control); 359 configure(r, config, hardware_flow_control);
356 360
357 irq.set_handler(Uarte::<T>::on_interrupt); 361 unsafe { T::Interrupt::steal() }.unpend();
358 irq.unpend(); 362 unsafe { T::Interrupt::steal() }.enable();
359 irq.enable();
360 363
361 let s = T::state(); 364 let s = T::state();
362 s.tx_rx_refcount.store(1, Ordering::Relaxed); 365 s.tx_rx_refcount.store(1, Ordering::Relaxed);
@@ -506,34 +509,33 @@ impl<'d, T: Instance> UarteRx<'d, T> {
506 /// Create a new rx-only UARTE without hardware flow control 509 /// Create a new rx-only UARTE without hardware flow control
507 pub fn new( 510 pub fn new(
508 uarte: impl Peripheral<P = T> + 'd, 511 uarte: impl Peripheral<P = T> + 'd,
509 irq: impl Peripheral<P = T::Interrupt> + 'd, 512 _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
510 rxd: impl Peripheral<P = impl GpioPin> + 'd, 513 rxd: impl Peripheral<P = impl GpioPin> + 'd,
511 config: Config, 514 config: Config,
512 ) -> Self { 515 ) -> Self {
513 into_ref!(rxd); 516 into_ref!(rxd);
514 Self::new_inner(uarte, irq, rxd.map_into(), None, config) 517 Self::new_inner(uarte, rxd.map_into(), None, config)
515 } 518 }
516 519
517 /// Create a new rx-only UARTE with hardware flow control (RTS/CTS) 520 /// Create a new rx-only UARTE with hardware flow control (RTS/CTS)
518 pub fn new_with_rtscts( 521 pub fn new_with_rtscts(
519 uarte: impl Peripheral<P = T> + 'd, 522 uarte: impl Peripheral<P = T> + 'd,
520 irq: impl Peripheral<P = T::Interrupt> + 'd, 523 _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
521 rxd: impl Peripheral<P = impl GpioPin> + 'd, 524 rxd: impl Peripheral<P = impl GpioPin> + 'd,
522 rts: impl Peripheral<P = impl GpioPin> + 'd, 525 rts: impl Peripheral<P = impl GpioPin> + 'd,
523 config: Config, 526 config: Config,
524 ) -> Self { 527 ) -> Self {
525 into_ref!(rxd, rts); 528 into_ref!(rxd, rts);
526 Self::new_inner(uarte, irq, rxd.map_into(), Some(rts.map_into()), config) 529 Self::new_inner(uarte, rxd.map_into(), Some(rts.map_into()), config)
527 } 530 }
528 531
529 fn new_inner( 532 fn new_inner(
530 uarte: impl Peripheral<P = T> + 'd, 533 uarte: impl Peripheral<P = T> + 'd,
531 irq: impl Peripheral<P = T::Interrupt> + 'd,
532 rxd: PeripheralRef<'d, AnyPin>, 534 rxd: PeripheralRef<'d, AnyPin>,
533 rts: Option<PeripheralRef<'d, AnyPin>>, 535 rts: Option<PeripheralRef<'d, AnyPin>>,
534 config: Config, 536 config: Config,
535 ) -> Self { 537 ) -> Self {
536 into_ref!(uarte, irq); 538 into_ref!(uarte);
537 539
538 let r = T::regs(); 540 let r = T::regs();
539 541
@@ -549,9 +551,8 @@ impl<'d, T: Instance> UarteRx<'d, T> {
549 r.psel.txd.write(|w| w.connect().disconnected()); 551 r.psel.txd.write(|w| w.connect().disconnected());
550 r.psel.cts.write(|w| w.connect().disconnected()); 552 r.psel.cts.write(|w| w.connect().disconnected());
551 553
552 irq.set_handler(Uarte::<T>::on_interrupt); 554 unsafe { T::Interrupt::steal() }.unpend();
553 irq.unpend(); 555 unsafe { T::Interrupt::steal() }.enable();
554 irq.enable();
555 556
556 let hardware_flow_control = rts.is_some(); 557 let hardware_flow_control = rts.is_some();
557 configure(r, config, hardware_flow_control); 558 configure(r, config, hardware_flow_control);
@@ -883,6 +884,7 @@ pub(crate) mod sealed {
883 pub trait Instance { 884 pub trait Instance {
884 fn regs() -> &'static pac::uarte0::RegisterBlock; 885 fn regs() -> &'static pac::uarte0::RegisterBlock;
885 fn state() -> &'static State; 886 fn state() -> &'static State;
887 fn buffered_state() -> &'static crate::buffered_uarte::State;
886 } 888 }
887} 889}
888 890
@@ -902,6 +904,10 @@ macro_rules! impl_uarte {
902 static STATE: crate::uarte::sealed::State = crate::uarte::sealed::State::new(); 904 static STATE: crate::uarte::sealed::State = crate::uarte::sealed::State::new();
903 &STATE 905 &STATE
904 } 906 }
907 fn buffered_state() -> &'static crate::buffered_uarte::State {
908 static STATE: crate::buffered_uarte::State = crate::buffered_uarte::State::new();
909 &STATE
910 }
905 } 911 }
906 impl crate::uarte::Instance for peripherals::$type { 912 impl crate::uarte::Instance for peripherals::$type {
907 type Interrupt = crate::interrupt::$irq; 913 type Interrupt = crate::interrupt::$irq;
diff --git a/embassy-nrf/src/usb.rs b/embassy-nrf/src/usb/mod.rs
index cd142f00f..56de511df 100644
--- a/embassy-nrf/src/usb.rs
+++ b/embassy-nrf/src/usb/mod.rs
@@ -2,10 +2,12 @@
2 2
3#![macro_use] 3#![macro_use]
4 4
5pub mod vbus_detect;
6
5use core::future::poll_fn; 7use core::future::poll_fn;
6use core::marker::PhantomData; 8use core::marker::PhantomData;
7use core::mem::MaybeUninit; 9use core::mem::MaybeUninit;
8use core::sync::atomic::{compiler_fence, AtomicBool, AtomicU32, Ordering}; 10use core::sync::atomic::{compiler_fence, AtomicU32, Ordering};
9use core::task::Poll; 11use core::task::Poll;
10 12
11use cortex_m::peripheral::NVIC; 13use cortex_m::peripheral::NVIC;
@@ -15,7 +17,8 @@ use embassy_usb_driver as driver;
15use embassy_usb_driver::{Direction, EndpointAddress, EndpointError, EndpointInfo, EndpointType, Event, Unsupported}; 17use embassy_usb_driver::{Direction, EndpointAddress, EndpointError, EndpointInfo, EndpointType, Event, Unsupported};
16use pac::usbd::RegisterBlock; 18use pac::usbd::RegisterBlock;
17 19
18use crate::interrupt::{Interrupt, InterruptExt}; 20use self::vbus_detect::VbusDetect;
21use crate::interrupt::{self, Interrupt, InterruptExt};
19use crate::util::slice_in_ram; 22use crate::util::slice_in_ram;
20use crate::{pac, Peripheral}; 23use crate::{pac, Peripheral};
21 24
@@ -26,185 +29,13 @@ static EP_IN_WAKERS: [AtomicWaker; 8] = [NEW_AW; 8];
26static EP_OUT_WAKERS: [AtomicWaker; 8] = [NEW_AW; 8]; 29static EP_OUT_WAKERS: [AtomicWaker; 8] = [NEW_AW; 8];
27static READY_ENDPOINTS: AtomicU32 = AtomicU32::new(0); 30static READY_ENDPOINTS: AtomicU32 = AtomicU32::new(0);
28 31
29/// Trait for detecting USB VBUS power. 32/// Interrupt handler.
30/// 33pub struct InterruptHandler<T: Instance> {
31/// There are multiple ways to detect USB power. The behavior 34 _phantom: PhantomData<T>,
32/// here provides a hook into determining whether it is.
33pub trait VbusDetect {
34 /// Report whether power is detected.
35 ///
36 /// This is indicated by the `USBREGSTATUS.VBUSDETECT` register, or the
37 /// `USBDETECTED`, `USBREMOVED` events from the `POWER` peripheral.
38 fn is_usb_detected(&self) -> bool;
39
40 /// Wait until USB power is ready.
41 ///
42 /// USB power ready is indicated by the `USBREGSTATUS.OUTPUTRDY` register, or the
43 /// `USBPWRRDY` event from the `POWER` peripheral.
44 async fn wait_power_ready(&mut self) -> Result<(), ()>;
45}
46
47/// [`VbusDetect`] implementation using the native hardware POWER peripheral.
48///
49/// Unsuitable for usage with the nRF softdevice, since it reserves exclusive acces
50/// to POWER. In that case, use [`VbusDetectSignal`].
51#[cfg(not(feature = "_nrf5340-app"))]
52pub struct HardwareVbusDetect {
53 _private: (),
54}
55
56static POWER_WAKER: AtomicWaker = NEW_AW;
57
58#[cfg(not(feature = "_nrf5340-app"))]
59impl HardwareVbusDetect {
60 /// Create a new `VbusDetectNative`.
61 pub fn new(power_irq: impl Interrupt) -> Self {
62 let regs = unsafe { &*pac::POWER::ptr() };
63
64 power_irq.set_handler(Self::on_interrupt);
65 power_irq.unpend();
66 power_irq.enable();
67
68 regs.intenset
69 .write(|w| w.usbdetected().set().usbremoved().set().usbpwrrdy().set());
70
71 Self { _private: () }
72 }
73
74 #[cfg(not(feature = "_nrf5340-app"))]
75 fn on_interrupt(_: *mut ()) {
76 let regs = unsafe { &*pac::POWER::ptr() };
77
78 if regs.events_usbdetected.read().bits() != 0 {
79 regs.events_usbdetected.reset();
80 BUS_WAKER.wake();
81 }
82
83 if regs.events_usbremoved.read().bits() != 0 {
84 regs.events_usbremoved.reset();
85 BUS_WAKER.wake();
86 POWER_WAKER.wake();
87 }
88
89 if regs.events_usbpwrrdy.read().bits() != 0 {
90 regs.events_usbpwrrdy.reset();
91 POWER_WAKER.wake();
92 }
93 }
94}
95
96#[cfg(not(feature = "_nrf5340-app"))]
97impl VbusDetect for HardwareVbusDetect {
98 fn is_usb_detected(&self) -> bool {
99 let regs = unsafe { &*pac::POWER::ptr() };
100 regs.usbregstatus.read().vbusdetect().is_vbus_present()
101 }
102
103 async fn wait_power_ready(&mut self) -> Result<(), ()> {
104 poll_fn(move |cx| {
105 POWER_WAKER.register(cx.waker());
106 let regs = unsafe { &*pac::POWER::ptr() };
107
108 if regs.usbregstatus.read().outputrdy().is_ready() {
109 Poll::Ready(Ok(()))
110 } else if !self.is_usb_detected() {
111 Poll::Ready(Err(()))
112 } else {
113 Poll::Pending
114 }
115 })
116 .await
117 }
118}
119
120/// Software-backed [`VbusDetect`] implementation.
121///
122/// This implementation does not interact with the hardware, it allows user code
123/// to notify the power events by calling functions instead.
124///
125/// This is suitable for use with the nRF softdevice, by calling the functions
126/// when the softdevice reports power-related events.
127pub struct SoftwareVbusDetect {
128 usb_detected: AtomicBool,
129 power_ready: AtomicBool,
130}
131
132impl SoftwareVbusDetect {
133 /// Create a new `SoftwareVbusDetect`.
134 pub fn new(usb_detected: bool, power_ready: bool) -> Self {
135 BUS_WAKER.wake();
136
137 Self {
138 usb_detected: AtomicBool::new(usb_detected),
139 power_ready: AtomicBool::new(power_ready),
140 }
141 }
142
143 /// Report whether power was detected.
144 ///
145 /// Equivalent to the `USBDETECTED`, `USBREMOVED` events from the `POWER` peripheral.
146 pub fn detected(&self, detected: bool) {
147 self.usb_detected.store(detected, Ordering::Relaxed);
148 self.power_ready.store(false, Ordering::Relaxed);
149 BUS_WAKER.wake();
150 POWER_WAKER.wake();
151 }
152
153 /// Report when USB power is ready.
154 ///
155 /// Equivalent to the `USBPWRRDY` event from the `POWER` peripheral.
156 pub fn ready(&self) {
157 self.power_ready.store(true, Ordering::Relaxed);
158 POWER_WAKER.wake();
159 }
160}
161
162impl VbusDetect for &SoftwareVbusDetect {
163 fn is_usb_detected(&self) -> bool {
164 self.usb_detected.load(Ordering::Relaxed)
165 }
166
167 async fn wait_power_ready(&mut self) -> Result<(), ()> {
168 poll_fn(move |cx| {
169 POWER_WAKER.register(cx.waker());
170
171 if self.power_ready.load(Ordering::Relaxed) {
172 Poll::Ready(Ok(()))
173 } else if !self.usb_detected.load(Ordering::Relaxed) {
174 Poll::Ready(Err(()))
175 } else {
176 Poll::Pending
177 }
178 })
179 .await
180 }
181} 35}
182 36
183/// USB driver. 37impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> {
184pub struct Driver<'d, T: Instance, P: VbusDetect> { 38 unsafe fn on_interrupt() {
185 _p: PeripheralRef<'d, T>,
186 alloc_in: Allocator,
187 alloc_out: Allocator,
188 usb_supply: P,
189}
190
191impl<'d, T: Instance, P: VbusDetect> Driver<'d, T, P> {
192 /// Create a new USB driver.
193 pub fn new(usb: impl Peripheral<P = T> + 'd, irq: impl Peripheral<P = T::Interrupt> + 'd, usb_supply: P) -> Self {
194 into_ref!(usb, irq);
195 irq.set_handler(Self::on_interrupt);
196 irq.unpend();
197 irq.enable();
198
199 Self {
200 _p: usb,
201 alloc_in: Allocator::new(),
202 alloc_out: Allocator::new(),
203 usb_supply,
204 }
205 }
206
207 fn on_interrupt(_: *mut ()) {
208 let regs = T::regs(); 39 let regs = T::regs();
209 40
210 if regs.events_usbreset.read().bits() != 0 { 41 if regs.events_usbreset.read().bits() != 0 {
@@ -255,11 +86,40 @@ impl<'d, T: Instance, P: VbusDetect> Driver<'d, T, P> {
255 } 86 }
256} 87}
257 88
258impl<'d, T: Instance, P: VbusDetect + 'd> driver::Driver<'d> for Driver<'d, T, P> { 89/// USB driver.
90pub struct Driver<'d, T: Instance, V: VbusDetect> {
91 _p: PeripheralRef<'d, T>,
92 alloc_in: Allocator,
93 alloc_out: Allocator,
94 vbus_detect: V,
95}
96
97impl<'d, T: Instance, V: VbusDetect> Driver<'d, T, V> {
98 /// Create a new USB driver.
99 pub fn new(
100 usb: impl Peripheral<P = T> + 'd,
101 _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
102 vbus_detect: V,
103 ) -> Self {
104 into_ref!(usb);
105
106 unsafe { T::Interrupt::steal() }.unpend();
107 unsafe { T::Interrupt::steal() }.enable();
108
109 Self {
110 _p: usb,
111 alloc_in: Allocator::new(),
112 alloc_out: Allocator::new(),
113 vbus_detect,
114 }
115 }
116}
117
118impl<'d, T: Instance, V: VbusDetect + 'd> driver::Driver<'d> for Driver<'d, T, V> {
259 type EndpointOut = Endpoint<'d, T, Out>; 119 type EndpointOut = Endpoint<'d, T, Out>;
260 type EndpointIn = Endpoint<'d, T, In>; 120 type EndpointIn = Endpoint<'d, T, In>;
261 type ControlPipe = ControlPipe<'d, T>; 121 type ControlPipe = ControlPipe<'d, T>;
262 type Bus = Bus<'d, T, P>; 122 type Bus = Bus<'d, T, V>;
263 123
264 fn alloc_endpoint_in( 124 fn alloc_endpoint_in(
265 &mut self, 125 &mut self,
@@ -298,7 +158,7 @@ impl<'d, T: Instance, P: VbusDetect + 'd> driver::Driver<'d> for Driver<'d, T, P
298 Bus { 158 Bus {
299 _p: unsafe { self._p.clone_unchecked() }, 159 _p: unsafe { self._p.clone_unchecked() },
300 power_available: false, 160 power_available: false,
301 usb_supply: self.usb_supply, 161 vbus_detect: self.vbus_detect,
302 }, 162 },
303 ControlPipe { 163 ControlPipe {
304 _p: self._p, 164 _p: self._p,
@@ -309,13 +169,13 @@ impl<'d, T: Instance, P: VbusDetect + 'd> driver::Driver<'d> for Driver<'d, T, P
309} 169}
310 170
311/// USB bus. 171/// USB bus.
312pub struct Bus<'d, T: Instance, P: VbusDetect> { 172pub struct Bus<'d, T: Instance, V: VbusDetect> {
313 _p: PeripheralRef<'d, T>, 173 _p: PeripheralRef<'d, T>,
314 power_available: bool, 174 power_available: bool,
315 usb_supply: P, 175 vbus_detect: V,
316} 176}
317 177
318impl<'d, T: Instance, P: VbusDetect> driver::Bus for Bus<'d, T, P> { 178impl<'d, T: Instance, V: VbusDetect> driver::Bus for Bus<'d, T, V> {
319 async fn enable(&mut self) { 179 async fn enable(&mut self) {
320 let regs = T::regs(); 180 let regs = T::regs();
321 181
@@ -347,7 +207,7 @@ impl<'d, T: Instance, P: VbusDetect> driver::Bus for Bus<'d, T, P> {
347 w 207 w
348 }); 208 });
349 209
350 if self.usb_supply.wait_power_ready().await.is_ok() { 210 if self.vbus_detect.wait_power_ready().await.is_ok() {
351 // Enable the USB pullup, allowing enumeration. 211 // Enable the USB pullup, allowing enumeration.
352 regs.usbpullup.write(|w| w.connect().enabled()); 212 regs.usbpullup.write(|w| w.connect().enabled());
353 trace!("enabled"); 213 trace!("enabled");
@@ -406,7 +266,7 @@ impl<'d, T: Instance, P: VbusDetect> driver::Bus for Bus<'d, T, P> {
406 trace!("USB event: ready"); 266 trace!("USB event: ready");
407 } 267 }
408 268
409 if self.usb_supply.is_usb_detected() != self.power_available { 269 if self.vbus_detect.is_usb_detected() != self.power_available {
410 self.power_available = !self.power_available; 270 self.power_available = !self.power_available;
411 if self.power_available { 271 if self.power_available {
412 trace!("Power event: available"); 272 trace!("Power event: available");
diff --git a/embassy-nrf/src/usb/vbus_detect.rs b/embassy-nrf/src/usb/vbus_detect.rs
new file mode 100644
index 000000000..cecd4c595
--- /dev/null
+++ b/embassy-nrf/src/usb/vbus_detect.rs
@@ -0,0 +1,177 @@
1//! Trait and implementations for performing VBUS detection.
2
3use core::future::poll_fn;
4use core::sync::atomic::{AtomicBool, Ordering};
5use core::task::Poll;
6
7use embassy_sync::waitqueue::AtomicWaker;
8
9use super::BUS_WAKER;
10use crate::interrupt::{self, Interrupt, InterruptExt};
11use crate::pac;
12
13/// Trait for detecting USB VBUS power.
14///
15/// There are multiple ways to detect USB power. The behavior
16/// here provides a hook into determining whether it is.
17pub trait VbusDetect {
18 /// Report whether power is detected.
19 ///
20 /// This is indicated by the `USBREGSTATUS.VBUSDETECT` register, or the
21 /// `USBDETECTED`, `USBREMOVED` events from the `POWER` peripheral.
22 fn is_usb_detected(&self) -> bool;
23
24 /// Wait until USB power is ready.
25 ///
26 /// USB power ready is indicated by the `USBREGSTATUS.OUTPUTRDY` register, or the
27 /// `USBPWRRDY` event from the `POWER` peripheral.
28 async fn wait_power_ready(&mut self) -> Result<(), ()>;
29}
30
31#[cfg(not(feature = "_nrf5340"))]
32type UsbRegIrq = interrupt::POWER_CLOCK;
33#[cfg(feature = "_nrf5340")]
34type UsbRegIrq = interrupt::USBREGULATOR;
35
36#[cfg(not(feature = "_nrf5340"))]
37type UsbRegPeri = pac::POWER;
38#[cfg(feature = "_nrf5340")]
39type UsbRegPeri = pac::USBREGULATOR;
40
41/// Interrupt handler.
42pub struct InterruptHandler {
43 _private: (),
44}
45
46impl interrupt::Handler<UsbRegIrq> for InterruptHandler {
47 unsafe fn on_interrupt() {
48 let regs = unsafe { &*UsbRegPeri::ptr() };
49
50 if regs.events_usbdetected.read().bits() != 0 {
51 regs.events_usbdetected.reset();
52 BUS_WAKER.wake();
53 }
54
55 if regs.events_usbremoved.read().bits() != 0 {
56 regs.events_usbremoved.reset();
57 BUS_WAKER.wake();
58 POWER_WAKER.wake();
59 }
60
61 if regs.events_usbpwrrdy.read().bits() != 0 {
62 regs.events_usbpwrrdy.reset();
63 POWER_WAKER.wake();
64 }
65 }
66}
67
68/// [`VbusDetect`] implementation using the native hardware POWER peripheral.
69///
70/// Unsuitable for usage with the nRF softdevice, since it reserves exclusive acces
71/// to POWER. In that case, use [`VbusDetectSignal`].
72pub struct HardwareVbusDetect {
73 _private: (),
74}
75
76static POWER_WAKER: AtomicWaker = AtomicWaker::new();
77
78impl HardwareVbusDetect {
79 /// Create a new `VbusDetectNative`.
80 pub fn new(_irq: impl interrupt::Binding<UsbRegIrq, InterruptHandler> + 'static) -> Self {
81 let regs = unsafe { &*UsbRegPeri::ptr() };
82
83 unsafe { UsbRegIrq::steal() }.unpend();
84 unsafe { UsbRegIrq::steal() }.enable();
85
86 regs.intenset
87 .write(|w| w.usbdetected().set().usbremoved().set().usbpwrrdy().set());
88
89 Self { _private: () }
90 }
91}
92
93impl VbusDetect for HardwareVbusDetect {
94 fn is_usb_detected(&self) -> bool {
95 let regs = unsafe { &*UsbRegPeri::ptr() };
96 regs.usbregstatus.read().vbusdetect().is_vbus_present()
97 }
98
99 async fn wait_power_ready(&mut self) -> Result<(), ()> {
100 poll_fn(move |cx| {
101 POWER_WAKER.register(cx.waker());
102 let regs = unsafe { &*UsbRegPeri::ptr() };
103
104 if regs.usbregstatus.read().outputrdy().is_ready() {
105 Poll::Ready(Ok(()))
106 } else if !self.is_usb_detected() {
107 Poll::Ready(Err(()))
108 } else {
109 Poll::Pending
110 }
111 })
112 .await
113 }
114}
115
116/// Software-backed [`VbusDetect`] implementation.
117///
118/// This implementation does not interact with the hardware, it allows user code
119/// to notify the power events by calling functions instead.
120///
121/// This is suitable for use with the nRF softdevice, by calling the functions
122/// when the softdevice reports power-related events.
123pub struct SoftwareVbusDetect {
124 usb_detected: AtomicBool,
125 power_ready: AtomicBool,
126}
127
128impl SoftwareVbusDetect {
129 /// Create a new `SoftwareVbusDetect`.
130 pub fn new(usb_detected: bool, power_ready: bool) -> Self {
131 BUS_WAKER.wake();
132
133 Self {
134 usb_detected: AtomicBool::new(usb_detected),
135 power_ready: AtomicBool::new(power_ready),
136 }
137 }
138
139 /// Report whether power was detected.
140 ///
141 /// Equivalent to the `USBDETECTED`, `USBREMOVED` events from the `POWER` peripheral.
142 pub fn detected(&self, detected: bool) {
143 self.usb_detected.store(detected, Ordering::Relaxed);
144 self.power_ready.store(false, Ordering::Relaxed);
145 BUS_WAKER.wake();
146 POWER_WAKER.wake();
147 }
148
149 /// Report when USB power is ready.
150 ///
151 /// Equivalent to the `USBPWRRDY` event from the `POWER` peripheral.
152 pub fn ready(&self) {
153 self.power_ready.store(true, Ordering::Relaxed);
154 POWER_WAKER.wake();
155 }
156}
157
158impl VbusDetect for &SoftwareVbusDetect {
159 fn is_usb_detected(&self) -> bool {
160 self.usb_detected.load(Ordering::Relaxed)
161 }
162
163 async fn wait_power_ready(&mut self) -> Result<(), ()> {
164 poll_fn(move |cx| {
165 POWER_WAKER.register(cx.waker());
166
167 if self.power_ready.load(Ordering::Relaxed) {
168 Poll::Ready(Ok(()))
169 } else if !self.usb_detected.load(Ordering::Relaxed) {
170 Poll::Ready(Err(()))
171 } else {
172 Poll::Pending
173 }
174 })
175 .await
176 }
177}
diff --git a/embassy-rp/src/adc.rs b/embassy-rp/src/adc.rs
index 025c6f917..145ba9c59 100644
--- a/embassy-rp/src/adc.rs
+++ b/embassy-rp/src/adc.rs
@@ -7,6 +7,7 @@ use embassy_hal_common::into_ref;
7use embassy_sync::waitqueue::AtomicWaker; 7use embassy_sync::waitqueue::AtomicWaker;
8use embedded_hal_02::adc::{Channel, OneShot}; 8use embedded_hal_02::adc::{Channel, OneShot};
9 9
10use crate::gpio::Pin;
10use crate::interrupt::{self, InterruptExt}; 11use crate::interrupt::{self, InterruptExt};
11use crate::peripherals::ADC; 12use crate::peripherals::ADC;
12use crate::{pac, peripherals, Peripheral}; 13use crate::{pac, peripherals, Peripheral};
@@ -90,9 +91,17 @@ impl<'d> Adc<'d> {
90 } 91 }
91 } 92 }
92 93
93 pub async fn read<PIN: Channel<Adc<'d>, ID = u8>>(&mut self, _pin: &mut PIN) -> u16 { 94 pub async fn read<PIN: Channel<Adc<'d>, ID = u8> + Pin>(&mut self, pin: &mut PIN) -> u16 {
94 let r = Self::regs(); 95 let r = Self::regs();
95 unsafe { 96 unsafe {
97 // disable pull-down and pull-up resistors
98 // pull-down resistors are enabled by default
99 pin.pad_ctrl().modify(|w| {
100 w.set_ie(true);
101 let (pu, pd) = (false, false);
102 w.set_pue(pu);
103 w.set_pde(pd);
104 });
96 r.cs().modify(|w| { 105 r.cs().modify(|w| {
97 w.set_ainsel(PIN::channel()); 106 w.set_ainsel(PIN::channel());
98 w.set_start_once(true) 107 w.set_start_once(true)
diff --git a/embassy-rp/src/dma.rs b/embassy-rp/src/dma.rs
index fd281fd5d..05adcecdd 100644
--- a/embassy-rp/src/dma.rs
+++ b/embassy-rp/src/dma.rs
@@ -151,6 +151,7 @@ fn copy_inner<'a, C: Channel>(
151 Transfer::new(ch) 151 Transfer::new(ch)
152} 152}
153 153
154#[must_use = "futures do nothing unless you `.await` or poll them"]
154pub struct Transfer<'a, C: Channel> { 155pub struct Transfer<'a, C: Channel> {
155 channel: PeripheralRef<'a, C>, 156 channel: PeripheralRef<'a, C>,
156} 157}
diff --git a/embassy-rp/src/gpio.rs b/embassy-rp/src/gpio.rs
index 76d4281ff..fb45ef7cf 100644
--- a/embassy-rp/src/gpio.rs
+++ b/embassy-rp/src/gpio.rs
@@ -174,7 +174,7 @@ unsafe fn IO_IRQ_BANK0() {
174 w.set_edge_low(pin_group, false); 174 w.set_edge_low(pin_group, false);
175 } 175 }
176 InterruptTrigger::LevelHigh => { 176 InterruptTrigger::LevelHigh => {
177 debug!("IO_IRQ_BANK0 pin {} LevelHigh triggered", pin); 177 trace!("IO_IRQ_BANK0 pin {} LevelHigh triggered", pin);
178 w.set_level_high(pin_group, false); 178 w.set_level_high(pin_group, false);
179 } 179 }
180 InterruptTrigger::LevelLow => { 180 InterruptTrigger::LevelLow => {
@@ -193,6 +193,7 @@ unsafe fn IO_IRQ_BANK0() {
193 } 193 }
194} 194}
195 195
196#[must_use = "futures do nothing unless you `.await` or poll them"]
196struct InputFuture<'a, T: Pin> { 197struct InputFuture<'a, T: Pin> {
197 pin: PeripheralRef<'a, T>, 198 pin: PeripheralRef<'a, T>,
198 level: InterruptTrigger, 199 level: InterruptTrigger,
@@ -213,7 +214,7 @@ impl<'d, T: Pin> InputFuture<'d, T> {
213 critical_section::with(|_| { 214 critical_section::with(|_| {
214 pin.int_proc().inte((pin.pin() / 8) as usize).modify(|w| match level { 215 pin.int_proc().inte((pin.pin() / 8) as usize).modify(|w| match level {
215 InterruptTrigger::LevelHigh => { 216 InterruptTrigger::LevelHigh => {
216 debug!("InputFuture::new enable LevelHigh for pin {}", pin.pin()); 217 trace!("InputFuture::new enable LevelHigh for pin {}", pin.pin());
217 w.set_level_high(pin_group, true); 218 w.set_level_high(pin_group, true);
218 } 219 }
219 InterruptTrigger::LevelLow => { 220 InterruptTrigger::LevelLow => {
@@ -260,45 +261,45 @@ impl<'d, T: Pin> Future for InputFuture<'d, T> {
260 // the pin and if it has been disabled that means it was done by the 261 // the pin and if it has been disabled that means it was done by the
261 // interrupt service routine, so we then know that the event/trigger 262 // interrupt service routine, so we then know that the event/trigger
262 // happened and Poll::Ready will be returned. 263 // happened and Poll::Ready will be returned.
263 debug!("{:?} for pin {}", self.level, self.pin.pin()); 264 trace!("{:?} for pin {}", self.level, self.pin.pin());
264 match self.level { 265 match self.level {
265 InterruptTrigger::AnyEdge => { 266 InterruptTrigger::AnyEdge => {
266 if !inte.edge_high(pin_group) && !inte.edge_low(pin_group) { 267 if !inte.edge_high(pin_group) && !inte.edge_low(pin_group) {
267 #[rustfmt::skip] 268 #[rustfmt::skip]
268 debug!("{:?} for pin {} was cleared, return Poll::Ready", self.level, self.pin.pin()); 269 trace!("{:?} for pin {} was cleared, return Poll::Ready", self.level, self.pin.pin());
269 return Poll::Ready(()); 270 return Poll::Ready(());
270 } 271 }
271 } 272 }
272 InterruptTrigger::LevelHigh => { 273 InterruptTrigger::LevelHigh => {
273 if !inte.level_high(pin_group) { 274 if !inte.level_high(pin_group) {
274 #[rustfmt::skip] 275 #[rustfmt::skip]
275 debug!("{:?} for pin {} was cleared, return Poll::Ready", self.level, self.pin.pin()); 276 trace!("{:?} for pin {} was cleared, return Poll::Ready", self.level, self.pin.pin());
276 return Poll::Ready(()); 277 return Poll::Ready(());
277 } 278 }
278 } 279 }
279 InterruptTrigger::LevelLow => { 280 InterruptTrigger::LevelLow => {
280 if !inte.level_low(pin_group) { 281 if !inte.level_low(pin_group) {
281 #[rustfmt::skip] 282 #[rustfmt::skip]
282 debug!("{:?} for pin {} was cleared, return Poll::Ready", self.level, self.pin.pin()); 283 trace!("{:?} for pin {} was cleared, return Poll::Ready", self.level, self.pin.pin());
283 return Poll::Ready(()); 284 return Poll::Ready(());
284 } 285 }
285 } 286 }
286 InterruptTrigger::EdgeHigh => { 287 InterruptTrigger::EdgeHigh => {
287 if !inte.edge_high(pin_group) { 288 if !inte.edge_high(pin_group) {
288 #[rustfmt::skip] 289 #[rustfmt::skip]
289 debug!("{:?} for pin {} was cleared, return Poll::Ready", self.level, self.pin.pin()); 290 trace!("{:?} for pin {} was cleared, return Poll::Ready", self.level, self.pin.pin());
290 return Poll::Ready(()); 291 return Poll::Ready(());
291 } 292 }
292 } 293 }
293 InterruptTrigger::EdgeLow => { 294 InterruptTrigger::EdgeLow => {
294 if !inte.edge_low(pin_group) { 295 if !inte.edge_low(pin_group) {
295 #[rustfmt::skip] 296 #[rustfmt::skip]
296 debug!("{:?} for pin {} was cleared, return Poll::Ready", self.level, self.pin.pin()); 297 trace!("{:?} for pin {} was cleared, return Poll::Ready", self.level, self.pin.pin());
297 return Poll::Ready(()); 298 return Poll::Ready(());
298 } 299 }
299 } 300 }
300 } 301 }
301 debug!("InputFuture::poll return Poll::Pending"); 302 trace!("InputFuture::poll return Poll::Pending");
302 Poll::Pending 303 Poll::Pending
303 } 304 }
304} 305}
diff --git a/embassy-rp/src/pio.rs b/embassy-rp/src/pio.rs
index 2fb2783de..3c7abea25 100644
--- a/embassy-rp/src/pio.rs
+++ b/embassy-rp/src/pio.rs
@@ -120,6 +120,7 @@ unsafe fn PIO1_IRQ_0() {
120} 120}
121 121
122/// Future that waits for TX-FIFO to become writable 122/// Future that waits for TX-FIFO to become writable
123#[must_use = "futures do nothing unless you `.await` or poll them"]
123pub struct FifoOutFuture<'a, PIO: PioInstance, SM: PioStateMachine + Unpin> { 124pub struct FifoOutFuture<'a, PIO: PioInstance, SM: PioStateMachine + Unpin> {
124 sm: &'a mut SM, 125 sm: &'a mut SM,
125 pio: PhantomData<PIO>, 126 pio: PhantomData<PIO>,
@@ -182,6 +183,7 @@ impl<'d, PIO: PioInstance, SM: PioStateMachine + Unpin> Drop for FifoOutFuture<'
182} 183}
183 184
184/// Future that waits for RX-FIFO to become readable 185/// Future that waits for RX-FIFO to become readable
186#[must_use = "futures do nothing unless you `.await` or poll them"]
185pub struct FifoInFuture<'a, PIO: PioInstance, SM: PioStateMachine> { 187pub struct FifoInFuture<'a, PIO: PioInstance, SM: PioStateMachine> {
186 sm: &'a mut SM, 188 sm: &'a mut SM,
187 pio: PhantomData<PIO>, 189 pio: PhantomData<PIO>,
@@ -241,6 +243,7 @@ impl<'d, PIO: PioInstance, SM: PioStateMachine> Drop for FifoInFuture<'d, PIO, S
241} 243}
242 244
243/// Future that waits for IRQ 245/// Future that waits for IRQ
246#[must_use = "futures do nothing unless you `.await` or poll them"]
244pub struct IrqFuture<PIO: PioInstance> { 247pub struct IrqFuture<PIO: PioInstance> {
245 pio: PhantomData<PIO>, 248 pio: PhantomData<PIO>,
246 irq_no: u8, 249 irq_no: u8,
diff --git a/embassy-rp/src/uart/mod.rs b/embassy-rp/src/uart/mod.rs
index bbbf97c01..42b3671a0 100644
--- a/embassy-rp/src/uart/mod.rs
+++ b/embassy-rp/src/uart/mod.rs
@@ -299,7 +299,7 @@ impl<'d, T: Instance> Uart<'d, T, Async> {
299 } 299 }
300} 300}
301 301
302impl<'d, T: Instance, M: Mode> Uart<'d, T, M> { 302impl<'d, T: Instance + 'd, M: Mode> Uart<'d, T, M> {
303 fn new_inner( 303 fn new_inner(
304 _uart: impl Peripheral<P = T> + 'd, 304 _uart: impl Peripheral<P = T> + 'd,
305 mut tx: PeripheralRef<'d, AnyPin>, 305 mut tx: PeripheralRef<'d, AnyPin>,
@@ -350,23 +350,7 @@ impl<'d, T: Instance, M: Mode> Uart<'d, T, M> {
350 pin.pad_ctrl().write(|w| w.set_ie(true)); 350 pin.pad_ctrl().write(|w| w.set_ie(true));
351 } 351 }
352 352
353 let clk_base = crate::clocks::clk_peri_freq(); 353 Self::set_baudrate_inner(config.baudrate);
354
355 let baud_rate_div = (8 * clk_base) / config.baudrate;
356 let mut baud_ibrd = baud_rate_div >> 7;
357 let mut baud_fbrd = ((baud_rate_div & 0x7f) + 1) / 2;
358
359 if baud_ibrd == 0 {
360 baud_ibrd = 1;
361 baud_fbrd = 0;
362 } else if baud_ibrd >= 65535 {
363 baud_ibrd = 65535;
364 baud_fbrd = 0;
365 }
366
367 // Load PL011's baud divisor registers
368 r.uartibrd().write_value(pac::uart::regs::Uartibrd(baud_ibrd));
369 r.uartfbrd().write_value(pac::uart::regs::Uartfbrd(baud_fbrd));
370 354
371 let (pen, eps) = match config.parity { 355 let (pen, eps) = match config.parity {
372 Parity::ParityNone => (false, false), 356 Parity::ParityNone => (false, false),
@@ -400,6 +384,35 @@ impl<'d, T: Instance, M: Mode> Uart<'d, T, M> {
400 }); 384 });
401 } 385 }
402 } 386 }
387
388 /// sets baudrate on runtime
389 pub fn set_baudrate(&mut self, baudrate: u32) {
390 Self::set_baudrate_inner(baudrate);
391 }
392
393 fn set_baudrate_inner(baudrate: u32) {
394 let r = T::regs();
395
396 let clk_base = crate::clocks::clk_peri_freq();
397
398 let baud_rate_div = (8 * clk_base) / baudrate;
399 let mut baud_ibrd = baud_rate_div >> 7;
400 let mut baud_fbrd = ((baud_rate_div & 0x7f) + 1) / 2;
401
402 if baud_ibrd == 0 {
403 baud_ibrd = 1;
404 baud_fbrd = 0;
405 } else if baud_ibrd >= 65535 {
406 baud_ibrd = 65535;
407 baud_fbrd = 0;
408 }
409
410 unsafe {
411 // Load PL011's baud divisor registers
412 r.uartibrd().write_value(pac::uart::regs::Uartibrd(baud_ibrd));
413 r.uartfbrd().write_value(pac::uart::regs::Uartfbrd(baud_fbrd));
414 }
415 }
403} 416}
404 417
405impl<'d, T: Instance, M: Mode> Uart<'d, T, M> { 418impl<'d, T: Instance, M: Mode> Uart<'d, T, M> {
diff --git a/embassy-stm32/src/dma/mod.rs b/embassy-stm32/src/dma/mod.rs
index f5a82fb7a..0030bd575 100644
--- a/embassy-stm32/src/dma/mod.rs
+++ b/embassy-stm32/src/dma/mod.rs
@@ -273,6 +273,7 @@ mod transfers {
273 Transfer::new(channel) 273 Transfer::new(channel)
274 } 274 }
275 275
276 #[must_use = "futures do nothing unless you `.await` or poll them"]
276 pub(crate) struct Transfer<'a, C: Channel> { 277 pub(crate) struct Transfer<'a, C: Channel> {
277 channel: PeripheralRef<'a, C>, 278 channel: PeripheralRef<'a, C>,
278 } 279 }
diff --git a/embassy-stm32/src/eth/mod.rs b/embassy-stm32/src/eth/mod.rs
index 9f62b61ee..e1d7a09b4 100644
--- a/embassy-stm32/src/eth/mod.rs
+++ b/embassy-stm32/src/eth/mod.rs
@@ -5,6 +5,7 @@
5mod _version; 5mod _version;
6pub mod generic_smi; 6pub mod generic_smi;
7 7
8use core::mem::MaybeUninit;
8use core::task::Context; 9use core::task::Context;
9 10
10use embassy_net_driver::{Capabilities, LinkState}; 11use embassy_net_driver::{Capabilities, LinkState};
@@ -39,6 +40,13 @@ impl<const TX: usize, const RX: usize> PacketQueue<TX, RX> {
39 rx_buf: [Packet([0; RX_BUFFER_SIZE]); RX], 40 rx_buf: [Packet([0; RX_BUFFER_SIZE]); RX],
40 } 41 }
41 } 42 }
43
44 // Allow to initialize a Self without requiring it to go on the stack
45 pub fn init(this: &mut MaybeUninit<Self>) {
46 unsafe {
47 this.as_mut_ptr().write_bytes(0u8, 1);
48 }
49 }
42} 50}
43 51
44static WAKER: AtomicWaker = AtomicWaker::new(); 52static WAKER: AtomicWaker = AtomicWaker::new();
diff --git a/embassy-stm32/src/exti.rs b/embassy-stm32/src/exti.rs
index c9c3ef62a..e1ce09a49 100644
--- a/embassy-stm32/src/exti.rs
+++ b/embassy-stm32/src/exti.rs
@@ -198,6 +198,7 @@ mod eha {
198 } 198 }
199} 199}
200 200
201#[must_use = "futures do nothing unless you `.await` or poll them"]
201struct ExtiInputFuture<'a> { 202struct ExtiInputFuture<'a> {
202 pin: u8, 203 pin: u8,
203 phantom: PhantomData<&'a mut AnyPin>, 204 phantom: PhantomData<&'a mut AnyPin>,
diff --git a/embassy-stm32/src/spi/mod.rs b/embassy-stm32/src/spi/mod.rs
index e5ba746e4..1f1708873 100644
--- a/embassy-stm32/src/spi/mod.rs
+++ b/embassy-stm32/src/spi/mod.rs
@@ -456,13 +456,14 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
456 T::REGS.cr1().modify(|w| { 456 T::REGS.cr1().modify(|w| {
457 w.set_spe(false); 457 w.set_spe(false);
458 }); 458 });
459 set_rxdmaen(T::REGS, true);
460 } 459 }
461 460
462 // SPIv3 clears rxfifo on SPE=0 461 // SPIv3 clears rxfifo on SPE=0
463 #[cfg(not(any(spi_v3, spi_v4)))] 462 #[cfg(not(any(spi_v3, spi_v4)))]
464 flush_rx_fifo(T::REGS); 463 flush_rx_fifo(T::REGS);
465 464
465 set_rxdmaen(T::REGS, true);
466
466 let clock_byte_count = data.len(); 467 let clock_byte_count = data.len();
467 468
468 let rx_request = self.rxdma.request(); 469 let rx_request = self.rxdma.request();
@@ -510,13 +511,14 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
510 T::REGS.cr1().modify(|w| { 511 T::REGS.cr1().modify(|w| {
511 w.set_spe(false); 512 w.set_spe(false);
512 }); 513 });
513 set_rxdmaen(T::REGS, true);
514 } 514 }
515 515
516 // SPIv3 clears rxfifo on SPE=0 516 // SPIv3 clears rxfifo on SPE=0
517 #[cfg(not(any(spi_v3, spi_v4)))] 517 #[cfg(not(any(spi_v3, spi_v4)))]
518 flush_rx_fifo(T::REGS); 518 flush_rx_fifo(T::REGS);
519 519
520 set_rxdmaen(T::REGS, true);
521
520 let rx_request = self.rxdma.request(); 522 let rx_request = self.rxdma.request();
521 let rx_src = T::REGS.rx_ptr(); 523 let rx_src = T::REGS.rx_ptr();
522 unsafe { self.rxdma.start_read(rx_request, rx_src, read, Default::default()) }; 524 unsafe { self.rxdma.start_read(rx_request, rx_src, read, Default::default()) };
diff --git a/embassy-sync/src/channel.rs b/embassy-sync/src/channel.rs
index 76f42d0e7..77352874d 100644
--- a/embassy-sync/src/channel.rs
+++ b/embassy-sync/src/channel.rs
@@ -181,6 +181,7 @@ where
181} 181}
182 182
183/// Future returned by [`Channel::recv`] and [`Receiver::recv`]. 183/// Future returned by [`Channel::recv`] and [`Receiver::recv`].
184#[must_use = "futures do nothing unless you `.await` or poll them"]
184pub struct RecvFuture<'ch, M, T, const N: usize> 185pub struct RecvFuture<'ch, M, T, const N: usize>
185where 186where
186 M: RawMutex, 187 M: RawMutex,
@@ -203,6 +204,7 @@ where
203} 204}
204 205
205/// Future returned by [`DynamicReceiver::recv`]. 206/// Future returned by [`DynamicReceiver::recv`].
207#[must_use = "futures do nothing unless you `.await` or poll them"]
206pub struct DynamicRecvFuture<'ch, T> { 208pub struct DynamicRecvFuture<'ch, T> {
207 channel: &'ch dyn DynamicChannel<T>, 209 channel: &'ch dyn DynamicChannel<T>,
208} 210}
@@ -219,6 +221,7 @@ impl<'ch, T> Future for DynamicRecvFuture<'ch, T> {
219} 221}
220 222
221/// Future returned by [`Channel::send`] and [`Sender::send`]. 223/// Future returned by [`Channel::send`] and [`Sender::send`].
224#[must_use = "futures do nothing unless you `.await` or poll them"]
222pub struct SendFuture<'ch, M, T, const N: usize> 225pub struct SendFuture<'ch, M, T, const N: usize>
223where 226where
224 M: RawMutex, 227 M: RawMutex,
@@ -250,6 +253,7 @@ where
250impl<'ch, M, T, const N: usize> Unpin for SendFuture<'ch, M, T, N> where M: RawMutex {} 253impl<'ch, M, T, const N: usize> Unpin for SendFuture<'ch, M, T, N> where M: RawMutex {}
251 254
252/// Future returned by [`DynamicSender::send`]. 255/// Future returned by [`DynamicSender::send`].
256#[must_use = "futures do nothing unless you `.await` or poll them"]
253pub struct DynamicSendFuture<'ch, T> { 257pub struct DynamicSendFuture<'ch, T> {
254 channel: &'ch dyn DynamicChannel<T>, 258 channel: &'ch dyn DynamicChannel<T>,
255 message: Option<T>, 259 message: Option<T>,
diff --git a/embassy-sync/src/pipe.rs b/embassy-sync/src/pipe.rs
index 905686acd..1977005fb 100644
--- a/embassy-sync/src/pipe.rs
+++ b/embassy-sync/src/pipe.rs
@@ -48,6 +48,7 @@ where
48} 48}
49 49
50/// Future returned by [`Pipe::write`] and [`Writer::write`]. 50/// Future returned by [`Pipe::write`] and [`Writer::write`].
51#[must_use = "futures do nothing unless you `.await` or poll them"]
51pub struct WriteFuture<'p, M, const N: usize> 52pub struct WriteFuture<'p, M, const N: usize>
52where 53where
53 M: RawMutex, 54 M: RawMutex,
@@ -110,6 +111,7 @@ where
110} 111}
111 112
112/// Future returned by [`Pipe::read`] and [`Reader::read`]. 113/// Future returned by [`Pipe::read`] and [`Reader::read`].
114#[must_use = "futures do nothing unless you `.await` or poll them"]
113pub struct ReadFuture<'p, M, const N: usize> 115pub struct ReadFuture<'p, M, const N: usize>
114where 116where
115 M: RawMutex, 117 M: RawMutex,
diff --git a/embassy-time/src/timer.rs b/embassy-time/src/timer.rs
index bd791b817..52620d233 100644
--- a/embassy-time/src/timer.rs
+++ b/embassy-time/src/timer.rs
@@ -1,4 +1,4 @@
1use core::future::Future; 1use core::future::{poll_fn, Future};
2use core::pin::Pin; 2use core::pin::Pin;
3use core::task::{Context, Poll, Waker}; 3use core::task::{Context, Poll, Waker};
4 4
@@ -26,6 +26,7 @@ pub async fn with_timeout<F: Future>(timeout: Duration, fut: F) -> Result<F::Out
26} 26}
27 27
28/// A future that completes at a specified [Instant](struct.Instant.html). 28/// A future that completes at a specified [Instant](struct.Instant.html).
29#[must_use = "futures do nothing unless you `.await` or poll them"]
29pub struct Timer { 30pub struct Timer {
30 expires_at: Instant, 31 expires_at: Instant,
31 yielded_once: bool, 32 yielded_once: bool,
@@ -131,6 +132,20 @@ impl Ticker {
131 let expires_at = Instant::now() + duration; 132 let expires_at = Instant::now() + duration;
132 Self { expires_at, duration } 133 Self { expires_at, duration }
133 } 134 }
135
136 /// Waits for the next tick
137 pub fn next(&mut self) -> impl Future<Output = ()> + '_ {
138 poll_fn(|cx| {
139 if self.expires_at <= Instant::now() {
140 let dur = self.duration;
141 self.expires_at += dur;
142 Poll::Ready(())
143 } else {
144 schedule_wake(self.expires_at, cx.waker());
145 Poll::Pending
146 }
147 })
148 }
134} 149}
135 150
136impl Unpin for Ticker {} 151impl Unpin for Ticker {}
diff --git a/embassy-usb/src/class/cdc_acm.rs b/embassy-usb/src/class/cdc_acm.rs
index ff82ad40d..a341e10da 100644
--- a/embassy-usb/src/class/cdc_acm.rs
+++ b/embassy-usb/src/class/cdc_acm.rs
@@ -276,6 +276,106 @@ impl<'d, D: Driver<'d>> CdcAcmClass<'d, D> {
276 pub async fn wait_connection(&mut self) { 276 pub async fn wait_connection(&mut self) {
277 self.read_ep.wait_enabled().await 277 self.read_ep.wait_enabled().await
278 } 278 }
279
280 /// Split the class into a sender and receiver.
281 ///
282 /// This allows concurrently sending and receiving packets from separate tasks.
283 pub fn split(self) -> (Sender<'d, D>, Receiver<'d, D>) {
284 (
285 Sender {
286 write_ep: self.write_ep,
287 control: self.control,
288 },
289 Receiver {
290 read_ep: self.read_ep,
291 control: self.control,
292 },
293 )
294 }
295}
296
297/// CDC ACM class packet sender.
298///
299/// You can obtain a `Sender` with [`CdcAcmClass::split`]
300pub struct Sender<'d, D: Driver<'d>> {
301 write_ep: D::EndpointIn,
302 control: &'d ControlShared,
303}
304
305impl<'d, D: Driver<'d>> Sender<'d, D> {
306 /// Gets the maximum packet size in bytes.
307 pub fn max_packet_size(&self) -> u16 {
308 // The size is the same for both endpoints.
309 self.write_ep.info().max_packet_size
310 }
311
312 /// Gets the current line coding. The line coding contains information that's mainly relevant
313 /// for USB to UART serial port emulators, and can be ignored if not relevant.
314 pub fn line_coding(&self) -> LineCoding {
315 self.control.line_coding.lock(|x| x.get())
316 }
317
318 /// Gets the DTR (data terminal ready) state
319 pub fn dtr(&self) -> bool {
320 self.control.dtr.load(Ordering::Relaxed)
321 }
322
323 /// Gets the RTS (request to send) state
324 pub fn rts(&self) -> bool {
325 self.control.rts.load(Ordering::Relaxed)
326 }
327
328 /// Writes a single packet into the IN endpoint.
329 pub async fn write_packet(&mut self, data: &[u8]) -> Result<(), EndpointError> {
330 self.write_ep.write(data).await
331 }
332
333 /// Waits for the USB host to enable this interface
334 pub async fn wait_connection(&mut self) {
335 self.write_ep.wait_enabled().await
336 }
337}
338
339/// CDC ACM class packet receiver.
340///
341/// You can obtain a `Receiver` with [`CdcAcmClass::split`]
342pub struct Receiver<'d, D: Driver<'d>> {
343 read_ep: D::EndpointOut,
344 control: &'d ControlShared,
345}
346
347impl<'d, D: Driver<'d>> Receiver<'d, D> {
348 /// Gets the maximum packet size in bytes.
349 pub fn max_packet_size(&self) -> u16 {
350 // The size is the same for both endpoints.
351 self.read_ep.info().max_packet_size
352 }
353
354 /// Gets the current line coding. The line coding contains information that's mainly relevant
355 /// for USB to UART serial port emulators, and can be ignored if not relevant.
356 pub fn line_coding(&self) -> LineCoding {
357 self.control.line_coding.lock(|x| x.get())
358 }
359
360 /// Gets the DTR (data terminal ready) state
361 pub fn dtr(&self) -> bool {
362 self.control.dtr.load(Ordering::Relaxed)
363 }
364
365 /// Gets the RTS (request to send) state
366 pub fn rts(&self) -> bool {
367 self.control.rts.load(Ordering::Relaxed)
368 }
369
370 /// Reads a single packet from the OUT endpoint.
371 pub async fn read_packet(&mut self, data: &mut [u8]) -> Result<usize, EndpointError> {
372 self.read_ep.read(data).await
373 }
374
375 /// Waits for the USB host to enable this interface
376 pub async fn wait_connection(&mut self) {
377 self.read_ep.wait_enabled().await
378 }
279} 379}
280 380
281/// Number of stop bits for LineCoding 381/// Number of stop bits for LineCoding
diff --git a/examples/nrf52840/Cargo.toml b/examples/nrf52840/Cargo.toml
index cfdda076e..cc88d92c7 100644
--- a/examples/nrf52840/Cargo.toml
+++ b/examples/nrf52840/Cargo.toml
@@ -6,7 +6,6 @@ license = "MIT OR Apache-2.0"
6 6
7[features] 7[features]
8default = ["nightly"] 8default = ["nightly"]
9msos-descriptor = ["embassy-usb/msos-descriptor"]
10nightly = ["embassy-executor/nightly", "embassy-nrf/nightly", "embassy-net/nightly", "embassy-nrf/unstable-traits", "embassy-usb", "embedded-io/async", "embassy-net", 9nightly = ["embassy-executor/nightly", "embassy-nrf/nightly", "embassy-net/nightly", "embassy-nrf/unstable-traits", "embassy-usb", "embedded-io/async", "embassy-net",
11 "embassy-lora", "lorawan-device", "lorawan"] 10 "embassy-lora", "lorawan-device", "lorawan"]
12 11
@@ -17,7 +16,7 @@ embassy-executor = { version = "0.1.0", path = "../../embassy-executor", feature
17embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } 16embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] }
18embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } 17embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] }
19embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"], optional = true } 18embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"], optional = true }
20embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"], optional = true } 19embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt", "msos-descriptor",], optional = true }
21embedded-io = "0.4.0" 20embedded-io = "0.4.0"
22embassy-lora = { version = "0.1.0", path = "../../embassy-lora", features = ["sx126x", "time", "defmt"], optional = true } 21embassy-lora = { version = "0.1.0", path = "../../embassy-lora", features = ["sx126x", "time", "defmt"], optional = true }
23 22
@@ -36,7 +35,3 @@ rand = { version = "0.8.4", default-features = false }
36embedded-storage = "0.3.0" 35embedded-storage = "0.3.0"
37usbd-hid = "0.6.0" 36usbd-hid = "0.6.0"
38serde = { version = "1.0.136", default-features = false } 37serde = { version = "1.0.136", default-features = false }
39
40[[bin]]
41name = "usb_serial_winusb"
42required-features = ["msos-descriptor"]
diff --git a/examples/nrf52840/src/bin/awaitable_timer.rs b/examples/nrf52840/src/bin/awaitable_timer.rs
deleted file mode 100644
index b32af236c..000000000
--- a/examples/nrf52840/src/bin/awaitable_timer.rs
+++ /dev/null
@@ -1,26 +0,0 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use defmt::info;
6use embassy_executor::Spawner;
7use embassy_nrf::interrupt;
8use embassy_nrf::timer::Timer;
9use {defmt_rtt as _, panic_probe as _};
10
11#[embassy_executor::main]
12async fn main(_spawner: Spawner) {
13 let p = embassy_nrf::init(Default::default());
14 let mut t = Timer::new_awaitable(p.TIMER0, interrupt::take!(TIMER0));
15 // default frequency is 1MHz, so this triggers every second
16 t.cc(0).write(1_000_000);
17 // clear the timer value on cc[0] compare match
18 t.cc(0).short_compare_clear();
19 t.start();
20
21 loop {
22 // wait for compare match
23 t.cc(0).wait().await;
24 info!("hardware timer tick");
25 }
26}
diff --git a/examples/nrf52840/src/bin/buffered_uart.rs b/examples/nrf52840/src/bin/buffered_uart.rs
index ea566f4b2..238695371 100644
--- a/examples/nrf52840/src/bin/buffered_uart.rs
+++ b/examples/nrf52840/src/bin/buffered_uart.rs
@@ -4,12 +4,15 @@
4 4
5use defmt::*; 5use defmt::*;
6use embassy_executor::Spawner; 6use embassy_executor::Spawner;
7use embassy_nrf::buffered_uarte::{BufferedUarte, State}; 7use embassy_nrf::buffered_uarte::{self, BufferedUarte};
8use embassy_nrf::{interrupt, uarte}; 8use embassy_nrf::{bind_interrupts, peripherals, uarte};
9use embedded_io::asynch::{BufRead, Write}; 9use embedded_io::asynch::Write;
10use futures::pin_mut;
11use {defmt_rtt as _, panic_probe as _}; 10use {defmt_rtt as _, panic_probe as _};
12 11
12bind_interrupts!(struct Irqs {
13 UARTE0_UART0 => buffered_uarte::InterruptHandler<peripherals::UARTE0>;
14});
15
13#[embassy_executor::main] 16#[embassy_executor::main]
14async fn main(_spawner: Spawner) { 17async fn main(_spawner: Spawner) {
15 let p = embassy_nrf::init(Default::default()); 18 let p = embassy_nrf::init(Default::default());
@@ -20,25 +23,19 @@ async fn main(_spawner: Spawner) {
20 let mut tx_buffer = [0u8; 4096]; 23 let mut tx_buffer = [0u8; 4096];
21 let mut rx_buffer = [0u8; 4096]; 24 let mut rx_buffer = [0u8; 4096];
22 25
23 let irq = interrupt::take!(UARTE0_UART0); 26 let mut u = BufferedUarte::new(
24 let mut state = State::new();
25 // Please note - important to have hardware flow control (https://github.com/embassy-rs/embassy/issues/536)
26 let u = BufferedUarte::new(
27 &mut state,
28 p.UARTE0, 27 p.UARTE0,
29 p.TIMER0, 28 p.TIMER0,
30 p.PPI_CH0, 29 p.PPI_CH0,
31 p.PPI_CH1, 30 p.PPI_CH1,
32 irq, 31 p.PPI_GROUP0,
32 Irqs,
33 p.P0_08, 33 p.P0_08,
34 p.P0_06, 34 p.P0_06,
35 p.P0_07,
36 p.P0_05,
37 config, 35 config,
38 &mut rx_buffer, 36 &mut rx_buffer,
39 &mut tx_buffer, 37 &mut tx_buffer,
40 ); 38 );
41 pin_mut!(u);
42 39
43 info!("uarte initialized!"); 40 info!("uarte initialized!");
44 41
diff --git a/examples/nrf52840/src/bin/i2s_effect.rs b/examples/nrf52840/src/bin/i2s_effect.rs
index 52d46e4f9..391514d93 100644
--- a/examples/nrf52840/src/bin/i2s_effect.rs
+++ b/examples/nrf52840/src/bin/i2s_effect.rs
@@ -7,7 +7,7 @@ use core::f32::consts::PI;
7use defmt::{error, info}; 7use defmt::{error, info};
8use embassy_executor::Spawner; 8use embassy_executor::Spawner;
9use embassy_nrf::i2s::{self, Channels, Config, MasterClock, MultiBuffering, Sample as _, SampleWidth, I2S}; 9use embassy_nrf::i2s::{self, Channels, Config, MasterClock, MultiBuffering, Sample as _, SampleWidth, I2S};
10use embassy_nrf::interrupt; 10use embassy_nrf::{bind_interrupts, peripherals};
11use {defmt_rtt as _, panic_probe as _}; 11use {defmt_rtt as _, panic_probe as _};
12 12
13type Sample = i16; 13type Sample = i16;
@@ -15,6 +15,10 @@ type Sample = i16;
15const NUM_BUFFERS: usize = 2; 15const NUM_BUFFERS: usize = 2;
16const NUM_SAMPLES: usize = 4; 16const NUM_SAMPLES: usize = 4;
17 17
18bind_interrupts!(struct Irqs {
19 I2S => i2s::InterruptHandler<peripherals::I2S>;
20});
21
18#[embassy_executor::main] 22#[embassy_executor::main]
19async fn main(_spawner: Spawner) { 23async fn main(_spawner: Spawner) {
20 let p = embassy_nrf::init(Default::default()); 24 let p = embassy_nrf::init(Default::default());
@@ -28,15 +32,10 @@ async fn main(_spawner: Spawner) {
28 config.sample_width = SampleWidth::_16bit; 32 config.sample_width = SampleWidth::_16bit;
29 config.channels = Channels::MonoLeft; 33 config.channels = Channels::MonoLeft;
30 34
31 let irq = interrupt::take!(I2S);
32 let buffers_out = MultiBuffering::<Sample, NUM_BUFFERS, NUM_SAMPLES>::new(); 35 let buffers_out = MultiBuffering::<Sample, NUM_BUFFERS, NUM_SAMPLES>::new();
33 let buffers_in = MultiBuffering::<Sample, NUM_BUFFERS, NUM_SAMPLES>::new(); 36 let buffers_in = MultiBuffering::<Sample, NUM_BUFFERS, NUM_SAMPLES>::new();
34 let mut full_duplex_stream = I2S::master(p.I2S, irq, p.P0_25, p.P0_26, p.P0_27, master_clock, config).full_duplex( 37 let mut full_duplex_stream = I2S::new_master(p.I2S, Irqs, p.P0_25, p.P0_26, p.P0_27, master_clock, config)
35 p.P0_29, 38 .full_duplex(p.P0_29, p.P0_28, buffers_out, buffers_in);
36 p.P0_28,
37 buffers_out,
38 buffers_in,
39 );
40 39
41 let mut modulator = SineOsc::new(); 40 let mut modulator = SineOsc::new();
42 modulator.set_frequency(8.0, 1.0 / sample_rate as f32); 41 modulator.set_frequency(8.0, 1.0 / sample_rate as f32);
diff --git a/examples/nrf52840/src/bin/i2s_monitor.rs b/examples/nrf52840/src/bin/i2s_monitor.rs
index 5ebfd9542..4ed597c0d 100644
--- a/examples/nrf52840/src/bin/i2s_monitor.rs
+++ b/examples/nrf52840/src/bin/i2s_monitor.rs
@@ -5,14 +5,18 @@
5use defmt::{debug, error, info}; 5use defmt::{debug, error, info};
6use embassy_executor::Spawner; 6use embassy_executor::Spawner;
7use embassy_nrf::i2s::{self, Channels, Config, DoubleBuffering, MasterClock, Sample as _, SampleWidth, I2S}; 7use embassy_nrf::i2s::{self, Channels, Config, DoubleBuffering, MasterClock, Sample as _, SampleWidth, I2S};
8use embassy_nrf::interrupt;
9use embassy_nrf::pwm::{Prescaler, SimplePwm}; 8use embassy_nrf::pwm::{Prescaler, SimplePwm};
9use embassy_nrf::{bind_interrupts, peripherals};
10use {defmt_rtt as _, panic_probe as _}; 10use {defmt_rtt as _, panic_probe as _};
11 11
12type Sample = i16; 12type Sample = i16;
13 13
14const NUM_SAMPLES: usize = 500; 14const NUM_SAMPLES: usize = 500;
15 15
16bind_interrupts!(struct Irqs {
17 I2S => i2s::InterruptHandler<peripherals::I2S>;
18});
19
16#[embassy_executor::main] 20#[embassy_executor::main]
17async fn main(_spawner: Spawner) { 21async fn main(_spawner: Spawner) {
18 let p = embassy_nrf::init(Default::default()); 22 let p = embassy_nrf::init(Default::default());
@@ -26,10 +30,9 @@ async fn main(_spawner: Spawner) {
26 config.sample_width = SampleWidth::_16bit; 30 config.sample_width = SampleWidth::_16bit;
27 config.channels = Channels::MonoLeft; 31 config.channels = Channels::MonoLeft;
28 32
29 let irq = interrupt::take!(I2S);
30 let buffers = DoubleBuffering::<Sample, NUM_SAMPLES>::new(); 33 let buffers = DoubleBuffering::<Sample, NUM_SAMPLES>::new();
31 let mut input_stream = 34 let mut input_stream =
32 I2S::master(p.I2S, irq, p.P0_25, p.P0_26, p.P0_27, master_clock, config).input(p.P0_29, buffers); 35 I2S::new_master(p.I2S, Irqs, p.P0_25, p.P0_26, p.P0_27, master_clock, config).input(p.P0_29, buffers);
33 36
34 // Configure the PWM to use the pins corresponding to the RGB leds 37 // Configure the PWM to use the pins corresponding to the RGB leds
35 let mut pwm = SimplePwm::new_3ch(p.PWM0, p.P0_23, p.P0_22, p.P0_24); 38 let mut pwm = SimplePwm::new_3ch(p.PWM0, p.P0_23, p.P0_22, p.P0_24);
diff --git a/examples/nrf52840/src/bin/i2s_waveform.rs b/examples/nrf52840/src/bin/i2s_waveform.rs
index eda930677..f2c1166b1 100644
--- a/examples/nrf52840/src/bin/i2s_waveform.rs
+++ b/examples/nrf52840/src/bin/i2s_waveform.rs
@@ -7,13 +7,17 @@ use core::f32::consts::PI;
7use defmt::{error, info}; 7use defmt::{error, info};
8use embassy_executor::Spawner; 8use embassy_executor::Spawner;
9use embassy_nrf::i2s::{self, Channels, Config, DoubleBuffering, MasterClock, Sample as _, SampleWidth, I2S}; 9use embassy_nrf::i2s::{self, Channels, Config, DoubleBuffering, MasterClock, Sample as _, SampleWidth, I2S};
10use embassy_nrf::interrupt; 10use embassy_nrf::{bind_interrupts, peripherals};
11use {defmt_rtt as _, panic_probe as _}; 11use {defmt_rtt as _, panic_probe as _};
12 12
13type Sample = i16; 13type Sample = i16;
14 14
15const NUM_SAMPLES: usize = 50; 15const NUM_SAMPLES: usize = 50;
16 16
17bind_interrupts!(struct Irqs {
18 I2S => i2s::InterruptHandler<peripherals::I2S>;
19});
20
17#[embassy_executor::main] 21#[embassy_executor::main]
18async fn main(_spawner: Spawner) { 22async fn main(_spawner: Spawner) {
19 let p = embassy_nrf::init(Default::default()); 23 let p = embassy_nrf::init(Default::default());
@@ -27,10 +31,9 @@ async fn main(_spawner: Spawner) {
27 config.sample_width = SampleWidth::_16bit; 31 config.sample_width = SampleWidth::_16bit;
28 config.channels = Channels::MonoLeft; 32 config.channels = Channels::MonoLeft;
29 33
30 let irq = interrupt::take!(I2S);
31 let buffers = DoubleBuffering::<Sample, NUM_SAMPLES>::new(); 34 let buffers = DoubleBuffering::<Sample, NUM_SAMPLES>::new();
32 let mut output_stream = 35 let mut output_stream =
33 I2S::master(p.I2S, irq, p.P0_25, p.P0_26, p.P0_27, master_clock, config).output(p.P0_28, buffers); 36 I2S::new_master(p.I2S, Irqs, p.P0_25, p.P0_26, p.P0_27, master_clock, config).output(p.P0_28, buffers);
34 37
35 let mut waveform = Waveform::new(1.0 / sample_rate as f32); 38 let mut waveform = Waveform::new(1.0 / sample_rate as f32);
36 39
diff --git a/examples/nrf52840/src/bin/lora_p2p_report.rs b/examples/nrf52840/src/bin/lora_p2p_report.rs
index d512b83f6..e24f0db03 100644
--- a/examples/nrf52840/src/bin/lora_p2p_report.rs
+++ b/examples/nrf52840/src/bin/lora_p2p_report.rs
@@ -11,11 +11,15 @@ use defmt::*;
11use embassy_executor::Spawner; 11use embassy_executor::Spawner;
12use embassy_lora::sx126x::*; 12use embassy_lora::sx126x::*;
13use embassy_nrf::gpio::{Input, Level, Output, OutputDrive, Pin as _, Pull}; 13use embassy_nrf::gpio::{Input, Level, Output, OutputDrive, Pin as _, Pull};
14use embassy_nrf::{interrupt, spim}; 14use embassy_nrf::{bind_interrupts, peripherals, spim};
15use embassy_time::{Duration, Timer}; 15use embassy_time::{Duration, Timer};
16use lorawan_device::async_device::radio::{Bandwidth, CodingRate, PhyRxTx, RfConfig, SpreadingFactor}; 16use lorawan_device::async_device::radio::{Bandwidth, CodingRate, PhyRxTx, RfConfig, SpreadingFactor};
17use {defmt_rtt as _, panic_probe as _}; 17use {defmt_rtt as _, panic_probe as _};
18 18
19bind_interrupts!(struct Irqs {
20 SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1 => spim::InterruptHandler<peripherals::TWISPI1>;
21});
22
19#[embassy_executor::main] 23#[embassy_executor::main]
20async fn main(_spawner: Spawner) { 24async fn main(_spawner: Spawner) {
21 let p = embassy_nrf::init(Default::default()); 25 let p = embassy_nrf::init(Default::default());
@@ -23,8 +27,7 @@ async fn main(_spawner: Spawner) {
23 spi_config.frequency = spim::Frequency::M16; 27 spi_config.frequency = spim::Frequency::M16;
24 28
25 let mut radio = { 29 let mut radio = {
26 let irq = interrupt::take!(SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1); 30 let spim = spim::Spim::new(p.TWISPI1, Irqs, p.P1_11, p.P1_13, p.P1_12, spi_config);
27 let spim = spim::Spim::new(p.TWISPI1, irq, p.P1_11, p.P1_13, p.P1_12, spi_config);
28 31
29 let cs = Output::new(p.P1_10.degrade(), Level::High, OutputDrive::Standard); 32 let cs = Output::new(p.P1_10.degrade(), Level::High, OutputDrive::Standard);
30 let reset = Output::new(p.P1_06.degrade(), Level::High, OutputDrive::Standard); 33 let reset = Output::new(p.P1_06.degrade(), Level::High, OutputDrive::Standard);
diff --git a/examples/nrf52840/src/bin/lora_p2p_sense.rs b/examples/nrf52840/src/bin/lora_p2p_sense.rs
index b9768874b..b6f41ffcc 100644
--- a/examples/nrf52840/src/bin/lora_p2p_sense.rs
+++ b/examples/nrf52840/src/bin/lora_p2p_sense.rs
@@ -12,13 +12,17 @@ use defmt::*;
12use embassy_executor::Spawner; 12use embassy_executor::Spawner;
13use embassy_lora::sx126x::*; 13use embassy_lora::sx126x::*;
14use embassy_nrf::gpio::{Input, Level, Output, OutputDrive, Pin as _, Pull}; 14use embassy_nrf::gpio::{Input, Level, Output, OutputDrive, Pin as _, Pull};
15use embassy_nrf::{interrupt, spim}; 15use embassy_nrf::{bind_interrupts, peripherals, spim};
16use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; 16use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
17use embassy_sync::pubsub::{PubSubChannel, Publisher}; 17use embassy_sync::pubsub::{PubSubChannel, Publisher};
18use embassy_time::{Duration, Timer}; 18use embassy_time::{Duration, Timer};
19use lorawan_device::async_device::radio::{Bandwidth, CodingRate, PhyRxTx, RfConfig, SpreadingFactor, TxConfig}; 19use lorawan_device::async_device::radio::{Bandwidth, CodingRate, PhyRxTx, RfConfig, SpreadingFactor, TxConfig};
20use {defmt_rtt as _, panic_probe as _, panic_probe as _}; 20use {defmt_rtt as _, panic_probe as _, panic_probe as _};
21 21
22bind_interrupts!(struct Irqs {
23 SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1 => spim::InterruptHandler<peripherals::TWISPI1>;
24});
25
22// Message bus: queue of 2, 1 subscriber (Lora P2P), 2 publishers (temperature, motion detection) 26// Message bus: queue of 2, 1 subscriber (Lora P2P), 2 publishers (temperature, motion detection)
23static MESSAGE_BUS: PubSubChannel<CriticalSectionRawMutex, Message, 2, 1, 2> = PubSubChannel::new(); 27static MESSAGE_BUS: PubSubChannel<CriticalSectionRawMutex, Message, 2, 1, 2> = PubSubChannel::new();
24 28
@@ -58,8 +62,7 @@ async fn main(spawner: Spawner) {
58 spi_config.frequency = spim::Frequency::M16; 62 spi_config.frequency = spim::Frequency::M16;
59 63
60 let mut radio = { 64 let mut radio = {
61 let irq = interrupt::take!(SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1); 65 let spim = spim::Spim::new(p.TWISPI1, Irqs, p.P1_11, p.P1_13, p.P1_12, spi_config);
62 let spim = spim::Spim::new(p.TWISPI1, irq, p.P1_11, p.P1_13, p.P1_12, spi_config);
63 66
64 let cs = Output::new(p.P1_10.degrade(), Level::High, OutputDrive::Standard); 67 let cs = Output::new(p.P1_10.degrade(), Level::High, OutputDrive::Standard);
65 let reset = Output::new(p.P1_06.degrade(), Level::High, OutputDrive::Standard); 68 let reset = Output::new(p.P1_06.degrade(), Level::High, OutputDrive::Standard);
diff --git a/examples/nrf52840/src/bin/multiprio.rs b/examples/nrf52840/src/bin/multiprio.rs
index 25806ae48..851e189ea 100644
--- a/examples/nrf52840/src/bin/multiprio.rs
+++ b/examples/nrf52840/src/bin/multiprio.rs
@@ -57,11 +57,14 @@
57#![no_main] 57#![no_main]
58#![feature(type_alias_impl_trait)] 58#![feature(type_alias_impl_trait)]
59 59
60use core::mem;
61
62use cortex_m::peripheral::NVIC;
60use cortex_m_rt::entry; 63use cortex_m_rt::entry;
61use defmt::{info, unwrap}; 64use defmt::{info, unwrap};
62use embassy_nrf::executor::{Executor, InterruptExecutor}; 65use embassy_nrf::executor::{Executor, InterruptExecutor};
63use embassy_nrf::interrupt; 66use embassy_nrf::interrupt;
64use embassy_nrf::interrupt::InterruptExt; 67use embassy_nrf::pac::Interrupt;
65use embassy_time::{Duration, Instant, Timer}; 68use embassy_time::{Duration, Instant, Timer};
66use static_cell::StaticCell; 69use static_cell::StaticCell;
67use {defmt_rtt as _, panic_probe as _}; 70use {defmt_rtt as _, panic_probe as _};
@@ -108,28 +111,35 @@ async fn run_low() {
108 } 111 }
109} 112}
110 113
111static EXECUTOR_HIGH: StaticCell<InterruptExecutor<interrupt::SWI1_EGU1>> = StaticCell::new(); 114static EXECUTOR_HIGH: InterruptExecutor = InterruptExecutor::new();
112static EXECUTOR_MED: StaticCell<InterruptExecutor<interrupt::SWI0_EGU0>> = StaticCell::new(); 115static EXECUTOR_MED: InterruptExecutor = InterruptExecutor::new();
113static EXECUTOR_LOW: StaticCell<Executor> = StaticCell::new(); 116static EXECUTOR_LOW: StaticCell<Executor> = StaticCell::new();
114 117
118#[interrupt]
119unsafe fn SWI1_EGU1() {
120 EXECUTOR_HIGH.on_interrupt()
121}
122
123#[interrupt]
124unsafe fn SWI0_EGU0() {
125 EXECUTOR_MED.on_interrupt()
126}
127
115#[entry] 128#[entry]
116fn main() -> ! { 129fn main() -> ! {
117 info!("Hello World!"); 130 info!("Hello World!");
118 131
119 let _p = embassy_nrf::init(Default::default()); 132 let _p = embassy_nrf::init(Default::default());
133 let mut nvic: NVIC = unsafe { mem::transmute(()) };
120 134
121 // High-priority executor: SWI1_EGU1, priority level 6 135 // High-priority executor: SWI1_EGU1, priority level 6
122 let irq = interrupt::take!(SWI1_EGU1); 136 unsafe { nvic.set_priority(Interrupt::SWI1_EGU1, 6 << 5) };
123 irq.set_priority(interrupt::Priority::P6); 137 let spawner = EXECUTOR_HIGH.start(Interrupt::SWI1_EGU1);
124 let executor = EXECUTOR_HIGH.init(InterruptExecutor::new(irq));
125 let spawner = executor.start();
126 unwrap!(spawner.spawn(run_high())); 138 unwrap!(spawner.spawn(run_high()));
127 139
128 // Medium-priority executor: SWI0_EGU0, priority level 7 140 // Medium-priority executor: SWI0_EGU0, priority level 7
129 let irq = interrupt::take!(SWI0_EGU0); 141 unsafe { nvic.set_priority(Interrupt::SWI0_EGU0, 7 << 5) };
130 irq.set_priority(interrupt::Priority::P7); 142 let spawner = EXECUTOR_MED.start(Interrupt::SWI0_EGU0);
131 let executor = EXECUTOR_MED.init(InterruptExecutor::new(irq));
132 let spawner = executor.start();
133 unwrap!(spawner.spawn(run_med())); 143 unwrap!(spawner.spawn(run_med()));
134 144
135 // Low priority executor: runs in thread mode, using WFE/SEV 145 // Low priority executor: runs in thread mode, using WFE/SEV
diff --git a/examples/nrf52840/src/bin/pdm.rs b/examples/nrf52840/src/bin/pdm.rs
index 7388580fb..6b41320ca 100644
--- a/examples/nrf52840/src/bin/pdm.rs
+++ b/examples/nrf52840/src/bin/pdm.rs
@@ -4,16 +4,20 @@
4 4
5use defmt::info; 5use defmt::info;
6use embassy_executor::Spawner; 6use embassy_executor::Spawner;
7use embassy_nrf::interrupt; 7use embassy_nrf::pdm::{self, Config, Pdm};
8use embassy_nrf::pdm::{Config, Pdm}; 8use embassy_nrf::{bind_interrupts, peripherals};
9use embassy_time::{Duration, Timer}; 9use embassy_time::{Duration, Timer};
10use {defmt_rtt as _, panic_probe as _}; 10use {defmt_rtt as _, panic_probe as _};
11 11
12bind_interrupts!(struct Irqs {
13 PDM => pdm::InterruptHandler<peripherals::PDM>;
14});
15
12#[embassy_executor::main] 16#[embassy_executor::main]
13async fn main(_p: Spawner) { 17async fn main(_p: Spawner) {
14 let p = embassy_nrf::init(Default::default()); 18 let p = embassy_nrf::init(Default::default());
15 let config = Config::default(); 19 let config = Config::default();
16 let mut pdm = Pdm::new(p.PDM, interrupt::take!(PDM), p.P0_01, p.P0_00, config); 20 let mut pdm = Pdm::new(p.PDM, Irqs, p.P0_01, p.P0_00, config);
17 21
18 loop { 22 loop {
19 pdm.start().await; 23 pdm.start().await;
diff --git a/examples/nrf52840/src/bin/qdec.rs b/examples/nrf52840/src/bin/qdec.rs
index 600bba07a..59783d312 100644
--- a/examples/nrf52840/src/bin/qdec.rs
+++ b/examples/nrf52840/src/bin/qdec.rs
@@ -4,16 +4,19 @@
4 4
5use defmt::info; 5use defmt::info;
6use embassy_executor::Spawner; 6use embassy_executor::Spawner;
7use embassy_nrf::interrupt;
8use embassy_nrf::qdec::{self, Qdec}; 7use embassy_nrf::qdec::{self, Qdec};
8use embassy_nrf::{bind_interrupts, peripherals};
9use {defmt_rtt as _, panic_probe as _}; 9use {defmt_rtt as _, panic_probe as _};
10 10
11bind_interrupts!(struct Irqs {
12 QDEC => qdec::InterruptHandler<peripherals::QDEC>;
13});
14
11#[embassy_executor::main] 15#[embassy_executor::main]
12async fn main(_spawner: Spawner) { 16async fn main(_spawner: Spawner) {
13 let p = embassy_nrf::init(Default::default()); 17 let p = embassy_nrf::init(Default::default());
14 let irq = interrupt::take!(QDEC);
15 let config = qdec::Config::default(); 18 let config = qdec::Config::default();
16 let mut rotary_enc = Qdec::new(p.QDEC, irq, p.P0_31, p.P0_30, config); 19 let mut rotary_enc = Qdec::new(p.QDEC, Irqs, p.P0_31, p.P0_30, config);
17 20
18 info!("Turn rotary encoder!"); 21 info!("Turn rotary encoder!");
19 let mut value = 0; 22 let mut value = 0;
diff --git a/examples/nrf52840/src/bin/qspi.rs b/examples/nrf52840/src/bin/qspi.rs
index bdcf710b8..9e8a01f4e 100644
--- a/examples/nrf52840/src/bin/qspi.rs
+++ b/examples/nrf52840/src/bin/qspi.rs
@@ -4,7 +4,8 @@
4 4
5use defmt::{assert_eq, info, unwrap}; 5use defmt::{assert_eq, info, unwrap};
6use embassy_executor::Spawner; 6use embassy_executor::Spawner;
7use embassy_nrf::{interrupt, qspi}; 7use embassy_nrf::qspi::Frequency;
8use embassy_nrf::{bind_interrupts, peripherals, qspi};
8use {defmt_rtt as _, panic_probe as _}; 9use {defmt_rtt as _, panic_probe as _};
9 10
10const PAGE_SIZE: usize = 4096; 11const PAGE_SIZE: usize = 4096;
@@ -14,18 +15,23 @@ const PAGE_SIZE: usize = 4096;
14#[repr(C, align(4))] 15#[repr(C, align(4))]
15struct AlignedBuf([u8; 4096]); 16struct AlignedBuf([u8; 4096]);
16 17
18bind_interrupts!(struct Irqs {
19 QSPI => qspi::InterruptHandler<peripherals::QSPI>;
20});
21
17#[embassy_executor::main] 22#[embassy_executor::main]
18async fn main(_spawner: Spawner) { 23async fn main(_spawner: Spawner) {
19 let p = embassy_nrf::init(Default::default()); 24 let p = embassy_nrf::init(Default::default());
20 // Config for the MX25R64 present in the nRF52840 DK 25 // Config for the MX25R64 present in the nRF52840 DK
21 let mut config = qspi::Config::default(); 26 let mut config = qspi::Config::default();
27 config.capacity = 8 * 1024 * 1024; // 8 MB
28 config.frequency = Frequency::M32;
22 config.read_opcode = qspi::ReadOpcode::READ4IO; 29 config.read_opcode = qspi::ReadOpcode::READ4IO;
23 config.write_opcode = qspi::WriteOpcode::PP4IO; 30 config.write_opcode = qspi::WriteOpcode::PP4IO;
24 config.write_page_size = qspi::WritePageSize::_256BYTES; 31 config.write_page_size = qspi::WritePageSize::_256BYTES;
25 32
26 let irq = interrupt::take!(QSPI); 33 let mut q = qspi::Qspi::new(
27 let mut q: qspi::Qspi<_, 67108864> = qspi::Qspi::new( 34 p.QSPI, Irqs, p.P0_19, p.P0_17, p.P0_20, p.P0_21, p.P0_22, p.P0_23, config,
28 p.QSPI, irq, p.P0_19, p.P0_17, p.P0_20, p.P0_21, p.P0_22, p.P0_23, config,
29 ); 35 );
30 36
31 let mut id = [1; 3]; 37 let mut id = [1; 3];
@@ -52,23 +58,23 @@ async fn main(_spawner: Spawner) {
52 58
53 for i in 0..8 { 59 for i in 0..8 {
54 info!("page {:?}: erasing... ", i); 60 info!("page {:?}: erasing... ", i);
55 unwrap!(q.erase(i * PAGE_SIZE).await); 61 unwrap!(q.erase(i * PAGE_SIZE as u32).await);
56 62
57 for j in 0..PAGE_SIZE { 63 for j in 0..PAGE_SIZE {
58 buf.0[j] = pattern((j + i * PAGE_SIZE) as u32); 64 buf.0[j] = pattern((j as u32 + i * PAGE_SIZE as u32) as u32);
59 } 65 }
60 66
61 info!("programming..."); 67 info!("programming...");
62 unwrap!(q.write(i * PAGE_SIZE, &buf.0).await); 68 unwrap!(q.write(i * PAGE_SIZE as u32, &buf.0).await);
63 } 69 }
64 70
65 for i in 0..8 { 71 for i in 0..8 {
66 info!("page {:?}: reading... ", i); 72 info!("page {:?}: reading... ", i);
67 unwrap!(q.read(i * PAGE_SIZE, &mut buf.0).await); 73 unwrap!(q.read(i * PAGE_SIZE as u32, &mut buf.0).await);
68 74
69 info!("verifying..."); 75 info!("verifying...");
70 for j in 0..PAGE_SIZE { 76 for j in 0..PAGE_SIZE {
71 assert_eq!(buf.0[j], pattern((j + i * PAGE_SIZE) as u32)); 77 assert_eq!(buf.0[j], pattern((j as u32 + i * PAGE_SIZE as u32) as u32));
72 } 78 }
73 } 79 }
74 80
diff --git a/examples/nrf52840/src/bin/qspi_lowpower.rs b/examples/nrf52840/src/bin/qspi_lowpower.rs
index 9341a2376..22a5c0c6d 100644
--- a/examples/nrf52840/src/bin/qspi_lowpower.rs
+++ b/examples/nrf52840/src/bin/qspi_lowpower.rs
@@ -6,7 +6,8 @@ use core::mem;
6 6
7use defmt::{info, unwrap}; 7use defmt::{info, unwrap};
8use embassy_executor::Spawner; 8use embassy_executor::Spawner;
9use embassy_nrf::{interrupt, qspi}; 9use embassy_nrf::qspi::Frequency;
10use embassy_nrf::{bind_interrupts, peripherals, qspi};
10use embassy_time::{Duration, Timer}; 11use embassy_time::{Duration, Timer};
11use {defmt_rtt as _, panic_probe as _}; 12use {defmt_rtt as _, panic_probe as _};
12 13
@@ -15,14 +16,19 @@ use {defmt_rtt as _, panic_probe as _};
15#[repr(C, align(4))] 16#[repr(C, align(4))]
16struct AlignedBuf([u8; 64]); 17struct AlignedBuf([u8; 64]);
17 18
19bind_interrupts!(struct Irqs {
20 QSPI => qspi::InterruptHandler<peripherals::QSPI>;
21});
22
18#[embassy_executor::main] 23#[embassy_executor::main]
19async fn main(_p: Spawner) { 24async fn main(_p: Spawner) {
20 let mut p = embassy_nrf::init(Default::default()); 25 let mut p = embassy_nrf::init(Default::default());
21 let mut irq = interrupt::take!(QSPI);
22 26
23 loop { 27 loop {
24 // Config for the MX25R64 present in the nRF52840 DK 28 // Config for the MX25R64 present in the nRF52840 DK
25 let mut config = qspi::Config::default(); 29 let mut config = qspi::Config::default();
30 config.capacity = 8 * 1024 * 1024; // 8 MB
31 config.frequency = Frequency::M32;
26 config.read_opcode = qspi::ReadOpcode::READ4IO; 32 config.read_opcode = qspi::ReadOpcode::READ4IO;
27 config.write_opcode = qspi::WriteOpcode::PP4IO; 33 config.write_opcode = qspi::WriteOpcode::PP4IO;
28 config.write_page_size = qspi::WritePageSize::_256BYTES; 34 config.write_page_size = qspi::WritePageSize::_256BYTES;
@@ -31,9 +37,9 @@ async fn main(_p: Spawner) {
31 exit_time: 3, // tRDP = 35uS 37 exit_time: 3, // tRDP = 35uS
32 }); 38 });
33 39
34 let mut q: qspi::Qspi<_, 67108864> = qspi::Qspi::new( 40 let mut q = qspi::Qspi::new(
35 &mut p.QSPI, 41 &mut p.QSPI,
36 &mut irq, 42 Irqs,
37 &mut p.P0_19, 43 &mut p.P0_19,
38 &mut p.P0_17, 44 &mut p.P0_17,
39 &mut p.P0_20, 45 &mut p.P0_20,
diff --git a/examples/nrf52840/src/bin/rng.rs b/examples/nrf52840/src/bin/rng.rs
index 647073949..855743f50 100644
--- a/examples/nrf52840/src/bin/rng.rs
+++ b/examples/nrf52840/src/bin/rng.rs
@@ -3,15 +3,19 @@
3#![feature(type_alias_impl_trait)] 3#![feature(type_alias_impl_trait)]
4 4
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_nrf::interrupt;
7use embassy_nrf::rng::Rng; 6use embassy_nrf::rng::Rng;
7use embassy_nrf::{bind_interrupts, peripherals, rng};
8use rand::Rng as _; 8use rand::Rng as _;
9use {defmt_rtt as _, panic_probe as _}; 9use {defmt_rtt as _, panic_probe as _};
10 10
11bind_interrupts!(struct Irqs {
12 RNG => rng::InterruptHandler<peripherals::RNG>;
13});
14
11#[embassy_executor::main] 15#[embassy_executor::main]
12async fn main(_spawner: Spawner) { 16async fn main(_spawner: Spawner) {
13 let p = embassy_nrf::init(Default::default()); 17 let p = embassy_nrf::init(Default::default());
14 let mut rng = Rng::new(p.RNG, interrupt::take!(RNG)); 18 let mut rng = Rng::new(p.RNG, Irqs);
15 19
16 // Async API 20 // Async API
17 let mut bytes = [0; 4]; 21 let mut bytes = [0; 4];
diff --git a/examples/nrf52840/src/bin/saadc.rs b/examples/nrf52840/src/bin/saadc.rs
index 7cf588090..ffd9a7f4b 100644
--- a/examples/nrf52840/src/bin/saadc.rs
+++ b/examples/nrf52840/src/bin/saadc.rs
@@ -4,17 +4,21 @@
4 4
5use defmt::info; 5use defmt::info;
6use embassy_executor::Spawner; 6use embassy_executor::Spawner;
7use embassy_nrf::interrupt;
8use embassy_nrf::saadc::{ChannelConfig, Config, Saadc}; 7use embassy_nrf::saadc::{ChannelConfig, Config, Saadc};
8use embassy_nrf::{bind_interrupts, saadc};
9use embassy_time::{Duration, Timer}; 9use embassy_time::{Duration, Timer};
10use {defmt_rtt as _, panic_probe as _}; 10use {defmt_rtt as _, panic_probe as _};
11 11
12bind_interrupts!(struct Irqs {
13 SAADC => saadc::InterruptHandler;
14});
15
12#[embassy_executor::main] 16#[embassy_executor::main]
13async fn main(_p: Spawner) { 17async fn main(_p: Spawner) {
14 let mut p = embassy_nrf::init(Default::default()); 18 let mut p = embassy_nrf::init(Default::default());
15 let config = Config::default(); 19 let config = Config::default();
16 let channel_config = ChannelConfig::single_ended(&mut p.P0_02); 20 let channel_config = ChannelConfig::single_ended(&mut p.P0_02);
17 let mut saadc = Saadc::new(p.SAADC, interrupt::take!(SAADC), config, [channel_config]); 21 let mut saadc = Saadc::new(p.SAADC, Irqs, config, [channel_config]);
18 22
19 loop { 23 loop {
20 let mut buf = [0; 1]; 24 let mut buf = [0; 1];
diff --git a/examples/nrf52840/src/bin/saadc_continuous.rs b/examples/nrf52840/src/bin/saadc_continuous.rs
index 2551d15fd..a25e17465 100644
--- a/examples/nrf52840/src/bin/saadc_continuous.rs
+++ b/examples/nrf52840/src/bin/saadc_continuous.rs
@@ -4,14 +4,18 @@
4 4
5use defmt::info; 5use defmt::info;
6use embassy_executor::Spawner; 6use embassy_executor::Spawner;
7use embassy_nrf::interrupt;
8use embassy_nrf::saadc::{CallbackResult, ChannelConfig, Config, Saadc}; 7use embassy_nrf::saadc::{CallbackResult, ChannelConfig, Config, Saadc};
9use embassy_nrf::timer::Frequency; 8use embassy_nrf::timer::Frequency;
9use embassy_nrf::{bind_interrupts, saadc};
10use embassy_time::Duration; 10use embassy_time::Duration;
11use {defmt_rtt as _, panic_probe as _}; 11use {defmt_rtt as _, panic_probe as _};
12 12
13// Demonstrates both continuous sampling and scanning multiple channels driven by a PPI linked timer 13// Demonstrates both continuous sampling and scanning multiple channels driven by a PPI linked timer
14 14
15bind_interrupts!(struct Irqs {
16 SAADC => saadc::InterruptHandler;
17});
18
15#[embassy_executor::main] 19#[embassy_executor::main]
16async fn main(_p: Spawner) { 20async fn main(_p: Spawner) {
17 let mut p = embassy_nrf::init(Default::default()); 21 let mut p = embassy_nrf::init(Default::default());
@@ -21,7 +25,7 @@ async fn main(_p: Spawner) {
21 let channel_3_config = ChannelConfig::single_ended(&mut p.P0_04); 25 let channel_3_config = ChannelConfig::single_ended(&mut p.P0_04);
22 let mut saadc = Saadc::new( 26 let mut saadc = Saadc::new(
23 p.SAADC, 27 p.SAADC,
24 interrupt::take!(SAADC), 28 Irqs,
25 config, 29 config,
26 [channel_1_config, channel_2_config, channel_3_config], 30 [channel_1_config, channel_2_config, channel_3_config],
27 ); 31 );
diff --git a/examples/nrf52840/src/bin/spim.rs b/examples/nrf52840/src/bin/spim.rs
index 132e01660..9d1843a8f 100644
--- a/examples/nrf52840/src/bin/spim.rs
+++ b/examples/nrf52840/src/bin/spim.rs
@@ -5,9 +5,13 @@
5use defmt::{info, unwrap}; 5use defmt::{info, unwrap};
6use embassy_executor::Spawner; 6use embassy_executor::Spawner;
7use embassy_nrf::gpio::{Level, Output, OutputDrive}; 7use embassy_nrf::gpio::{Level, Output, OutputDrive};
8use embassy_nrf::{interrupt, spim}; 8use embassy_nrf::{bind_interrupts, peripherals, spim};
9use {defmt_rtt as _, panic_probe as _}; 9use {defmt_rtt as _, panic_probe as _};
10 10
11bind_interrupts!(struct Irqs {
12 SPIM3 => spim::InterruptHandler<peripherals::SPI3>;
13});
14
11#[embassy_executor::main] 15#[embassy_executor::main]
12async fn main(_spawner: Spawner) { 16async fn main(_spawner: Spawner) {
13 let p = embassy_nrf::init(Default::default()); 17 let p = embassy_nrf::init(Default::default());
@@ -16,8 +20,7 @@ async fn main(_spawner: Spawner) {
16 let mut config = spim::Config::default(); 20 let mut config = spim::Config::default();
17 config.frequency = spim::Frequency::M16; 21 config.frequency = spim::Frequency::M16;
18 22
19 let irq = interrupt::take!(SPIM3); 23 let mut spim = spim::Spim::new(p.SPI3, Irqs, p.P0_29, p.P0_28, p.P0_30, config);
20 let mut spim = spim::Spim::new(p.SPI3, irq, p.P0_29, p.P0_28, p.P0_30, config);
21 24
22 let mut ncs = Output::new(p.P0_31, Level::High, OutputDrive::Standard); 25 let mut ncs = Output::new(p.P0_31, Level::High, OutputDrive::Standard);
23 26
diff --git a/examples/nrf52840/src/bin/spis.rs b/examples/nrf52840/src/bin/spis.rs
index fe3b0c53d..77b6e8b64 100644
--- a/examples/nrf52840/src/bin/spis.rs
+++ b/examples/nrf52840/src/bin/spis.rs
@@ -4,17 +4,20 @@
4 4
5use defmt::info; 5use defmt::info;
6use embassy_executor::Spawner; 6use embassy_executor::Spawner;
7use embassy_nrf::interrupt;
8use embassy_nrf::spis::{Config, Spis}; 7use embassy_nrf::spis::{Config, Spis};
8use embassy_nrf::{bind_interrupts, peripherals, spis};
9use {defmt_rtt as _, panic_probe as _}; 9use {defmt_rtt as _, panic_probe as _};
10 10
11bind_interrupts!(struct Irqs {
12 SPIM2_SPIS2_SPI2 => spis::InterruptHandler<peripherals::SPI2>;
13});
14
11#[embassy_executor::main] 15#[embassy_executor::main]
12async fn main(_spawner: Spawner) { 16async fn main(_spawner: Spawner) {
13 let p = embassy_nrf::init(Default::default()); 17 let p = embassy_nrf::init(Default::default());
14 info!("Running!"); 18 info!("Running!");
15 19
16 let irq = interrupt::take!(SPIM2_SPIS2_SPI2); 20 let mut spis = Spis::new(p.SPI2, Irqs, p.P0_31, p.P0_29, p.P0_28, p.P0_30, Config::default());
17 let mut spis = Spis::new(p.SPI2, irq, p.P0_31, p.P0_29, p.P0_28, p.P0_30, Config::default());
18 21
19 loop { 22 loop {
20 let mut rx_buf = [0_u8; 64]; 23 let mut rx_buf = [0_u8; 64];
diff --git a/examples/nrf52840/src/bin/temp.rs b/examples/nrf52840/src/bin/temp.rs
index b06ac709e..70957548f 100644
--- a/examples/nrf52840/src/bin/temp.rs
+++ b/examples/nrf52840/src/bin/temp.rs
@@ -4,16 +4,19 @@
4 4
5use defmt::info; 5use defmt::info;
6use embassy_executor::Spawner; 6use embassy_executor::Spawner;
7use embassy_nrf::interrupt;
8use embassy_nrf::temp::Temp; 7use embassy_nrf::temp::Temp;
8use embassy_nrf::{bind_interrupts, temp};
9use embassy_time::{Duration, Timer}; 9use embassy_time::{Duration, Timer};
10use {defmt_rtt as _, panic_probe as _}; 10use {defmt_rtt as _, panic_probe as _};
11 11
12bind_interrupts!(struct Irqs {
13 TEMP => temp::InterruptHandler;
14});
15
12#[embassy_executor::main] 16#[embassy_executor::main]
13async fn main(_spawner: Spawner) { 17async fn main(_spawner: Spawner) {
14 let p = embassy_nrf::init(Default::default()); 18 let p = embassy_nrf::init(Default::default());
15 let irq = interrupt::take!(TEMP); 19 let mut temp = Temp::new(p.TEMP, Irqs);
16 let mut temp = Temp::new(p.TEMP, irq);
17 20
18 loop { 21 loop {
19 let value = temp.read().await; 22 let value = temp.read().await;
diff --git a/examples/nrf52840/src/bin/twim.rs b/examples/nrf52840/src/bin/twim.rs
index a027cc1e7..959e3a4be 100644
--- a/examples/nrf52840/src/bin/twim.rs
+++ b/examples/nrf52840/src/bin/twim.rs
@@ -8,19 +8,22 @@
8 8
9use defmt::*; 9use defmt::*;
10use embassy_executor::Spawner; 10use embassy_executor::Spawner;
11use embassy_nrf::interrupt;
12use embassy_nrf::twim::{self, Twim}; 11use embassy_nrf::twim::{self, Twim};
12use embassy_nrf::{bind_interrupts, peripherals};
13use {defmt_rtt as _, panic_probe as _}; 13use {defmt_rtt as _, panic_probe as _};
14 14
15const ADDRESS: u8 = 0x50; 15const ADDRESS: u8 = 0x50;
16 16
17bind_interrupts!(struct Irqs {
18 SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0 => twim::InterruptHandler<peripherals::TWISPI0>;
19});
20
17#[embassy_executor::main] 21#[embassy_executor::main]
18async fn main(_spawner: Spawner) { 22async fn main(_spawner: Spawner) {
19 let p = embassy_nrf::init(Default::default()); 23 let p = embassy_nrf::init(Default::default());
20 info!("Initializing TWI..."); 24 info!("Initializing TWI...");
21 let config = twim::Config::default(); 25 let config = twim::Config::default();
22 let irq = interrupt::take!(SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0); 26 let mut twi = Twim::new(p.TWISPI0, Irqs, p.P0_03, p.P0_04, config);
23 let mut twi = Twim::new(p.TWISPI0, irq, p.P0_03, p.P0_04, config);
24 27
25 info!("Reading..."); 28 info!("Reading...");
26 29
diff --git a/examples/nrf52840/src/bin/twim_lowpower.rs b/examples/nrf52840/src/bin/twim_lowpower.rs
index e30cc9688..0970d3c3c 100644
--- a/examples/nrf52840/src/bin/twim_lowpower.rs
+++ b/examples/nrf52840/src/bin/twim_lowpower.rs
@@ -12,25 +12,28 @@ use core::mem;
12 12
13use defmt::*; 13use defmt::*;
14use embassy_executor::Spawner; 14use embassy_executor::Spawner;
15use embassy_nrf::interrupt;
16use embassy_nrf::twim::{self, Twim}; 15use embassy_nrf::twim::{self, Twim};
16use embassy_nrf::{bind_interrupts, peripherals};
17use embassy_time::{Duration, Timer}; 17use embassy_time::{Duration, Timer};
18use {defmt_rtt as _, panic_probe as _}; 18use {defmt_rtt as _, panic_probe as _};
19 19
20const ADDRESS: u8 = 0x50; 20const ADDRESS: u8 = 0x50;
21 21
22bind_interrupts!(struct Irqs {
23 SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0 => twim::InterruptHandler<peripherals::TWISPI0>;
24});
25
22#[embassy_executor::main] 26#[embassy_executor::main]
23async fn main(_p: Spawner) { 27async fn main(_p: Spawner) {
24 let mut p = embassy_nrf::init(Default::default()); 28 let mut p = embassy_nrf::init(Default::default());
25 info!("Started!"); 29 info!("Started!");
26 let mut irq = interrupt::take!(SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0);
27 30
28 loop { 31 loop {
29 info!("Initializing TWI..."); 32 info!("Initializing TWI...");
30 let config = twim::Config::default(); 33 let config = twim::Config::default();
31 34
32 // Create the TWIM instance with borrowed singletons, so they're not consumed. 35 // Create the TWIM instance with borrowed singletons, so they're not consumed.
33 let mut twi = Twim::new(&mut p.TWISPI0, &mut irq, &mut p.P0_03, &mut p.P0_04, config); 36 let mut twi = Twim::new(&mut p.TWISPI0, Irqs, &mut p.P0_03, &mut p.P0_04, config);
34 37
35 info!("Reading..."); 38 info!("Reading...");
36 39
diff --git a/examples/nrf52840/src/bin/twis.rs b/examples/nrf52840/src/bin/twis.rs
index 54cba9494..aa42b679e 100644
--- a/examples/nrf52840/src/bin/twis.rs
+++ b/examples/nrf52840/src/bin/twis.rs
@@ -6,19 +6,21 @@
6 6
7use defmt::*; 7use defmt::*;
8use embassy_executor::Spawner; 8use embassy_executor::Spawner;
9use embassy_nrf::interrupt;
10use embassy_nrf::twis::{self, Command, Twis}; 9use embassy_nrf::twis::{self, Command, Twis};
10use embassy_nrf::{bind_interrupts, peripherals};
11use {defmt_rtt as _, panic_probe as _}; 11use {defmt_rtt as _, panic_probe as _};
12 12
13bind_interrupts!(struct Irqs {
14 SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0 => twis::InterruptHandler<peripherals::TWISPI0>;
15});
16
13#[embassy_executor::main] 17#[embassy_executor::main]
14async fn main(_spawner: Spawner) { 18async fn main(_spawner: Spawner) {
15 let p = embassy_nrf::init(Default::default()); 19 let p = embassy_nrf::init(Default::default());
16 20
17 let irq = interrupt::take!(SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0);
18 let mut config = twis::Config::default(); 21 let mut config = twis::Config::default();
19 // Set i2c address 22 config.address0 = 0x55; // Set i2c address
20 config.address0 = 0x55; 23 let mut i2c = Twis::new(p.TWISPI0, Irqs, p.P0_03, p.P0_04, config);
21 let mut i2c = Twis::new(p.TWISPI0, irq, p.P0_03, p.P0_04, config);
22 24
23 info!("Listening..."); 25 info!("Listening...");
24 loop { 26 loop {
diff --git a/examples/nrf52840/src/bin/uart.rs b/examples/nrf52840/src/bin/uart.rs
index 600f7a6ef..50d5cab8c 100644
--- a/examples/nrf52840/src/bin/uart.rs
+++ b/examples/nrf52840/src/bin/uart.rs
@@ -4,9 +4,13 @@
4 4
5use defmt::*; 5use defmt::*;
6use embassy_executor::Spawner; 6use embassy_executor::Spawner;
7use embassy_nrf::{interrupt, uarte}; 7use embassy_nrf::{bind_interrupts, peripherals, uarte};
8use {defmt_rtt as _, panic_probe as _}; 8use {defmt_rtt as _, panic_probe as _};
9 9
10bind_interrupts!(struct Irqs {
11 UARTE0_UART0 => uarte::InterruptHandler<peripherals::UARTE0>;
12});
13
10#[embassy_executor::main] 14#[embassy_executor::main]
11async fn main(_spawner: Spawner) { 15async fn main(_spawner: Spawner) {
12 let p = embassy_nrf::init(Default::default()); 16 let p = embassy_nrf::init(Default::default());
@@ -14,8 +18,7 @@ async fn main(_spawner: Spawner) {
14 config.parity = uarte::Parity::EXCLUDED; 18 config.parity = uarte::Parity::EXCLUDED;
15 config.baudrate = uarte::Baudrate::BAUD115200; 19 config.baudrate = uarte::Baudrate::BAUD115200;
16 20
17 let irq = interrupt::take!(UARTE0_UART0); 21 let mut uart = uarte::Uarte::new(p.UARTE0, Irqs, p.P0_08, p.P0_06, config);
18 let mut uart = uarte::Uarte::new(p.UARTE0, irq, p.P0_08, p.P0_06, config);
19 22
20 info!("uarte initialized!"); 23 info!("uarte initialized!");
21 24
diff --git a/examples/nrf52840/src/bin/uart_idle.rs b/examples/nrf52840/src/bin/uart_idle.rs
index 6af4f7097..e1f42fa6c 100644
--- a/examples/nrf52840/src/bin/uart_idle.rs
+++ b/examples/nrf52840/src/bin/uart_idle.rs
@@ -4,9 +4,14 @@
4 4
5use defmt::*; 5use defmt::*;
6use embassy_executor::Spawner; 6use embassy_executor::Spawner;
7use embassy_nrf::{interrupt, uarte}; 7use embassy_nrf::peripherals::UARTE0;
8use embassy_nrf::{bind_interrupts, uarte};
8use {defmt_rtt as _, panic_probe as _}; 9use {defmt_rtt as _, panic_probe as _};
9 10
11bind_interrupts!(struct Irqs {
12 UARTE0_UART0 => uarte::InterruptHandler<UARTE0>;
13});
14
10#[embassy_executor::main] 15#[embassy_executor::main]
11async fn main(_spawner: Spawner) { 16async fn main(_spawner: Spawner) {
12 let p = embassy_nrf::init(Default::default()); 17 let p = embassy_nrf::init(Default::default());
@@ -14,8 +19,7 @@ async fn main(_spawner: Spawner) {
14 config.parity = uarte::Parity::EXCLUDED; 19 config.parity = uarte::Parity::EXCLUDED;
15 config.baudrate = uarte::Baudrate::BAUD115200; 20 config.baudrate = uarte::Baudrate::BAUD115200;
16 21
17 let irq = interrupt::take!(UARTE0_UART0); 22 let uart = uarte::Uarte::new(p.UARTE0, Irqs, p.P0_08, p.P0_06, config);
18 let uart = uarte::Uarte::new(p.UARTE0, irq, p.P0_08, p.P0_06, config);
19 let (mut tx, mut rx) = uart.split_with_idle(p.TIMER0, p.PPI_CH0, p.PPI_CH1); 23 let (mut tx, mut rx) = uart.split_with_idle(p.TIMER0, p.PPI_CH0, p.PPI_CH1);
20 24
21 info!("uarte initialized!"); 25 info!("uarte initialized!");
diff --git a/examples/nrf52840/src/bin/uart_split.rs b/examples/nrf52840/src/bin/uart_split.rs
index 1adaf53fd..9979a1d53 100644
--- a/examples/nrf52840/src/bin/uart_split.rs
+++ b/examples/nrf52840/src/bin/uart_split.rs
@@ -6,13 +6,17 @@ use defmt::*;
6use embassy_executor::Spawner; 6use embassy_executor::Spawner;
7use embassy_nrf::peripherals::UARTE0; 7use embassy_nrf::peripherals::UARTE0;
8use embassy_nrf::uarte::UarteRx; 8use embassy_nrf::uarte::UarteRx;
9use embassy_nrf::{interrupt, uarte}; 9use embassy_nrf::{bind_interrupts, uarte};
10use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex; 10use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex;
11use embassy_sync::channel::Channel; 11use embassy_sync::channel::Channel;
12use {defmt_rtt as _, panic_probe as _}; 12use {defmt_rtt as _, panic_probe as _};
13 13
14static CHANNEL: Channel<ThreadModeRawMutex, [u8; 8], 1> = Channel::new(); 14static CHANNEL: Channel<ThreadModeRawMutex, [u8; 8], 1> = Channel::new();
15 15
16bind_interrupts!(struct Irqs {
17 UARTE0_UART0 => uarte::InterruptHandler<UARTE0>;
18});
19
16#[embassy_executor::main] 20#[embassy_executor::main]
17async fn main(spawner: Spawner) { 21async fn main(spawner: Spawner) {
18 let p = embassy_nrf::init(Default::default()); 22 let p = embassy_nrf::init(Default::default());
@@ -20,8 +24,7 @@ async fn main(spawner: Spawner) {
20 config.parity = uarte::Parity::EXCLUDED; 24 config.parity = uarte::Parity::EXCLUDED;
21 config.baudrate = uarte::Baudrate::BAUD115200; 25 config.baudrate = uarte::Baudrate::BAUD115200;
22 26
23 let irq = interrupt::take!(UARTE0_UART0); 27 let uart = uarte::Uarte::new(p.UARTE0, Irqs, p.P0_08, p.P0_06, config);
24 let uart = uarte::Uarte::new(p.UARTE0, irq, p.P0_08, p.P0_06, config);
25 let (mut tx, rx) = uart.split(); 28 let (mut tx, rx) = uart.split();
26 29
27 info!("uarte initialized!"); 30 info!("uarte initialized!");
diff --git a/examples/nrf52840/src/bin/usb_ethernet.rs b/examples/nrf52840/src/bin/usb_ethernet.rs
index 430468adf..b8a72313a 100644
--- a/examples/nrf52840/src/bin/usb_ethernet.rs
+++ b/examples/nrf52840/src/bin/usb_ethernet.rs
@@ -9,8 +9,9 @@ use embassy_executor::Spawner;
9use embassy_net::tcp::TcpSocket; 9use embassy_net::tcp::TcpSocket;
10use embassy_net::{Stack, StackResources}; 10use embassy_net::{Stack, StackResources};
11use embassy_nrf::rng::Rng; 11use embassy_nrf::rng::Rng;
12use embassy_nrf::usb::{Driver, HardwareVbusDetect}; 12use embassy_nrf::usb::vbus_detect::HardwareVbusDetect;
13use embassy_nrf::{interrupt, pac, peripherals}; 13use embassy_nrf::usb::Driver;
14use embassy_nrf::{bind_interrupts, pac, peripherals, rng, usb};
14use embassy_usb::class::cdc_ncm::embassy_net::{Device, Runner, State as NetState}; 15use embassy_usb::class::cdc_ncm::embassy_net::{Device, Runner, State as NetState};
15use embassy_usb::class::cdc_ncm::{CdcNcmClass, State}; 16use embassy_usb::class::cdc_ncm::{CdcNcmClass, State};
16use embassy_usb::{Builder, Config, UsbDevice}; 17use embassy_usb::{Builder, Config, UsbDevice};
@@ -18,6 +19,12 @@ use embedded_io::asynch::Write;
18use static_cell::StaticCell; 19use static_cell::StaticCell;
19use {defmt_rtt as _, panic_probe as _}; 20use {defmt_rtt as _, panic_probe as _};
20 21
22bind_interrupts!(struct Irqs {
23 USBD => usb::InterruptHandler<peripherals::USBD>;
24 POWER_CLOCK => usb::vbus_detect::InterruptHandler;
25 RNG => rng::InterruptHandler<peripherals::RNG>;
26});
27
21type MyDriver = Driver<'static, peripherals::USBD, HardwareVbusDetect>; 28type MyDriver = Driver<'static, peripherals::USBD, HardwareVbusDetect>;
22 29
23macro_rules! singleton { 30macro_rules! singleton {
@@ -46,31 +53,8 @@ async fn net_task(stack: &'static Stack<Device<'static, MTU>>) -> ! {
46 stack.run().await 53 stack.run().await
47} 54}
48 55
49#[inline(never)]
50pub fn test_function() -> (usize, u32, [u32; 2]) {
51 let mut array = [3; 2];
52
53 let mut index = 0;
54 let mut result = 0;
55
56 for x in [1, 2] {
57 if x == 1 {
58 array[1] = 99;
59 } else {
60 index = if x == 2 { 1 } else { 0 };
61
62 // grabs value from array[0], not array[1]
63 result = array[index];
64 }
65 }
66
67 (index, result, array)
68}
69
70#[embassy_executor::main] 56#[embassy_executor::main]
71async fn main(spawner: Spawner) { 57async fn main(spawner: Spawner) {
72 info!("{:?}", test_function());
73
74 let p = embassy_nrf::init(Default::default()); 58 let p = embassy_nrf::init(Default::default());
75 let clock: pac::CLOCK = unsafe { mem::transmute(()) }; 59 let clock: pac::CLOCK = unsafe { mem::transmute(()) };
76 60
@@ -79,9 +63,7 @@ async fn main(spawner: Spawner) {
79 while clock.events_hfclkstarted.read().bits() != 1 {} 63 while clock.events_hfclkstarted.read().bits() != 1 {}
80 64
81 // Create the driver, from the HAL. 65 // Create the driver, from the HAL.
82 let irq = interrupt::take!(USBD); 66 let driver = Driver::new(p.USBD, Irqs, HardwareVbusDetect::new(Irqs));
83 let power_irq = interrupt::take!(POWER_CLOCK);
84 let driver = Driver::new(p.USBD, irq, HardwareVbusDetect::new(power_irq));
85 67
86 // Create embassy-usb Config 68 // Create embassy-usb Config
87 let mut config = Config::new(0xc0de, 0xcafe); 69 let mut config = Config::new(0xc0de, 0xcafe);
@@ -105,6 +87,7 @@ async fn main(spawner: Spawner) {
105 &mut singleton!([0; 256])[..], 87 &mut singleton!([0; 256])[..],
106 &mut singleton!([0; 256])[..], 88 &mut singleton!([0; 256])[..],
107 &mut singleton!([0; 128])[..], 89 &mut singleton!([0; 128])[..],
90 &mut singleton!([0; 128])[..],
108 ); 91 );
109 92
110 // Our MAC addr. 93 // Our MAC addr.
@@ -131,7 +114,7 @@ async fn main(spawner: Spawner) {
131 //}); 114 //});
132 115
133 // Generate random seed 116 // Generate random seed
134 let mut rng = Rng::new(p.RNG, interrupt::take!(RNG)); 117 let mut rng = Rng::new(p.RNG, Irqs);
135 let mut seed = [0; 8]; 118 let mut seed = [0; 8];
136 rng.blocking_fill_bytes(&mut seed); 119 rng.blocking_fill_bytes(&mut seed);
137 let seed = u64::from_le_bytes(seed); 120 let seed = u64::from_le_bytes(seed);
diff --git a/examples/nrf52840/src/bin/usb_hid_keyboard.rs b/examples/nrf52840/src/bin/usb_hid_keyboard.rs
index 3d8a114cd..7ccd2946a 100644
--- a/examples/nrf52840/src/bin/usb_hid_keyboard.rs
+++ b/examples/nrf52840/src/bin/usb_hid_keyboard.rs
@@ -10,8 +10,9 @@ use embassy_executor::Spawner;
10use embassy_futures::join::join; 10use embassy_futures::join::join;
11use embassy_futures::select::{select, Either}; 11use embassy_futures::select::{select, Either};
12use embassy_nrf::gpio::{Input, Pin, Pull}; 12use embassy_nrf::gpio::{Input, Pin, Pull};
13use embassy_nrf::usb::{Driver, HardwareVbusDetect}; 13use embassy_nrf::usb::vbus_detect::HardwareVbusDetect;
14use embassy_nrf::{interrupt, pac}; 14use embassy_nrf::usb::Driver;
15use embassy_nrf::{bind_interrupts, pac, peripherals, usb};
15use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; 16use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
16use embassy_sync::signal::Signal; 17use embassy_sync::signal::Signal;
17use embassy_usb::class::hid::{HidReaderWriter, ReportId, RequestHandler, State}; 18use embassy_usb::class::hid::{HidReaderWriter, ReportId, RequestHandler, State};
@@ -20,6 +21,11 @@ use embassy_usb::{Builder, Config, Handler};
20use usbd_hid::descriptor::{KeyboardReport, SerializedDescriptor}; 21use usbd_hid::descriptor::{KeyboardReport, SerializedDescriptor};
21use {defmt_rtt as _, panic_probe as _}; 22use {defmt_rtt as _, panic_probe as _};
22 23
24bind_interrupts!(struct Irqs {
25 USBD => usb::InterruptHandler<peripherals::USBD>;
26 POWER_CLOCK => usb::vbus_detect::InterruptHandler;
27});
28
23static SUSPENDED: AtomicBool = AtomicBool::new(false); 29static SUSPENDED: AtomicBool = AtomicBool::new(false);
24 30
25#[embassy_executor::main] 31#[embassy_executor::main]
@@ -32,9 +38,7 @@ async fn main(_spawner: Spawner) {
32 while clock.events_hfclkstarted.read().bits() != 1 {} 38 while clock.events_hfclkstarted.read().bits() != 1 {}
33 39
34 // Create the driver, from the HAL. 40 // Create the driver, from the HAL.
35 let irq = interrupt::take!(USBD); 41 let driver = Driver::new(p.USBD, Irqs, HardwareVbusDetect::new(Irqs));
36 let power_irq = interrupt::take!(POWER_CLOCK);
37 let driver = Driver::new(p.USBD, irq, HardwareVbusDetect::new(power_irq));
38 42
39 // Create embassy-usb Config 43 // Create embassy-usb Config
40 let mut config = Config::new(0xc0de, 0xcafe); 44 let mut config = Config::new(0xc0de, 0xcafe);
@@ -50,6 +54,7 @@ async fn main(_spawner: Spawner) {
50 let mut device_descriptor = [0; 256]; 54 let mut device_descriptor = [0; 256];
51 let mut config_descriptor = [0; 256]; 55 let mut config_descriptor = [0; 256];
52 let mut bos_descriptor = [0; 256]; 56 let mut bos_descriptor = [0; 256];
57 let mut msos_descriptor = [0; 256];
53 let mut control_buf = [0; 64]; 58 let mut control_buf = [0; 64];
54 let request_handler = MyRequestHandler {}; 59 let request_handler = MyRequestHandler {};
55 let mut device_handler = MyDeviceHandler::new(); 60 let mut device_handler = MyDeviceHandler::new();
@@ -62,6 +67,7 @@ async fn main(_spawner: Spawner) {
62 &mut device_descriptor, 67 &mut device_descriptor,
63 &mut config_descriptor, 68 &mut config_descriptor,
64 &mut bos_descriptor, 69 &mut bos_descriptor,
70 &mut msos_descriptor,
65 &mut control_buf, 71 &mut control_buf,
66 ); 72 );
67 73
diff --git a/examples/nrf52840/src/bin/usb_hid_mouse.rs b/examples/nrf52840/src/bin/usb_hid_mouse.rs
index d7c9d55b7..edf634a5e 100644
--- a/examples/nrf52840/src/bin/usb_hid_mouse.rs
+++ b/examples/nrf52840/src/bin/usb_hid_mouse.rs
@@ -7,8 +7,9 @@ use core::mem;
7use defmt::*; 7use defmt::*;
8use embassy_executor::Spawner; 8use embassy_executor::Spawner;
9use embassy_futures::join::join; 9use embassy_futures::join::join;
10use embassy_nrf::usb::{Driver, HardwareVbusDetect}; 10use embassy_nrf::usb::vbus_detect::HardwareVbusDetect;
11use embassy_nrf::{interrupt, pac}; 11use embassy_nrf::usb::Driver;
12use embassy_nrf::{bind_interrupts, pac, peripherals, usb};
12use embassy_time::{Duration, Timer}; 13use embassy_time::{Duration, Timer};
13use embassy_usb::class::hid::{HidWriter, ReportId, RequestHandler, State}; 14use embassy_usb::class::hid::{HidWriter, ReportId, RequestHandler, State};
14use embassy_usb::control::OutResponse; 15use embassy_usb::control::OutResponse;
@@ -16,6 +17,11 @@ use embassy_usb::{Builder, Config};
16use usbd_hid::descriptor::{MouseReport, SerializedDescriptor}; 17use usbd_hid::descriptor::{MouseReport, SerializedDescriptor};
17use {defmt_rtt as _, panic_probe as _}; 18use {defmt_rtt as _, panic_probe as _};
18 19
20bind_interrupts!(struct Irqs {
21 USBD => usb::InterruptHandler<peripherals::USBD>;
22 POWER_CLOCK => usb::vbus_detect::InterruptHandler;
23});
24
19#[embassy_executor::main] 25#[embassy_executor::main]
20async fn main(_spawner: Spawner) { 26async fn main(_spawner: Spawner) {
21 let p = embassy_nrf::init(Default::default()); 27 let p = embassy_nrf::init(Default::default());
@@ -26,9 +32,7 @@ async fn main(_spawner: Spawner) {
26 while clock.events_hfclkstarted.read().bits() != 1 {} 32 while clock.events_hfclkstarted.read().bits() != 1 {}
27 33
28 // Create the driver, from the HAL. 34 // Create the driver, from the HAL.
29 let irq = interrupt::take!(USBD); 35 let driver = Driver::new(p.USBD, Irqs, HardwareVbusDetect::new(Irqs));
30 let power_irq = interrupt::take!(POWER_CLOCK);
31 let driver = Driver::new(p.USBD, irq, HardwareVbusDetect::new(power_irq));
32 36
33 // Create embassy-usb Config 37 // Create embassy-usb Config
34 let mut config = Config::new(0xc0de, 0xcafe); 38 let mut config = Config::new(0xc0de, 0xcafe);
@@ -43,6 +47,7 @@ async fn main(_spawner: Spawner) {
43 let mut device_descriptor = [0; 256]; 47 let mut device_descriptor = [0; 256];
44 let mut config_descriptor = [0; 256]; 48 let mut config_descriptor = [0; 256];
45 let mut bos_descriptor = [0; 256]; 49 let mut bos_descriptor = [0; 256];
50 let mut msos_descriptor = [0; 256];
46 let mut control_buf = [0; 64]; 51 let mut control_buf = [0; 64];
47 let request_handler = MyRequestHandler {}; 52 let request_handler = MyRequestHandler {};
48 53
@@ -54,6 +59,7 @@ async fn main(_spawner: Spawner) {
54 &mut device_descriptor, 59 &mut device_descriptor,
55 &mut config_descriptor, 60 &mut config_descriptor,
56 &mut bos_descriptor, 61 &mut bos_descriptor,
62 &mut msos_descriptor,
57 &mut control_buf, 63 &mut control_buf,
58 ); 64 );
59 65
diff --git a/examples/nrf52840/src/bin/usb_serial.rs b/examples/nrf52840/src/bin/usb_serial.rs
index 102d7ea60..9727a4f57 100644
--- a/examples/nrf52840/src/bin/usb_serial.rs
+++ b/examples/nrf52840/src/bin/usb_serial.rs
@@ -7,13 +7,19 @@ use core::mem;
7use defmt::{info, panic}; 7use defmt::{info, panic};
8use embassy_executor::Spawner; 8use embassy_executor::Spawner;
9use embassy_futures::join::join; 9use embassy_futures::join::join;
10use embassy_nrf::usb::{Driver, HardwareVbusDetect, Instance, VbusDetect}; 10use embassy_nrf::usb::vbus_detect::{HardwareVbusDetect, VbusDetect};
11use embassy_nrf::{interrupt, pac}; 11use embassy_nrf::usb::{Driver, Instance};
12use embassy_nrf::{bind_interrupts, pac, peripherals, usb};
12use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; 13use embassy_usb::class::cdc_acm::{CdcAcmClass, State};
13use embassy_usb::driver::EndpointError; 14use embassy_usb::driver::EndpointError;
14use embassy_usb::{Builder, Config}; 15use embassy_usb::{Builder, Config};
15use {defmt_rtt as _, panic_probe as _}; 16use {defmt_rtt as _, panic_probe as _};
16 17
18bind_interrupts!(struct Irqs {
19 USBD => usb::InterruptHandler<peripherals::USBD>;
20 POWER_CLOCK => usb::vbus_detect::InterruptHandler;
21});
22
17#[embassy_executor::main] 23#[embassy_executor::main]
18async fn main(_spawner: Spawner) { 24async fn main(_spawner: Spawner) {
19 let p = embassy_nrf::init(Default::default()); 25 let p = embassy_nrf::init(Default::default());
@@ -24,9 +30,7 @@ async fn main(_spawner: Spawner) {
24 while clock.events_hfclkstarted.read().bits() != 1 {} 30 while clock.events_hfclkstarted.read().bits() != 1 {}
25 31
26 // Create the driver, from the HAL. 32 // Create the driver, from the HAL.
27 let irq = interrupt::take!(USBD); 33 let driver = Driver::new(p.USBD, Irqs, HardwareVbusDetect::new(Irqs));
28 let power_irq = interrupt::take!(POWER_CLOCK);
29 let driver = Driver::new(p.USBD, irq, HardwareVbusDetect::new(power_irq));
30 34
31 // Create embassy-usb Config 35 // Create embassy-usb Config
32 let mut config = Config::new(0xc0de, 0xcafe); 36 let mut config = Config::new(0xc0de, 0xcafe);
@@ -48,6 +52,7 @@ async fn main(_spawner: Spawner) {
48 let mut device_descriptor = [0; 256]; 52 let mut device_descriptor = [0; 256];
49 let mut config_descriptor = [0; 256]; 53 let mut config_descriptor = [0; 256];
50 let mut bos_descriptor = [0; 256]; 54 let mut bos_descriptor = [0; 256];
55 let mut msos_descriptor = [0; 256];
51 let mut control_buf = [0; 64]; 56 let mut control_buf = [0; 64];
52 57
53 let mut state = State::new(); 58 let mut state = State::new();
@@ -58,6 +63,7 @@ async fn main(_spawner: Spawner) {
58 &mut device_descriptor, 63 &mut device_descriptor,
59 &mut config_descriptor, 64 &mut config_descriptor,
60 &mut bos_descriptor, 65 &mut bos_descriptor,
66 &mut msos_descriptor,
61 &mut control_buf, 67 &mut control_buf,
62 ); 68 );
63 69
diff --git a/examples/nrf52840/src/bin/usb_serial_multitask.rs b/examples/nrf52840/src/bin/usb_serial_multitask.rs
index 558d4ba60..6da2c2a2f 100644
--- a/examples/nrf52840/src/bin/usb_serial_multitask.rs
+++ b/examples/nrf52840/src/bin/usb_serial_multitask.rs
@@ -6,14 +6,29 @@ use core::mem;
6 6
7use defmt::{info, panic, unwrap}; 7use defmt::{info, panic, unwrap};
8use embassy_executor::Spawner; 8use embassy_executor::Spawner;
9use embassy_nrf::usb::{Driver, HardwareVbusDetect}; 9use embassy_nrf::usb::vbus_detect::HardwareVbusDetect;
10use embassy_nrf::{interrupt, pac, peripherals}; 10use embassy_nrf::usb::Driver;
11use embassy_nrf::{bind_interrupts, pac, peripherals, usb};
11use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; 12use embassy_usb::class::cdc_acm::{CdcAcmClass, State};
12use embassy_usb::driver::EndpointError; 13use embassy_usb::driver::EndpointError;
13use embassy_usb::{Builder, Config, UsbDevice}; 14use embassy_usb::{Builder, Config, UsbDevice};
14use static_cell::StaticCell; 15use static_cell::StaticCell;
15use {defmt_rtt as _, panic_probe as _}; 16use {defmt_rtt as _, panic_probe as _};
16 17
18bind_interrupts!(struct Irqs {
19 USBD => usb::InterruptHandler<peripherals::USBD>;
20 POWER_CLOCK => usb::vbus_detect::InterruptHandler;
21});
22
23macro_rules! singleton {
24 ($val:expr) => {{
25 type T = impl Sized;
26 static STATIC_CELL: StaticCell<T> = StaticCell::new();
27 let (x,) = STATIC_CELL.init(($val,));
28 x
29 }};
30}
31
17type MyDriver = Driver<'static, peripherals::USBD, HardwareVbusDetect>; 32type MyDriver = Driver<'static, peripherals::USBD, HardwareVbusDetect>;
18 33
19#[embassy_executor::task] 34#[embassy_executor::task]
@@ -39,10 +54,9 @@ async fn main(spawner: Spawner) {
39 info!("Enabling ext hfosc..."); 54 info!("Enabling ext hfosc...");
40 clock.tasks_hfclkstart.write(|w| unsafe { w.bits(1) }); 55 clock.tasks_hfclkstart.write(|w| unsafe { w.bits(1) });
41 while clock.events_hfclkstarted.read().bits() != 1 {} 56 while clock.events_hfclkstarted.read().bits() != 1 {}
57
42 // Create the driver, from the HAL. 58 // Create the driver, from the HAL.
43 let irq = interrupt::take!(USBD); 59 let driver = Driver::new(p.USBD, Irqs, HardwareVbusDetect::new(Irqs));
44 let power_irq = interrupt::take!(POWER_CLOCK);
45 let driver = Driver::new(p.USBD, irq, HardwareVbusDetect::new(power_irq));
46 60
47 // Create embassy-usb Config 61 // Create embassy-usb Config
48 let mut config = Config::new(0xc0de, 0xcafe); 62 let mut config = Config::new(0xc0de, 0xcafe);
@@ -59,34 +73,21 @@ async fn main(spawner: Spawner) {
59 config.device_protocol = 0x01; 73 config.device_protocol = 0x01;
60 config.composite_with_iads = true; 74 config.composite_with_iads = true;
61 75
62 struct Resources { 76 let state = singleton!(State::new());
63 device_descriptor: [u8; 256],
64 config_descriptor: [u8; 256],
65 bos_descriptor: [u8; 256],
66 control_buf: [u8; 64],
67 serial_state: State<'static>,
68 }
69 static RESOURCES: StaticCell<Resources> = StaticCell::new();
70 let res = RESOURCES.init(Resources {
71 device_descriptor: [0; 256],
72 config_descriptor: [0; 256],
73 bos_descriptor: [0; 256],
74 control_buf: [0; 64],
75 serial_state: State::new(),
76 });
77 77
78 // Create embassy-usb DeviceBuilder using the driver and config. 78 // Create embassy-usb DeviceBuilder using the driver and config.
79 let mut builder = Builder::new( 79 let mut builder = Builder::new(
80 driver, 80 driver,
81 config, 81 config,
82 &mut res.device_descriptor, 82 &mut singleton!([0; 256])[..],
83 &mut res.config_descriptor, 83 &mut singleton!([0; 256])[..],
84 &mut res.bos_descriptor, 84 &mut singleton!([0; 256])[..],
85 &mut res.control_buf, 85 &mut singleton!([0; 128])[..],
86 &mut singleton!([0; 128])[..],
86 ); 87 );
87 88
88 // Create classes on the builder. 89 // Create classes on the builder.
89 let class = CdcAcmClass::new(&mut builder, &mut res.serial_state, 64); 90 let class = CdcAcmClass::new(&mut builder, state, 64);
90 91
91 // Build the builder. 92 // Build the builder.
92 let usb = builder.build(); 93 let usb = builder.build();
diff --git a/examples/nrf52840/src/bin/usb_serial_winusb.rs b/examples/nrf52840/src/bin/usb_serial_winusb.rs
index 6561fc3b4..6e4f71a48 100644
--- a/examples/nrf52840/src/bin/usb_serial_winusb.rs
+++ b/examples/nrf52840/src/bin/usb_serial_winusb.rs
@@ -7,8 +7,9 @@ use core::mem;
7use defmt::{info, panic}; 7use defmt::{info, panic};
8use embassy_executor::Spawner; 8use embassy_executor::Spawner;
9use embassy_futures::join::join; 9use embassy_futures::join::join;
10use embassy_nrf::usb::{Driver, HardwareVbusDetect, Instance, VbusDetect}; 10use embassy_nrf::usb::vbus_detect::{HardwareVbusDetect, VbusDetect};
11use embassy_nrf::{interrupt, pac}; 11use embassy_nrf::usb::{Driver, Instance};
12use embassy_nrf::{bind_interrupts, pac, peripherals, usb};
12use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; 13use embassy_usb::class::cdc_acm::{CdcAcmClass, State};
13use embassy_usb::driver::EndpointError; 14use embassy_usb::driver::EndpointError;
14use embassy_usb::msos::{self, windows_version}; 15use embassy_usb::msos::{self, windows_version};
@@ -16,6 +17,11 @@ use embassy_usb::types::InterfaceNumber;
16use embassy_usb::{Builder, Config}; 17use embassy_usb::{Builder, Config};
17use {defmt_rtt as _, panic_probe as _}; 18use {defmt_rtt as _, panic_probe as _};
18 19
20bind_interrupts!(struct Irqs {
21 USBD => usb::InterruptHandler<peripherals::USBD>;
22 POWER_CLOCK => usb::vbus_detect::InterruptHandler;
23});
24
19// This is a randomly generated GUID to allow clients on Windows to find our device 25// This is a randomly generated GUID to allow clients on Windows to find our device
20const DEVICE_INTERFACE_GUIDS: &[&str] = &["{EAA9A5DC-30BA-44BC-9232-606CDC875321}"]; 26const DEVICE_INTERFACE_GUIDS: &[&str] = &["{EAA9A5DC-30BA-44BC-9232-606CDC875321}"];
21 27
@@ -29,9 +35,7 @@ async fn main(_spawner: Spawner) {
29 while clock.events_hfclkstarted.read().bits() != 1 {} 35 while clock.events_hfclkstarted.read().bits() != 1 {}
30 36
31 // Create the driver, from the HAL. 37 // Create the driver, from the HAL.
32 let irq = interrupt::take!(USBD); 38 let driver = Driver::new(p.USBD, Irqs, HardwareVbusDetect::new(Irqs));
33 let power_irq = interrupt::take!(POWER_CLOCK);
34 let driver = Driver::new(p.USBD, irq, HardwareVbusDetect::new(power_irq));
35 39
36 // Create embassy-usb Config 40 // Create embassy-usb Config
37 let mut config = Config::new(0xc0de, 0xcafe); 41 let mut config = Config::new(0xc0de, 0xcafe);
diff --git a/examples/nrf5340/Cargo.toml b/examples/nrf5340/Cargo.toml
index eed493012..e88ddf2f7 100644
--- a/examples/nrf5340/Cargo.toml
+++ b/examples/nrf5340/Cargo.toml
@@ -4,24 +4,13 @@ name = "embassy-nrf5340-examples"
4version = "0.1.0" 4version = "0.1.0"
5license = "MIT OR Apache-2.0" 5license = "MIT OR Apache-2.0"
6 6
7[features]
8default = ["nightly"]
9nightly = [
10 "embassy-executor/nightly",
11 "embassy-nrf/nightly",
12 "embassy-net/nightly",
13 "embassy-nrf/unstable-traits",
14 "embassy-usb",
15 "embedded-io/async",
16 "embassy-net",
17]
18
19[dependencies] 7[dependencies]
20embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } 8embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
21embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = [ 9embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = [
22 "defmt", 10 "defmt",
23] } 11] }
24embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = [ 12embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = [
13 "nightly",
25 "defmt", 14 "defmt",
26 "integrated-timers", 15 "integrated-timers",
27] } 16] }
@@ -30,6 +19,8 @@ embassy-time = { version = "0.1.0", path = "../../embassy-time", features = [
30 "defmt-timestamp-uptime", 19 "defmt-timestamp-uptime",
31] } 20] }
32embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = [ 21embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = [
22 "nightly",
23 "unstable-traits",
33 "defmt", 24 "defmt",
34 "nrf5340-app-s", 25 "nrf5340-app-s",
35 "time-driver-rtc1", 26 "time-driver-rtc1",
@@ -37,16 +28,16 @@ embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = [
37 "unstable-pac", 28 "unstable-pac",
38] } 29] }
39embassy-net = { version = "0.1.0", path = "../../embassy-net", features = [ 30embassy-net = { version = "0.1.0", path = "../../embassy-net", features = [
31 "nightly",
40 "defmt", 32 "defmt",
41 "tcp", 33 "tcp",
42 "dhcpv4", 34 "dhcpv4",
43 "medium-ethernet", 35 "medium-ethernet",
44], optional = true } 36] }
45embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = [ 37embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = [
46 "defmt", 38 "defmt",
47], optional = true } 39] }
48embedded-io = "0.4.0" 40embedded-io = { version = "0.4.0", features = [ "async" ]}
49
50 41
51defmt = "0.3" 42defmt = "0.3"
52defmt-rtt = "0.4" 43defmt-rtt = "0.4"
diff --git a/examples/nrf5340/src/bin/uart.rs b/examples/nrf5340/src/bin/uart.rs
index 5f448c2ba..d68539702 100644
--- a/examples/nrf5340/src/bin/uart.rs
+++ b/examples/nrf5340/src/bin/uart.rs
@@ -4,9 +4,14 @@
4 4
5use defmt::*; 5use defmt::*;
6use embassy_executor::Spawner; 6use embassy_executor::Spawner;
7use embassy_nrf::{interrupt, uarte}; 7use embassy_nrf::peripherals::SERIAL0;
8use embassy_nrf::{bind_interrupts, uarte};
8use {defmt_rtt as _, panic_probe as _}; 9use {defmt_rtt as _, panic_probe as _};
9 10
11bind_interrupts!(struct Irqs {
12 SERIAL0 => uarte::InterruptHandler<SERIAL0>;
13});
14
10#[embassy_executor::main] 15#[embassy_executor::main]
11async fn main(_spawner: Spawner) { 16async fn main(_spawner: Spawner) {
12 let p = embassy_nrf::init(Default::default()); 17 let p = embassy_nrf::init(Default::default());
@@ -14,8 +19,7 @@ async fn main(_spawner: Spawner) {
14 config.parity = uarte::Parity::EXCLUDED; 19 config.parity = uarte::Parity::EXCLUDED;
15 config.baudrate = uarte::Baudrate::BAUD115200; 20 config.baudrate = uarte::Baudrate::BAUD115200;
16 21
17 let irq = interrupt::take!(SERIAL0); 22 let mut uart = uarte::Uarte::new(p.SERIAL0, Irqs, p.P1_00, p.P1_01, config);
18 let mut uart = uarte::Uarte::new(p.SERIAL0, irq, p.P1_00, p.P1_01, config);
19 23
20 info!("uarte initialized!"); 24 info!("uarte initialized!");
21 25
diff --git a/examples/std/src/bin/net.rs b/examples/std/src/bin/net.rs
index 451850d99..e018e18c9 100644
--- a/examples/std/src/bin/net.rs
+++ b/examples/std/src/bin/net.rs
@@ -65,7 +65,7 @@ async fn main_task(spawner: Spawner) {
65 let seed = u64::from_le_bytes(seed); 65 let seed = u64::from_le_bytes(seed);
66 66
67 // Init network stack 67 // Init network stack
68 let stack = &*singleton!(Stack::new(device, config, singleton!(StackResources::<2>::new()), seed)); 68 let stack = &*singleton!(Stack::new(device, config, singleton!(StackResources::<3>::new()), seed));
69 69
70 // Launch network task 70 // Launch network task
71 spawner.spawn(net_task(stack)).unwrap(); 71 spawner.spawn(net_task(stack)).unwrap();
diff --git a/examples/std/src/bin/net_dns.rs b/examples/std/src/bin/net_dns.rs
index e1cc45a38..d1e1f8212 100644
--- a/examples/std/src/bin/net_dns.rs
+++ b/examples/std/src/bin/net_dns.rs
@@ -65,7 +65,7 @@ async fn main_task(spawner: Spawner) {
65 let seed = u64::from_le_bytes(seed); 65 let seed = u64::from_le_bytes(seed);
66 66
67 // Init network stack 67 // Init network stack
68 let stack: &Stack<_> = &*singleton!(Stack::new(device, config, singleton!(StackResources::<2>::new()), seed)); 68 let stack: &Stack<_> = &*singleton!(Stack::new(device, config, singleton!(StackResources::<3>::new()), seed));
69 69
70 // Launch network task 70 // Launch network task
71 spawner.spawn(net_task(stack)).unwrap(); 71 spawner.spawn(net_task(stack)).unwrap();
diff --git a/examples/std/src/bin/net_udp.rs b/examples/std/src/bin/net_udp.rs
index f1923f180..328a0536c 100644
--- a/examples/std/src/bin/net_udp.rs
+++ b/examples/std/src/bin/net_udp.rs
@@ -62,7 +62,7 @@ async fn main_task(spawner: Spawner) {
62 let seed = u64::from_le_bytes(seed); 62 let seed = u64::from_le_bytes(seed);
63 63
64 // Init network stack 64 // Init network stack
65 let stack = &*singleton!(Stack::new(device, config, singleton!(StackResources::<2>::new()), seed)); 65 let stack = &*singleton!(Stack::new(device, config, singleton!(StackResources::<3>::new()), seed));
66 66
67 // Launch network task 67 // Launch network task
68 spawner.spawn(net_task(stack)).unwrap(); 68 spawner.spawn(net_task(stack)).unwrap();
diff --git a/examples/stm32f0/Cargo.toml b/examples/stm32f0/Cargo.toml
index d4afbb8f8..89d99b6d3 100644
--- a/examples/stm32f0/Cargo.toml
+++ b/examples/stm32f0/Cargo.toml
@@ -15,5 +15,5 @@ panic-probe = "0.3"
15embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] } 15embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] }
16embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["defmt", "integrated-timers"] } 16embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["defmt", "integrated-timers"] }
17embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 17embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
18embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "memory-x", "stm32f091rc", "time-driver-any", "exti"] } 18embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "memory-x", "stm32f091rc", "time-driver-any", "exti", "unstable-pac"] }
19static_cell = "1.0" 19static_cell = "1.0"
diff --git a/examples/stm32f0/src/bin/priority.rs b/examples/stm32f0/src/bin/multiprio.rs
index 7fed6a773..e0dc8c989 100644
--- a/examples/stm32f0/src/bin/priority.rs
+++ b/examples/stm32f0/src/bin/multiprio.rs
@@ -57,11 +57,14 @@
57#![no_main] 57#![no_main]
58#![feature(type_alias_impl_trait)] 58#![feature(type_alias_impl_trait)]
59 59
60use core::mem;
61
62use cortex_m::peripheral::NVIC;
60use cortex_m_rt::entry; 63use cortex_m_rt::entry;
61use defmt::*; 64use defmt::*;
62use embassy_stm32::executor::{Executor, InterruptExecutor}; 65use embassy_stm32::executor::{Executor, InterruptExecutor};
63use embassy_stm32::interrupt; 66use embassy_stm32::interrupt;
64use embassy_stm32::interrupt::InterruptExt; 67use embassy_stm32::pac::Interrupt;
65use embassy_time::{Duration, Instant, Timer}; 68use embassy_time::{Duration, Instant, Timer};
66use static_cell::StaticCell; 69use static_cell::StaticCell;
67use {defmt_rtt as _, panic_probe as _}; 70use {defmt_rtt as _, panic_probe as _};
@@ -108,27 +111,34 @@ async fn run_low() {
108 } 111 }
109} 112}
110 113
111static EXECUTOR_HIGH: StaticCell<InterruptExecutor<interrupt::USART1>> = StaticCell::new(); 114static EXECUTOR_HIGH: InterruptExecutor = InterruptExecutor::new();
112static EXECUTOR_MED: StaticCell<InterruptExecutor<interrupt::USART2>> = StaticCell::new(); 115static EXECUTOR_MED: InterruptExecutor = InterruptExecutor::new();
113static EXECUTOR_LOW: StaticCell<Executor> = StaticCell::new(); 116static EXECUTOR_LOW: StaticCell<Executor> = StaticCell::new();
114 117
118#[interrupt]
119unsafe fn USART1() {
120 EXECUTOR_HIGH.on_interrupt()
121}
122
123#[interrupt]
124unsafe fn USART2() {
125 EXECUTOR_MED.on_interrupt()
126}
127
115#[entry] 128#[entry]
116fn main() -> ! { 129fn main() -> ! {
117 // Initialize and create handle for devicer peripherals 130 // Initialize and create handle for devicer peripherals
118 let _p = embassy_stm32::init(Default::default()); 131 let _p = embassy_stm32::init(Default::default());
132 let mut nvic: NVIC = unsafe { mem::transmute(()) };
119 133
120 // High-priority executor: USART1, priority level 6 134 // High-priority executor: USART1, priority level 6
121 let irq = interrupt::take!(USART1); 135 unsafe { nvic.set_priority(Interrupt::USART1, 6 << 4) };
122 irq.set_priority(interrupt::Priority::P6); 136 let spawner = EXECUTOR_HIGH.start(Interrupt::USART1);
123 let executor = EXECUTOR_HIGH.init(InterruptExecutor::new(irq));
124 let spawner = executor.start();
125 unwrap!(spawner.spawn(run_high())); 137 unwrap!(spawner.spawn(run_high()));
126 138
127 // Medium-priority executor: USART2, priority level 7 139 // Medium-priority executor: USART2, priority level 7
128 let irq = interrupt::take!(USART2); 140 unsafe { nvic.set_priority(Interrupt::USART2, 7 << 4) };
129 irq.set_priority(interrupt::Priority::P7); 141 let spawner = EXECUTOR_MED.start(Interrupt::USART2);
130 let executor = EXECUTOR_MED.init(InterruptExecutor::new(irq));
131 let spawner = executor.start();
132 unwrap!(spawner.spawn(run_med())); 142 unwrap!(spawner.spawn(run_med()));
133 143
134 // Low priority executor: runs in thread mode, using WFE/SEV 144 // Low priority executor: runs in thread mode, using WFE/SEV
diff --git a/examples/stm32f3/src/bin/multiprio.rs b/examples/stm32f3/src/bin/multiprio.rs
index 9e8228a4b..77df51ac7 100644
--- a/examples/stm32f3/src/bin/multiprio.rs
+++ b/examples/stm32f3/src/bin/multiprio.rs
@@ -57,11 +57,14 @@
57#![no_main] 57#![no_main]
58#![feature(type_alias_impl_trait)] 58#![feature(type_alias_impl_trait)]
59 59
60use core::mem;
61
62use cortex_m::peripheral::NVIC;
60use cortex_m_rt::entry; 63use cortex_m_rt::entry;
61use defmt::*; 64use defmt::*;
62use embassy_stm32::executor::{Executor, InterruptExecutor}; 65use embassy_stm32::executor::{Executor, InterruptExecutor};
63use embassy_stm32::interrupt; 66use embassy_stm32::interrupt;
64use embassy_stm32::interrupt::InterruptExt; 67use embassy_stm32::pac::Interrupt;
65use embassy_time::{Duration, Instant, Timer}; 68use embassy_time::{Duration, Instant, Timer};
66use static_cell::StaticCell; 69use static_cell::StaticCell;
67use {defmt_rtt as _, panic_probe as _}; 70use {defmt_rtt as _, panic_probe as _};
@@ -108,28 +111,35 @@ async fn run_low() {
108 } 111 }
109} 112}
110 113
111static EXECUTOR_HIGH: StaticCell<InterruptExecutor<interrupt::UART4>> = StaticCell::new(); 114static EXECUTOR_HIGH: InterruptExecutor = InterruptExecutor::new();
112static EXECUTOR_MED: StaticCell<InterruptExecutor<interrupt::UART5>> = StaticCell::new(); 115static EXECUTOR_MED: InterruptExecutor = InterruptExecutor::new();
113static EXECUTOR_LOW: StaticCell<Executor> = StaticCell::new(); 116static EXECUTOR_LOW: StaticCell<Executor> = StaticCell::new();
114 117
118#[interrupt]
119unsafe fn UART4() {
120 EXECUTOR_HIGH.on_interrupt()
121}
122
123#[interrupt]
124unsafe fn UART5() {
125 EXECUTOR_MED.on_interrupt()
126}
127
115#[entry] 128#[entry]
116fn main() -> ! { 129fn main() -> ! {
117 info!("Hello World!"); 130 info!("Hello World!");
118 131
119 let _p = embassy_stm32::init(Default::default()); 132 let _p = embassy_stm32::init(Default::default());
133 let mut nvic: NVIC = unsafe { mem::transmute(()) };
120 134
121 // High-priority executor: SWI1_EGU1, priority level 6 135 // High-priority executor: UART4, priority level 6
122 let irq = interrupt::take!(UART4); 136 unsafe { nvic.set_priority(Interrupt::UART4, 6 << 4) };
123 irq.set_priority(interrupt::Priority::P6); 137 let spawner = EXECUTOR_HIGH.start(Interrupt::UART4);
124 let executor = EXECUTOR_HIGH.init(InterruptExecutor::new(irq));
125 let spawner = executor.start();
126 unwrap!(spawner.spawn(run_high())); 138 unwrap!(spawner.spawn(run_high()));
127 139
128 // Medium-priority executor: SWI0_EGU0, priority level 7 140 // Medium-priority executor: UART5, priority level 7
129 let irq = interrupt::take!(UART5); 141 unsafe { nvic.set_priority(Interrupt::UART5, 7 << 4) };
130 irq.set_priority(interrupt::Priority::P7); 142 let spawner = EXECUTOR_MED.start(Interrupt::UART5);
131 let executor = EXECUTOR_MED.init(InterruptExecutor::new(irq));
132 let spawner = executor.start();
133 unwrap!(spawner.spawn(run_med())); 143 unwrap!(spawner.spawn(run_med()));
134 144
135 // Low priority executor: runs in thread mode, using WFE/SEV 145 // Low priority executor: runs in thread mode, using WFE/SEV
diff --git a/examples/stm32f4/Cargo.toml b/examples/stm32f4/Cargo.toml
index e2b17bfcb..7a7bab5bb 100644
--- a/examples/stm32f4/Cargo.toml
+++ b/examples/stm32f4/Cargo.toml
@@ -10,7 +10,7 @@ embassy-executor = { version = "0.1.0", path = "../../embassy-executor", feature
10embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "unstable-traits", "tick-hz-32_768"] } 10embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "unstable-traits", "tick-hz-32_768"] }
11embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "unstable-traits", "defmt", "stm32f429zi", "unstable-pac", "memory-x", "time-driver-any", "exti"] } 11embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "unstable-traits", "defmt", "stm32f429zi", "unstable-pac", "memory-x", "time-driver-any", "exti"] }
12embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } 12embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] }
13embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "nightly"], optional = true } 13embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "nightly"] }
14 14
15defmt = "0.3" 15defmt = "0.3"
16defmt-rtt = "0.4" 16defmt-rtt = "0.4"
@@ -27,9 +27,5 @@ embedded-storage = "0.3.0"
27micromath = "2.0.0" 27micromath = "2.0.0"
28static_cell = "1.0" 28static_cell = "1.0"
29 29
30[[bin]]
31name = "usb_ethernet"
32required-features = ["embassy-net"]
33
34[profile.release] 30[profile.release]
35debug = 2 31debug = 2
diff --git a/examples/stm32f4/src/bin/multiprio.rs b/examples/stm32f4/src/bin/multiprio.rs
index 9e8228a4b..77df51ac7 100644
--- a/examples/stm32f4/src/bin/multiprio.rs
+++ b/examples/stm32f4/src/bin/multiprio.rs
@@ -57,11 +57,14 @@
57#![no_main] 57#![no_main]
58#![feature(type_alias_impl_trait)] 58#![feature(type_alias_impl_trait)]
59 59
60use core::mem;
61
62use cortex_m::peripheral::NVIC;
60use cortex_m_rt::entry; 63use cortex_m_rt::entry;
61use defmt::*; 64use defmt::*;
62use embassy_stm32::executor::{Executor, InterruptExecutor}; 65use embassy_stm32::executor::{Executor, InterruptExecutor};
63use embassy_stm32::interrupt; 66use embassy_stm32::interrupt;
64use embassy_stm32::interrupt::InterruptExt; 67use embassy_stm32::pac::Interrupt;
65use embassy_time::{Duration, Instant, Timer}; 68use embassy_time::{Duration, Instant, Timer};
66use static_cell::StaticCell; 69use static_cell::StaticCell;
67use {defmt_rtt as _, panic_probe as _}; 70use {defmt_rtt as _, panic_probe as _};
@@ -108,28 +111,35 @@ async fn run_low() {
108 } 111 }
109} 112}
110 113
111static EXECUTOR_HIGH: StaticCell<InterruptExecutor<interrupt::UART4>> = StaticCell::new(); 114static EXECUTOR_HIGH: InterruptExecutor = InterruptExecutor::new();
112static EXECUTOR_MED: StaticCell<InterruptExecutor<interrupt::UART5>> = StaticCell::new(); 115static EXECUTOR_MED: InterruptExecutor = InterruptExecutor::new();
113static EXECUTOR_LOW: StaticCell<Executor> = StaticCell::new(); 116static EXECUTOR_LOW: StaticCell<Executor> = StaticCell::new();
114 117
118#[interrupt]
119unsafe fn UART4() {
120 EXECUTOR_HIGH.on_interrupt()
121}
122
123#[interrupt]
124unsafe fn UART5() {
125 EXECUTOR_MED.on_interrupt()
126}
127
115#[entry] 128#[entry]
116fn main() -> ! { 129fn main() -> ! {
117 info!("Hello World!"); 130 info!("Hello World!");
118 131
119 let _p = embassy_stm32::init(Default::default()); 132 let _p = embassy_stm32::init(Default::default());
133 let mut nvic: NVIC = unsafe { mem::transmute(()) };
120 134
121 // High-priority executor: SWI1_EGU1, priority level 6 135 // High-priority executor: UART4, priority level 6
122 let irq = interrupt::take!(UART4); 136 unsafe { nvic.set_priority(Interrupt::UART4, 6 << 4) };
123 irq.set_priority(interrupt::Priority::P6); 137 let spawner = EXECUTOR_HIGH.start(Interrupt::UART4);
124 let executor = EXECUTOR_HIGH.init(InterruptExecutor::new(irq));
125 let spawner = executor.start();
126 unwrap!(spawner.spawn(run_high())); 138 unwrap!(spawner.spawn(run_high()));
127 139
128 // Medium-priority executor: SWI0_EGU0, priority level 7 140 // Medium-priority executor: UART5, priority level 7
129 let irq = interrupt::take!(UART5); 141 unsafe { nvic.set_priority(Interrupt::UART5, 7 << 4) };
130 irq.set_priority(interrupt::Priority::P7); 142 let spawner = EXECUTOR_MED.start(Interrupt::UART5);
131 let executor = EXECUTOR_MED.init(InterruptExecutor::new(irq));
132 let spawner = executor.start();
133 unwrap!(spawner.spawn(run_med())); 143 unwrap!(spawner.spawn(run_med()));
134 144
135 // Low priority executor: runs in thread mode, using WFE/SEV 145 // Low priority executor: runs in thread mode, using WFE/SEV
diff --git a/examples/stm32f4/src/bin/usb_ethernet.rs b/examples/stm32f4/src/bin/usb_ethernet.rs
index 4a16aac07..db9e18393 100644
--- a/examples/stm32f4/src/bin/usb_ethernet.rs
+++ b/examples/stm32f4/src/bin/usb_ethernet.rs
@@ -100,8 +100,8 @@ async fn main(spawner: Spawner) {
100 let (runner, device) = class.into_embassy_net_device::<MTU, 4, 4>(singleton!(NetState::new()), our_mac_addr); 100 let (runner, device) = class.into_embassy_net_device::<MTU, 4, 4>(singleton!(NetState::new()), our_mac_addr);
101 unwrap!(spawner.spawn(usb_ncm_task(runner))); 101 unwrap!(spawner.spawn(usb_ncm_task(runner)));
102 102
103 let config = embassy_net::ConfigStrategy::Dhcp; 103 let config = embassy_net::Config::Dhcp(Default::default());
104 //let config = embassy_net::ConfigStrategy::Static(embassy_net::Config { 104 //let config = embassy_net::Config::Static(embassy_net::StaticConfig {
105 // address: Ipv4Cidr::new(Ipv4Address::new(10, 42, 0, 61), 24), 105 // address: Ipv4Cidr::new(Ipv4Address::new(10, 42, 0, 61), 24),
106 // dns_servers: Vec::new(), 106 // dns_servers: Vec::new(),
107 // gateway: Some(Ipv4Address::new(10, 42, 0, 1)), 107 // gateway: Some(Ipv4Address::new(10, 42, 0, 1)),
@@ -114,12 +114,7 @@ async fn main(spawner: Spawner) {
114 let seed = u64::from_le_bytes(seed); 114 let seed = u64::from_le_bytes(seed);
115 115
116 // Init network stack 116 // Init network stack
117 let stack = &*singleton!(Stack::new( 117 let stack = &*singleton!(Stack::new(device, config, singleton!(StackResources::<2>::new()), seed));
118 device,
119 config,
120 singleton!(StackResources::<1, 2, 8>::new()),
121 seed
122 ));
123 118
124 unwrap!(spawner.spawn(net_task(stack))); 119 unwrap!(spawner.spawn(net_task(stack)));
125 120
diff --git a/examples/stm32l4/Cargo.toml b/examples/stm32l4/Cargo.toml
index 5627760ef..644c90b1a 100644
--- a/examples/stm32l4/Cargo.toml
+++ b/examples/stm32l4/Cargo.toml
@@ -4,8 +4,6 @@ name = "embassy-stm32l4-examples"
4version = "0.1.0" 4version = "0.1.0"
5license = "MIT OR Apache-2.0" 5license = "MIT OR Apache-2.0"
6 6
7[features]
8
9[dependencies] 7[dependencies]
10embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] } 8embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] }
11embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["defmt", "integrated-timers"] } 9embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["defmt", "integrated-timers"] }
diff --git a/examples/stm32l5/Cargo.toml b/examples/stm32l5/Cargo.toml
index c0accb0d6..f880328dc 100644
--- a/examples/stm32l5/Cargo.toml
+++ b/examples/stm32l5/Cargo.toml
@@ -4,8 +4,6 @@ name = "embassy-stm32l5-examples"
4version = "0.1.0" 4version = "0.1.0"
5license = "MIT OR Apache-2.0" 5license = "MIT OR Apache-2.0"
6 6
7[features]
8
9[dependencies] 7[dependencies]
10embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] } 8embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] }
11embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["defmt", "integrated-timers"] } 9embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["defmt", "integrated-timers"] }
diff --git a/tests/nrf/.cargo/config.toml b/tests/nrf/.cargo/config.toml
new file mode 100644
index 000000000..4eec189d4
--- /dev/null
+++ b/tests/nrf/.cargo/config.toml
@@ -0,0 +1,9 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2#runner = "teleprobe local run --chip nRF52840_xxAA --elf"
3runner = "teleprobe client run --target nrf52840-dk --elf"
4
5[build]
6target = "thumbv7em-none-eabi"
7
8[env]
9DEFMT_LOG = "trace"
diff --git a/tests/nrf/Cargo.toml b/tests/nrf/Cargo.toml
new file mode 100644
index 000000000..2a4e8cf41
--- /dev/null
+++ b/tests/nrf/Cargo.toml
@@ -0,0 +1,20 @@
1[package]
2edition = "2021"
3name = "embassy-nrf-examples"
4version = "0.1.0"
5license = "MIT OR Apache-2.0"
6
7[dependencies]
8embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
9embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt", "nightly"] }
10embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["defmt", "nightly", "integrated-timers"] }
11embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "nightly", "defmt-timestamp-uptime"] }
12embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["defmt", "nightly", "unstable-traits", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac"] }
13embedded-io = { version = "0.4.0", features = ["async"] }
14
15defmt = "0.3"
16defmt-rtt = "0.4"
17
18cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] }
19cortex-m-rt = "0.7.0"
20panic-probe = { version = "0.3", features = ["print-defmt"] } \ No newline at end of file
diff --git a/tests/nrf/build.rs b/tests/nrf/build.rs
new file mode 100644
index 000000000..6f4872249
--- /dev/null
+++ b/tests/nrf/build.rs
@@ -0,0 +1,16 @@
1use std::error::Error;
2use std::path::PathBuf;
3use std::{env, fs};
4
5fn main() -> Result<(), Box<dyn Error>> {
6 let out = PathBuf::from(env::var("OUT_DIR").unwrap());
7 fs::write(out.join("link_ram.x"), include_bytes!("link_ram.x")).unwrap();
8 println!("cargo:rustc-link-search={}", out.display());
9 println!("cargo:rerun-if-changed=link_ram.x");
10
11 println!("cargo:rustc-link-arg-bins=--nmagic");
12 println!("cargo:rustc-link-arg-bins=-Tlink_ram.x");
13 println!("cargo:rustc-link-arg-bins=-Tdefmt.x");
14
15 Ok(())
16}
diff --git a/tests/nrf/link_ram.x b/tests/nrf/link_ram.x
new file mode 100644
index 000000000..26da86baa
--- /dev/null
+++ b/tests/nrf/link_ram.x
@@ -0,0 +1,254 @@
1/* ##### EMBASSY NOTE
2 Originally from https://github.com/rust-embedded/cortex-m-rt/blob/master/link.x.in
3 Adjusted to put everything in RAM
4*/
5
6/* # Developer notes
7
8- Symbols that start with a double underscore (__) are considered "private"
9
10- Symbols that start with a single underscore (_) are considered "semi-public"; they can be
11 overridden in a user linker script, but should not be referred from user code (e.g. `extern "C" {
12 static mut __sbss }`).
13
14- `EXTERN` forces the linker to keep a symbol in the final binary. We use this to make sure a
15 symbol if not dropped if it appears in or near the front of the linker arguments and "it's not
16 needed" by any of the preceding objects (linker arguments)
17
18- `PROVIDE` is used to provide default values that can be overridden by a user linker script
19
20- On alignment: it's important for correctness that the VMA boundaries of both .bss and .data *and*
21 the LMA of .data are all 4-byte aligned. These alignments are assumed by the RAM initialization
22 routine. There's also a second benefit: 4-byte aligned boundaries means that you won't see
23 "Address (..) is out of bounds" in the disassembly produced by `objdump`.
24*/
25
26/* Provides information about the memory layout of the device */
27/* This will be provided by the user (see `memory.x`) or by a Board Support Crate */
28INCLUDE memory.x
29
30/* # Entry point = reset vector */
31EXTERN(__RESET_VECTOR);
32EXTERN(Reset);
33ENTRY(Reset);
34
35/* # Exception vectors */
36/* This is effectively weak aliasing at the linker level */
37/* The user can override any of these aliases by defining the corresponding symbol themselves (cf.
38 the `exception!` macro) */
39EXTERN(__EXCEPTIONS); /* depends on all the these PROVIDED symbols */
40
41EXTERN(DefaultHandler);
42
43PROVIDE(NonMaskableInt = DefaultHandler);
44EXTERN(HardFaultTrampoline);
45PROVIDE(MemoryManagement = DefaultHandler);
46PROVIDE(BusFault = DefaultHandler);
47PROVIDE(UsageFault = DefaultHandler);
48PROVIDE(SecureFault = DefaultHandler);
49PROVIDE(SVCall = DefaultHandler);
50PROVIDE(DebugMonitor = DefaultHandler);
51PROVIDE(PendSV = DefaultHandler);
52PROVIDE(SysTick = DefaultHandler);
53
54PROVIDE(DefaultHandler = DefaultHandler_);
55PROVIDE(HardFault = HardFault_);
56
57/* # Interrupt vectors */
58EXTERN(__INTERRUPTS); /* `static` variable similar to `__EXCEPTIONS` */
59
60/* # Pre-initialization function */
61/* If the user overrides this using the `pre_init!` macro or by creating a `__pre_init` function,
62 then the function this points to will be called before the RAM is initialized. */
63PROVIDE(__pre_init = DefaultPreInit);
64
65/* # Sections */
66SECTIONS
67{
68 PROVIDE(_stack_start = ORIGIN(RAM) + LENGTH(RAM));
69
70 /* ## Sections in RAM */
71 /* ### Vector table */
72 .vector_table ORIGIN(RAM) :
73 {
74 /* Initial Stack Pointer (SP) value */
75 LONG(_stack_start);
76
77 /* Reset vector */
78 KEEP(*(.vector_table.reset_vector)); /* this is the `__RESET_VECTOR` symbol */
79 __reset_vector = .;
80
81 /* Exceptions */
82 KEEP(*(.vector_table.exceptions)); /* this is the `__EXCEPTIONS` symbol */
83 __eexceptions = .;
84
85 /* Device specific interrupts */
86 KEEP(*(.vector_table.interrupts)); /* this is the `__INTERRUPTS` symbol */
87 } > RAM
88
89 PROVIDE(_stext = ADDR(.vector_table) + SIZEOF(.vector_table));
90
91 /* ### .text */
92 .text _stext :
93 {
94 __stext = .;
95 *(.Reset);
96
97 *(.text .text.*);
98
99 /* The HardFaultTrampoline uses the `b` instruction to enter `HardFault`,
100 so must be placed close to it. */
101 *(.HardFaultTrampoline);
102 *(.HardFault.*);
103
104 . = ALIGN(4); /* Pad .text to the alignment to workaround overlapping load section bug in old lld */
105 __etext = .;
106 } > RAM
107
108 /* ### .rodata */
109 .rodata : ALIGN(4)
110 {
111 . = ALIGN(4);
112 __srodata = .;
113 *(.rodata .rodata.*);
114
115 /* 4-byte align the end (VMA) of this section.
116 This is required by LLD to ensure the LMA of the following .data
117 section will have the correct alignment. */
118 . = ALIGN(4);
119 __erodata = .;
120 } > RAM
121
122 /* ## Sections in RAM */
123 /* ### .data */
124 .data : ALIGN(4)
125 {
126 . = ALIGN(4);
127 __sdata = .;
128 __edata = .;
129 *(.data .data.*);
130 . = ALIGN(4); /* 4-byte align the end (VMA) of this section */
131 } > RAM
132 /* Allow sections from user `memory.x` injected using `INSERT AFTER .data` to
133 * use the .data loading mechanism by pushing __edata. Note: do not change
134 * output region or load region in those user sections! */
135 . = ALIGN(4);
136
137 /* LMA of .data */
138 __sidata = LOADADDR(.data);
139
140 /* ### .gnu.sgstubs
141 This section contains the TrustZone-M veneers put there by the Arm GNU linker. */
142 /* Security Attribution Unit blocks must be 32 bytes aligned. */
143 /* Note that this pads the RAM usage to 32 byte alignment. */
144 .gnu.sgstubs : ALIGN(32)
145 {
146 . = ALIGN(32);
147 __veneer_base = .;
148 *(.gnu.sgstubs*)
149 . = ALIGN(32);
150 __veneer_limit = .;
151 } > RAM
152
153 /* ### .bss */
154 .bss (NOLOAD) : ALIGN(4)
155 {
156 . = ALIGN(4);
157 __sbss = .;
158 *(.bss .bss.*);
159 *(COMMON); /* Uninitialized C statics */
160 . = ALIGN(4); /* 4-byte align the end (VMA) of this section */
161 } > RAM
162 /* Allow sections from user `memory.x` injected using `INSERT AFTER .bss` to
163 * use the .bss zeroing mechanism by pushing __ebss. Note: do not change
164 * output region or load region in those user sections! */
165 . = ALIGN(4);
166 __ebss = .;
167
168 /* ### .uninit */
169 .uninit (NOLOAD) : ALIGN(4)
170 {
171 . = ALIGN(4);
172 __suninit = .;
173 *(.uninit .uninit.*);
174 . = ALIGN(4);
175 __euninit = .;
176 } > RAM
177
178 /* Place the heap right after `.uninit` in RAM */
179 PROVIDE(__sheap = __euninit);
180
181 /* ## .got */
182 /* Dynamic relocations are unsupported. This section is only used to detect relocatable code in
183 the input files and raise an error if relocatable code is found */
184 .got (NOLOAD) :
185 {
186 KEEP(*(.got .got.*));
187 }
188
189 /* ## Discarded sections */
190 /DISCARD/ :
191 {
192 /* Unused exception related info that only wastes space */
193 *(.ARM.exidx);
194 *(.ARM.exidx.*);
195 *(.ARM.extab.*);
196 }
197}
198
199/* Do not exceed this mark in the error messages below | */
200/* # Alignment checks */
201ASSERT(ORIGIN(RAM) % 4 == 0, "
202ERROR(cortex-m-rt): the start of the RAM region must be 4-byte aligned");
203
204ASSERT(__sdata % 4 == 0 && __edata % 4 == 0, "
205BUG(cortex-m-rt): .data is not 4-byte aligned");
206
207ASSERT(__sidata % 4 == 0, "
208BUG(cortex-m-rt): the LMA of .data is not 4-byte aligned");
209
210ASSERT(__sbss % 4 == 0 && __ebss % 4 == 0, "
211BUG(cortex-m-rt): .bss is not 4-byte aligned");
212
213ASSERT(__sheap % 4 == 0, "
214BUG(cortex-m-rt): start of .heap is not 4-byte aligned");
215
216/* # Position checks */
217
218/* ## .vector_table */
219ASSERT(__reset_vector == ADDR(.vector_table) + 0x8, "
220BUG(cortex-m-rt): the reset vector is missing");
221
222ASSERT(__eexceptions == ADDR(.vector_table) + 0x40, "
223BUG(cortex-m-rt): the exception vectors are missing");
224
225ASSERT(SIZEOF(.vector_table) > 0x40, "
226ERROR(cortex-m-rt): The interrupt vectors are missing.
227Possible solutions, from most likely to less likely:
228- Link to a svd2rust generated device crate
229- Check that you actually use the device/hal/bsp crate in your code
230- Disable the 'device' feature of cortex-m-rt to build a generic application (a dependency
231may be enabling it)
232- Supply the interrupt handlers yourself. Check the documentation for details.");
233
234/* ## .text */
235ASSERT(ADDR(.vector_table) + SIZEOF(.vector_table) <= _stext, "
236ERROR(cortex-m-rt): The .text section can't be placed inside the .vector_table section
237Set _stext to an address greater than the end of .vector_table (See output of `nm`)");
238
239ASSERT(_stext + SIZEOF(.text) < ORIGIN(RAM) + LENGTH(RAM), "
240ERROR(cortex-m-rt): The .text section must be placed inside the RAM memory.
241Set _stext to an address smaller than 'ORIGIN(RAM) + LENGTH(RAM)'");
242
243/* # Other checks */
244ASSERT(SIZEOF(.got) == 0, "
245ERROR(cortex-m-rt): .got section detected in the input object files
246Dynamic relocations are not supported. If you are linking to C code compiled using
247the 'cc' crate then modify your build script to compile the C code _without_
248the -fPIC flag. See the documentation of the `cc::Build.pic` method for details.");
249/* Do not exceed this mark in the error messages above | */
250
251
252/* Provides weak aliases (cf. PROVIDED) for device specific interrupt handlers */
253/* This will usually be provided by a device crate generated using svd2rust (see `device.x`) */
254INCLUDE device.x \ No newline at end of file
diff --git a/tests/nrf/memory.x b/tests/nrf/memory.x
new file mode 100644
index 000000000..58900a7bd
--- /dev/null
+++ b/tests/nrf/memory.x
@@ -0,0 +1,5 @@
1MEMORY
2{
3 FLASH : ORIGIN = 0x00000000, LENGTH = 1024K
4 RAM : ORIGIN = 0x20000000, LENGTH = 256K
5}
diff --git a/tests/nrf/src/bin/buffered_uart.rs b/tests/nrf/src/bin/buffered_uart.rs
new file mode 100644
index 000000000..e73d4f0b0
--- /dev/null
+++ b/tests/nrf/src/bin/buffered_uart.rs
@@ -0,0 +1,78 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use defmt::{assert_eq, *};
6use embassy_executor::Spawner;
7use embassy_futures::join::join;
8use embassy_nrf::buffered_uarte::{self, BufferedUarte};
9use embassy_nrf::{bind_interrupts, peripherals, uarte};
10use {defmt_rtt as _, panic_probe as _};
11
12bind_interrupts!(struct Irqs {
13 UARTE0_UART0 => buffered_uarte::InterruptHandler<peripherals::UARTE0>;
14});
15
16#[embassy_executor::main]
17async fn main(_spawner: Spawner) {
18 let p = embassy_nrf::init(Default::default());
19 let mut config = uarte::Config::default();
20 config.parity = uarte::Parity::EXCLUDED;
21 config.baudrate = uarte::Baudrate::BAUD1M;
22
23 let mut tx_buffer = [0u8; 1024];
24 let mut rx_buffer = [0u8; 1024];
25
26 let mut u = BufferedUarte::new(
27 p.UARTE0,
28 p.TIMER0,
29 p.PPI_CH0,
30 p.PPI_CH1,
31 p.PPI_GROUP0,
32 Irqs,
33 p.P1_03,
34 p.P1_02,
35 config.clone(),
36 &mut rx_buffer,
37 &mut tx_buffer,
38 );
39
40 info!("uarte initialized!");
41
42 let (mut rx, mut tx) = u.split();
43
44 const COUNT: usize = 40_000;
45
46 let tx_fut = async {
47 let mut tx_buf = [0; 215];
48 let mut i = 0;
49 while i < COUNT {
50 let n = tx_buf.len().min(COUNT - i);
51 let tx_buf = &mut tx_buf[..n];
52 for (j, b) in tx_buf.iter_mut().enumerate() {
53 *b = (i + j) as u8;
54 }
55 let n = unwrap!(tx.write(tx_buf).await);
56 i += n;
57 }
58 };
59 let rx_fut = async {
60 let mut i = 0;
61 while i < COUNT {
62 let buf = unwrap!(rx.fill_buf().await);
63
64 for &b in buf {
65 assert_eq!(b, i as u8);
66 i = i + 1;
67 }
68
69 let n = buf.len();
70 rx.consume(n);
71 }
72 };
73
74 join(rx_fut, tx_fut).await;
75
76 info!("Test OK");
77 cortex_m::asm::bkpt();
78}
diff --git a/tests/nrf/src/bin/buffered_uart_spam.rs b/tests/nrf/src/bin/buffered_uart_spam.rs
new file mode 100644
index 000000000..74eda6d01
--- /dev/null
+++ b/tests/nrf/src/bin/buffered_uart_spam.rs
@@ -0,0 +1,91 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use core::mem;
6use core::ptr::NonNull;
7
8use defmt::{assert_eq, *};
9use embassy_executor::Spawner;
10use embassy_nrf::buffered_uarte::{self, BufferedUarte};
11use embassy_nrf::gpio::{Level, Output, OutputDrive};
12use embassy_nrf::ppi::{Event, Ppi, Task};
13use embassy_nrf::uarte::Uarte;
14use embassy_nrf::{bind_interrupts, pac, peripherals, uarte};
15use embassy_time::{Duration, Timer};
16use {defmt_rtt as _, panic_probe as _};
17
18bind_interrupts!(struct Irqs {
19 UARTE0_UART0 => buffered_uarte::InterruptHandler<peripherals::UARTE0>;
20 UARTE1 => uarte::InterruptHandler<peripherals::UARTE1>;
21});
22
23#[embassy_executor::main]
24async fn main(_spawner: Spawner) {
25 let mut p = embassy_nrf::init(Default::default());
26 let mut config = uarte::Config::default();
27 config.parity = uarte::Parity::EXCLUDED;
28 config.baudrate = uarte::Baudrate::BAUD1M;
29
30 let mut tx_buffer = [0u8; 1024];
31 let mut rx_buffer = [0u8; 1024];
32
33 mem::forget(Output::new(&mut p.P1_02, Level::High, OutputDrive::Standard));
34
35 let mut u = BufferedUarte::new(
36 p.UARTE0,
37 p.TIMER0,
38 p.PPI_CH0,
39 p.PPI_CH1,
40 p.PPI_GROUP0,
41 Irqs,
42 p.P1_03,
43 p.P1_04,
44 config.clone(),
45 &mut rx_buffer,
46 &mut tx_buffer,
47 );
48
49 info!("uarte initialized!");
50
51 // uarte needs some quiet time to start rxing properly.
52 Timer::after(Duration::from_millis(10)).await;
53
54 // Tx spam in a loop.
55 const NSPAM: usize = 17;
56 static mut TX_BUF: [u8; NSPAM] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16];
57 let _spam = Uarte::new(p.UARTE1, Irqs, p.P1_01, p.P1_02, config.clone());
58 let spam_peri: pac::UARTE1 = unsafe { mem::transmute(()) };
59 let event = unsafe { Event::new_unchecked(NonNull::new_unchecked(&spam_peri.events_endtx as *const _ as _)) };
60 let task = unsafe { Task::new_unchecked(NonNull::new_unchecked(&spam_peri.tasks_starttx as *const _ as _)) };
61 let mut spam_ppi = Ppi::new_one_to_one(p.PPI_CH2, event, task);
62 spam_ppi.enable();
63 let p = unsafe { TX_BUF.as_mut_ptr() };
64 spam_peri.txd.ptr.write(|w| unsafe { w.ptr().bits(p as u32) });
65 spam_peri.txd.maxcnt.write(|w| unsafe { w.maxcnt().bits(NSPAM as _) });
66 spam_peri.tasks_starttx.write(|w| unsafe { w.bits(1) });
67
68 let mut i = 0;
69 let mut total = 0;
70 while total < 256 * 1024 {
71 let buf = unwrap!(u.fill_buf().await);
72 //info!("rx {}", buf);
73
74 for &b in buf {
75 assert_eq!(b, unsafe { TX_BUF[i] });
76
77 i = i + 1;
78 if i == NSPAM {
79 i = 0;
80 }
81 }
82
83 // Read bytes have to be explicitly consumed, otherwise fill_buf() will return them again
84 let n = buf.len();
85 u.consume(n);
86 total += n;
87 }
88
89 info!("Test OK");
90 cortex_m::asm::bkpt();
91}