diff options
| author | Mehmet Ali Anil <[email protected]> | 2023-03-07 10:46:59 +0100 |
|---|---|---|
| committer | Mehmet Ali Anil <[email protected]> | 2023-03-07 23:16:54 +0100 |
| commit | 935633c90b817b15c6c2cf180e107992ad5dd9a6 (patch) | |
| tree | 5e4c33aa5992a7eb941a0920b0c080a624cd15a5 | |
| parent | bc0cb43307c2a46330ce253505203dbc607bcc6c (diff) | |
| parent | 18fe398673f55b07159d01a230910bb9689c1525 (diff) | |
Merge upstream
105 files changed, 3053 insertions, 1581 deletions
| @@ -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** - |
| 19 | No 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. | 23 | No 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. |
| @@ -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)] |
| 1197 | mod tests { | 1198 | mod 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. |
| 2 | use core::marker::PhantomData; | ||
| 3 | 2 | ||
| 3 | use core::cell::UnsafeCell; | ||
| 4 | use core::mem::MaybeUninit; | ||
| 5 | |||
| 6 | use atomic_polyfill::{AtomicBool, Ordering}; | ||
| 7 | use cortex_m::interrupt::InterruptNumber; | ||
| 8 | use cortex_m::peripheral::NVIC; | ||
| 4 | pub use embassy_executor::*; | 9 | pub use embassy_executor::*; |
| 5 | 10 | ||
| 6 | use crate::interrupt::{Interrupt, InterruptExt}; | 11 | #[derive(Clone, Copy)] |
| 12 | struct N(u16); | ||
| 13 | unsafe impl cortex_m::interrupt::InterruptNumber for N { | ||
| 14 | fn number(self) -> u16 { | ||
| 15 | self.0 | ||
| 16 | } | ||
| 17 | } | ||
| 7 | 18 | ||
| 8 | fn pend_by_number(n: u16) { | 19 | fn 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. |
| 40 | pub struct InterruptExecutor<I: Interrupt> { | 44 | pub 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 | ||
| 46 | impl<I: Interrupt> InterruptExecutor<I> { | 49 | unsafe impl Send for InterruptExecutor {} |
| 47 | /// Create a new Executor. | 50 | unsafe impl Sync for InterruptExecutor {} |
| 48 | pub fn new(irq: I) -> Self { | 51 | |
| 49 | let ctx = irq.number() as *mut (); | 52 | impl 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. | ||
| 21 | pub 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. | ||
| 44 | pub 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)] |
| 18 | pub struct Handler { | 48 | pub struct DynHandler { |
| 19 | pub func: AtomicPtr<()>, | 49 | pub func: AtomicPtr<()>, |
| 20 | pub ctx: AtomicPtr<()>, | 50 | pub ctx: AtomicPtr<()>, |
| 21 | } | 51 | } |
| 22 | 52 | ||
| 23 | impl Handler { | 53 | impl 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"] | ||
| 27 | struct YieldNowFuture { | 28 | struct 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). |
| 16 | pub struct RingBuffer { | 16 | pub 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 | ||
| 23 | pub struct Reader<'a>(&'a RingBuffer); | 31 | pub 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 | ||
| 16 | use core::cell::RefCell; | ||
| 17 | use core::cmp::min; | 11 | use core::cmp::min; |
| 18 | use core::future::poll_fn; | 12 | use core::future::poll_fn; |
| 19 | use core::sync::atomic::{compiler_fence, Ordering}; | 13 | use core::marker::PhantomData; |
| 14 | use core::slice; | ||
| 15 | use core::sync::atomic::{compiler_fence, AtomicU8, AtomicUsize, Ordering}; | ||
| 20 | use core::task::Poll; | 16 | use core::task::Poll; |
| 21 | 17 | ||
| 22 | use embassy_cortex_m::peripheral::{PeripheralMutex, PeripheralState, StateStorage}; | 18 | use embassy_cortex_m::interrupt::Interrupt; |
| 23 | use embassy_hal_common::ring_buffer::RingBuffer; | 19 | use embassy_hal_common::atomic_ring_buffer::RingBuffer; |
| 24 | use embassy_hal_common::{into_ref, PeripheralRef}; | 20 | use embassy_hal_common::{into_ref, PeripheralRef}; |
| 25 | use embassy_sync::waitqueue::WakerRegistration; | 21 | use 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 |
| 27 | pub use pac::uarte0::{baudrate::BAUDRATE_A as Baudrate, config::PARITY_A as Parity}; | 23 | pub use pac::uarte0::{baudrate::BAUDRATE_A as Baudrate, config::PARITY_A as Parity}; |
| 28 | 24 | ||
| 29 | use crate::gpio::{self, Pin as GpioPin}; | 25 | use crate::gpio::sealed::Pin; |
| 30 | use crate::interrupt::InterruptExt; | 26 | use crate::gpio::{self, AnyPin, Pin as GpioPin, PselBits}; |
| 31 | use crate::ppi::{AnyConfigurableChannel, ConfigurableChannel, Event, Ppi, Task}; | 27 | use crate::interrupt::{self, InterruptExt}; |
| 32 | use crate::timer::{Frequency, Instance as TimerInstance, Timer}; | 28 | use crate::ppi::{ |
| 29 | self, AnyConfigurableChannel, AnyGroup, Channel, ConfigurableChannel, Event, Group, Ppi, PpiGroup, Task, | ||
| 30 | }; | ||
| 31 | use crate::timer::{Instance as TimerInstance, Timer}; | ||
| 33 | use crate::uarte::{apply_workaround_for_enable_anomaly, Config, Instance as UarteInstance}; | 32 | use crate::uarte::{apply_workaround_for_enable_anomaly, Config, Instance as UarteInstance}; |
| 34 | use crate::{pac, Peripheral}; | 33 | use crate::{pac, Peripheral}; |
| 35 | 34 | ||
| 36 | #[derive(Copy, Clone, Debug, PartialEq)] | 35 | mod sealed { |
| 37 | enum 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. |
| 43 | enum TxState { | 51 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] |
| 44 | Idle, | 52 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] |
| 45 | Transmitting(usize), | 53 | #[non_exhaustive] |
| 54 | pub 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. | 58 | pub(crate) use sealed::State; |
| 49 | pub struct State<'d, U: UarteInstance, T: TimerInstance>(StateStorage<StateInner<'d, U, T>>); | 59 | |
| 50 | impl<'d, U: UarteInstance, T: TimerInstance> State<'d, U, T> { | 60 | impl 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 | ||
| 57 | struct StateInner<'d, U: UarteInstance, T: TimerInstance> { | 75 | /// Interrupt handler. |
| 58 | _peri: PeripheralRef<'d, U>, | 76 | pub 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 | |
| 80 | impl<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. |
| 73 | pub struct BufferedUarte<'d, U: UarteInstance, T: TimerInstance> { | 183 | pub 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 | ||
| 77 | impl<'d, U: UarteInstance, T: TimerInstance> Unpin for BufferedUarte<'d, U, T> {} | 191 | impl<'d, U: UarteInstance, T: TimerInstance> Unpin for BufferedUarte<'d, U, T> {} |
| 78 | 192 | ||
| 79 | impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> { | 193 | impl<'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 | ||
| 538 | impl<'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. |
| 332 | pub struct BufferedUarteRx<'u, 'd, U: UarteInstance, T: TimerInstance> { | 551 | pub 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 | ||
| 336 | impl<'d, U: UarteInstance, T: TimerInstance> embedded_io::Io for BufferedUarte<'d, U, T> { | 555 | impl<'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 | ||
| 340 | impl<'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 | ||
| 344 | impl<'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 | ||
| 348 | impl<'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> { | 573 | mod _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 | ||
| 354 | impl<'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 | ||
| 360 | impl<'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 | ||
| 370 | impl<'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 | ||
| 380 | impl<'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 | ||
| 390 | impl<'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 | ||
| 400 | impl<'a, U: UarteInstance, T: TimerInstance> Drop for StateInner<'a, U, T> { | 647 | impl<'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 | ||
| 424 | impl<'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 | ||
| 141 | impl_twis!(TWI0, TWIS0, TWIM0_TWIS0_TWI0); | 141 | impl_twis!(TWI0, TWIS0, TWIM0_TWIS0_TWI0); |
| 142 | 142 | ||
| 143 | impl_qdec!(QDEC, QDEC, QDEC); | ||
| 144 | |||
| 145 | impl_rng!(RNG, RNG, RNG); | ||
| 146 | |||
| 143 | impl_timer!(TIMER0, TIMER0, TIMER0); | 147 | impl_timer!(TIMER0, TIMER0, TIMER0); |
| 144 | impl_timer!(TIMER1, TIMER1, TIMER1); | 148 | impl_timer!(TIMER1, TIMER1, TIMER1); |
| 145 | impl_timer!(TIMER2, TIMER2, TIMER2); | 149 | impl_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 | ||
| 149 | impl_pwm!(PWM0, PWM0, PWM0); | 149 | impl_pwm!(PWM0, PWM0, PWM0); |
| 150 | 150 | ||
| 151 | impl_pdm!(PDM, PDM, PDM); | ||
| 152 | |||
| 153 | impl_qdec!(QDEC, QDEC, QDEC); | ||
| 154 | |||
| 155 | impl_rng!(RNG, RNG, RNG); | ||
| 156 | |||
| 151 | impl_timer!(TIMER0, TIMER0, TIMER0); | 157 | impl_timer!(TIMER0, TIMER0, TIMER0); |
| 152 | impl_timer!(TIMER1, TIMER1, TIMER1); | 158 | impl_timer!(TIMER1, TIMER1, TIMER1); |
| 153 | impl_timer!(TIMER2, TIMER2, TIMER2); | 159 | impl_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 | ||
| 151 | impl_pwm!(PWM0, PWM0, PWM0); | 151 | impl_pwm!(PWM0, PWM0, PWM0); |
| 152 | 152 | ||
| 153 | impl_pdm!(PDM, PDM, PDM); | ||
| 154 | |||
| 155 | impl_qdec!(QDEC, QDEC, QDEC); | ||
| 156 | |||
| 157 | impl_rng!(RNG, RNG, RNG); | ||
| 158 | |||
| 153 | impl_timer!(TIMER0, TIMER0, TIMER0); | 159 | impl_timer!(TIMER0, TIMER0, TIMER0); |
| 154 | impl_timer!(TIMER1, TIMER1, TIMER1); | 160 | impl_timer!(TIMER1, TIMER1, TIMER1); |
| 155 | impl_timer!(TIMER2, TIMER2, TIMER2); | 161 | impl_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); | |||
| 153 | impl_timer!(TIMER2, TIMER2, TIMER2); | 153 | impl_timer!(TIMER2, TIMER2, TIMER2); |
| 154 | impl_timer!(TIMER3, TIMER3, TIMER3, extended); | 154 | impl_timer!(TIMER3, TIMER3, TIMER3, extended); |
| 155 | 155 | ||
| 156 | impl_qdec!(QDEC, QDEC, QDEC); | ||
| 157 | |||
| 158 | impl_rng!(RNG, RNG, RNG); | ||
| 159 | |||
| 156 | impl_pin!(P0_00, 0, 0); | 160 | impl_pin!(P0_00, 0, 0); |
| 157 | impl_pin!(P0_01, 0, 1); | 161 | impl_pin!(P0_01, 0, 1); |
| 158 | impl_pin!(P0_02, 0, 2); | 162 | impl_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 | ||
| 151 | impl_uarte!(UARTE0, UARTE0, UARTE0_UART0); | 154 | impl_uarte!(UARTE0, UARTE0, UARTE0_UART0); |
| @@ -168,6 +171,12 @@ impl_pwm!(PWM0, PWM0, PWM0); | |||
| 168 | impl_pwm!(PWM1, PWM1, PWM1); | 171 | impl_pwm!(PWM1, PWM1, PWM1); |
| 169 | impl_pwm!(PWM2, PWM2, PWM2); | 172 | impl_pwm!(PWM2, PWM2, PWM2); |
| 170 | 173 | ||
| 174 | impl_pdm!(PDM, PDM, PDM); | ||
| 175 | |||
| 176 | impl_qdec!(QDEC, QDEC, QDEC); | ||
| 177 | |||
| 178 | impl_rng!(RNG, RNG, RNG); | ||
| 179 | |||
| 171 | impl_timer!(TIMER0, TIMER0, TIMER0); | 180 | impl_timer!(TIMER0, TIMER0, TIMER0); |
| 172 | impl_timer!(TIMER1, TIMER1, TIMER1); | 181 | impl_timer!(TIMER1, TIMER1, TIMER1); |
| 173 | impl_timer!(TIMER2, TIMER2, TIMER2); | 182 | impl_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); | |||
| 197 | impl_pwm!(PWM2, PWM2, PWM2); | 197 | impl_pwm!(PWM2, PWM2, PWM2); |
| 198 | impl_pwm!(PWM3, PWM3, PWM3); | 198 | impl_pwm!(PWM3, PWM3, PWM3); |
| 199 | 199 | ||
| 200 | impl_pdm!(PDM, PDM, PDM); | ||
| 201 | |||
| 202 | impl_qdec!(QDEC, QDEC, QDEC); | ||
| 203 | |||
| 204 | impl_rng!(RNG, RNG, RNG); | ||
| 205 | |||
| 200 | impl_timer!(TIMER0, TIMER0, TIMER0); | 206 | impl_timer!(TIMER0, TIMER0, TIMER0); |
| 201 | impl_timer!(TIMER1, TIMER1, TIMER1); | 207 | impl_timer!(TIMER1, TIMER1, TIMER1); |
| 202 | impl_timer!(TIMER2, TIMER2, TIMER2); | 208 | impl_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 | ||
| 209 | impl_qspi!(QSPI, QSPI, QSPI); | 209 | impl_qspi!(QSPI, QSPI, QSPI); |
| 210 | 210 | ||
| 211 | impl_pdm!(PDM, PDM, PDM); | ||
| 212 | |||
| 213 | impl_qdec!(QDEC, QDEC, QDEC); | ||
| 214 | |||
| 215 | impl_rng!(RNG, RNG, RNG); | ||
| 216 | |||
| 211 | impl_pin!(P0_00, 0, 0); | 217 | impl_pin!(P0_00, 0, 0); |
| 212 | impl_pin!(P0_01, 0, 1); | 218 | impl_pin!(P0_01, 0, 1); |
| 213 | impl_pin!(P0_02, 0, 2); | 219 | impl_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); | |||
| 393 | impl_timer!(TIMER1, TIMER1, TIMER1); | 403 | impl_timer!(TIMER1, TIMER1, TIMER1); |
| 394 | impl_timer!(TIMER2, TIMER2, TIMER2); | 404 | impl_timer!(TIMER2, TIMER2, TIMER2); |
| 395 | 405 | ||
| 406 | impl_qspi!(QSPI, QSPI, QSPI); | ||
| 407 | |||
| 408 | impl_pdm!(PDM0, PDM0, PDM0); | ||
| 409 | |||
| 410 | impl_qdec!(QDEC0, QDEC0, QDEC0); | ||
| 411 | impl_qdec!(QDEC1, QDEC1, QDEC1); | ||
| 412 | |||
| 396 | impl_pin!(P0_00, 0, 0); | 413 | impl_pin!(P0_00, 0, 0); |
| 397 | impl_pin!(P0_01, 0, 1); | 414 | impl_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); | |||
| 252 | impl_timer!(TIMER1, TIMER1, TIMER1); | 255 | impl_timer!(TIMER1, TIMER1, TIMER1); |
| 253 | impl_timer!(TIMER2, TIMER2, TIMER2); | 256 | impl_timer!(TIMER2, TIMER2, TIMER2); |
| 254 | 257 | ||
| 258 | impl_rng!(RNG, RNG, RNG); | ||
| 259 | |||
| 255 | impl_pin!(P0_00, 0, 0); | 260 | impl_pin!(P0_00, 0, 0); |
| 256 | impl_pin!(P0_01, 0, 1); | 261 | impl_pin!(P0_01, 0, 1); |
| 257 | impl_pin!(P0_02, 0, 2); | 262 | impl_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); | |||
| 301 | impl_pwm!(PWM2, PWM2, PWM2); | 301 | impl_pwm!(PWM2, PWM2, PWM2); |
| 302 | impl_pwm!(PWM3, PWM3, PWM3); | 302 | impl_pwm!(PWM3, PWM3, PWM3); |
| 303 | 303 | ||
| 304 | impl_pdm!(PDM, PDM, PDM); | ||
| 305 | |||
| 304 | impl_timer!(TIMER0, TIMER0, TIMER0); | 306 | impl_timer!(TIMER0, TIMER0, TIMER0); |
| 305 | impl_timer!(TIMER1, TIMER1, TIMER1); | 307 | impl_timer!(TIMER1, TIMER1, TIMER1); |
| 306 | impl_timer!(TIMER2, TIMER2, TIMER2); | 308 | impl_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"] | ||
| 318 | pub(crate) struct PortInputFuture<'a> { | 319 | pub(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; | |||
| 14 | use embassy_hal_common::{into_ref, PeripheralRef}; | 14 | use embassy_hal_common::{into_ref, PeripheralRef}; |
| 15 | 15 | ||
| 16 | use crate::gpio::{AnyPin, Pin as GpioPin}; | 16 | use crate::gpio::{AnyPin, Pin as GpioPin}; |
| 17 | use crate::interrupt::Interrupt; | 17 | use crate::interrupt::{self, Interrupt}; |
| 18 | use crate::pac::i2s::RegisterBlock; | 18 | use crate::pac::i2s::RegisterBlock; |
| 19 | use crate::util::{slice_in_ram_or, slice_ptr_parts}; | 19 | use crate::util::{slice_in_ram_or, slice_ptr_parts}; |
| 20 | use crate::{Peripheral, EASY_DMA_SIZE}; | 20 | use crate::{Peripheral, EASY_DMA_SIZE}; |
| @@ -363,10 +363,39 @@ impl From<Channels> for u8 { | |||
| 363 | } | 363 | } |
| 364 | } | 364 | } |
| 365 | 365 | ||
| 366 | /// Interrupt handler. | ||
| 367 | pub struct InterruptHandler<T: Instance> { | ||
| 368 | _phantom: PhantomData<T>, | ||
| 369 | } | ||
| 370 | |||
| 371 | impl<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. |
| 367 | pub struct I2S<'d, T: Instance> { | 397 | pub 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 | ||
| 379 | impl<'d, T: Instance> I2S<'d, T> { | 408 | impl<'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. |
| 1172 | pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static + Send { | 1175 | pub 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")] |
| 38 | mod time_driver; | 38 | mod time_driver; |
| 39 | 39 | ||
| 40 | #[cfg(feature = "nightly")] | ||
| 41 | pub mod buffered_uarte; | 40 | pub mod buffered_uarte; |
| 42 | pub mod gpio; | 41 | pub 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 | ))] |
| 55 | pub mod pdm; | 56 | pub mod pdm; |
| 56 | pub mod ppi; | 57 | pub mod ppi; |
| 57 | #[cfg(not(any(feature = "nrf52805", feature = "nrf52820", feature = "_nrf5340-net")))] | 58 | #[cfg(not(any(feature = "nrf52805", feature = "nrf52820", feature = "_nrf5340-net")))] |
| 58 | pub mod pwm; | 59 | pub mod pwm; |
| 59 | #[cfg(not(any(feature = "nrf51", feature = "_nrf9160", feature = "_nrf5340")))] | 60 | #[cfg(not(any(feature = "nrf51", feature = "_nrf9160", feature = "_nrf5340-net")))] |
| 60 | pub mod qdec; | 61 | pub mod qdec; |
| 61 | #[cfg(feature = "nrf52840")] | 62 | #[cfg(any(feature = "nrf52840", feature = "_nrf5340-app"))] |
| 62 | pub mod qspi; | 63 | pub mod qspi; |
| 63 | #[cfg(not(any(feature = "_nrf5340", feature = "_nrf9160")))] | 64 | #[cfg(not(any(feature = "_nrf5340-app", feature = "_nrf9160")))] |
| 64 | pub mod rng; | 65 | pub mod rng; |
| 65 | #[cfg(not(any(feature = "nrf52820", feature = "_nrf5340-net")))] | 66 | #[cfg(not(any(feature = "nrf52820", feature = "_nrf5340-net")))] |
| 66 | pub mod saadc; | 67 | pub 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")] |
| 97 | mod chip; | 98 | mod chip; |
| 98 | 99 | ||
| 99 | pub use chip::EASY_DMA_SIZE; | ||
| 100 | |||
| 101 | pub mod interrupt { | 100 | pub 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 { | |||
| 112 | pub use chip::pac; | 138 | pub use chip::pac; |
| 113 | #[cfg(not(feature = "unstable-pac"))] | 139 | #[cfg(not(feature = "unstable-pac"))] |
| 114 | pub(crate) use chip::pac; | 140 | pub(crate) use chip::pac; |
| 115 | pub use chip::{peripherals, Peripherals}; | 141 | pub use chip::{peripherals, Peripherals, EASY_DMA_SIZE}; |
| 116 | pub use embassy_cortex_m::executor; | 142 | pub use embassy_cortex_m::executor; |
| 117 | pub use embassy_cortex_m::interrupt::_export::interrupt; | 143 | pub use embassy_cortex_m::interrupt::_export::interrupt; |
| 118 | pub use embassy_hal_common::{into_ref, Peripheral, PeripheralRef}; | 144 | pub 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 | |||
| 3 | use core::marker::PhantomData; | 5 | use core::marker::PhantomData; |
| 4 | use core::sync::atomic::{compiler_fence, Ordering}; | 6 | use core::sync::atomic::{compiler_fence, Ordering}; |
| 5 | use core::task::Poll; | 7 | use core::task::Poll; |
| 6 | 8 | ||
| 9 | use embassy_cortex_m::interrupt::Interrupt; | ||
| 7 | use embassy_hal_common::drop::OnDrop; | 10 | use embassy_hal_common::drop::OnDrop; |
| 8 | use embassy_hal_common::{into_ref, PeripheralRef}; | 11 | use embassy_hal_common::{into_ref, PeripheralRef}; |
| 9 | use embassy_sync::waitqueue::AtomicWaker; | ||
| 10 | use futures::future::poll_fn; | 12 | use futures::future::poll_fn; |
| 11 | 13 | ||
| 12 | use crate::chip::EASY_DMA_SIZE; | 14 | use crate::chip::EASY_DMA_SIZE; |
| 13 | use crate::gpio::sealed::Pin; | 15 | use crate::gpio::sealed::Pin; |
| 14 | use crate::gpio::{AnyPin, Pin as GpioPin}; | 16 | use crate::gpio::{AnyPin, Pin as GpioPin}; |
| 15 | use crate::interrupt::{self, InterruptExt}; | 17 | use crate::interrupt::{self, InterruptExt}; |
| 16 | use crate::peripherals::PDM; | 18 | use crate::Peripheral; |
| 17 | use crate::{pac, Peripheral}; | 19 | |
| 20 | /// Interrupt handler. | ||
| 21 | pub struct InterruptHandler<T: Instance> { | ||
| 22 | _phantom: PhantomData<T>, | ||
| 23 | } | ||
| 24 | |||
| 25 | impl<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 |
| 20 | pub struct Pdm<'d> { | 33 | pub 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 | ||
| 38 | static WAKER: AtomicWaker = AtomicWaker::new(); | ||
| 39 | static DUMMY_BUFFER: [i16; 1] = [0; 1]; | 50 | static DUMMY_BUFFER: [i16; 1] = [0; 1]; |
| 40 | 51 | ||
| 41 | impl<'d> Pdm<'d> { | 52 | impl<'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 | ||
| 241 | impl<'d> Drop for Pdm<'d> { | 239 | impl<'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 | |||
| 252 | pub(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. | ||
| 275 | pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static + Send { | ||
| 276 | /// Interrupt for this peripheral. | ||
| 277 | type Interrupt: Interrupt; | ||
| 278 | } | ||
| 279 | |||
| 280 | macro_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}; | |||
| 6 | const DPPI_ENABLE_BIT: u32 = 0x8000_0000; | 6 | const DPPI_ENABLE_BIT: u32 = 0x8000_0000; |
| 7 | const DPPI_CHANNEL_MASK: u32 = 0x0000_00FF; | 7 | const DPPI_CHANNEL_MASK: u32 = 0x0000_00FF; |
| 8 | 8 | ||
| 9 | fn regs() -> &'static pac::dppic::RegisterBlock { | 9 | pub(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 | ||
| 18 | use core::ptr::NonNull; | 18 | use core::ptr::NonNull; |
| 19 | 19 | ||
| 20 | use embassy_hal_common::{impl_peripheral, PeripheralRef}; | 20 | use embassy_hal_common::{impl_peripheral, into_ref, PeripheralRef}; |
| 21 | 21 | ||
| 22 | use crate::{peripherals, Peripheral}; | 22 | use crate::{peripherals, Peripheral}; |
| 23 | 23 | ||
| 24 | #[cfg(feature = "_dppi")] | 24 | #[cfg_attr(feature = "_dppi", path = "dppi.rs")] |
| 25 | mod dppi; | 25 | #[cfg_attr(feature = "_ppi", path = "ppi.rs")] |
| 26 | #[cfg(feature = "_ppi")] | 26 | mod _version; |
| 27 | mod ppi; | 27 | pub(crate) use _version::*; |
| 28 | 28 | ||
| 29 | /// An instance of the Programmable peripheral interconnect on nRF devices. | 29 | /// PPI channel driver. |
| 30 | pub struct Ppi<'d, C: Channel, const EVENT_COUNT: usize, const TASK_COUNT: usize> { | 30 | pub 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. | ||
| 39 | pub struct PpiGroup<'d, G: Group> { | ||
| 40 | g: PeripheralRef<'d, G>, | ||
| 41 | } | ||
| 42 | |||
| 43 | impl<'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(®s().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(®s().tasks_chg[n].dis) | ||
| 109 | } | ||
| 110 | } | ||
| 111 | |||
| 112 | impl<'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")] |
| 39 | const REGISTER_DPPI_CONFIG_OFFSET: usize = 0x80 / core::mem::size_of::<u32>(); | 121 | const 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. |
| 115 | pub trait Channel: sealed::Channel + Peripheral<P = Self> + Sized { | 197 | pub 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. |
| 133 | pub trait Group: sealed::Group + Sized { | 215 | pub 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 | ||
| 17 | fn regs() -> &'static pac::ppi::RegisterBlock { | 17 | pub(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 | |||
| 3 | use core::future::poll_fn; | 5 | use core::future::poll_fn; |
| 6 | use core::marker::PhantomData; | ||
| 4 | use core::task::Poll; | 7 | use core::task::Poll; |
| 5 | 8 | ||
| 9 | use embassy_cortex_m::interrupt::Interrupt; | ||
| 6 | use embassy_hal_common::{into_ref, PeripheralRef}; | 10 | use embassy_hal_common::{into_ref, PeripheralRef}; |
| 7 | use embassy_sync::waitqueue::AtomicWaker; | ||
| 8 | 11 | ||
| 9 | use crate::gpio::sealed::Pin as _; | 12 | use crate::gpio::sealed::Pin as _; |
| 10 | use crate::gpio::{AnyPin, Pin as GpioPin}; | 13 | use crate::gpio::{AnyPin, Pin as GpioPin}; |
| 11 | use crate::interrupt::InterruptExt; | 14 | use crate::interrupt::InterruptExt; |
| 12 | use crate::peripherals::QDEC; | 15 | use crate::{interrupt, Peripheral}; |
| 13 | use crate::{interrupt, pac, Peripheral}; | ||
| 14 | 16 | ||
| 15 | /// Quadrature decoder driver. | 17 | /// Quadrature decoder driver. |
| 16 | pub struct Qdec<'d> { | 18 | pub 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 | ||
| 47 | static WAKER: AtomicWaker = AtomicWaker::new(); | 49 | /// Interrupt handler. |
| 50 | pub struct InterruptHandler<T: Instance> { | ||
| 51 | _phantom: PhantomData<T>, | ||
| 52 | } | ||
| 48 | 53 | ||
| 49 | impl<'d> Qdec<'d> { | 54 | impl<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 | |||
| 61 | impl<'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 | |||
| 241 | pub(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. | ||
| 264 | pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static + Send { | ||
| 265 | /// Interrupt for this peripheral. | ||
| 266 | type Interrupt: Interrupt; | ||
| 267 | } | ||
| 268 | |||
| 269 | macro_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 | ||
| 5 | use core::future::poll_fn; | 5 | use core::future::poll_fn; |
| 6 | use core::marker::PhantomData; | ||
| 6 | use core::ptr; | 7 | use core::ptr; |
| 7 | use core::task::Poll; | 8 | use core::task::Poll; |
| 8 | 9 | ||
| 9 | use embassy_hal_common::drop::OnDrop; | 10 | use embassy_hal_common::drop::OnDrop; |
| 10 | use embassy_hal_common::{into_ref, PeripheralRef}; | 11 | use embassy_hal_common::{into_ref, PeripheralRef}; |
| 12 | use embedded_storage::nor_flash::{ErrorType, NorFlash, NorFlashError, NorFlashErrorKind, ReadNorFlash}; | ||
| 11 | 13 | ||
| 12 | use crate::gpio::{self, Pin as GpioPin}; | 14 | use crate::gpio::{self, Pin as GpioPin}; |
| 13 | use crate::interrupt::{Interrupt, InterruptExt}; | 15 | use crate::interrupt::{self, Interrupt, InterruptExt}; |
| 14 | pub use crate::pac::qspi::ifconfig0::{ | 16 | pub 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 | }; |
| 17 | pub use crate::pac::qspi::ifconfig1::SPIMODE_A as SpiMode; | 19 | pub use crate::pac::qspi::ifconfig1::SPIMODE_A as SpiMode; |
| 18 | use crate::{pac, Peripheral}; | 20 | use crate::Peripheral; |
| 19 | 21 | ||
| 20 | /// Deep power-down config. | 22 | /// Deep power-down config. |
| 21 | pub struct DeepPowerDownConfig { | 23 | pub 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 | ||
| 87 | impl Default for Config { | 91 | impl 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. | ||
| 119 | pub struct InterruptHandler<T: Instance> { | ||
| 120 | _phantom: PhantomData<T>, | ||
| 121 | } | ||
| 122 | |||
| 123 | impl<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. |
| 114 | pub struct Qspi<'d, T: Instance, const FLASH_SIZE: usize> { | 136 | pub 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 | ||
| 119 | impl<'d, T: Instance, const FLASH_SIZE: usize> Qspi<'d, T, FLASH_SIZE> { | 142 | impl<'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 | ||
| 441 | impl<'d, T: Instance, const FLASH_SIZE: usize> Drop for Qspi<'d, T, FLASH_SIZE> { | 505 | impl<'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 | ||
| 486 | use embedded_storage::nor_flash::{ErrorType, NorFlash, NorFlashError, NorFlashErrorKind, ReadNorFlash}; | 548 | impl<'d, T: Instance> ErrorType for Qspi<'d, T> { |
| 487 | |||
| 488 | impl<'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 | ||
| 498 | impl<'d, T: Instance, const FLASH_SIZE: usize> ReadNorFlash for Qspi<'d, T, FLASH_SIZE> { | 558 | impl<'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 | ||
| 511 | impl<'d, T: Instance, const FLASH_SIZE: usize> NorFlash for Qspi<'d, T, FLASH_SIZE> { | 571 | impl<'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 | ||
| 528 | cfg_if::cfg_if! { | 588 | #[cfg(feature = "nightly")] |
| 529 | if #[cfg(feature = "nightly")] | 589 | mod _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! { | |||
| 562 | pub(crate) mod sealed { | 622 | pub(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. |
| 585 | pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static { | 645 | pub 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 { | |||
| 590 | macro_rules! impl_qspi { | 650 | macro_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 | |||
| 3 | use core::future::poll_fn; | 5 | use core::future::poll_fn; |
| 6 | use core::marker::PhantomData; | ||
| 4 | use core::ptr; | 7 | use core::ptr; |
| 5 | use core::sync::atomic::{AtomicPtr, Ordering}; | 8 | use core::sync::atomic::{AtomicPtr, Ordering}; |
| 6 | use core::task::Poll; | 9 | use core::task::Poll; |
| 7 | 10 | ||
| 11 | use embassy_cortex_m::interrupt::Interrupt; | ||
| 8 | use embassy_hal_common::drop::OnDrop; | 12 | use embassy_hal_common::drop::OnDrop; |
| 9 | use embassy_hal_common::{into_ref, PeripheralRef}; | 13 | use embassy_hal_common::{into_ref, PeripheralRef}; |
| 10 | use embassy_sync::waitqueue::AtomicWaker; | 14 | use embassy_sync::waitqueue::AtomicWaker; |
| 11 | 15 | ||
| 12 | use crate::interrupt::InterruptExt; | 16 | use crate::interrupt::InterruptExt; |
| 13 | use crate::peripherals::RNG; | 17 | use crate::{interrupt, Peripheral}; |
| 14 | use crate::{interrupt, pac, Peripheral}; | ||
| 15 | |||
| 16 | impl RNG { | ||
| 17 | fn regs() -> &'static pac::rng::RegisterBlock { | ||
| 18 | unsafe { &*pac::RNG::ptr() } | ||
| 19 | } | ||
| 20 | } | ||
| 21 | |||
| 22 | static STATE: State = State { | ||
| 23 | ptr: AtomicPtr::new(ptr::null_mut()), | ||
| 24 | end: AtomicPtr::new(ptr::null_mut()), | ||
| 25 | waker: AtomicWaker::new(), | ||
| 26 | }; | ||
| 27 | 18 | ||
| 28 | struct State { | 19 | /// Interrupt handler. |
| 29 | ptr: AtomicPtr<u8>, | 20 | pub 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. | 24 | impl<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(); |
| 37 | pub struct Rng<'d> { | 27 | let r = T::regs(); |
| 38 | irq: PeripheralRef<'d, interrupt::RNG>, | ||
| 39 | } | ||
| 40 | |||
| 41 | impl<'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`. | ||
| 80 | pub struct Rng<'d, T: Instance> { | ||
| 81 | _peri: PeripheralRef<'d, T>, | ||
| 82 | } | ||
| 83 | |||
| 84 | impl<'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 | ||
| 196 | impl<'d> Drop for Rng<'d> { | 195 | impl<'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 | ||
| 202 | impl<'d> rand_core::RngCore for Rng<'d> { | 204 | impl<'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 | ||
| 226 | impl<'d> rand_core::CryptoRng for Rng<'d> {} | 228 | impl<'d, T: Instance> rand_core::CryptoRng for Rng<'d, T> {} |
| 229 | |||
| 230 | pub(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. | ||
| 257 | pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static + Send { | ||
| 258 | /// Interrupt for this peripheral. | ||
| 259 | type Interrupt: Interrupt; | ||
| 260 | } | ||
| 261 | |||
| 262 | macro_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; | |||
| 6 | use core::sync::atomic::{compiler_fence, Ordering}; | 6 | use core::sync::atomic::{compiler_fence, Ordering}; |
| 7 | use core::task::Poll; | 7 | use core::task::Poll; |
| 8 | 8 | ||
| 9 | use embassy_cortex_m::interrupt::{Interrupt, InterruptExt}; | ||
| 9 | use embassy_hal_common::drop::OnDrop; | 10 | use embassy_hal_common::drop::OnDrop; |
| 10 | use embassy_hal_common::{impl_peripheral, into_ref, PeripheralRef}; | 11 | use embassy_hal_common::{impl_peripheral, into_ref, PeripheralRef}; |
| 11 | use embassy_sync::waitqueue::AtomicWaker; | 12 | use embassy_sync::waitqueue::AtomicWaker; |
| @@ -17,7 +18,6 @@ use saadc::oversample::OVERSAMPLE_A; | |||
| 17 | use saadc::resolution::VAL_A; | 18 | use saadc::resolution::VAL_A; |
| 18 | 19 | ||
| 19 | use self::sealed::Input as _; | 20 | use self::sealed::Input as _; |
| 20 | use crate::interrupt::InterruptExt; | ||
| 21 | use crate::ppi::{ConfigurableChannel, Event, Ppi, Task}; | 21 | use crate::ppi::{ConfigurableChannel, Event, Ppi, Task}; |
| 22 | use crate::timer::{Frequency, Instance as TimerInstance, Timer}; | 22 | use crate::timer::{Frequency, Instance as TimerInstance, Timer}; |
| 23 | use crate::{interrupt, pac, peripherals, Peripheral}; | 23 | use crate::{interrupt, pac, peripherals, Peripheral}; |
| @@ -28,9 +28,30 @@ use crate::{interrupt, pac, peripherals, Peripheral}; | |||
| 28 | #[non_exhaustive] | 28 | #[non_exhaustive] |
| 29 | pub enum Error {} | 29 | pub enum Error {} |
| 30 | 30 | ||
| 31 | /// One-shot and continuous SAADC. | 31 | /// Interrupt handler. |
| 32 | pub struct Saadc<'d, const N: usize> { | 32 | pub struct InterruptHandler { |
| 33 | _p: PeripheralRef<'d, peripherals::SAADC>, | 33 | _private: (), |
| 34 | } | ||
| 35 | |||
| 36 | impl 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 | ||
| 36 | static WAKER: AtomicWaker = AtomicWaker::new(); | 57 | static 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. | ||
| 139 | pub struct Saadc<'d, const N: usize> { | ||
| 140 | _p: PeripheralRef<'d, peripherals::SAADC>, | ||
| 141 | } | ||
| 142 | |||
| 117 | impl<'d, const N: usize> Saadc<'d, N> { | 143 | impl<'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 | ||
| 5 | use core::future::poll_fn; | 5 | use core::future::poll_fn; |
| 6 | use core::marker::PhantomData; | ||
| 6 | use core::sync::atomic::{compiler_fence, Ordering}; | 7 | use core::sync::atomic::{compiler_fence, Ordering}; |
| 7 | use core::task::Poll; | 8 | use core::task::Poll; |
| 8 | 9 | ||
| @@ -14,7 +15,7 @@ pub use pac::spim0::frequency::FREQUENCY_A as Frequency; | |||
| 14 | use crate::chip::FORCE_COPY_BUFFER_SIZE; | 15 | use crate::chip::FORCE_COPY_BUFFER_SIZE; |
| 15 | use crate::gpio::sealed::Pin as _; | 16 | use crate::gpio::sealed::Pin as _; |
| 16 | use crate::gpio::{self, AnyPin, Pin as GpioPin, PselBits}; | 17 | use crate::gpio::{self, AnyPin, Pin as GpioPin, PselBits}; |
| 17 | use crate::interrupt::{Interrupt, InterruptExt}; | 18 | use crate::interrupt::{self, Interrupt, InterruptExt}; |
| 18 | use crate::util::{slice_in_ram_or, slice_ptr_parts, slice_ptr_parts_mut}; | 19 | use crate::util::{slice_in_ram_or, slice_ptr_parts, slice_ptr_parts_mut}; |
| 19 | use crate::{pac, Peripheral}; | 20 | use crate::{pac, Peripheral}; |
| 20 | 21 | ||
| @@ -31,11 +32,6 @@ pub enum Error { | |||
| 31 | BufferNotInRAM, | 32 | BufferNotInRAM, |
| 32 | } | 33 | } |
| 33 | 34 | ||
| 34 | /// SPIM driver. | ||
| 35 | pub struct Spim<'d, T: Instance> { | ||
| 36 | _p: PeripheralRef<'d, T>, | ||
| 37 | } | ||
| 38 | |||
| 39 | /// SPIM configuration. | 35 | /// SPIM configuration. |
| 40 | #[non_exhaustive] | 36 | #[non_exhaustive] |
| 41 | pub struct Config { | 37 | pub struct Config { |
| @@ -62,11 +58,33 @@ impl Default for Config { | |||
| 62 | } | 58 | } |
| 63 | } | 59 | } |
| 64 | 60 | ||
| 61 | /// Interrupt handler. | ||
| 62 | pub struct InterruptHandler<T: Instance> { | ||
| 63 | _phantom: PhantomData<T>, | ||
| 64 | } | ||
| 65 | |||
| 66 | impl<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. | ||
| 79 | pub struct Spim<'d, T: Instance> { | ||
| 80 | _p: PeripheralRef<'d, T>, | ||
| 81 | } | ||
| 82 | |||
| 65 | impl<'d, T: Instance> Spim<'d, T> { | 83 | impl<'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] |
| 4 | use core::future::poll_fn; | 4 | use core::future::poll_fn; |
| 5 | use core::marker::PhantomData; | ||
| 5 | use core::sync::atomic::{compiler_fence, Ordering}; | 6 | use core::sync::atomic::{compiler_fence, Ordering}; |
| 6 | use core::task::Poll; | 7 | use 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 | |||
| 12 | use crate::chip::FORCE_COPY_BUFFER_SIZE; | 13 | use crate::chip::FORCE_COPY_BUFFER_SIZE; |
| 13 | use crate::gpio::sealed::Pin as _; | 14 | use crate::gpio::sealed::Pin as _; |
| 14 | use crate::gpio::{self, AnyPin, Pin as GpioPin}; | 15 | use crate::gpio::{self, AnyPin, Pin as GpioPin}; |
| 15 | use crate::interrupt::{Interrupt, InterruptExt}; | 16 | use crate::interrupt::{self, Interrupt, InterruptExt}; |
| 16 | use crate::util::{slice_in_ram_or, slice_ptr_parts, slice_ptr_parts_mut}; | 17 | use crate::util::{slice_in_ram_or, slice_ptr_parts, slice_ptr_parts_mut}; |
| 17 | use crate::{pac, Peripheral}; | 18 | use crate::{pac, Peripheral}; |
| 18 | 19 | ||
| @@ -29,11 +30,6 @@ pub enum Error { | |||
| 29 | BufferNotInRAM, | 30 | BufferNotInRAM, |
| 30 | } | 31 | } |
| 31 | 32 | ||
| 32 | /// SPIS driver. | ||
| 33 | pub struct Spis<'d, T: Instance> { | ||
| 34 | _p: PeripheralRef<'d, T>, | ||
| 35 | } | ||
| 36 | |||
| 37 | /// SPIS configuration. | 33 | /// SPIS configuration. |
| 38 | #[non_exhaustive] | 34 | #[non_exhaustive] |
| 39 | pub struct Config { | 35 | pub struct Config { |
| @@ -67,11 +63,38 @@ impl Default for Config { | |||
| 67 | } | 63 | } |
| 68 | } | 64 | } |
| 69 | 65 | ||
| 66 | /// Interrupt handler. | ||
| 67 | pub struct InterruptHandler<T: Instance> { | ||
| 68 | _phantom: PhantomData<T>, | ||
| 69 | } | ||
| 70 | |||
| 71 | impl<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. | ||
| 89 | pub struct Spis<'d, T: Instance> { | ||
| 90 | _p: PeripheralRef<'d, T>, | ||
| 91 | } | ||
| 92 | |||
| 70 | impl<'d, T: Instance> Spis<'d, T> { | 93 | impl<'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 @@ | |||
| 3 | use core::future::poll_fn; | 3 | use core::future::poll_fn; |
| 4 | use core::task::Poll; | 4 | use core::task::Poll; |
| 5 | 5 | ||
| 6 | use embassy_cortex_m::interrupt::Interrupt; | ||
| 6 | use embassy_hal_common::drop::OnDrop; | 7 | use embassy_hal_common::drop::OnDrop; |
| 7 | use embassy_hal_common::{into_ref, PeripheralRef}; | 8 | use embassy_hal_common::{into_ref, PeripheralRef}; |
| 8 | use embassy_sync::waitqueue::AtomicWaker; | 9 | use embassy_sync::waitqueue::AtomicWaker; |
| @@ -12,27 +13,39 @@ use crate::interrupt::InterruptExt; | |||
| 12 | use crate::peripherals::TEMP; | 13 | use crate::peripherals::TEMP; |
| 13 | use crate::{interrupt, pac, Peripheral}; | 14 | use crate::{interrupt, pac, Peripheral}; |
| 14 | 15 | ||
| 16 | /// Interrupt handler. | ||
| 17 | pub struct InterruptHandler { | ||
| 18 | _private: (), | ||
| 19 | } | ||
| 20 | |||
| 21 | impl 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. |
| 16 | pub struct Temp<'d> { | 30 | pub struct Temp<'d> { |
| 17 | _irq: PeripheralRef<'d, interrupt::TEMP>, | 31 | _peri: PeripheralRef<'d, TEMP>, |
| 18 | } | 32 | } |
| 19 | 33 | ||
| 20 | static WAKER: AtomicWaker = AtomicWaker::new(); | 34 | static WAKER: AtomicWaker = AtomicWaker::new(); |
| 21 | 35 | ||
| 22 | impl<'d> Temp<'d> { | 36 | impl<'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 | ||
| 9 | use core::future::poll_fn; | ||
| 10 | use core::marker::PhantomData; | ||
| 11 | use core::task::Poll; | ||
| 12 | |||
| 13 | use embassy_hal_common::drop::OnDrop; | ||
| 14 | use embassy_hal_common::{into_ref, PeripheralRef}; | 9 | use embassy_hal_common::{into_ref, PeripheralRef}; |
| 15 | use embassy_sync::waitqueue::AtomicWaker; | ||
| 16 | 10 | ||
| 17 | use crate::interrupt::{Interrupt, InterruptExt}; | 11 | use crate::interrupt::Interrupt; |
| 18 | use crate::ppi::{Event, Task}; | 12 | use crate::ppi::{Event, Task}; |
| 19 | use crate::{pac, Peripheral}; | 13 | use 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 | ||
| 107 | pub trait TimerType: sealed::TimerType {} | ||
| 108 | |||
| 109 | /// Marker type indicating the timer driver can await expiration (it owns the timer interrupt). | ||
| 110 | pub enum Awaitable {} | ||
| 111 | |||
| 112 | /// Marker type indicating the timer driver cannot await expiration (it does not own the timer interrupt). | ||
| 113 | pub enum NotAwaitable {} | ||
| 114 | |||
| 115 | impl sealed::TimerType for Awaitable {} | ||
| 116 | impl sealed::TimerType for NotAwaitable {} | ||
| 117 | impl TimerType for Awaitable {} | ||
| 118 | impl TimerType for NotAwaitable {} | ||
| 119 | |||
| 120 | /// Timer driver. | 93 | /// Timer driver. |
| 121 | pub struct Timer<'d, T: Instance, I: TimerType = NotAwaitable> { | 94 | pub struct Timer<'d, T: Instance> { |
| 122 | _p: PeripheralRef<'d, T>, | 95 | _p: PeripheralRef<'d, T>, |
| 123 | _i: PhantomData<I>, | ||
| 124 | } | 96 | } |
| 125 | 97 | ||
| 126 | impl<'d, T: Instance> Timer<'d, T, Awaitable> { | 98 | impl<'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 | |||
| 139 | impl<'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 | ||
| 149 | impl<'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 |
| 278 | pub struct Cc<'d, T: Instance, I: TimerType = NotAwaitable> { | 234 | pub 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 | |||
| 284 | impl<'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 | } |
| 318 | impl<'d, T: Instance> Cc<'d, T, NotAwaitable> {} | ||
| 319 | 238 | ||
| 320 | impl<'d, T: Instance, I: TimerType> Cc<'d, T, I> { | 239 | impl<'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 | ||
| 5 | use core::future::{poll_fn, Future}; | 5 | use core::future::{poll_fn, Future}; |
| 6 | use core::marker::PhantomData; | ||
| 6 | use core::sync::atomic::compiler_fence; | 7 | use core::sync::atomic::compiler_fence; |
| 7 | use core::sync::atomic::Ordering::SeqCst; | 8 | use core::sync::atomic::Ordering::SeqCst; |
| 8 | use core::task::Poll; | 9 | use core::task::Poll; |
| @@ -15,7 +16,7 @@ use embassy_time::{Duration, Instant}; | |||
| 15 | 16 | ||
| 16 | use crate::chip::{EASY_DMA_SIZE, FORCE_COPY_BUFFER_SIZE}; | 17 | use crate::chip::{EASY_DMA_SIZE, FORCE_COPY_BUFFER_SIZE}; |
| 17 | use crate::gpio::Pin as GpioPin; | 18 | use crate::gpio::Pin as GpioPin; |
| 18 | use crate::interrupt::{Interrupt, InterruptExt}; | 19 | use crate::interrupt::{self, Interrupt, InterruptExt}; |
| 19 | use crate::util::{slice_in_ram, slice_in_ram_or}; | 20 | use crate::util::{slice_in_ram, slice_in_ram_or}; |
| 20 | use crate::{gpio, pac, Peripheral}; | 21 | use crate::{gpio, pac, Peripheral}; |
| 21 | 22 | ||
| @@ -92,6 +93,27 @@ pub enum Error { | |||
| 92 | Timeout, | 93 | Timeout, |
| 93 | } | 94 | } |
| 94 | 95 | ||
| 96 | /// Interrupt handler. | ||
| 97 | pub struct InterruptHandler<T: Instance> { | ||
| 98 | _phantom: PhantomData<T>, | ||
| 99 | } | ||
| 100 | |||
| 101 | impl<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. |
| 96 | pub struct Twim<'d, T: Instance> { | 118 | pub 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 | ||
| 5 | use core::future::{poll_fn, Future}; | 5 | use core::future::{poll_fn, Future}; |
| 6 | use core::marker::PhantomData; | ||
| 6 | use core::sync::atomic::compiler_fence; | 7 | use core::sync::atomic::compiler_fence; |
| 7 | use core::sync::atomic::Ordering::SeqCst; | 8 | use core::sync::atomic::Ordering::SeqCst; |
| 8 | use core::task::Poll; | 9 | use core::task::Poll; |
| @@ -14,7 +15,7 @@ use embassy_time::{Duration, Instant}; | |||
| 14 | 15 | ||
| 15 | use crate::chip::{EASY_DMA_SIZE, FORCE_COPY_BUFFER_SIZE}; | 16 | use crate::chip::{EASY_DMA_SIZE, FORCE_COPY_BUFFER_SIZE}; |
| 16 | use crate::gpio::Pin as GpioPin; | 17 | use crate::gpio::Pin as GpioPin; |
| 17 | use crate::interrupt::{Interrupt, InterruptExt}; | 18 | use crate::interrupt::{self, Interrupt, InterruptExt}; |
| 18 | use crate::util::slice_in_ram_or; | 19 | use crate::util::slice_in_ram_or; |
| 19 | use crate::{gpio, pac, Peripheral}; | 20 | use 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. | ||
| 113 | pub struct InterruptHandler<T: Instance> { | ||
| 114 | _phantom: PhantomData<T>, | ||
| 115 | } | ||
| 116 | |||
| 117 | impl<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. |
| 112 | pub struct Twis<'d, T: Instance> { | 138 | pub 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 | ||
| 16 | use core::future::poll_fn; | 16 | use core::future::poll_fn; |
| 17 | use core::marker::PhantomData; | ||
| 17 | use core::sync::atomic::{compiler_fence, Ordering}; | 18 | use core::sync::atomic::{compiler_fence, Ordering}; |
| 18 | use core::task::Poll; | 19 | use core::task::Poll; |
| 19 | 20 | ||
| @@ -26,7 +27,7 @@ pub use pac::uarte0::{baudrate::BAUDRATE_A as Baudrate, config::PARITY_A as Pari | |||
| 26 | use crate::chip::{EASY_DMA_SIZE, FORCE_COPY_BUFFER_SIZE}; | 27 | use crate::chip::{EASY_DMA_SIZE, FORCE_COPY_BUFFER_SIZE}; |
| 27 | use crate::gpio::sealed::Pin as _; | 28 | use crate::gpio::sealed::Pin as _; |
| 28 | use crate::gpio::{self, AnyPin, Pin as GpioPin, PselBits}; | 29 | use crate::gpio::{self, AnyPin, Pin as GpioPin, PselBits}; |
| 29 | use crate::interrupt::{Interrupt, InterruptExt}; | 30 | use crate::interrupt::{self, Interrupt, InterruptExt}; |
| 30 | use crate::ppi::{AnyConfigurableChannel, ConfigurableChannel, Event, Ppi, Task}; | 31 | use crate::ppi::{AnyConfigurableChannel, ConfigurableChannel, Event, Ppi, Task}; |
| 31 | use crate::timer::{Frequency, Instance as TimerInstance, Timer}; | 32 | use crate::timer::{Frequency, Instance as TimerInstance, Timer}; |
| 32 | use crate::util::slice_in_ram_or; | 33 | use crate::util::slice_in_ram_or; |
| @@ -62,6 +63,27 @@ pub enum Error { | |||
| 62 | BufferNotInRAM, | 63 | BufferNotInRAM, |
| 63 | } | 64 | } |
| 64 | 65 | ||
| 66 | /// Interrupt handler. | ||
| 67 | pub struct InterruptHandler<T: Instance> { | ||
| 68 | _phantom: PhantomData<T>, | ||
| 69 | } | ||
| 70 | |||
| 71 | impl<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. |
| 66 | pub struct Uarte<'d, T: Instance> { | 88 | pub 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 | ||
| 5 | pub mod vbus_detect; | ||
| 6 | |||
| 5 | use core::future::poll_fn; | 7 | use core::future::poll_fn; |
| 6 | use core::marker::PhantomData; | 8 | use core::marker::PhantomData; |
| 7 | use core::mem::MaybeUninit; | 9 | use core::mem::MaybeUninit; |
| 8 | use core::sync::atomic::{compiler_fence, AtomicBool, AtomicU32, Ordering}; | 10 | use core::sync::atomic::{compiler_fence, AtomicU32, Ordering}; |
| 9 | use core::task::Poll; | 11 | use core::task::Poll; |
| 10 | 12 | ||
| 11 | use cortex_m::peripheral::NVIC; | 13 | use cortex_m::peripheral::NVIC; |
| @@ -15,7 +17,8 @@ use embassy_usb_driver as driver; | |||
| 15 | use embassy_usb_driver::{Direction, EndpointAddress, EndpointError, EndpointInfo, EndpointType, Event, Unsupported}; | 17 | use embassy_usb_driver::{Direction, EndpointAddress, EndpointError, EndpointInfo, EndpointType, Event, Unsupported}; |
| 16 | use pac::usbd::RegisterBlock; | 18 | use pac::usbd::RegisterBlock; |
| 17 | 19 | ||
| 18 | use crate::interrupt::{Interrupt, InterruptExt}; | 20 | use self::vbus_detect::VbusDetect; |
| 21 | use crate::interrupt::{self, Interrupt, InterruptExt}; | ||
| 19 | use crate::util::slice_in_ram; | 22 | use crate::util::slice_in_ram; |
| 20 | use crate::{pac, Peripheral}; | 23 | use crate::{pac, Peripheral}; |
| 21 | 24 | ||
| @@ -26,185 +29,13 @@ static EP_IN_WAKERS: [AtomicWaker; 8] = [NEW_AW; 8]; | |||
| 26 | static EP_OUT_WAKERS: [AtomicWaker; 8] = [NEW_AW; 8]; | 29 | static EP_OUT_WAKERS: [AtomicWaker; 8] = [NEW_AW; 8]; |
| 27 | static READY_ENDPOINTS: AtomicU32 = AtomicU32::new(0); | 30 | static READY_ENDPOINTS: AtomicU32 = AtomicU32::new(0); |
| 28 | 31 | ||
| 29 | /// Trait for detecting USB VBUS power. | 32 | /// Interrupt handler. |
| 30 | /// | 33 | pub 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. | ||
| 33 | pub 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"))] | ||
| 52 | pub struct HardwareVbusDetect { | ||
| 53 | _private: (), | ||
| 54 | } | ||
| 55 | |||
| 56 | static POWER_WAKER: AtomicWaker = NEW_AW; | ||
| 57 | |||
| 58 | #[cfg(not(feature = "_nrf5340-app"))] | ||
| 59 | impl 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"))] | ||
| 97 | impl 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. | ||
| 127 | pub struct SoftwareVbusDetect { | ||
| 128 | usb_detected: AtomicBool, | ||
| 129 | power_ready: AtomicBool, | ||
| 130 | } | ||
| 131 | |||
| 132 | impl 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 | |||
| 162 | impl 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. | 37 | impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> { |
| 184 | pub 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 | |||
| 191 | impl<'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 | ||
| 258 | impl<'d, T: Instance, P: VbusDetect + 'd> driver::Driver<'d> for Driver<'d, T, P> { | 89 | /// USB driver. |
| 90 | pub 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 | |||
| 97 | impl<'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 | |||
| 118 | impl<'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. |
| 312 | pub struct Bus<'d, T: Instance, P: VbusDetect> { | 172 | pub 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 | ||
| 318 | impl<'d, T: Instance, P: VbusDetect> driver::Bus for Bus<'d, T, P> { | 178 | impl<'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 | |||
| 3 | use core::future::poll_fn; | ||
| 4 | use core::sync::atomic::{AtomicBool, Ordering}; | ||
| 5 | use core::task::Poll; | ||
| 6 | |||
| 7 | use embassy_sync::waitqueue::AtomicWaker; | ||
| 8 | |||
| 9 | use super::BUS_WAKER; | ||
| 10 | use crate::interrupt::{self, Interrupt, InterruptExt}; | ||
| 11 | use 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. | ||
| 17 | pub 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"))] | ||
| 32 | type UsbRegIrq = interrupt::POWER_CLOCK; | ||
| 33 | #[cfg(feature = "_nrf5340")] | ||
| 34 | type UsbRegIrq = interrupt::USBREGULATOR; | ||
| 35 | |||
| 36 | #[cfg(not(feature = "_nrf5340"))] | ||
| 37 | type UsbRegPeri = pac::POWER; | ||
| 38 | #[cfg(feature = "_nrf5340")] | ||
| 39 | type UsbRegPeri = pac::USBREGULATOR; | ||
| 40 | |||
| 41 | /// Interrupt handler. | ||
| 42 | pub struct InterruptHandler { | ||
| 43 | _private: (), | ||
| 44 | } | ||
| 45 | |||
| 46 | impl 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`]. | ||
| 72 | pub struct HardwareVbusDetect { | ||
| 73 | _private: (), | ||
| 74 | } | ||
| 75 | |||
| 76 | static POWER_WAKER: AtomicWaker = AtomicWaker::new(); | ||
| 77 | |||
| 78 | impl 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 | |||
| 93 | impl 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. | ||
| 123 | pub struct SoftwareVbusDetect { | ||
| 124 | usb_detected: AtomicBool, | ||
| 125 | power_ready: AtomicBool, | ||
| 126 | } | ||
| 127 | |||
| 128 | impl 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 | |||
| 158 | impl 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; | |||
| 7 | use embassy_sync::waitqueue::AtomicWaker; | 7 | use embassy_sync::waitqueue::AtomicWaker; |
| 8 | use embedded_hal_02::adc::{Channel, OneShot}; | 8 | use embedded_hal_02::adc::{Channel, OneShot}; |
| 9 | 9 | ||
| 10 | use crate::gpio::Pin; | ||
| 10 | use crate::interrupt::{self, InterruptExt}; | 11 | use crate::interrupt::{self, InterruptExt}; |
| 11 | use crate::peripherals::ADC; | 12 | use crate::peripherals::ADC; |
| 12 | use crate::{pac, peripherals, Peripheral}; | 13 | use 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"] | ||
| 154 | pub struct Transfer<'a, C: Channel> { | 155 | pub 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"] | ||
| 196 | struct InputFuture<'a, T: Pin> { | 197 | struct 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"] | ||
| 123 | pub struct FifoOutFuture<'a, PIO: PioInstance, SM: PioStateMachine + Unpin> { | 124 | pub 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"] | ||
| 185 | pub struct FifoInFuture<'a, PIO: PioInstance, SM: PioStateMachine> { | 187 | pub 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"] | ||
| 244 | pub struct IrqFuture<PIO: PioInstance> { | 247 | pub 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 | ||
| 302 | impl<'d, T: Instance, M: Mode> Uart<'d, T, M> { | 302 | impl<'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 | ||
| 405 | impl<'d, T: Instance, M: Mode> Uart<'d, T, M> { | 418 | impl<'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 @@ | |||
| 5 | mod _version; | 5 | mod _version; |
| 6 | pub mod generic_smi; | 6 | pub mod generic_smi; |
| 7 | 7 | ||
| 8 | use core::mem::MaybeUninit; | ||
| 8 | use core::task::Context; | 9 | use core::task::Context; |
| 9 | 10 | ||
| 10 | use embassy_net_driver::{Capabilities, LinkState}; | 11 | use 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 | ||
| 44 | static WAKER: AtomicWaker = AtomicWaker::new(); | 52 | static 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"] | ||
| 201 | struct ExtiInputFuture<'a> { | 202 | struct 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"] | ||
| 184 | pub struct RecvFuture<'ch, M, T, const N: usize> | 185 | pub struct RecvFuture<'ch, M, T, const N: usize> |
| 185 | where | 186 | where |
| 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"] | ||
| 206 | pub struct DynamicRecvFuture<'ch, T> { | 208 | pub 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"] | ||
| 222 | pub struct SendFuture<'ch, M, T, const N: usize> | 225 | pub struct SendFuture<'ch, M, T, const N: usize> |
| 223 | where | 226 | where |
| 224 | M: RawMutex, | 227 | M: RawMutex, |
| @@ -250,6 +253,7 @@ where | |||
| 250 | impl<'ch, M, T, const N: usize> Unpin for SendFuture<'ch, M, T, N> where M: RawMutex {} | 253 | impl<'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"] | ||
| 253 | pub struct DynamicSendFuture<'ch, T> { | 257 | pub 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"] | ||
| 51 | pub struct WriteFuture<'p, M, const N: usize> | 52 | pub struct WriteFuture<'p, M, const N: usize> |
| 52 | where | 53 | where |
| 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"] | ||
| 113 | pub struct ReadFuture<'p, M, const N: usize> | 115 | pub struct ReadFuture<'p, M, const N: usize> |
| 114 | where | 116 | where |
| 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 @@ | |||
| 1 | use core::future::Future; | 1 | use core::future::{poll_fn, Future}; |
| 2 | use core::pin::Pin; | 2 | use core::pin::Pin; |
| 3 | use core::task::{Context, Poll, Waker}; | 3 | use 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"] | ||
| 29 | pub struct Timer { | 30 | pub 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 | ||
| 136 | impl Unpin for Ticker {} | 151 | impl 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`] | ||
| 300 | pub struct Sender<'d, D: Driver<'d>> { | ||
| 301 | write_ep: D::EndpointIn, | ||
| 302 | control: &'d ControlShared, | ||
| 303 | } | ||
| 304 | |||
| 305 | impl<'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`] | ||
| 342 | pub struct Receiver<'d, D: Driver<'d>> { | ||
| 343 | read_ep: D::EndpointOut, | ||
| 344 | control: &'d ControlShared, | ||
| 345 | } | ||
| 346 | |||
| 347 | impl<'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] |
| 8 | default = ["nightly"] | 8 | default = ["nightly"] |
| 9 | msos-descriptor = ["embassy-usb/msos-descriptor"] | ||
| 10 | nightly = ["embassy-executor/nightly", "embassy-nrf/nightly", "embassy-net/nightly", "embassy-nrf/unstable-traits", "embassy-usb", "embedded-io/async", "embassy-net", | 9 | nightly = ["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 | |||
| 17 | embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } | 16 | embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } |
| 18 | embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } | 17 | embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } |
| 19 | embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"], optional = true } | 18 | embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"], optional = true } |
| 20 | embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"], optional = true } | 19 | embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt", "msos-descriptor",], optional = true } |
| 21 | embedded-io = "0.4.0" | 20 | embedded-io = "0.4.0" |
| 22 | embassy-lora = { version = "0.1.0", path = "../../embassy-lora", features = ["sx126x", "time", "defmt"], optional = true } | 21 | embassy-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 } | |||
| 36 | embedded-storage = "0.3.0" | 35 | embedded-storage = "0.3.0" |
| 37 | usbd-hid = "0.6.0" | 36 | usbd-hid = "0.6.0" |
| 38 | serde = { version = "1.0.136", default-features = false } | 37 | serde = { version = "1.0.136", default-features = false } |
| 39 | |||
| 40 | [[bin]] | ||
| 41 | name = "usb_serial_winusb" | ||
| 42 | required-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 | |||
| 5 | use defmt::info; | ||
| 6 | use embassy_executor::Spawner; | ||
| 7 | use embassy_nrf::interrupt; | ||
| 8 | use embassy_nrf::timer::Timer; | ||
| 9 | use {defmt_rtt as _, panic_probe as _}; | ||
| 10 | |||
| 11 | #[embassy_executor::main] | ||
| 12 | async 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 | ||
| 5 | use defmt::*; | 5 | use defmt::*; |
| 6 | use embassy_executor::Spawner; | 6 | use embassy_executor::Spawner; |
| 7 | use embassy_nrf::buffered_uarte::{BufferedUarte, State}; | 7 | use embassy_nrf::buffered_uarte::{self, BufferedUarte}; |
| 8 | use embassy_nrf::{interrupt, uarte}; | 8 | use embassy_nrf::{bind_interrupts, peripherals, uarte}; |
| 9 | use embedded_io::asynch::{BufRead, Write}; | 9 | use embedded_io::asynch::Write; |
| 10 | use futures::pin_mut; | ||
| 11 | use {defmt_rtt as _, panic_probe as _}; | 10 | use {defmt_rtt as _, panic_probe as _}; |
| 12 | 11 | ||
| 12 | bind_interrupts!(struct Irqs { | ||
| 13 | UARTE0_UART0 => buffered_uarte::InterruptHandler<peripherals::UARTE0>; | ||
| 14 | }); | ||
| 15 | |||
| 13 | #[embassy_executor::main] | 16 | #[embassy_executor::main] |
| 14 | async fn main(_spawner: Spawner) { | 17 | async 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; | |||
| 7 | use defmt::{error, info}; | 7 | use defmt::{error, info}; |
| 8 | use embassy_executor::Spawner; | 8 | use embassy_executor::Spawner; |
| 9 | use embassy_nrf::i2s::{self, Channels, Config, MasterClock, MultiBuffering, Sample as _, SampleWidth, I2S}; | 9 | use embassy_nrf::i2s::{self, Channels, Config, MasterClock, MultiBuffering, Sample as _, SampleWidth, I2S}; |
| 10 | use embassy_nrf::interrupt; | 10 | use embassy_nrf::{bind_interrupts, peripherals}; |
| 11 | use {defmt_rtt as _, panic_probe as _}; | 11 | use {defmt_rtt as _, panic_probe as _}; |
| 12 | 12 | ||
| 13 | type Sample = i16; | 13 | type Sample = i16; |
| @@ -15,6 +15,10 @@ type Sample = i16; | |||
| 15 | const NUM_BUFFERS: usize = 2; | 15 | const NUM_BUFFERS: usize = 2; |
| 16 | const NUM_SAMPLES: usize = 4; | 16 | const NUM_SAMPLES: usize = 4; |
| 17 | 17 | ||
| 18 | bind_interrupts!(struct Irqs { | ||
| 19 | I2S => i2s::InterruptHandler<peripherals::I2S>; | ||
| 20 | }); | ||
| 21 | |||
| 18 | #[embassy_executor::main] | 22 | #[embassy_executor::main] |
| 19 | async fn main(_spawner: Spawner) { | 23 | async 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 @@ | |||
| 5 | use defmt::{debug, error, info}; | 5 | use defmt::{debug, error, info}; |
| 6 | use embassy_executor::Spawner; | 6 | use embassy_executor::Spawner; |
| 7 | use embassy_nrf::i2s::{self, Channels, Config, DoubleBuffering, MasterClock, Sample as _, SampleWidth, I2S}; | 7 | use embassy_nrf::i2s::{self, Channels, Config, DoubleBuffering, MasterClock, Sample as _, SampleWidth, I2S}; |
| 8 | use embassy_nrf::interrupt; | ||
| 9 | use embassy_nrf::pwm::{Prescaler, SimplePwm}; | 8 | use embassy_nrf::pwm::{Prescaler, SimplePwm}; |
| 9 | use embassy_nrf::{bind_interrupts, peripherals}; | ||
| 10 | use {defmt_rtt as _, panic_probe as _}; | 10 | use {defmt_rtt as _, panic_probe as _}; |
| 11 | 11 | ||
| 12 | type Sample = i16; | 12 | type Sample = i16; |
| 13 | 13 | ||
| 14 | const NUM_SAMPLES: usize = 500; | 14 | const NUM_SAMPLES: usize = 500; |
| 15 | 15 | ||
| 16 | bind_interrupts!(struct Irqs { | ||
| 17 | I2S => i2s::InterruptHandler<peripherals::I2S>; | ||
| 18 | }); | ||
| 19 | |||
| 16 | #[embassy_executor::main] | 20 | #[embassy_executor::main] |
| 17 | async fn main(_spawner: Spawner) { | 21 | async 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; | |||
| 7 | use defmt::{error, info}; | 7 | use defmt::{error, info}; |
| 8 | use embassy_executor::Spawner; | 8 | use embassy_executor::Spawner; |
| 9 | use embassy_nrf::i2s::{self, Channels, Config, DoubleBuffering, MasterClock, Sample as _, SampleWidth, I2S}; | 9 | use embassy_nrf::i2s::{self, Channels, Config, DoubleBuffering, MasterClock, Sample as _, SampleWidth, I2S}; |
| 10 | use embassy_nrf::interrupt; | 10 | use embassy_nrf::{bind_interrupts, peripherals}; |
| 11 | use {defmt_rtt as _, panic_probe as _}; | 11 | use {defmt_rtt as _, panic_probe as _}; |
| 12 | 12 | ||
| 13 | type Sample = i16; | 13 | type Sample = i16; |
| 14 | 14 | ||
| 15 | const NUM_SAMPLES: usize = 50; | 15 | const NUM_SAMPLES: usize = 50; |
| 16 | 16 | ||
| 17 | bind_interrupts!(struct Irqs { | ||
| 18 | I2S => i2s::InterruptHandler<peripherals::I2S>; | ||
| 19 | }); | ||
| 20 | |||
| 17 | #[embassy_executor::main] | 21 | #[embassy_executor::main] |
| 18 | async fn main(_spawner: Spawner) { | 22 | async 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::*; | |||
| 11 | use embassy_executor::Spawner; | 11 | use embassy_executor::Spawner; |
| 12 | use embassy_lora::sx126x::*; | 12 | use embassy_lora::sx126x::*; |
| 13 | use embassy_nrf::gpio::{Input, Level, Output, OutputDrive, Pin as _, Pull}; | 13 | use embassy_nrf::gpio::{Input, Level, Output, OutputDrive, Pin as _, Pull}; |
| 14 | use embassy_nrf::{interrupt, spim}; | 14 | use embassy_nrf::{bind_interrupts, peripherals, spim}; |
| 15 | use embassy_time::{Duration, Timer}; | 15 | use embassy_time::{Duration, Timer}; |
| 16 | use lorawan_device::async_device::radio::{Bandwidth, CodingRate, PhyRxTx, RfConfig, SpreadingFactor}; | 16 | use lorawan_device::async_device::radio::{Bandwidth, CodingRate, PhyRxTx, RfConfig, SpreadingFactor}; |
| 17 | use {defmt_rtt as _, panic_probe as _}; | 17 | use {defmt_rtt as _, panic_probe as _}; |
| 18 | 18 | ||
| 19 | bind_interrupts!(struct Irqs { | ||
| 20 | SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1 => spim::InterruptHandler<peripherals::TWISPI1>; | ||
| 21 | }); | ||
| 22 | |||
| 19 | #[embassy_executor::main] | 23 | #[embassy_executor::main] |
| 20 | async fn main(_spawner: Spawner) { | 24 | async 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::*; | |||
| 12 | use embassy_executor::Spawner; | 12 | use embassy_executor::Spawner; |
| 13 | use embassy_lora::sx126x::*; | 13 | use embassy_lora::sx126x::*; |
| 14 | use embassy_nrf::gpio::{Input, Level, Output, OutputDrive, Pin as _, Pull}; | 14 | use embassy_nrf::gpio::{Input, Level, Output, OutputDrive, Pin as _, Pull}; |
| 15 | use embassy_nrf::{interrupt, spim}; | 15 | use embassy_nrf::{bind_interrupts, peripherals, spim}; |
| 16 | use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; | 16 | use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; |
| 17 | use embassy_sync::pubsub::{PubSubChannel, Publisher}; | 17 | use embassy_sync::pubsub::{PubSubChannel, Publisher}; |
| 18 | use embassy_time::{Duration, Timer}; | 18 | use embassy_time::{Duration, Timer}; |
| 19 | use lorawan_device::async_device::radio::{Bandwidth, CodingRate, PhyRxTx, RfConfig, SpreadingFactor, TxConfig}; | 19 | use lorawan_device::async_device::radio::{Bandwidth, CodingRate, PhyRxTx, RfConfig, SpreadingFactor, TxConfig}; |
| 20 | use {defmt_rtt as _, panic_probe as _, panic_probe as _}; | 20 | use {defmt_rtt as _, panic_probe as _, panic_probe as _}; |
| 21 | 21 | ||
| 22 | bind_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) |
| 23 | static MESSAGE_BUS: PubSubChannel<CriticalSectionRawMutex, Message, 2, 1, 2> = PubSubChannel::new(); | 27 | static 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 | ||
| 60 | use core::mem; | ||
| 61 | |||
| 62 | use cortex_m::peripheral::NVIC; | ||
| 60 | use cortex_m_rt::entry; | 63 | use cortex_m_rt::entry; |
| 61 | use defmt::{info, unwrap}; | 64 | use defmt::{info, unwrap}; |
| 62 | use embassy_nrf::executor::{Executor, InterruptExecutor}; | 65 | use embassy_nrf::executor::{Executor, InterruptExecutor}; |
| 63 | use embassy_nrf::interrupt; | 66 | use embassy_nrf::interrupt; |
| 64 | use embassy_nrf::interrupt::InterruptExt; | 67 | use embassy_nrf::pac::Interrupt; |
| 65 | use embassy_time::{Duration, Instant, Timer}; | 68 | use embassy_time::{Duration, Instant, Timer}; |
| 66 | use static_cell::StaticCell; | 69 | use static_cell::StaticCell; |
| 67 | use {defmt_rtt as _, panic_probe as _}; | 70 | use {defmt_rtt as _, panic_probe as _}; |
| @@ -108,28 +111,35 @@ async fn run_low() { | |||
| 108 | } | 111 | } |
| 109 | } | 112 | } |
| 110 | 113 | ||
| 111 | static EXECUTOR_HIGH: StaticCell<InterruptExecutor<interrupt::SWI1_EGU1>> = StaticCell::new(); | 114 | static EXECUTOR_HIGH: InterruptExecutor = InterruptExecutor::new(); |
| 112 | static EXECUTOR_MED: StaticCell<InterruptExecutor<interrupt::SWI0_EGU0>> = StaticCell::new(); | 115 | static EXECUTOR_MED: InterruptExecutor = InterruptExecutor::new(); |
| 113 | static EXECUTOR_LOW: StaticCell<Executor> = StaticCell::new(); | 116 | static EXECUTOR_LOW: StaticCell<Executor> = StaticCell::new(); |
| 114 | 117 | ||
| 118 | #[interrupt] | ||
| 119 | unsafe fn SWI1_EGU1() { | ||
| 120 | EXECUTOR_HIGH.on_interrupt() | ||
| 121 | } | ||
| 122 | |||
| 123 | #[interrupt] | ||
| 124 | unsafe fn SWI0_EGU0() { | ||
| 125 | EXECUTOR_MED.on_interrupt() | ||
| 126 | } | ||
| 127 | |||
| 115 | #[entry] | 128 | #[entry] |
| 116 | fn main() -> ! { | 129 | fn 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 | ||
| 5 | use defmt::info; | 5 | use defmt::info; |
| 6 | use embassy_executor::Spawner; | 6 | use embassy_executor::Spawner; |
| 7 | use embassy_nrf::interrupt; | 7 | use embassy_nrf::pdm::{self, Config, Pdm}; |
| 8 | use embassy_nrf::pdm::{Config, Pdm}; | 8 | use embassy_nrf::{bind_interrupts, peripherals}; |
| 9 | use embassy_time::{Duration, Timer}; | 9 | use embassy_time::{Duration, Timer}; |
| 10 | use {defmt_rtt as _, panic_probe as _}; | 10 | use {defmt_rtt as _, panic_probe as _}; |
| 11 | 11 | ||
| 12 | bind_interrupts!(struct Irqs { | ||
| 13 | PDM => pdm::InterruptHandler<peripherals::PDM>; | ||
| 14 | }); | ||
| 15 | |||
| 12 | #[embassy_executor::main] | 16 | #[embassy_executor::main] |
| 13 | async fn main(_p: Spawner) { | 17 | async 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 | ||
| 5 | use defmt::info; | 5 | use defmt::info; |
| 6 | use embassy_executor::Spawner; | 6 | use embassy_executor::Spawner; |
| 7 | use embassy_nrf::interrupt; | ||
| 8 | use embassy_nrf::qdec::{self, Qdec}; | 7 | use embassy_nrf::qdec::{self, Qdec}; |
| 8 | use embassy_nrf::{bind_interrupts, peripherals}; | ||
| 9 | use {defmt_rtt as _, panic_probe as _}; | 9 | use {defmt_rtt as _, panic_probe as _}; |
| 10 | 10 | ||
| 11 | bind_interrupts!(struct Irqs { | ||
| 12 | QDEC => qdec::InterruptHandler<peripherals::QDEC>; | ||
| 13 | }); | ||
| 14 | |||
| 11 | #[embassy_executor::main] | 15 | #[embassy_executor::main] |
| 12 | async fn main(_spawner: Spawner) { | 16 | async 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 | ||
| 5 | use defmt::{assert_eq, info, unwrap}; | 5 | use defmt::{assert_eq, info, unwrap}; |
| 6 | use embassy_executor::Spawner; | 6 | use embassy_executor::Spawner; |
| 7 | use embassy_nrf::{interrupt, qspi}; | 7 | use embassy_nrf::qspi::Frequency; |
| 8 | use embassy_nrf::{bind_interrupts, peripherals, qspi}; | ||
| 8 | use {defmt_rtt as _, panic_probe as _}; | 9 | use {defmt_rtt as _, panic_probe as _}; |
| 9 | 10 | ||
| 10 | const PAGE_SIZE: usize = 4096; | 11 | const PAGE_SIZE: usize = 4096; |
| @@ -14,18 +15,23 @@ const PAGE_SIZE: usize = 4096; | |||
| 14 | #[repr(C, align(4))] | 15 | #[repr(C, align(4))] |
| 15 | struct AlignedBuf([u8; 4096]); | 16 | struct AlignedBuf([u8; 4096]); |
| 16 | 17 | ||
| 18 | bind_interrupts!(struct Irqs { | ||
| 19 | QSPI => qspi::InterruptHandler<peripherals::QSPI>; | ||
| 20 | }); | ||
| 21 | |||
| 17 | #[embassy_executor::main] | 22 | #[embassy_executor::main] |
| 18 | async fn main(_spawner: Spawner) { | 23 | async 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 | ||
| 7 | use defmt::{info, unwrap}; | 7 | use defmt::{info, unwrap}; |
| 8 | use embassy_executor::Spawner; | 8 | use embassy_executor::Spawner; |
| 9 | use embassy_nrf::{interrupt, qspi}; | 9 | use embassy_nrf::qspi::Frequency; |
| 10 | use embassy_nrf::{bind_interrupts, peripherals, qspi}; | ||
| 10 | use embassy_time::{Duration, Timer}; | 11 | use embassy_time::{Duration, Timer}; |
| 11 | use {defmt_rtt as _, panic_probe as _}; | 12 | use {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))] |
| 16 | struct AlignedBuf([u8; 64]); | 17 | struct AlignedBuf([u8; 64]); |
| 17 | 18 | ||
| 19 | bind_interrupts!(struct Irqs { | ||
| 20 | QSPI => qspi::InterruptHandler<peripherals::QSPI>; | ||
| 21 | }); | ||
| 22 | |||
| 18 | #[embassy_executor::main] | 23 | #[embassy_executor::main] |
| 19 | async fn main(_p: Spawner) { | 24 | async 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 | ||
| 5 | use embassy_executor::Spawner; | 5 | use embassy_executor::Spawner; |
| 6 | use embassy_nrf::interrupt; | ||
| 7 | use embassy_nrf::rng::Rng; | 6 | use embassy_nrf::rng::Rng; |
| 7 | use embassy_nrf::{bind_interrupts, peripherals, rng}; | ||
| 8 | use rand::Rng as _; | 8 | use rand::Rng as _; |
| 9 | use {defmt_rtt as _, panic_probe as _}; | 9 | use {defmt_rtt as _, panic_probe as _}; |
| 10 | 10 | ||
| 11 | bind_interrupts!(struct Irqs { | ||
| 12 | RNG => rng::InterruptHandler<peripherals::RNG>; | ||
| 13 | }); | ||
| 14 | |||
| 11 | #[embassy_executor::main] | 15 | #[embassy_executor::main] |
| 12 | async fn main(_spawner: Spawner) { | 16 | async 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 | ||
| 5 | use defmt::info; | 5 | use defmt::info; |
| 6 | use embassy_executor::Spawner; | 6 | use embassy_executor::Spawner; |
| 7 | use embassy_nrf::interrupt; | ||
| 8 | use embassy_nrf::saadc::{ChannelConfig, Config, Saadc}; | 7 | use embassy_nrf::saadc::{ChannelConfig, Config, Saadc}; |
| 8 | use embassy_nrf::{bind_interrupts, saadc}; | ||
| 9 | use embassy_time::{Duration, Timer}; | 9 | use embassy_time::{Duration, Timer}; |
| 10 | use {defmt_rtt as _, panic_probe as _}; | 10 | use {defmt_rtt as _, panic_probe as _}; |
| 11 | 11 | ||
| 12 | bind_interrupts!(struct Irqs { | ||
| 13 | SAADC => saadc::InterruptHandler; | ||
| 14 | }); | ||
| 15 | |||
| 12 | #[embassy_executor::main] | 16 | #[embassy_executor::main] |
| 13 | async fn main(_p: Spawner) { | 17 | async 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 | ||
| 5 | use defmt::info; | 5 | use defmt::info; |
| 6 | use embassy_executor::Spawner; | 6 | use embassy_executor::Spawner; |
| 7 | use embassy_nrf::interrupt; | ||
| 8 | use embassy_nrf::saadc::{CallbackResult, ChannelConfig, Config, Saadc}; | 7 | use embassy_nrf::saadc::{CallbackResult, ChannelConfig, Config, Saadc}; |
| 9 | use embassy_nrf::timer::Frequency; | 8 | use embassy_nrf::timer::Frequency; |
| 9 | use embassy_nrf::{bind_interrupts, saadc}; | ||
| 10 | use embassy_time::Duration; | 10 | use embassy_time::Duration; |
| 11 | use {defmt_rtt as _, panic_probe as _}; | 11 | use {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 | ||
| 15 | bind_interrupts!(struct Irqs { | ||
| 16 | SAADC => saadc::InterruptHandler; | ||
| 17 | }); | ||
| 18 | |||
| 15 | #[embassy_executor::main] | 19 | #[embassy_executor::main] |
| 16 | async fn main(_p: Spawner) { | 20 | async 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 @@ | |||
| 5 | use defmt::{info, unwrap}; | 5 | use defmt::{info, unwrap}; |
| 6 | use embassy_executor::Spawner; | 6 | use embassy_executor::Spawner; |
| 7 | use embassy_nrf::gpio::{Level, Output, OutputDrive}; | 7 | use embassy_nrf::gpio::{Level, Output, OutputDrive}; |
| 8 | use embassy_nrf::{interrupt, spim}; | 8 | use embassy_nrf::{bind_interrupts, peripherals, spim}; |
| 9 | use {defmt_rtt as _, panic_probe as _}; | 9 | use {defmt_rtt as _, panic_probe as _}; |
| 10 | 10 | ||
| 11 | bind_interrupts!(struct Irqs { | ||
| 12 | SPIM3 => spim::InterruptHandler<peripherals::SPI3>; | ||
| 13 | }); | ||
| 14 | |||
| 11 | #[embassy_executor::main] | 15 | #[embassy_executor::main] |
| 12 | async fn main(_spawner: Spawner) { | 16 | async 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 | ||
| 5 | use defmt::info; | 5 | use defmt::info; |
| 6 | use embassy_executor::Spawner; | 6 | use embassy_executor::Spawner; |
| 7 | use embassy_nrf::interrupt; | ||
| 8 | use embassy_nrf::spis::{Config, Spis}; | 7 | use embassy_nrf::spis::{Config, Spis}; |
| 8 | use embassy_nrf::{bind_interrupts, peripherals, spis}; | ||
| 9 | use {defmt_rtt as _, panic_probe as _}; | 9 | use {defmt_rtt as _, panic_probe as _}; |
| 10 | 10 | ||
| 11 | bind_interrupts!(struct Irqs { | ||
| 12 | SPIM2_SPIS2_SPI2 => spis::InterruptHandler<peripherals::SPI2>; | ||
| 13 | }); | ||
| 14 | |||
| 11 | #[embassy_executor::main] | 15 | #[embassy_executor::main] |
| 12 | async fn main(_spawner: Spawner) { | 16 | async 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 | ||
| 5 | use defmt::info; | 5 | use defmt::info; |
| 6 | use embassy_executor::Spawner; | 6 | use embassy_executor::Spawner; |
| 7 | use embassy_nrf::interrupt; | ||
| 8 | use embassy_nrf::temp::Temp; | 7 | use embassy_nrf::temp::Temp; |
| 8 | use embassy_nrf::{bind_interrupts, temp}; | ||
| 9 | use embassy_time::{Duration, Timer}; | 9 | use embassy_time::{Duration, Timer}; |
| 10 | use {defmt_rtt as _, panic_probe as _}; | 10 | use {defmt_rtt as _, panic_probe as _}; |
| 11 | 11 | ||
| 12 | bind_interrupts!(struct Irqs { | ||
| 13 | TEMP => temp::InterruptHandler; | ||
| 14 | }); | ||
| 15 | |||
| 12 | #[embassy_executor::main] | 16 | #[embassy_executor::main] |
| 13 | async fn main(_spawner: Spawner) { | 17 | async 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 | ||
| 9 | use defmt::*; | 9 | use defmt::*; |
| 10 | use embassy_executor::Spawner; | 10 | use embassy_executor::Spawner; |
| 11 | use embassy_nrf::interrupt; | ||
| 12 | use embassy_nrf::twim::{self, Twim}; | 11 | use embassy_nrf::twim::{self, Twim}; |
| 12 | use embassy_nrf::{bind_interrupts, peripherals}; | ||
| 13 | use {defmt_rtt as _, panic_probe as _}; | 13 | use {defmt_rtt as _, panic_probe as _}; |
| 14 | 14 | ||
| 15 | const ADDRESS: u8 = 0x50; | 15 | const ADDRESS: u8 = 0x50; |
| 16 | 16 | ||
| 17 | bind_interrupts!(struct Irqs { | ||
| 18 | SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0 => twim::InterruptHandler<peripherals::TWISPI0>; | ||
| 19 | }); | ||
| 20 | |||
| 17 | #[embassy_executor::main] | 21 | #[embassy_executor::main] |
| 18 | async fn main(_spawner: Spawner) { | 22 | async 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 | ||
| 13 | use defmt::*; | 13 | use defmt::*; |
| 14 | use embassy_executor::Spawner; | 14 | use embassy_executor::Spawner; |
| 15 | use embassy_nrf::interrupt; | ||
| 16 | use embassy_nrf::twim::{self, Twim}; | 15 | use embassy_nrf::twim::{self, Twim}; |
| 16 | use embassy_nrf::{bind_interrupts, peripherals}; | ||
| 17 | use embassy_time::{Duration, Timer}; | 17 | use embassy_time::{Duration, Timer}; |
| 18 | use {defmt_rtt as _, panic_probe as _}; | 18 | use {defmt_rtt as _, panic_probe as _}; |
| 19 | 19 | ||
| 20 | const ADDRESS: u8 = 0x50; | 20 | const ADDRESS: u8 = 0x50; |
| 21 | 21 | ||
| 22 | bind_interrupts!(struct Irqs { | ||
| 23 | SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0 => twim::InterruptHandler<peripherals::TWISPI0>; | ||
| 24 | }); | ||
| 25 | |||
| 22 | #[embassy_executor::main] | 26 | #[embassy_executor::main] |
| 23 | async fn main(_p: Spawner) { | 27 | async 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 | ||
| 7 | use defmt::*; | 7 | use defmt::*; |
| 8 | use embassy_executor::Spawner; | 8 | use embassy_executor::Spawner; |
| 9 | use embassy_nrf::interrupt; | ||
| 10 | use embassy_nrf::twis::{self, Command, Twis}; | 9 | use embassy_nrf::twis::{self, Command, Twis}; |
| 10 | use embassy_nrf::{bind_interrupts, peripherals}; | ||
| 11 | use {defmt_rtt as _, panic_probe as _}; | 11 | use {defmt_rtt as _, panic_probe as _}; |
| 12 | 12 | ||
| 13 | bind_interrupts!(struct Irqs { | ||
| 14 | SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0 => twis::InterruptHandler<peripherals::TWISPI0>; | ||
| 15 | }); | ||
| 16 | |||
| 13 | #[embassy_executor::main] | 17 | #[embassy_executor::main] |
| 14 | async fn main(_spawner: Spawner) { | 18 | async 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 | ||
| 5 | use defmt::*; | 5 | use defmt::*; |
| 6 | use embassy_executor::Spawner; | 6 | use embassy_executor::Spawner; |
| 7 | use embassy_nrf::{interrupt, uarte}; | 7 | use embassy_nrf::{bind_interrupts, peripherals, uarte}; |
| 8 | use {defmt_rtt as _, panic_probe as _}; | 8 | use {defmt_rtt as _, panic_probe as _}; |
| 9 | 9 | ||
| 10 | bind_interrupts!(struct Irqs { | ||
| 11 | UARTE0_UART0 => uarte::InterruptHandler<peripherals::UARTE0>; | ||
| 12 | }); | ||
| 13 | |||
| 10 | #[embassy_executor::main] | 14 | #[embassy_executor::main] |
| 11 | async fn main(_spawner: Spawner) { | 15 | async 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 | ||
| 5 | use defmt::*; | 5 | use defmt::*; |
| 6 | use embassy_executor::Spawner; | 6 | use embassy_executor::Spawner; |
| 7 | use embassy_nrf::{interrupt, uarte}; | 7 | use embassy_nrf::peripherals::UARTE0; |
| 8 | use embassy_nrf::{bind_interrupts, uarte}; | ||
| 8 | use {defmt_rtt as _, panic_probe as _}; | 9 | use {defmt_rtt as _, panic_probe as _}; |
| 9 | 10 | ||
| 11 | bind_interrupts!(struct Irqs { | ||
| 12 | UARTE0_UART0 => uarte::InterruptHandler<UARTE0>; | ||
| 13 | }); | ||
| 14 | |||
| 10 | #[embassy_executor::main] | 15 | #[embassy_executor::main] |
| 11 | async fn main(_spawner: Spawner) { | 16 | async 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::*; | |||
| 6 | use embassy_executor::Spawner; | 6 | use embassy_executor::Spawner; |
| 7 | use embassy_nrf::peripherals::UARTE0; | 7 | use embassy_nrf::peripherals::UARTE0; |
| 8 | use embassy_nrf::uarte::UarteRx; | 8 | use embassy_nrf::uarte::UarteRx; |
| 9 | use embassy_nrf::{interrupt, uarte}; | 9 | use embassy_nrf::{bind_interrupts, uarte}; |
| 10 | use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex; | 10 | use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex; |
| 11 | use embassy_sync::channel::Channel; | 11 | use embassy_sync::channel::Channel; |
| 12 | use {defmt_rtt as _, panic_probe as _}; | 12 | use {defmt_rtt as _, panic_probe as _}; |
| 13 | 13 | ||
| 14 | static CHANNEL: Channel<ThreadModeRawMutex, [u8; 8], 1> = Channel::new(); | 14 | static CHANNEL: Channel<ThreadModeRawMutex, [u8; 8], 1> = Channel::new(); |
| 15 | 15 | ||
| 16 | bind_interrupts!(struct Irqs { | ||
| 17 | UARTE0_UART0 => uarte::InterruptHandler<UARTE0>; | ||
| 18 | }); | ||
| 19 | |||
| 16 | #[embassy_executor::main] | 20 | #[embassy_executor::main] |
| 17 | async fn main(spawner: Spawner) { | 21 | async 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; | |||
| 9 | use embassy_net::tcp::TcpSocket; | 9 | use embassy_net::tcp::TcpSocket; |
| 10 | use embassy_net::{Stack, StackResources}; | 10 | use embassy_net::{Stack, StackResources}; |
| 11 | use embassy_nrf::rng::Rng; | 11 | use embassy_nrf::rng::Rng; |
| 12 | use embassy_nrf::usb::{Driver, HardwareVbusDetect}; | 12 | use embassy_nrf::usb::vbus_detect::HardwareVbusDetect; |
| 13 | use embassy_nrf::{interrupt, pac, peripherals}; | 13 | use embassy_nrf::usb::Driver; |
| 14 | use embassy_nrf::{bind_interrupts, pac, peripherals, rng, usb}; | ||
| 14 | use embassy_usb::class::cdc_ncm::embassy_net::{Device, Runner, State as NetState}; | 15 | use embassy_usb::class::cdc_ncm::embassy_net::{Device, Runner, State as NetState}; |
| 15 | use embassy_usb::class::cdc_ncm::{CdcNcmClass, State}; | 16 | use embassy_usb::class::cdc_ncm::{CdcNcmClass, State}; |
| 16 | use embassy_usb::{Builder, Config, UsbDevice}; | 17 | use embassy_usb::{Builder, Config, UsbDevice}; |
| @@ -18,6 +19,12 @@ use embedded_io::asynch::Write; | |||
| 18 | use static_cell::StaticCell; | 19 | use static_cell::StaticCell; |
| 19 | use {defmt_rtt as _, panic_probe as _}; | 20 | use {defmt_rtt as _, panic_probe as _}; |
| 20 | 21 | ||
| 22 | bind_interrupts!(struct Irqs { | ||
| 23 | USBD => usb::InterruptHandler<peripherals::USBD>; | ||
| 24 | POWER_CLOCK => usb::vbus_detect::InterruptHandler; | ||
| 25 | RNG => rng::InterruptHandler<peripherals::RNG>; | ||
| 26 | }); | ||
| 27 | |||
| 21 | type MyDriver = Driver<'static, peripherals::USBD, HardwareVbusDetect>; | 28 | type MyDriver = Driver<'static, peripherals::USBD, HardwareVbusDetect>; |
| 22 | 29 | ||
| 23 | macro_rules! singleton { | 30 | macro_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)] | ||
| 50 | pub 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] |
| 71 | async fn main(spawner: Spawner) { | 57 | async 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; | |||
| 10 | use embassy_futures::join::join; | 10 | use embassy_futures::join::join; |
| 11 | use embassy_futures::select::{select, Either}; | 11 | use embassy_futures::select::{select, Either}; |
| 12 | use embassy_nrf::gpio::{Input, Pin, Pull}; | 12 | use embassy_nrf::gpio::{Input, Pin, Pull}; |
| 13 | use embassy_nrf::usb::{Driver, HardwareVbusDetect}; | 13 | use embassy_nrf::usb::vbus_detect::HardwareVbusDetect; |
| 14 | use embassy_nrf::{interrupt, pac}; | 14 | use embassy_nrf::usb::Driver; |
| 15 | use embassy_nrf::{bind_interrupts, pac, peripherals, usb}; | ||
| 15 | use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; | 16 | use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; |
| 16 | use embassy_sync::signal::Signal; | 17 | use embassy_sync::signal::Signal; |
| 17 | use embassy_usb::class::hid::{HidReaderWriter, ReportId, RequestHandler, State}; | 18 | use embassy_usb::class::hid::{HidReaderWriter, ReportId, RequestHandler, State}; |
| @@ -20,6 +21,11 @@ use embassy_usb::{Builder, Config, Handler}; | |||
| 20 | use usbd_hid::descriptor::{KeyboardReport, SerializedDescriptor}; | 21 | use usbd_hid::descriptor::{KeyboardReport, SerializedDescriptor}; |
| 21 | use {defmt_rtt as _, panic_probe as _}; | 22 | use {defmt_rtt as _, panic_probe as _}; |
| 22 | 23 | ||
| 24 | bind_interrupts!(struct Irqs { | ||
| 25 | USBD => usb::InterruptHandler<peripherals::USBD>; | ||
| 26 | POWER_CLOCK => usb::vbus_detect::InterruptHandler; | ||
| 27 | }); | ||
| 28 | |||
| 23 | static SUSPENDED: AtomicBool = AtomicBool::new(false); | 29 | static 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; | |||
| 7 | use defmt::*; | 7 | use defmt::*; |
| 8 | use embassy_executor::Spawner; | 8 | use embassy_executor::Spawner; |
| 9 | use embassy_futures::join::join; | 9 | use embassy_futures::join::join; |
| 10 | use embassy_nrf::usb::{Driver, HardwareVbusDetect}; | 10 | use embassy_nrf::usb::vbus_detect::HardwareVbusDetect; |
| 11 | use embassy_nrf::{interrupt, pac}; | 11 | use embassy_nrf::usb::Driver; |
| 12 | use embassy_nrf::{bind_interrupts, pac, peripherals, usb}; | ||
| 12 | use embassy_time::{Duration, Timer}; | 13 | use embassy_time::{Duration, Timer}; |
| 13 | use embassy_usb::class::hid::{HidWriter, ReportId, RequestHandler, State}; | 14 | use embassy_usb::class::hid::{HidWriter, ReportId, RequestHandler, State}; |
| 14 | use embassy_usb::control::OutResponse; | 15 | use embassy_usb::control::OutResponse; |
| @@ -16,6 +17,11 @@ use embassy_usb::{Builder, Config}; | |||
| 16 | use usbd_hid::descriptor::{MouseReport, SerializedDescriptor}; | 17 | use usbd_hid::descriptor::{MouseReport, SerializedDescriptor}; |
| 17 | use {defmt_rtt as _, panic_probe as _}; | 18 | use {defmt_rtt as _, panic_probe as _}; |
| 18 | 19 | ||
| 20 | bind_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] |
| 20 | async fn main(_spawner: Spawner) { | 26 | async 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; | |||
| 7 | use defmt::{info, panic}; | 7 | use defmt::{info, panic}; |
| 8 | use embassy_executor::Spawner; | 8 | use embassy_executor::Spawner; |
| 9 | use embassy_futures::join::join; | 9 | use embassy_futures::join::join; |
| 10 | use embassy_nrf::usb::{Driver, HardwareVbusDetect, Instance, VbusDetect}; | 10 | use embassy_nrf::usb::vbus_detect::{HardwareVbusDetect, VbusDetect}; |
| 11 | use embassy_nrf::{interrupt, pac}; | 11 | use embassy_nrf::usb::{Driver, Instance}; |
| 12 | use embassy_nrf::{bind_interrupts, pac, peripherals, usb}; | ||
| 12 | use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; | 13 | use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; |
| 13 | use embassy_usb::driver::EndpointError; | 14 | use embassy_usb::driver::EndpointError; |
| 14 | use embassy_usb::{Builder, Config}; | 15 | use embassy_usb::{Builder, Config}; |
| 15 | use {defmt_rtt as _, panic_probe as _}; | 16 | use {defmt_rtt as _, panic_probe as _}; |
| 16 | 17 | ||
| 18 | bind_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] |
| 18 | async fn main(_spawner: Spawner) { | 24 | async 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 | ||
| 7 | use defmt::{info, panic, unwrap}; | 7 | use defmt::{info, panic, unwrap}; |
| 8 | use embassy_executor::Spawner; | 8 | use embassy_executor::Spawner; |
| 9 | use embassy_nrf::usb::{Driver, HardwareVbusDetect}; | 9 | use embassy_nrf::usb::vbus_detect::HardwareVbusDetect; |
| 10 | use embassy_nrf::{interrupt, pac, peripherals}; | 10 | use embassy_nrf::usb::Driver; |
| 11 | use embassy_nrf::{bind_interrupts, pac, peripherals, usb}; | ||
| 11 | use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; | 12 | use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; |
| 12 | use embassy_usb::driver::EndpointError; | 13 | use embassy_usb::driver::EndpointError; |
| 13 | use embassy_usb::{Builder, Config, UsbDevice}; | 14 | use embassy_usb::{Builder, Config, UsbDevice}; |
| 14 | use static_cell::StaticCell; | 15 | use static_cell::StaticCell; |
| 15 | use {defmt_rtt as _, panic_probe as _}; | 16 | use {defmt_rtt as _, panic_probe as _}; |
| 16 | 17 | ||
| 18 | bind_interrupts!(struct Irqs { | ||
| 19 | USBD => usb::InterruptHandler<peripherals::USBD>; | ||
| 20 | POWER_CLOCK => usb::vbus_detect::InterruptHandler; | ||
| 21 | }); | ||
| 22 | |||
| 23 | macro_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 | |||
| 17 | type MyDriver = Driver<'static, peripherals::USBD, HardwareVbusDetect>; | 32 | type 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; | |||
| 7 | use defmt::{info, panic}; | 7 | use defmt::{info, panic}; |
| 8 | use embassy_executor::Spawner; | 8 | use embassy_executor::Spawner; |
| 9 | use embassy_futures::join::join; | 9 | use embassy_futures::join::join; |
| 10 | use embassy_nrf::usb::{Driver, HardwareVbusDetect, Instance, VbusDetect}; | 10 | use embassy_nrf::usb::vbus_detect::{HardwareVbusDetect, VbusDetect}; |
| 11 | use embassy_nrf::{interrupt, pac}; | 11 | use embassy_nrf::usb::{Driver, Instance}; |
| 12 | use embassy_nrf::{bind_interrupts, pac, peripherals, usb}; | ||
| 12 | use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; | 13 | use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; |
| 13 | use embassy_usb::driver::EndpointError; | 14 | use embassy_usb::driver::EndpointError; |
| 14 | use embassy_usb::msos::{self, windows_version}; | 15 | use embassy_usb::msos::{self, windows_version}; |
| @@ -16,6 +17,11 @@ use embassy_usb::types::InterfaceNumber; | |||
| 16 | use embassy_usb::{Builder, Config}; | 17 | use embassy_usb::{Builder, Config}; |
| 17 | use {defmt_rtt as _, panic_probe as _}; | 18 | use {defmt_rtt as _, panic_probe as _}; |
| 18 | 19 | ||
| 20 | bind_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 |
| 20 | const DEVICE_INTERFACE_GUIDS: &[&str] = &["{EAA9A5DC-30BA-44BC-9232-606CDC875321}"]; | 26 | const 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" | |||
| 4 | version = "0.1.0" | 4 | version = "0.1.0" |
| 5 | license = "MIT OR Apache-2.0" | 5 | license = "MIT OR Apache-2.0" |
| 6 | 6 | ||
| 7 | [features] | ||
| 8 | default = ["nightly"] | ||
| 9 | nightly = [ | ||
| 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] |
| 20 | embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } | 8 | embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } |
| 21 | embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = [ | 9 | embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = [ |
| 22 | "defmt", | 10 | "defmt", |
| 23 | ] } | 11 | ] } |
| 24 | embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = [ | 12 | embassy-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 | ] } |
| 32 | embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = [ | 21 | embassy-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 | ] } |
| 39 | embassy-net = { version = "0.1.0", path = "../../embassy-net", features = [ | 30 | embassy-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 | ] } |
| 45 | embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = [ | 37 | embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = [ |
| 46 | "defmt", | 38 | "defmt", |
| 47 | ], optional = true } | 39 | ] } |
| 48 | embedded-io = "0.4.0" | 40 | embedded-io = { version = "0.4.0", features = [ "async" ]} |
| 49 | |||
| 50 | 41 | ||
| 51 | defmt = "0.3" | 42 | defmt = "0.3" |
| 52 | defmt-rtt = "0.4" | 43 | defmt-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 | ||
| 5 | use defmt::*; | 5 | use defmt::*; |
| 6 | use embassy_executor::Spawner; | 6 | use embassy_executor::Spawner; |
| 7 | use embassy_nrf::{interrupt, uarte}; | 7 | use embassy_nrf::peripherals::SERIAL0; |
| 8 | use embassy_nrf::{bind_interrupts, uarte}; | ||
| 8 | use {defmt_rtt as _, panic_probe as _}; | 9 | use {defmt_rtt as _, panic_probe as _}; |
| 9 | 10 | ||
| 11 | bind_interrupts!(struct Irqs { | ||
| 12 | SERIAL0 => uarte::InterruptHandler<SERIAL0>; | ||
| 13 | }); | ||
| 14 | |||
| 10 | #[embassy_executor::main] | 15 | #[embassy_executor::main] |
| 11 | async fn main(_spawner: Spawner) { | 16 | async 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" | |||
| 15 | embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] } | 15 | embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] } |
| 16 | embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["defmt", "integrated-timers"] } | 16 | embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["defmt", "integrated-timers"] } |
| 17 | embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } | 17 | embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } |
| 18 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "memory-x", "stm32f091rc", "time-driver-any", "exti"] } | 18 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "memory-x", "stm32f091rc", "time-driver-any", "exti", "unstable-pac"] } |
| 19 | static_cell = "1.0" | 19 | static_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 | ||
| 60 | use core::mem; | ||
| 61 | |||
| 62 | use cortex_m::peripheral::NVIC; | ||
| 60 | use cortex_m_rt::entry; | 63 | use cortex_m_rt::entry; |
| 61 | use defmt::*; | 64 | use defmt::*; |
| 62 | use embassy_stm32::executor::{Executor, InterruptExecutor}; | 65 | use embassy_stm32::executor::{Executor, InterruptExecutor}; |
| 63 | use embassy_stm32::interrupt; | 66 | use embassy_stm32::interrupt; |
| 64 | use embassy_stm32::interrupt::InterruptExt; | 67 | use embassy_stm32::pac::Interrupt; |
| 65 | use embassy_time::{Duration, Instant, Timer}; | 68 | use embassy_time::{Duration, Instant, Timer}; |
| 66 | use static_cell::StaticCell; | 69 | use static_cell::StaticCell; |
| 67 | use {defmt_rtt as _, panic_probe as _}; | 70 | use {defmt_rtt as _, panic_probe as _}; |
| @@ -108,27 +111,34 @@ async fn run_low() { | |||
| 108 | } | 111 | } |
| 109 | } | 112 | } |
| 110 | 113 | ||
| 111 | static EXECUTOR_HIGH: StaticCell<InterruptExecutor<interrupt::USART1>> = StaticCell::new(); | 114 | static EXECUTOR_HIGH: InterruptExecutor = InterruptExecutor::new(); |
| 112 | static EXECUTOR_MED: StaticCell<InterruptExecutor<interrupt::USART2>> = StaticCell::new(); | 115 | static EXECUTOR_MED: InterruptExecutor = InterruptExecutor::new(); |
| 113 | static EXECUTOR_LOW: StaticCell<Executor> = StaticCell::new(); | 116 | static EXECUTOR_LOW: StaticCell<Executor> = StaticCell::new(); |
| 114 | 117 | ||
| 118 | #[interrupt] | ||
| 119 | unsafe fn USART1() { | ||
| 120 | EXECUTOR_HIGH.on_interrupt() | ||
| 121 | } | ||
| 122 | |||
| 123 | #[interrupt] | ||
| 124 | unsafe fn USART2() { | ||
| 125 | EXECUTOR_MED.on_interrupt() | ||
| 126 | } | ||
| 127 | |||
| 115 | #[entry] | 128 | #[entry] |
| 116 | fn main() -> ! { | 129 | fn 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 | ||
| 60 | use core::mem; | ||
| 61 | |||
| 62 | use cortex_m::peripheral::NVIC; | ||
| 60 | use cortex_m_rt::entry; | 63 | use cortex_m_rt::entry; |
| 61 | use defmt::*; | 64 | use defmt::*; |
| 62 | use embassy_stm32::executor::{Executor, InterruptExecutor}; | 65 | use embassy_stm32::executor::{Executor, InterruptExecutor}; |
| 63 | use embassy_stm32::interrupt; | 66 | use embassy_stm32::interrupt; |
| 64 | use embassy_stm32::interrupt::InterruptExt; | 67 | use embassy_stm32::pac::Interrupt; |
| 65 | use embassy_time::{Duration, Instant, Timer}; | 68 | use embassy_time::{Duration, Instant, Timer}; |
| 66 | use static_cell::StaticCell; | 69 | use static_cell::StaticCell; |
| 67 | use {defmt_rtt as _, panic_probe as _}; | 70 | use {defmt_rtt as _, panic_probe as _}; |
| @@ -108,28 +111,35 @@ async fn run_low() { | |||
| 108 | } | 111 | } |
| 109 | } | 112 | } |
| 110 | 113 | ||
| 111 | static EXECUTOR_HIGH: StaticCell<InterruptExecutor<interrupt::UART4>> = StaticCell::new(); | 114 | static EXECUTOR_HIGH: InterruptExecutor = InterruptExecutor::new(); |
| 112 | static EXECUTOR_MED: StaticCell<InterruptExecutor<interrupt::UART5>> = StaticCell::new(); | 115 | static EXECUTOR_MED: InterruptExecutor = InterruptExecutor::new(); |
| 113 | static EXECUTOR_LOW: StaticCell<Executor> = StaticCell::new(); | 116 | static EXECUTOR_LOW: StaticCell<Executor> = StaticCell::new(); |
| 114 | 117 | ||
| 118 | #[interrupt] | ||
| 119 | unsafe fn UART4() { | ||
| 120 | EXECUTOR_HIGH.on_interrupt() | ||
| 121 | } | ||
| 122 | |||
| 123 | #[interrupt] | ||
| 124 | unsafe fn UART5() { | ||
| 125 | EXECUTOR_MED.on_interrupt() | ||
| 126 | } | ||
| 127 | |||
| 115 | #[entry] | 128 | #[entry] |
| 116 | fn main() -> ! { | 129 | fn 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 | |||
| 10 | embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "unstable-traits", "tick-hz-32_768"] } | 10 | embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "unstable-traits", "tick-hz-32_768"] } |
| 11 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "unstable-traits", "defmt", "stm32f429zi", "unstable-pac", "memory-x", "time-driver-any", "exti"] } | 11 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "unstable-traits", "defmt", "stm32f429zi", "unstable-pac", "memory-x", "time-driver-any", "exti"] } |
| 12 | embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } | 12 | embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } |
| 13 | embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "nightly"], optional = true } | 13 | embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "nightly"] } |
| 14 | 14 | ||
| 15 | defmt = "0.3" | 15 | defmt = "0.3" |
| 16 | defmt-rtt = "0.4" | 16 | defmt-rtt = "0.4" |
| @@ -27,9 +27,5 @@ embedded-storage = "0.3.0" | |||
| 27 | micromath = "2.0.0" | 27 | micromath = "2.0.0" |
| 28 | static_cell = "1.0" | 28 | static_cell = "1.0" |
| 29 | 29 | ||
| 30 | [[bin]] | ||
| 31 | name = "usb_ethernet" | ||
| 32 | required-features = ["embassy-net"] | ||
| 33 | |||
| 34 | [profile.release] | 30 | [profile.release] |
| 35 | debug = 2 | 31 | debug = 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 | ||
| 60 | use core::mem; | ||
| 61 | |||
| 62 | use cortex_m::peripheral::NVIC; | ||
| 60 | use cortex_m_rt::entry; | 63 | use cortex_m_rt::entry; |
| 61 | use defmt::*; | 64 | use defmt::*; |
| 62 | use embassy_stm32::executor::{Executor, InterruptExecutor}; | 65 | use embassy_stm32::executor::{Executor, InterruptExecutor}; |
| 63 | use embassy_stm32::interrupt; | 66 | use embassy_stm32::interrupt; |
| 64 | use embassy_stm32::interrupt::InterruptExt; | 67 | use embassy_stm32::pac::Interrupt; |
| 65 | use embassy_time::{Duration, Instant, Timer}; | 68 | use embassy_time::{Duration, Instant, Timer}; |
| 66 | use static_cell::StaticCell; | 69 | use static_cell::StaticCell; |
| 67 | use {defmt_rtt as _, panic_probe as _}; | 70 | use {defmt_rtt as _, panic_probe as _}; |
| @@ -108,28 +111,35 @@ async fn run_low() { | |||
| 108 | } | 111 | } |
| 109 | } | 112 | } |
| 110 | 113 | ||
| 111 | static EXECUTOR_HIGH: StaticCell<InterruptExecutor<interrupt::UART4>> = StaticCell::new(); | 114 | static EXECUTOR_HIGH: InterruptExecutor = InterruptExecutor::new(); |
| 112 | static EXECUTOR_MED: StaticCell<InterruptExecutor<interrupt::UART5>> = StaticCell::new(); | 115 | static EXECUTOR_MED: InterruptExecutor = InterruptExecutor::new(); |
| 113 | static EXECUTOR_LOW: StaticCell<Executor> = StaticCell::new(); | 116 | static EXECUTOR_LOW: StaticCell<Executor> = StaticCell::new(); |
| 114 | 117 | ||
| 118 | #[interrupt] | ||
| 119 | unsafe fn UART4() { | ||
| 120 | EXECUTOR_HIGH.on_interrupt() | ||
| 121 | } | ||
| 122 | |||
| 123 | #[interrupt] | ||
| 124 | unsafe fn UART5() { | ||
| 125 | EXECUTOR_MED.on_interrupt() | ||
| 126 | } | ||
| 127 | |||
| 115 | #[entry] | 128 | #[entry] |
| 116 | fn main() -> ! { | 129 | fn 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" | |||
| 4 | version = "0.1.0" | 4 | version = "0.1.0" |
| 5 | license = "MIT OR Apache-2.0" | 5 | license = "MIT OR Apache-2.0" |
| 6 | 6 | ||
| 7 | [features] | ||
| 8 | |||
| 9 | [dependencies] | 7 | [dependencies] |
| 10 | embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] } | 8 | embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] } |
| 11 | embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["defmt", "integrated-timers"] } | 9 | embassy-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" | |||
| 4 | version = "0.1.0" | 4 | version = "0.1.0" |
| 5 | license = "MIT OR Apache-2.0" | 5 | license = "MIT OR Apache-2.0" |
| 6 | 6 | ||
| 7 | [features] | ||
| 8 | |||
| 9 | [dependencies] | 7 | [dependencies] |
| 10 | embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] } | 8 | embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] } |
| 11 | embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["defmt", "integrated-timers"] } | 9 | embassy-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" | ||
| 3 | runner = "teleprobe client run --target nrf52840-dk --elf" | ||
| 4 | |||
| 5 | [build] | ||
| 6 | target = "thumbv7em-none-eabi" | ||
| 7 | |||
| 8 | [env] | ||
| 9 | DEFMT_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] | ||
| 2 | edition = "2021" | ||
| 3 | name = "embassy-nrf-examples" | ||
| 4 | version = "0.1.0" | ||
| 5 | license = "MIT OR Apache-2.0" | ||
| 6 | |||
| 7 | [dependencies] | ||
| 8 | embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } | ||
| 9 | embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt", "nightly"] } | ||
| 10 | embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["defmt", "nightly", "integrated-timers"] } | ||
| 11 | embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "nightly", "defmt-timestamp-uptime"] } | ||
| 12 | embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["defmt", "nightly", "unstable-traits", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac"] } | ||
| 13 | embedded-io = { version = "0.4.0", features = ["async"] } | ||
| 14 | |||
| 15 | defmt = "0.3" | ||
| 16 | defmt-rtt = "0.4" | ||
| 17 | |||
| 18 | cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } | ||
| 19 | cortex-m-rt = "0.7.0" | ||
| 20 | panic-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 @@ | |||
| 1 | use std::error::Error; | ||
| 2 | use std::path::PathBuf; | ||
| 3 | use std::{env, fs}; | ||
| 4 | |||
| 5 | fn 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 */ | ||
| 28 | INCLUDE memory.x | ||
| 29 | |||
| 30 | /* # Entry point = reset vector */ | ||
| 31 | EXTERN(__RESET_VECTOR); | ||
| 32 | EXTERN(Reset); | ||
| 33 | ENTRY(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) */ | ||
| 39 | EXTERN(__EXCEPTIONS); /* depends on all the these PROVIDED symbols */ | ||
| 40 | |||
| 41 | EXTERN(DefaultHandler); | ||
| 42 | |||
| 43 | PROVIDE(NonMaskableInt = DefaultHandler); | ||
| 44 | EXTERN(HardFaultTrampoline); | ||
| 45 | PROVIDE(MemoryManagement = DefaultHandler); | ||
| 46 | PROVIDE(BusFault = DefaultHandler); | ||
| 47 | PROVIDE(UsageFault = DefaultHandler); | ||
| 48 | PROVIDE(SecureFault = DefaultHandler); | ||
| 49 | PROVIDE(SVCall = DefaultHandler); | ||
| 50 | PROVIDE(DebugMonitor = DefaultHandler); | ||
| 51 | PROVIDE(PendSV = DefaultHandler); | ||
| 52 | PROVIDE(SysTick = DefaultHandler); | ||
| 53 | |||
| 54 | PROVIDE(DefaultHandler = DefaultHandler_); | ||
| 55 | PROVIDE(HardFault = HardFault_); | ||
| 56 | |||
| 57 | /* # Interrupt vectors */ | ||
| 58 | EXTERN(__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. */ | ||
| 63 | PROVIDE(__pre_init = DefaultPreInit); | ||
| 64 | |||
| 65 | /* # Sections */ | ||
| 66 | SECTIONS | ||
| 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 */ | ||
| 201 | ASSERT(ORIGIN(RAM) % 4 == 0, " | ||
| 202 | ERROR(cortex-m-rt): the start of the RAM region must be 4-byte aligned"); | ||
| 203 | |||
| 204 | ASSERT(__sdata % 4 == 0 && __edata % 4 == 0, " | ||
| 205 | BUG(cortex-m-rt): .data is not 4-byte aligned"); | ||
| 206 | |||
| 207 | ASSERT(__sidata % 4 == 0, " | ||
| 208 | BUG(cortex-m-rt): the LMA of .data is not 4-byte aligned"); | ||
| 209 | |||
| 210 | ASSERT(__sbss % 4 == 0 && __ebss % 4 == 0, " | ||
| 211 | BUG(cortex-m-rt): .bss is not 4-byte aligned"); | ||
| 212 | |||
| 213 | ASSERT(__sheap % 4 == 0, " | ||
| 214 | BUG(cortex-m-rt): start of .heap is not 4-byte aligned"); | ||
| 215 | |||
| 216 | /* # Position checks */ | ||
| 217 | |||
| 218 | /* ## .vector_table */ | ||
| 219 | ASSERT(__reset_vector == ADDR(.vector_table) + 0x8, " | ||
| 220 | BUG(cortex-m-rt): the reset vector is missing"); | ||
| 221 | |||
| 222 | ASSERT(__eexceptions == ADDR(.vector_table) + 0x40, " | ||
| 223 | BUG(cortex-m-rt): the exception vectors are missing"); | ||
| 224 | |||
| 225 | ASSERT(SIZEOF(.vector_table) > 0x40, " | ||
| 226 | ERROR(cortex-m-rt): The interrupt vectors are missing. | ||
| 227 | Possible 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 | ||
| 231 | may be enabling it) | ||
| 232 | - Supply the interrupt handlers yourself. Check the documentation for details."); | ||
| 233 | |||
| 234 | /* ## .text */ | ||
| 235 | ASSERT(ADDR(.vector_table) + SIZEOF(.vector_table) <= _stext, " | ||
| 236 | ERROR(cortex-m-rt): The .text section can't be placed inside the .vector_table section | ||
| 237 | Set _stext to an address greater than the end of .vector_table (See output of `nm`)"); | ||
| 238 | |||
| 239 | ASSERT(_stext + SIZEOF(.text) < ORIGIN(RAM) + LENGTH(RAM), " | ||
| 240 | ERROR(cortex-m-rt): The .text section must be placed inside the RAM memory. | ||
| 241 | Set _stext to an address smaller than 'ORIGIN(RAM) + LENGTH(RAM)'"); | ||
| 242 | |||
| 243 | /* # Other checks */ | ||
| 244 | ASSERT(SIZEOF(.got) == 0, " | ||
| 245 | ERROR(cortex-m-rt): .got section detected in the input object files | ||
| 246 | Dynamic relocations are not supported. If you are linking to C code compiled using | ||
| 247 | the 'cc' crate then modify your build script to compile the C code _without_ | ||
| 248 | the -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`) */ | ||
| 254 | INCLUDE 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 @@ | |||
| 1 | MEMORY | ||
| 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 | |||
| 5 | use defmt::{assert_eq, *}; | ||
| 6 | use embassy_executor::Spawner; | ||
| 7 | use embassy_futures::join::join; | ||
| 8 | use embassy_nrf::buffered_uarte::{self, BufferedUarte}; | ||
| 9 | use embassy_nrf::{bind_interrupts, peripherals, uarte}; | ||
| 10 | use {defmt_rtt as _, panic_probe as _}; | ||
| 11 | |||
| 12 | bind_interrupts!(struct Irqs { | ||
| 13 | UARTE0_UART0 => buffered_uarte::InterruptHandler<peripherals::UARTE0>; | ||
| 14 | }); | ||
| 15 | |||
| 16 | #[embassy_executor::main] | ||
| 17 | async 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 | |||
| 5 | use core::mem; | ||
| 6 | use core::ptr::NonNull; | ||
| 7 | |||
| 8 | use defmt::{assert_eq, *}; | ||
| 9 | use embassy_executor::Spawner; | ||
| 10 | use embassy_nrf::buffered_uarte::{self, BufferedUarte}; | ||
| 11 | use embassy_nrf::gpio::{Level, Output, OutputDrive}; | ||
| 12 | use embassy_nrf::ppi::{Event, Ppi, Task}; | ||
| 13 | use embassy_nrf::uarte::Uarte; | ||
| 14 | use embassy_nrf::{bind_interrupts, pac, peripherals, uarte}; | ||
| 15 | use embassy_time::{Duration, Timer}; | ||
| 16 | use {defmt_rtt as _, panic_probe as _}; | ||
| 17 | |||
| 18 | bind_interrupts!(struct Irqs { | ||
| 19 | UARTE0_UART0 => buffered_uarte::InterruptHandler<peripherals::UARTE0>; | ||
| 20 | UARTE1 => uarte::InterruptHandler<peripherals::UARTE1>; | ||
| 21 | }); | ||
| 22 | |||
| 23 | #[embassy_executor::main] | ||
| 24 | async 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 | } | ||
