From 7086642ce43de7c2fe476da94ec53ed6282087ec Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Thu, 13 Jan 2022 19:27:10 +0100 Subject: [PATCH 1/9] nrf/spim: share code between blocking+async. --- embassy-nrf/src/spim.rs | 209 ++++++++++++++-------------------------- embassy-nrf/src/util.rs | 22 ++++- 2 files changed, 89 insertions(+), 142 deletions(-) diff --git a/embassy-nrf/src/spim.rs b/embassy-nrf/src/spim.rs index bc5823f6a..8159cefe8 100644 --- a/embassy-nrf/src/spim.rs +++ b/embassy-nrf/src/spim.rs @@ -15,6 +15,7 @@ use crate::gpio; use crate::gpio::sealed::Pin as _; use crate::gpio::{OptionalPin, Pin as GpioPin}; use crate::interrupt::Interrupt; +use crate::util::{slice_ptr_parts, slice_ptr_parts_mut}; use crate::{pac, util::slice_in_ram_or}; pub use embedded_hal::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3}; @@ -157,6 +158,74 @@ impl<'d, T: Instance> Spim<'d, T> { r.intenclr.write(|w| w.end().clear()); } } + + fn start_transfer(&mut self, rx: *mut [u8], tx: *const [u8]) -> Result<(), Error> { + slice_in_ram_or(tx, Error::DMABufferNotInDataMemory)?; + // NOTE: RAM slice check for rx is not necessary, as a mutable + // slice can only be built from data located in RAM. + + // Conservative compiler fence to prevent optimizations that do not + // take in to account actions by DMA. The fence has been placed here, + // before any DMA action has started. + compiler_fence(Ordering::SeqCst); + + let r = T::regs(); + + // Set up the DMA write. + let (ptr, len) = slice_ptr_parts(tx); + r.txd.ptr.write(|w| unsafe { w.ptr().bits(ptr as _) }); + r.txd.maxcnt.write(|w| unsafe { w.maxcnt().bits(len as _) }); + + // Set up the DMA read. + let (ptr, len) = slice_ptr_parts_mut(rx); + r.rxd.ptr.write(|w| unsafe { w.ptr().bits(ptr as _) }); + r.rxd.maxcnt.write(|w| unsafe { w.maxcnt().bits(len as _) }); + + // Reset and enable the event + r.events_end.reset(); + r.intenset.write(|w| w.end().set()); + + // Start SPI transaction. + r.tasks_start.write(|w| unsafe { w.bits(1) }); + + Ok(()) + } + + fn blocking_transfer(&mut self, rx: *mut [u8], tx: *const [u8]) -> Result<(), Error> { + self.start_transfer(rx, tx)?; + + // Wait for 'end' event. + while T::regs().events_end.read().bits() == 0 {} + + // Conservative compiler fence to prevent optimizations that do not + // take in to account actions by DMA. The fence has been placed here, + // after all possible DMA actions have completed. + compiler_fence(Ordering::SeqCst); + + Ok(()) + } + + async fn async_transfer(&mut self, rx: *mut [u8], tx: *const [u8]) -> Result<(), Error> { + self.start_transfer(rx, tx)?; + + // Wait for 'end' event. + poll_fn(|cx| { + T::state().end_waker.register(cx.waker()); + if T::regs().events_end.read().bits() != 0 { + return Poll::Ready(()); + } + + Poll::Pending + }) + .await; + + // Conservative compiler fence to prevent optimizations that do not + // take in to account actions by DMA. The fence has been placed here, + // after all possible DMA actions have completed. + compiler_fence(Ordering::SeqCst); + + Ok(()) + } } impl<'d, T: Instance> Drop for Spim<'d, T> { @@ -210,108 +279,14 @@ impl<'d, T: Instance> FullDuplex for Spim<'d, T> { = impl Future> + 'a; fn read_write<'a>(&'a mut self, rx: &'a mut [u8], tx: &'a [u8]) -> Self::WriteReadFuture<'a> { - async move { - slice_in_ram_or(tx, Error::DMABufferNotInDataMemory)?; - // NOTE: RAM slice check for rx is not necessary, as a mutable - // slice can only be built from data located in RAM. - - // Conservative compiler fence to prevent optimizations that do not - // take in to account actions by DMA. The fence has been placed here, - // before any DMA action has started. - compiler_fence(Ordering::SeqCst); - - let r = T::regs(); - let s = T::state(); - - // Set up the DMA write. - r.txd - .ptr - .write(|w| unsafe { w.ptr().bits(tx.as_ptr() as u32) }); - r.txd - .maxcnt - .write(|w| unsafe { w.maxcnt().bits(tx.len() as _) }); - - // Set up the DMA read. - r.rxd - .ptr - .write(|w| unsafe { w.ptr().bits(rx.as_mut_ptr() as u32) }); - r.rxd - .maxcnt - .write(|w| unsafe { w.maxcnt().bits(rx.len() as _) }); - - // Reset and enable the event - r.events_end.reset(); - r.intenset.write(|w| w.end().set()); - - // Start SPI transaction. - r.tasks_start.write(|w| unsafe { w.bits(1) }); - - // Conservative compiler fence to prevent optimizations that do not - // take in to account actions by DMA. The fence has been placed here, - // after all possible DMA actions have completed. - compiler_fence(Ordering::SeqCst); - - // Wait for 'end' event. - poll_fn(|cx| { - s.end_waker.register(cx.waker()); - if r.events_end.read().bits() != 0 { - return Poll::Ready(()); - } - - Poll::Pending - }) - .await; - - Ok(()) - } + self.async_transfer(rx, tx) } } -// Blocking functions are provided by implementing `embedded_hal` traits. -// -// Code could be shared between traits to reduce code size. impl<'d, T: Instance> embedded_hal::blocking::spi::Transfer for Spim<'d, T> { type Error = Error; fn transfer<'w>(&mut self, words: &'w mut [u8]) -> Result<&'w [u8], Self::Error> { - slice_in_ram_or(words, Error::DMABufferNotInDataMemory)?; - - // Conservative compiler fence to prevent optimizations that do not - // take in to account actions by DMA. The fence has been placed here, - // before any DMA action has started. - compiler_fence(Ordering::SeqCst); - - let r = T::regs(); - - // Set up the DMA write. - r.txd - .ptr - .write(|w| unsafe { w.ptr().bits(words.as_ptr() as u32) }); - r.txd - .maxcnt - .write(|w| unsafe { w.maxcnt().bits(words.len() as _) }); - - // Set up the DMA read. - r.rxd - .ptr - .write(|w| unsafe { w.ptr().bits(words.as_mut_ptr() as u32) }); - r.rxd - .maxcnt - .write(|w| unsafe { w.maxcnt().bits(words.len() as _) }); - - // Disable the end event since we are busy-polling. - r.events_end.reset(); - - // Start SPI transaction. - r.tasks_start.write(|w| unsafe { w.bits(1) }); - - // Wait for 'end' event. - while r.events_end.read().bits() == 0 {} - - // Conservative compiler fence to prevent optimizations that do not - // take in to account actions by DMA. The fence has been placed here, - // after all possible DMA actions have completed. - compiler_fence(Ordering::SeqCst); - + self.blocking_transfer(words, words)?; Ok(words) } } @@ -320,47 +295,7 @@ impl<'d, T: Instance> embedded_hal::blocking::spi::Write for Spim<'d, T> { type Error = Error; fn write(&mut self, words: &[u8]) -> Result<(), Self::Error> { - slice_in_ram_or(words, Error::DMABufferNotInDataMemory)?; - let recv: &mut [u8] = &mut []; - - // Conservative compiler fence to prevent optimizations that do not - // take in to account actions by DMA. The fence has been placed here, - // before any DMA action has started. - compiler_fence(Ordering::SeqCst); - - let r = T::regs(); - - // Set up the DMA write. - r.txd - .ptr - .write(|w| unsafe { w.ptr().bits(words.as_ptr() as u32) }); - r.txd - .maxcnt - .write(|w| unsafe { w.maxcnt().bits(words.len() as _) }); - - // Set up the DMA read. - r.rxd - .ptr - .write(|w| unsafe { w.ptr().bits(recv.as_mut_ptr() as u32) }); - r.rxd - .maxcnt - .write(|w| unsafe { w.maxcnt().bits(recv.len() as _) }); - - // Disable the end event since we are busy-polling. - r.events_end.reset(); - - // Start SPI transaction. - r.tasks_start.write(|w| unsafe { w.bits(1) }); - - // Wait for 'end' event. - while r.events_end.read().bits() == 0 {} - - // Conservative compiler fence to prevent optimizations that do not - // take in to account actions by DMA. The fence has been placed here, - // after all possible DMA actions have completed. - compiler_fence(Ordering::SeqCst); - - Ok(()) + self.blocking_transfer(&mut [], words) } } diff --git a/embassy-nrf/src/util.rs b/embassy-nrf/src/util.rs index 2fd0bc5a8..76162b701 100644 --- a/embassy-nrf/src/util.rs +++ b/embassy-nrf/src/util.rs @@ -1,16 +1,28 @@ +use core::mem; + const SRAM_LOWER: usize = 0x2000_0000; const SRAM_UPPER: usize = 0x3000_0000; +// TODO: replace transmutes with core::ptr::metadata once it's stable + +pub(crate) fn slice_ptr_parts(slice: *const [T]) -> (usize, usize) { + unsafe { mem::transmute(slice) } +} + +pub(crate) fn slice_ptr_parts_mut(slice: *mut [T]) -> (usize, usize) { + unsafe { mem::transmute(slice) } +} + /// Does this slice reside entirely within RAM? -pub(crate) fn slice_in_ram(slice: &[T]) -> bool { - let ptr = slice.as_ptr() as usize; - ptr >= SRAM_LOWER && (ptr + slice.len() * core::mem::size_of::()) < SRAM_UPPER +pub(crate) fn slice_in_ram(slice: *const [T]) -> bool { + let (ptr, len) = slice_ptr_parts(slice); + ptr >= SRAM_LOWER && (ptr + len * core::mem::size_of::()) < SRAM_UPPER } /// Return an error if slice is not in RAM. #[cfg(not(feature = "nrf51"))] -pub(crate) fn slice_in_ram_or(slice: &[T], err: E) -> Result<(), E> { - if slice.is_empty() || slice_in_ram(slice) { +pub(crate) fn slice_in_ram_or(slice: *const [T], err: E) -> Result<(), E> { + if slice_in_ram(slice) { Ok(()) } else { Err(err) From a287fef687b47edc57e17131e3d663cd860ad471 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Thu, 13 Jan 2022 20:00:33 +0100 Subject: [PATCH 2/9] nrf/spim: expose all functionality as inherent methods. --- embassy-nrf/src/spim.rs | 65 ++++++++++++++++++++++++------------ examples/nrf/src/bin/spim.rs | 9 +++-- 2 files changed, 47 insertions(+), 27 deletions(-) diff --git a/embassy-nrf/src/spim.rs b/embassy-nrf/src/spim.rs index 8159cefe8..e767bc703 100644 --- a/embassy-nrf/src/spim.rs +++ b/embassy-nrf/src/spim.rs @@ -133,9 +133,7 @@ impl<'d, T: Instance> Spim<'d, T> { // Set over-read character let orc = config.orc; - r.orc.write(|w| - // The ORC field is 8 bits long, so any u8 is a valid value to write. - unsafe { w.orc().bits(orc) }); + r.orc.write(|w| unsafe { w.orc().bits(orc) }); // Disable all events interrupts r.intenclr.write(|w| unsafe { w.bits(0xFFFF_FFFF) }); @@ -159,14 +157,11 @@ impl<'d, T: Instance> Spim<'d, T> { } } - fn start_transfer(&mut self, rx: *mut [u8], tx: *const [u8]) -> Result<(), Error> { + fn prepare(&mut self, rx: *mut [u8], tx: *const [u8]) -> Result<(), Error> { slice_in_ram_or(tx, Error::DMABufferNotInDataMemory)?; // NOTE: RAM slice check for rx is not necessary, as a mutable // slice can only be built from data located in RAM. - // Conservative compiler fence to prevent optimizations that do not - // take in to account actions by DMA. The fence has been placed here, - // before any DMA action has started. compiler_fence(Ordering::SeqCst); let r = T::regs(); @@ -191,22 +186,19 @@ impl<'d, T: Instance> Spim<'d, T> { Ok(()) } - fn blocking_transfer(&mut self, rx: *mut [u8], tx: *const [u8]) -> Result<(), Error> { - self.start_transfer(rx, tx)?; + fn blocking_inner(&mut self, rx: *mut [u8], tx: *const [u8]) -> Result<(), Error> { + self.prepare(rx, tx)?; // Wait for 'end' event. while T::regs().events_end.read().bits() == 0 {} - // Conservative compiler fence to prevent optimizations that do not - // take in to account actions by DMA. The fence has been placed here, - // after all possible DMA actions have completed. compiler_fence(Ordering::SeqCst); Ok(()) } - async fn async_transfer(&mut self, rx: *mut [u8], tx: *const [u8]) -> Result<(), Error> { - self.start_transfer(rx, tx)?; + async fn async_inner(&mut self, rx: *mut [u8], tx: *const [u8]) -> Result<(), Error> { + self.prepare(rx, tx)?; // Wait for 'end' event. poll_fn(|cx| { @@ -219,13 +211,42 @@ impl<'d, T: Instance> Spim<'d, T> { }) .await; - // Conservative compiler fence to prevent optimizations that do not - // take in to account actions by DMA. The fence has been placed here, - // after all possible DMA actions have completed. compiler_fence(Ordering::SeqCst); Ok(()) } + + pub fn blocking_read(&mut self, data: &mut [u8]) -> Result<(), Error> { + self.blocking_inner(data, &[]) + } + + pub fn blocking_transfer(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), Error> { + self.blocking_inner(read, write) + } + + pub fn blocking_transfer_in_place(&mut self, data: &mut [u8]) -> Result<(), Error> { + self.blocking_inner(data, data) + } + + pub fn blocking_write(&mut self, data: &[u8]) -> Result<(), Error> { + self.blocking_inner(&mut [], data) + } + + pub async fn read(&mut self, data: &mut [u8]) -> Result<(), Error> { + self.async_inner(data, &[]).await + } + + pub async fn transfer(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), Error> { + self.async_inner(read, write).await + } + + pub async fn transfer_in_place(&mut self, data: &mut [u8]) -> Result<(), Error> { + self.async_inner(data, data).await + } + + pub async fn write(&mut self, data: &[u8]) -> Result<(), Error> { + self.async_inner(&mut [], data).await + } } impl<'d, T: Instance> Drop for Spim<'d, T> { @@ -257,7 +278,7 @@ impl<'d, T: Instance> Read for Spim<'d, T> { = impl Future> + 'a; fn read<'a>(&'a mut self, data: &'a mut [u8]) -> Self::ReadFuture<'a> { - self.read_write(data, &[]) + self.read(data) } } @@ -268,7 +289,7 @@ impl<'d, T: Instance> Write for Spim<'d, T> { = impl Future> + 'a; fn write<'a>(&'a mut self, data: &'a [u8]) -> Self::WriteFuture<'a> { - self.read_write(&mut [], data) + self.write(data) } } @@ -279,14 +300,14 @@ impl<'d, T: Instance> FullDuplex for Spim<'d, T> { = impl Future> + 'a; fn read_write<'a>(&'a mut self, rx: &'a mut [u8], tx: &'a [u8]) -> Self::WriteReadFuture<'a> { - self.async_transfer(rx, tx) + self.transfer(rx, tx) } } impl<'d, T: Instance> embedded_hal::blocking::spi::Transfer for Spim<'d, T> { type Error = Error; fn transfer<'w>(&mut self, words: &'w mut [u8]) -> Result<&'w [u8], Self::Error> { - self.blocking_transfer(words, words)?; + self.blocking_transfer_in_place(words)?; Ok(words) } } @@ -295,7 +316,7 @@ impl<'d, T: Instance> embedded_hal::blocking::spi::Write for Spim<'d, T> { type Error = Error; fn write(&mut self, words: &[u8]) -> Result<(), Self::Error> { - self.blocking_transfer(&mut [], words) + self.blocking_write(words) } } diff --git a/examples/nrf/src/bin/spim.rs b/examples/nrf/src/bin/spim.rs index fc31d140a..cda3baa26 100644 --- a/examples/nrf/src/bin/spim.rs +++ b/examples/nrf/src/bin/spim.rs @@ -9,7 +9,6 @@ use embassy::executor::Spawner; use embassy_nrf::gpio::{Level, Output, OutputDrive}; use embassy_nrf::Peripherals; use embassy_nrf::{interrupt, spim}; -use embassy_traits::spi::FullDuplex; use example_common::*; #[embassy::main] @@ -31,7 +30,7 @@ async fn main(_spawner: Spawner, p: Peripherals) { ncs.set_low(); cortex_m::asm::delay(5); let tx = [0xFF]; - unwrap!(spim.read_write(&mut [], &tx).await); + unwrap!(spim.transfer(&mut [], &tx).await); cortex_m::asm::delay(10); ncs.set_high(); @@ -44,7 +43,7 @@ async fn main(_spawner: Spawner, p: Peripherals) { ncs.set_low(); cortex_m::asm::delay(5000); let tx = [0b000_11101, 0]; - unwrap!(spim.read_write(&mut rx, &tx).await); + unwrap!(spim.transfer(&mut rx, &tx).await); cortex_m::asm::delay(5000); ncs.set_high(); info!("estat: {=[?]}", rx); @@ -54,7 +53,7 @@ async fn main(_spawner: Spawner, p: Peripherals) { ncs.set_low(); cortex_m::asm::delay(5); let tx = [0b100_11111, 0b11]; - unwrap!(spim.read_write(&mut rx, &tx).await); + unwrap!(spim.transfer(&mut rx, &tx).await); cortex_m::asm::delay(10); ncs.set_high(); @@ -63,7 +62,7 @@ async fn main(_spawner: Spawner, p: Peripherals) { ncs.set_low(); cortex_m::asm::delay(5); let tx = [0b000_10010, 0]; - unwrap!(spim.read_write(&mut rx, &tx).await); + unwrap!(spim.transfer(&mut rx, &tx).await); cortex_m::asm::delay(10); ncs.set_high(); From ecb4f8fb00e8e1c220cfb24252e562b80f8de457 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Thu, 13 Jan 2022 20:47:28 +0100 Subject: [PATCH 3/9] nrf/twim: expose all functionality as inherent methods. --- embassy-nrf/src/twim.rs | 420 ++++++++++---------------- examples/nrf/src/bin/twim.rs | 2 +- examples/nrf/src/bin/twim_lowpower.rs | 2 +- 3 files changed, 157 insertions(+), 267 deletions(-) diff --git a/embassy-nrf/src/twim.rs b/embassy-nrf/src/twim.rs index 3cc79227e..ab649c470 100644 --- a/embassy-nrf/src/twim.rs +++ b/embassy-nrf/src/twim.rs @@ -201,7 +201,7 @@ impl<'d, T: Instance> Twim<'d, T> { } /// Get Error instance, if any occurred. - fn read_errorsrc(&self) -> Result<(), Error> { + fn check_errorsrc(&self) -> Result<(), Error> { let r = T::regs(); let err = r.errorsrc.read(); @@ -217,8 +217,26 @@ impl<'d, T: Instance> Twim<'d, T> { Ok(()) } + fn check_rx(&self, len: usize) -> Result<(), Error> { + let r = T::regs(); + if r.rxd.amount.read().bits() != len as u32 { + Err(Error::Receive) + } else { + Ok(()) + } + } + + fn check_tx(&self, len: usize) -> Result<(), Error> { + let r = T::regs(); + if r.txd.amount.read().bits() != len as u32 { + Err(Error::Transmit) + } else { + Ok(()) + } + } + /// Wait for stop or error - fn wait(&mut self) { + fn blocking_wait(&mut self) { let r = T::regs(); loop { if r.events_stopped.read().bits() != 0 { @@ -232,16 +250,32 @@ impl<'d, T: Instance> Twim<'d, T> { } } - /// Write to an I2C slave. - /// - /// The buffer must have a length of at most 255 bytes on the nRF52832 - /// and at most 65535 bytes on the nRF52840. - pub fn write(&mut self, address: u8, buffer: &[u8]) -> Result<(), Error> { + /// Wait for stop or error + fn async_wait(&mut self) -> impl Future { + poll_fn(move |cx| { + let r = T::regs(); + let s = T::state(); + + s.end_waker.register(cx.waker()); + if r.events_stopped.read().bits() != 0 { + r.events_stopped.reset(); + + return Poll::Ready(()); + } + + // stop if an error occured + if r.events_error.read().bits() != 0 { + r.events_error.reset(); + r.tasks_stop.write(|w| unsafe { w.bits(1) }); + } + + Poll::Pending + }) + } + + fn setup_write(&mut self, address: u8, buffer: &[u8], inten: bool) -> Result<(), Error> { let r = T::regs(); - // Conservative compiler fence to prevent optimizations that do not - // take in to account actions by DMA. The fence has been placed here, - // before any DMA action has started. compiler_fence(SeqCst); r.address.write(|w| unsafe { w.address().bits(address) }); @@ -255,38 +289,21 @@ impl<'d, T: Instance> Twim<'d, T> { r.events_lasttx.reset(); self.clear_errorsrc(); - // Start write operation. - r.shorts.write(|w| w.lasttx_stop().enabled()); - r.tasks_starttx.write(|w| - // `1` is a valid value to write to task registers. - unsafe { w.bits(1) }); - - self.wait(); - - // Conservative compiler fence to prevent optimizations that do not - // take in to account actions by DMA. The fence has been placed here, - // after all possible DMA actions have completed. - compiler_fence(SeqCst); - - self.read_errorsrc()?; - - if r.txd.amount.read().bits() != buffer.len() as u32 { - return Err(Error::Transmit); + if inten { + r.intenset.write(|w| w.stopped().set().error().set()); + } else { + r.intenclr.write(|w| w.stopped().clear().error().clear()); } + // Start write operation. + r.shorts.write(|w| w.lasttx_stop().enabled()); + r.tasks_starttx.write(|w| unsafe { w.bits(1) }); Ok(()) } - /// Read from an I2C slave. - /// - /// The buffer must have a length of at most 255 bytes on the nRF52832 - /// and at most 65535 bytes on the nRF52840. - pub fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error> { + fn setup_read(&mut self, address: u8, buffer: &mut [u8], inten: bool) -> Result<(), Error> { let r = T::regs(); - // Conservative compiler fence to prevent optimizations that do not - // take in to account actions by DMA. The fence has been placed here, - // before any DMA action has started. compiler_fence(SeqCst); r.address.write(|w| unsafe { w.address().bits(address) }); @@ -299,44 +316,27 @@ impl<'d, T: Instance> Twim<'d, T> { r.events_error.reset(); self.clear_errorsrc(); - // Start read operation. - r.shorts.write(|w| w.lastrx_stop().enabled()); - r.tasks_startrx.write(|w| - // `1` is a valid value to write to task registers. - unsafe { w.bits(1) }); - - self.wait(); - - // Conservative compiler fence to prevent optimizations that do not - // take in to account actions by DMA. The fence has been placed here, - // after all possible DMA actions have completed. - compiler_fence(SeqCst); - - self.read_errorsrc()?; - - if r.rxd.amount.read().bits() != buffer.len() as u32 { - return Err(Error::Receive); + if inten { + r.intenset.write(|w| w.stopped().set().error().set()); + } else { + r.intenclr.write(|w| w.stopped().clear().error().clear()); } + // Start read operation. + r.shorts.write(|w| w.lastrx_stop().enabled()); + r.tasks_startrx.write(|w| unsafe { w.bits(1) }); Ok(()) } - /// Write data to an I2C slave, then read data from the slave without - /// triggering a stop condition between the two. - /// - /// The buffers must have a length of at most 255 bytes on the nRF52832 - /// and at most 65535 bytes on the nRF52840. - pub fn write_then_read( + fn setup_write_read( &mut self, address: u8, wr_buffer: &[u8], rd_buffer: &mut [u8], + inten: bool, ) -> Result<(), Error> { let r = T::regs(); - // Conservative compiler fence to prevent optimizations that do not - // take in to account actions by DMA. The fence has been placed here, - // before any DMA action has started. compiler_fence(SeqCst); r.address.write(|w| unsafe { w.address().bits(address) }); @@ -352,35 +352,65 @@ impl<'d, T: Instance> Twim<'d, T> { r.events_error.reset(); self.clear_errorsrc(); + if inten { + r.intenset.write(|w| w.stopped().set().error().set()); + } else { + r.intenclr.write(|w| w.stopped().clear().error().clear()); + } + // Start write+read operation. r.shorts.write(|w| { w.lasttx_startrx().enabled(); w.lastrx_stop().enabled(); w }); - // `1` is a valid value to write to task registers. r.tasks_starttx.write(|w| unsafe { w.bits(1) }); + Ok(()) + } - self.wait(); - - // Conservative compiler fence to prevent optimizations that do not - // take in to account actions by DMA. The fence has been placed here, - // after all possible DMA actions have completed. + /// Write to an I2C slave. + /// + /// The buffer must have a length of at most 255 bytes on the nRF52832 + /// and at most 65535 bytes on the nRF52840. + pub fn blocking_write(&mut self, address: u8, buffer: &[u8]) -> Result<(), Error> { + self.setup_write(address, buffer, false)?; + self.blocking_wait(); compiler_fence(SeqCst); + self.check_errorsrc()?; + self.check_tx(buffer.len())?; + Ok(()) + } - self.read_errorsrc()?; - - let bad_write = r.txd.amount.read().bits() != wr_buffer.len() as u32; - let bad_read = r.rxd.amount.read().bits() != rd_buffer.len() as u32; - - if bad_write { - return Err(Error::Transmit); - } - - if bad_read { - return Err(Error::Receive); - } + /// Read from an I2C slave. + /// + /// The buffer must have a length of at most 255 bytes on the nRF52832 + /// and at most 65535 bytes on the nRF52840. + pub fn blocking_read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error> { + self.setup_read(address, buffer, false)?; + self.blocking_wait(); + compiler_fence(SeqCst); + self.check_errorsrc()?; + self.check_rx(buffer.len())?; + Ok(()) + } + /// Write data to an I2C slave, then read data from the slave without + /// triggering a stop condition between the two. + /// + /// The buffers must have a length of at most 255 bytes on the nRF52832 + /// and at most 65535 bytes on the nRF52840. + pub fn blocking_write_read( + &mut self, + address: u8, + wr_buffer: &[u8], + rd_buffer: &mut [u8], + ) -> Result<(), Error> { + self.setup_write_read(address, wr_buffer, rd_buffer, false)?; + self.blocking_wait(); + compiler_fence(SeqCst); + self.check_errorsrc()?; + self.check_tx(wr_buffer.len())?; + self.check_rx(rd_buffer.len())?; Ok(()) } @@ -388,7 +418,7 @@ impl<'d, T: Instance> Twim<'d, T> { /// /// The write buffer must have a length of at most 255 bytes on the nRF52832 /// and at most 1024 bytes on the nRF52840. - pub fn copy_write(&mut self, address: u8, wr_buffer: &[u8]) -> Result<(), Error> { + pub fn blocking_copy_write(&mut self, address: u8, wr_buffer: &[u8]) -> Result<(), Error> { if wr_buffer.len() > FORCE_COPY_BUFFER_SIZE { return Err(Error::TxBufferTooLong); } @@ -397,7 +427,7 @@ impl<'d, T: Instance> Twim<'d, T> { let wr_ram_buffer = &mut [0; FORCE_COPY_BUFFER_SIZE][..wr_buffer.len()]; wr_ram_buffer.copy_from_slice(wr_buffer); - self.write(address, wr_ram_buffer) + self.blocking_write(address, wr_ram_buffer) } /// Copy data into RAM and write to an I2C slave, then read data from the slave without @@ -408,7 +438,7 @@ impl<'d, T: Instance> Twim<'d, T> { /// /// The read buffer must have a length of at most 255 bytes on the nRF52832 /// and at most 65535 bytes on the nRF52840. - pub fn copy_write_then_read( + pub fn blocking_copy_write_read( &mut self, address: u8, wr_buffer: &[u8], @@ -422,27 +452,40 @@ impl<'d, T: Instance> Twim<'d, T> { let wr_ram_buffer = &mut [0; FORCE_COPY_BUFFER_SIZE][..wr_buffer.len()]; wr_ram_buffer.copy_from_slice(wr_buffer); - self.write_then_read(address, wr_ram_buffer, rd_buffer) + self.blocking_write_read(address, wr_ram_buffer, rd_buffer) } - fn wait_for_stopped_event(cx: &mut core::task::Context) -> Poll<()> { - let r = T::regs(); - let s = T::state(); + pub async fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error> { + self.setup_read(address, buffer, true)?; + self.async_wait().await; + compiler_fence(SeqCst); + self.check_errorsrc()?; + self.check_rx(buffer.len())?; + Ok(()) + } - s.end_waker.register(cx.waker()); - if r.events_stopped.read().bits() != 0 { - r.events_stopped.reset(); + pub async fn write(&mut self, address: u8, buffer: &[u8]) -> Result<(), Error> { + self.setup_write(address, buffer, true)?; + self.async_wait().await; + compiler_fence(SeqCst); + self.check_errorsrc()?; + self.check_tx(buffer.len())?; + Ok(()) + } - return Poll::Ready(()); - } - - // stop if an error occured - if r.events_error.read().bits() != 0 { - r.events_error.reset(); - r.tasks_stop.write(|w| unsafe { w.bits(1) }); - } - - Poll::Pending + pub async fn write_read( + &mut self, + address: u8, + wr_buffer: &[u8], + rd_buffer: &mut [u8], + ) -> Result<(), Error> { + self.setup_write_read(address, wr_buffer, rd_buffer, true)?; + self.async_wait().await; + compiler_fence(SeqCst); + self.check_errorsrc()?; + self.check_tx(wr_buffer.len())?; + self.check_rx(rd_buffer.len())?; + Ok(()) } } @@ -450,7 +493,7 @@ impl<'a, T: Instance> Drop for Twim<'a, T> { fn drop(&mut self) { trace!("twim drop"); - // TODO when implementing async here, check for abort + // TODO: check for abort // disable! let r = T::regs(); @@ -483,174 +526,20 @@ where = impl Future> + 'a; fn read<'a>(&'a mut self, address: u8, buffer: &'a mut [u8]) -> Self::ReadFuture<'a> { - async move { - // NOTE: RAM slice check for buffer is not necessary, as a mutable - // slice can only be built from data located in RAM. - - let r = T::regs(); - - // Conservative compiler fence to prevent optimizations that do not - // take in to account actions by DMA. The fence has been placed here, - // before any DMA action has started. - compiler_fence(SeqCst); - - r.address.write(|w| unsafe { w.address().bits(address) }); - - // Set up the DMA read. - unsafe { self.set_rx_buffer(buffer)? }; - - // Reset events - r.events_stopped.reset(); - r.events_error.reset(); - self.clear_errorsrc(); - - // Enable events - r.intenset.write(|w| w.stopped().set().error().set()); - - // Start read operation. - r.shorts.write(|w| w.lastrx_stop().enabled()); - r.tasks_startrx.write(|w| - // `1` is a valid value to write to task registers. - unsafe { w.bits(1) }); - - // Conservative compiler fence to prevent optimizations that do not - // take in to account actions by DMA. The fence has been placed here, - // after all possible DMA actions have completed. - compiler_fence(SeqCst); - - // Wait for 'stopped' event. - poll_fn(Self::wait_for_stopped_event).await; - - self.read_errorsrc()?; - - if r.rxd.amount.read().bits() != buffer.len() as u32 { - return Err(Error::Receive); - } - - Ok(()) - } + self.read(address, buffer) } - fn write<'a>(&'a mut self, address: u8, bytes: &'a [u8]) -> Self::WriteFuture<'a> { - async move { - slice_in_ram_or(bytes, Error::DMABufferNotInDataMemory)?; - - // Conservative compiler fence to prevent optimizations that do not - // take in to account actions by DMA. The fence has been placed here, - // before any DMA action has started. - compiler_fence(SeqCst); - - let r = T::regs(); - - // Set up current address we're trying to talk to - r.address.write(|w| unsafe { w.address().bits(address) }); - - // Set up DMA write. - unsafe { - self.set_tx_buffer(bytes)?; - } - - // Reset events - r.events_stopped.reset(); - r.events_error.reset(); - r.events_lasttx.reset(); - self.clear_errorsrc(); - - // Enable events - r.intenset.write(|w| w.stopped().set().error().set()); - - // Start write operation. - r.shorts.write(|w| w.lasttx_stop().enabled()); - r.tasks_starttx.write(|w| - // `1` is a valid value to write to task registers. - unsafe { w.bits(1) }); - - // Conservative compiler fence to prevent optimizations that do not - // take in to account actions by DMA. The fence has been placed here, - // after all possible DMA actions have completed. - compiler_fence(SeqCst); - - // Wait for 'stopped' event. - poll_fn(Self::wait_for_stopped_event).await; - - self.read_errorsrc()?; - - if r.txd.amount.read().bits() != bytes.len() as u32 { - return Err(Error::Transmit); - } - - Ok(()) - } + fn write<'a>(&'a mut self, address: u8, buffer: &'a [u8]) -> Self::WriteFuture<'a> { + self.write(address, buffer) } fn write_read<'a>( &'a mut self, address: u8, - bytes: &'a [u8], - buffer: &'a mut [u8], + wr_buffer: &'a [u8], + rd_buffer: &'a mut [u8], ) -> Self::WriteReadFuture<'a> { - async move { - slice_in_ram_or(bytes, Error::DMABufferNotInDataMemory)?; - // NOTE: RAM slice check for buffer is not necessary, as a mutable - // slice can only be built from data located in RAM. - - // Conservative compiler fence to prevent optimizations that do not - // take in to account actions by DMA. The fence has been placed here, - // before any DMA action has started. - compiler_fence(SeqCst); - - let r = T::regs(); - - // Set up current address we're trying to talk to - r.address.write(|w| unsafe { w.address().bits(address) }); - - // Set up DMA buffers. - unsafe { - self.set_tx_buffer(bytes)?; - self.set_rx_buffer(buffer)?; - } - - // Reset events - r.events_stopped.reset(); - r.events_error.reset(); - r.events_lasttx.reset(); - self.clear_errorsrc(); - - // Enable events - r.intenset.write(|w| w.stopped().set().error().set()); - - // Start write+read operation. - r.shorts.write(|w| { - w.lasttx_startrx().enabled(); - w.lastrx_stop().enabled(); - w - }); - // `1` is a valid value to write to task registers. - r.tasks_starttx.write(|w| unsafe { w.bits(1) }); - - // Conservative compiler fence to prevent optimizations that do not - // take in to account actions by DMA. The fence has been placed here, - // after all possible DMA actions have completed. - compiler_fence(SeqCst); - - // Wait for 'stopped' event. - poll_fn(Self::wait_for_stopped_event).await; - - self.read_errorsrc()?; - - let bad_write = r.txd.amount.read().bits() != bytes.len() as u32; - let bad_read = r.rxd.amount.read().bits() != buffer.len() as u32; - - if bad_write { - return Err(Error::Transmit); - } - - if bad_read { - return Err(Error::Receive); - } - - Ok(()) - } + self.write_read(address, wr_buffer, rd_buffer) } } @@ -659,12 +548,12 @@ impl<'a, T: Instance> embedded_hal::blocking::i2c::Write for Twim<'a, T> { fn write<'w>(&mut self, addr: u8, bytes: &'w [u8]) -> Result<(), Error> { if slice_in_ram(bytes) { - self.write(addr, bytes) + self.blocking_write(addr, bytes) } else { let buf = &mut [0; FORCE_COPY_BUFFER_SIZE][..]; for chunk in bytes.chunks(FORCE_COPY_BUFFER_SIZE) { buf[..chunk.len()].copy_from_slice(chunk); - self.write(addr, &buf[..chunk.len()])?; + self.blocking_write(addr, &buf[..chunk.len()])?; } Ok(()) } @@ -675,7 +564,7 @@ impl<'a, T: Instance> embedded_hal::blocking::i2c::Read for Twim<'a, T> { type Error = Error; fn read<'w>(&mut self, addr: u8, bytes: &'w mut [u8]) -> Result<(), Error> { - self.read(addr, bytes) + self.blocking_read(addr, bytes) } } @@ -689,15 +578,16 @@ impl<'a, T: Instance> embedded_hal::blocking::i2c::WriteRead for Twim<'a, T> { buffer: &'w mut [u8], ) -> Result<(), Error> { if slice_in_ram(bytes) { - self.write_then_read(addr, bytes, buffer) + self.blocking_write_read(addr, bytes, buffer) } else { - self.copy_write_then_read(addr, bytes, buffer) + self.blocking_copy_write_read(addr, bytes, buffer) } } } #[derive(Debug, Copy, Clone, Eq, PartialEq)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[non_exhaustive] pub enum Error { TxBufferTooLong, RxBufferTooLong, diff --git a/examples/nrf/src/bin/twim.rs b/examples/nrf/src/bin/twim.rs index 4c2f2bf2e..1ac3a3945 100644 --- a/examples/nrf/src/bin/twim.rs +++ b/examples/nrf/src/bin/twim.rs @@ -26,7 +26,7 @@ async fn main(_spawner: Spawner, p: Peripherals) { info!("Reading..."); let mut buf = [0u8; 16]; - unwrap!(twi.write_then_read(ADDRESS, &mut [0x00], &mut buf)); + unwrap!(twi.blocking_write_read(ADDRESS, &mut [0x00], &mut buf)); info!("Read: {=[u8]:x}", buf); } diff --git a/examples/nrf/src/bin/twim_lowpower.rs b/examples/nrf/src/bin/twim_lowpower.rs index 62a5f0c94..4a0596437 100644 --- a/examples/nrf/src/bin/twim_lowpower.rs +++ b/examples/nrf/src/bin/twim_lowpower.rs @@ -36,7 +36,7 @@ async fn main(_spawner: Spawner, mut p: Peripherals) { info!("Reading..."); let mut buf = [0u8; 16]; - unwrap!(twi.write_then_read(ADDRESS, &mut [0x00], &mut buf)); + unwrap!(twi.blocking_write_read(ADDRESS, &mut [0x00], &mut buf)); info!("Read: {=[u8]:x}", buf); From 3ca01cba8d2ffbd6f7479b436f4384f002a381eb Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Thu, 13 Jan 2022 21:15:27 +0100 Subject: [PATCH 4/9] nrf/gpio: Rename FlexPin to Flex. FlexPin sounds like it's an owned pin singleton, like AnyPin or NoPin. --- embassy-nrf/src/gpio.rs | 24 ++++++++++++------------ embassy-nrf/src/gpiote.rs | 8 ++++---- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/embassy-nrf/src/gpio.rs b/embassy-nrf/src/gpio.rs index ddc84cf5d..8a3e8a1b0 100644 --- a/embassy-nrf/src/gpio.rs +++ b/embassy-nrf/src/gpio.rs @@ -37,12 +37,12 @@ pub enum Pull { /// GPIO input driver. pub struct Input<'d, T: Pin> { - pub(crate) pin: FlexPin<'d, T>, + pub(crate) pin: Flex<'d, T>, } impl<'d, T: Pin> Input<'d, T> { pub fn new(pin: impl Unborrow + 'd, pull: Pull) -> Self { - let mut pin = FlexPin::new(pin); + let mut pin = Flex::new(pin); pin.set_as_input(pull); Self { pin } @@ -102,7 +102,7 @@ pub enum OutputDrive { /// GPIO output driver. pub struct Output<'d, T: Pin> { - pub(crate) pin: FlexPin<'d, T>, + pub(crate) pin: Flex<'d, T>, } impl<'d, T: Pin> Output<'d, T> { @@ -111,7 +111,7 @@ impl<'d, T: Pin> Output<'d, T> { initial_output: Level, drive: OutputDrive, ) -> Self { - let mut pin = FlexPin::new(pin); + let mut pin = Flex::new(pin); match initial_output { Level::High => pin.set_high(), Level::Low => pin.set_low(), @@ -169,13 +169,13 @@ impl<'d, T: Pin> StatefulOutputPin for Output<'d, T> { /// This pin can either be a disconnected, input, or output pin. The level register bit will remain /// set while not in output mode, so the pin's level will be 'remembered' when it is not in output /// mode. -pub struct FlexPin<'d, T: Pin> { +pub struct Flex<'d, T: Pin> { pub(crate) pin: T, phantom: PhantomData<&'d mut T>, } -impl<'d, T: Pin> FlexPin<'d, T> { - /// Wrap the pin in a `FlexPin`. +impl<'d, T: Pin> Flex<'d, T> { + /// Wrap the pin in a `Flex`. /// /// The pin remains disconnected. The initial output level is unspecified, but can be changed /// before the pin is put into output mode. @@ -270,16 +270,16 @@ impl<'d, T: Pin> FlexPin<'d, T> { } } -impl<'d, T: Pin> Drop for FlexPin<'d, T> { +impl<'d, T: Pin> Drop for Flex<'d, T> { fn drop(&mut self) { self.pin.conf().reset(); } } -/// Implement [`InputPin`] for [`FlexPin`]; +/// Implement [`InputPin`] for [`Flex`]; /// /// If the pin is not in input mode the result is unspecified. -impl<'d, T: Pin> InputPin for FlexPin<'d, T> { +impl<'d, T: Pin> InputPin for Flex<'d, T> { type Error = Infallible; fn is_high(&self) -> Result { @@ -291,7 +291,7 @@ impl<'d, T: Pin> InputPin for FlexPin<'d, T> { } } -impl<'d, T: Pin> OutputPin for FlexPin<'d, T> { +impl<'d, T: Pin> OutputPin for Flex<'d, T> { type Error = Infallible; fn set_high(&mut self) -> Result<(), Self::Error> { @@ -303,7 +303,7 @@ impl<'d, T: Pin> OutputPin for FlexPin<'d, T> { } } -impl<'d, T: Pin> StatefulOutputPin for FlexPin<'d, T> { +impl<'d, T: Pin> StatefulOutputPin for Flex<'d, T> { fn is_set_high(&self) -> Result { Ok(self.is_set_high()) } diff --git a/embassy-nrf/src/gpiote.rs b/embassy-nrf/src/gpiote.rs index 99dfd1ebd..8e7af2666 100644 --- a/embassy-nrf/src/gpiote.rs +++ b/embassy-nrf/src/gpiote.rs @@ -9,7 +9,7 @@ use embedded_hal::digital::v2::InputPin; use futures::future::poll_fn; use crate::gpio::sealed::Pin as _; -use crate::gpio::{AnyPin, FlexPin, Input, Output, Pin as GpioPin}; +use crate::gpio::{AnyPin, Flex, Input, Output, Pin as GpioPin}; use crate::pac; use crate::ppi::{Event, Task}; use crate::{interrupt, peripherals}; @@ -375,7 +375,7 @@ impl<'d, T: GpioPin> embassy::traits::gpio::WaitForAnyEdge for Input<'d, T> { } } -impl<'d, T: GpioPin> embassy::traits::gpio::WaitForHigh for FlexPin<'d, T> { +impl<'d, T: GpioPin> embassy::traits::gpio::WaitForHigh for Flex<'d, T> { type Future<'a> where Self: 'a, @@ -391,7 +391,7 @@ impl<'d, T: GpioPin> embassy::traits::gpio::WaitForHigh for FlexPin<'d, T> { } } -impl<'d, T: GpioPin> embassy::traits::gpio::WaitForLow for FlexPin<'d, T> { +impl<'d, T: GpioPin> embassy::traits::gpio::WaitForLow for Flex<'d, T> { type Future<'a> where Self: 'a, @@ -407,7 +407,7 @@ impl<'d, T: GpioPin> embassy::traits::gpio::WaitForLow for FlexPin<'d, T> { } } -impl<'d, T: GpioPin> embassy::traits::gpio::WaitForAnyEdge for FlexPin<'d, T> { +impl<'d, T: GpioPin> embassy::traits::gpio::WaitForAnyEdge for Flex<'d, T> { type Future<'a> where Self: 'a, From c432d036c78480303827d832db3611cc7d2680f5 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Thu, 13 Jan 2022 21:24:06 +0100 Subject: [PATCH 5/9] nrf/gpiote: expose all functionality as inherent methods. --- embassy-nrf/src/gpio.rs | 8 +-- embassy-nrf/src/gpiote.rs | 85 ++++++++++++----------------- examples/nrf/src/bin/gpiote_port.rs | 1 - examples/nrf/src/bin/wdt.rs | 1 - 4 files changed, 36 insertions(+), 59 deletions(-) diff --git a/embassy-nrf/src/gpio.rs b/embassy-nrf/src/gpio.rs index 8a3e8a1b0..abda909f0 100644 --- a/embassy-nrf/src/gpio.rs +++ b/embassy-nrf/src/gpio.rs @@ -350,17 +350,13 @@ pub(crate) mod sealed { /// Set the output as high. #[inline] fn set_high(&self) { - unsafe { - self.block().outset.write(|w| w.bits(1u32 << self._pin())); - } + unsafe { self.block().outset.write(|w| w.bits(1u32 << self._pin())) } } /// Set the output as low. #[inline] fn set_low(&self) { - unsafe { - self.block().outclr.write(|w| w.bits(1u32 << self._pin())); - } + unsafe { self.block().outclr.write(|w| w.bits(1u32 << self._pin())) } } } diff --git a/embassy-nrf/src/gpiote.rs b/embassy-nrf/src/gpiote.rs index 8e7af2666..f1104904b 100644 --- a/embassy-nrf/src/gpiote.rs +++ b/embassy-nrf/src/gpiote.rs @@ -342,78 +342,60 @@ impl<'a> Future for PortInputFuture<'a> { } } -impl<'d, T: GpioPin> embassy::traits::gpio::WaitForHigh for Input<'d, T> { - type Future<'a> - where - Self: 'a, - = impl Future + Unpin + 'a; +impl<'d, T: GpioPin> Input<'d, T> { + pub async fn wait_for_high(&mut self) { + self.pin.wait_for_high().await + } - fn wait_for_high<'a>(&'a mut self) -> Self::Future<'a> { - self.pin.wait_for_high() + pub async fn wait_for_low(&mut self) { + self.pin.wait_for_low().await + } + + pub async fn wait_for_rising_edge(&mut self) { + self.pin.wait_for_rising_edge().await + } + + pub async fn wait_for_falling_edge(&mut self) { + self.pin.wait_for_falling_edge().await + } + + pub async fn wait_for_any_edge(&mut self) { + self.pin.wait_for_any_edge().await } } -impl<'d, T: GpioPin> embassy::traits::gpio::WaitForLow for Input<'d, T> { - type Future<'a> - where - Self: 'a, - = impl Future + Unpin + 'a; - - fn wait_for_low<'a>(&'a mut self) -> Self::Future<'a> { - self.pin.wait_for_low() - } -} - -impl<'d, T: GpioPin> embassy::traits::gpio::WaitForAnyEdge for Input<'d, T> { - type Future<'a> - where - Self: 'a, - = impl Future + Unpin + 'a; - - fn wait_for_any_edge<'a>(&'a mut self) -> Self::Future<'a> { - self.pin.wait_for_any_edge() - } -} - -impl<'d, T: GpioPin> embassy::traits::gpio::WaitForHigh for Flex<'d, T> { - type Future<'a> - where - Self: 'a, - = impl Future + Unpin + 'a; - - fn wait_for_high<'a>(&'a mut self) -> Self::Future<'a> { +impl<'d, T: GpioPin> Flex<'d, T> { + pub async fn wait_for_high(&mut self) { self.pin.conf().modify(|_, w| w.sense().high()); PortInputFuture { pin_port: self.pin.pin_port(), phantom: PhantomData, } + .await } -} -impl<'d, T: GpioPin> embassy::traits::gpio::WaitForLow for Flex<'d, T> { - type Future<'a> - where - Self: 'a, - = impl Future + Unpin + 'a; - - fn wait_for_low<'a>(&'a mut self) -> Self::Future<'a> { + pub async fn wait_for_low(&mut self) { self.pin.conf().modify(|_, w| w.sense().low()); PortInputFuture { pin_port: self.pin.pin_port(), phantom: PhantomData, } + .await } -} -impl<'d, T: GpioPin> embassy::traits::gpio::WaitForAnyEdge for Flex<'d, T> { - type Future<'a> - where - Self: 'a, - = impl Future + Unpin + 'a; + pub async fn wait_for_rising_edge(&mut self) { + self.wait_for_low().await; + self.wait_for_high().await; + } - fn wait_for_any_edge<'a>(&'a mut self) -> Self::Future<'a> { + pub async fn wait_for_falling_edge(&mut self) { + self.wait_for_high().await; + self.wait_for_low().await; + } + + pub async fn wait_for_any_edge(&mut self) { if self.is_high() { self.pin.conf().modify(|_, w| w.sense().low()); } else { @@ -423,6 +405,7 @@ impl<'d, T: GpioPin> embassy::traits::gpio::WaitForAnyEdge for Flex<'d, T> { pin_port: self.pin.pin_port(), phantom: PhantomData, } + .await } } diff --git a/examples/nrf/src/bin/gpiote_port.rs b/examples/nrf/src/bin/gpiote_port.rs index 76c861d95..3ea9a6e67 100644 --- a/examples/nrf/src/bin/gpiote_port.rs +++ b/examples/nrf/src/bin/gpiote_port.rs @@ -6,7 +6,6 @@ mod example_common; use embassy::executor::Spawner; -use embassy::traits::gpio::{WaitForHigh, WaitForLow}; use embassy_nrf::gpio::{AnyPin, Input, Pin as _, Pull}; use embassy_nrf::Peripherals; use example_common::*; diff --git a/examples/nrf/src/bin/wdt.rs b/examples/nrf/src/bin/wdt.rs index 78c2205d9..cc199be9d 100644 --- a/examples/nrf/src/bin/wdt.rs +++ b/examples/nrf/src/bin/wdt.rs @@ -10,7 +10,6 @@ use embassy::executor::Spawner; use embassy_nrf::gpio::{Input, Pull}; use embassy_nrf::wdt::{Config, Watchdog}; use embassy_nrf::Peripherals; -use embassy_traits::gpio::{WaitForHigh, WaitForLow}; #[embassy::main] async fn main(_spawner: Spawner, p: Peripherals) { From 3e503e73356f4805d459d50fa1cded7b65ecd6d8 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Thu, 13 Jan 2022 22:24:13 +0100 Subject: [PATCH 6/9] nrf/uarte: expose all functionality as inherent methods. --- embassy-nrf/src/uarte.rs | 495 +++++++++++++++++------------ examples/nrf/src/bin/uart.rs | 1 - examples/nrf/src/bin/uart_idle.rs | 10 +- examples/nrf/src/bin/uart_split.rs | 11 +- 4 files changed, 292 insertions(+), 225 deletions(-) diff --git a/embassy-nrf/src/uarte.rs b/embassy-nrf/src/uarte.rs index 38480ecca..07cec5d6b 100644 --- a/embassy-nrf/src/uarte.rs +++ b/embassy-nrf/src/uarte.rs @@ -13,12 +13,10 @@ //! memory may be used given that buffers are passed in directly to its read and write //! methods. -use core::future::Future; use core::marker::PhantomData; use core::sync::atomic::{compiler_fence, Ordering}; use core::task::Poll; use embassy::interrupt::InterruptExt; -use embassy::traits::uart::{Error as TraitError, Read, ReadUntilIdle, Write}; use embassy::util::Unborrow; use embassy_hal_common::drop::OnDrop; use embassy_hal_common::unborrow; @@ -32,6 +30,7 @@ use crate::pac; use crate::ppi::{AnyConfigurableChannel, ConfigurableChannel, Event, Ppi, Task}; use crate::timer::Instance as TimerInstance; use crate::timer::{Frequency, Timer}; +use crate::util::slice_in_ram_or; // Re-export SVD variants to allow user to directly set values. pub use pac::uarte0::{baudrate::BAUDRATE_A as Baudrate, config::PARITY_A as Parity}; @@ -51,6 +50,16 @@ impl Default for Config { } } +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[non_exhaustive] +pub enum Error { + BufferTooLong, + BufferZeroLength, + DMABufferNotInDataMemory, + // TODO: add other error variants. +} + /// Interface to the UARTE peripheral pub struct Uarte<'d, T: Instance> { phantom: PhantomData<&'d mut T>, @@ -139,8 +148,12 @@ impl<'d, T: Instance> Uarte<'d, T> { Self { phantom: PhantomData, - tx: UarteTx::new(), - rx: UarteRx::new(), + tx: UarteTx { + phantom: PhantomData, + }, + rx: UarteRx { + phantom: PhantomData, + }, } } @@ -170,92 +183,110 @@ impl<'d, T: Instance> Uarte<'d, T> { r.intenclr.write(|w| w.endtx().clear()); } } -} -impl<'d, T: Instance> Read for Uarte<'d, T> { - type ReadFuture<'a> - where - Self: 'a, - = impl Future> + 'a; - - fn read<'a>(&'a mut self, rx_buffer: &'a mut [u8]) -> Self::ReadFuture<'a> { - self.rx.read(rx_buffer) + pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> { + self.rx.read(buffer).await } -} -impl<'d, T: Instance> Write for Uarte<'d, T> { - type WriteFuture<'a> - where - Self: 'a, - = impl Future> + 'a; + pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error> { + self.tx.write(buffer).await + } - fn write<'a>(&'a mut self, tx_buffer: &'a [u8]) -> Self::WriteFuture<'a> { - self.tx.write(tx_buffer) + pub fn blocking_read(&mut self, buffer: &mut [u8]) -> Result<(), Error> { + self.rx.blocking_read(buffer) + } + + pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> { + self.tx.blocking_write(buffer) } } impl<'d, T: Instance> UarteTx<'d, T> { - pub fn new() -> Self { - Self { - phantom: PhantomData, + pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error> { + slice_in_ram_or(buffer, Error::DMABufferNotInDataMemory)?; + if buffer.len() == 0 { + return Err(Error::BufferZeroLength); } + if buffer.len() > EASY_DMA_SIZE { + return Err(Error::BufferTooLong); + } + + let ptr = buffer.as_ptr(); + let len = buffer.len(); + + let r = T::regs(); + let s = T::state(); + + let drop = OnDrop::new(move || { + trace!("write drop: stopping"); + + r.intenclr.write(|w| w.endtx().clear()); + r.events_txstopped.reset(); + r.tasks_stoptx.write(|w| unsafe { w.bits(1) }); + + // TX is stopped almost instantly, spinning is fine. + while r.events_endtx.read().bits() == 0 {} + trace!("write drop: stopped"); + }); + + r.txd.ptr.write(|w| unsafe { w.ptr().bits(ptr as u32) }); + r.txd.maxcnt.write(|w| unsafe { w.maxcnt().bits(len as _) }); + + r.events_endtx.reset(); + r.intenset.write(|w| w.endtx().set()); + + compiler_fence(Ordering::SeqCst); + + trace!("starttx"); + r.tasks_starttx.write(|w| unsafe { w.bits(1) }); + + poll_fn(|cx| { + s.endtx_waker.register(cx.waker()); + if r.events_endtx.read().bits() != 0 { + return Poll::Ready(()); + } + Poll::Pending + }) + .await; + + compiler_fence(Ordering::SeqCst); + r.events_txstarted.reset(); + drop.defuse(); + + Ok(()) } -} -impl<'d, T: Instance> Write for UarteTx<'d, T> { - type WriteFuture<'a> - where - Self: 'a, - = impl Future> + 'a; - - fn write<'a>(&'a mut self, tx_buffer: &'a [u8]) -> Self::WriteFuture<'a> { - async move { - let ptr = tx_buffer.as_ptr(); - let len = tx_buffer.len(); - assert!(len <= EASY_DMA_SIZE); - // TODO: panic if buffer is not in SRAM - - let r = T::regs(); - let s = T::state(); - - let drop = OnDrop::new(move || { - trace!("write drop: stopping"); - - r.intenclr.write(|w| w.endtx().clear()); - r.events_txstopped.reset(); - r.tasks_stoptx.write(|w| unsafe { w.bits(1) }); - - // TX is stopped almost instantly, spinning is fine. - while r.events_endtx.read().bits() == 0 {} - trace!("write drop: stopped"); - }); - - r.txd.ptr.write(|w| unsafe { w.ptr().bits(ptr as u32) }); - r.txd.maxcnt.write(|w| unsafe { w.maxcnt().bits(len as _) }); - - r.events_endtx.reset(); - r.intenset.write(|w| w.endtx().set()); - - compiler_fence(Ordering::SeqCst); - - trace!("starttx"); - r.tasks_starttx.write(|w| unsafe { w.bits(1) }); - - poll_fn(|cx| { - s.endtx_waker.register(cx.waker()); - if r.events_endtx.read().bits() != 0 { - return Poll::Ready(()); - } - Poll::Pending - }) - .await; - - compiler_fence(Ordering::SeqCst); - r.events_txstarted.reset(); - drop.defuse(); - - Ok(()) + pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> { + slice_in_ram_or(buffer, Error::DMABufferNotInDataMemory)?; + if buffer.len() == 0 { + return Err(Error::BufferZeroLength); } + if buffer.len() > EASY_DMA_SIZE { + return Err(Error::BufferTooLong); + } + + let ptr = buffer.as_ptr(); + let len = buffer.len(); + + let r = T::regs(); + + r.txd.ptr.write(|w| unsafe { w.ptr().bits(ptr as u32) }); + r.txd.maxcnt.write(|w| unsafe { w.maxcnt().bits(len as _) }); + + r.events_endtx.reset(); + r.intenclr.write(|w| w.endtx().clear()); + + compiler_fence(Ordering::SeqCst); + + trace!("starttx"); + r.tasks_starttx.write(|w| unsafe { w.bits(1) }); + + while r.events_endtx.read().bits() == 0 {} + + compiler_fence(Ordering::SeqCst); + r.events_txstarted.reset(); + + Ok(()) } } @@ -278,66 +309,89 @@ impl<'a, T: Instance> Drop for UarteTx<'a, T> { } impl<'d, T: Instance> UarteRx<'d, T> { - pub fn new() -> Self { - Self { - phantom: PhantomData, + pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> { + if buffer.len() == 0 { + return Err(Error::BufferZeroLength); } + if buffer.len() > EASY_DMA_SIZE { + return Err(Error::BufferTooLong); + } + + let ptr = buffer.as_ptr(); + let len = buffer.len(); + + let r = T::regs(); + let s = T::state(); + + let drop = OnDrop::new(move || { + trace!("read drop: stopping"); + + r.intenclr.write(|w| w.endrx().clear()); + r.events_rxto.reset(); + r.tasks_stoprx.write(|w| unsafe { w.bits(1) }); + + while r.events_endrx.read().bits() == 0 {} + + trace!("read drop: stopped"); + }); + + r.rxd.ptr.write(|w| unsafe { w.ptr().bits(ptr as u32) }); + r.rxd.maxcnt.write(|w| unsafe { w.maxcnt().bits(len as _) }); + + r.events_endrx.reset(); + r.intenset.write(|w| w.endrx().set()); + + compiler_fence(Ordering::SeqCst); + + trace!("startrx"); + r.tasks_startrx.write(|w| unsafe { w.bits(1) }); + + poll_fn(|cx| { + s.endrx_waker.register(cx.waker()); + if r.events_endrx.read().bits() != 0 { + return Poll::Ready(()); + } + Poll::Pending + }) + .await; + + compiler_fence(Ordering::SeqCst); + r.events_rxstarted.reset(); + drop.defuse(); + + Ok(()) } -} -impl<'d, T: Instance> Read for UarteRx<'d, T> { - type ReadFuture<'a> - where - Self: 'a, - = impl Future> + 'a; - - fn read<'a>(&'a mut self, rx_buffer: &'a mut [u8]) -> Self::ReadFuture<'a> { - async move { - let ptr = rx_buffer.as_ptr(); - let len = rx_buffer.len(); - assert!(len <= EASY_DMA_SIZE); - - let r = T::regs(); - let s = T::state(); - - let drop = OnDrop::new(move || { - trace!("read drop: stopping"); - - r.intenclr.write(|w| w.endrx().clear()); - r.events_rxto.reset(); - r.tasks_stoprx.write(|w| unsafe { w.bits(1) }); - - while r.events_endrx.read().bits() == 0 {} - - trace!("read drop: stopped"); - }); - - r.rxd.ptr.write(|w| unsafe { w.ptr().bits(ptr as u32) }); - r.rxd.maxcnt.write(|w| unsafe { w.maxcnt().bits(len as _) }); - - r.events_endrx.reset(); - r.intenset.write(|w| w.endrx().set()); - - compiler_fence(Ordering::SeqCst); - - trace!("startrx"); - r.tasks_startrx.write(|w| unsafe { w.bits(1) }); - - poll_fn(|cx| { - s.endrx_waker.register(cx.waker()); - if r.events_endrx.read().bits() != 0 { - return Poll::Ready(()); - } - Poll::Pending - }) - .await; - - compiler_fence(Ordering::SeqCst); - r.events_rxstarted.reset(); - drop.defuse(); - - Ok(()) + pub fn blocking_read(&mut self, buffer: &mut [u8]) -> Result<(), Error> { + if buffer.len() == 0 { + return Err(Error::BufferZeroLength); } + if buffer.len() > EASY_DMA_SIZE { + return Err(Error::BufferTooLong); + } + + let ptr = buffer.as_ptr(); + let len = buffer.len(); + + let r = T::regs(); + + r.rxd.ptr.write(|w| unsafe { w.ptr().bits(ptr as u32) }); + r.rxd.maxcnt.write(|w| unsafe { w.maxcnt().bits(len as _) }); + + r.events_endrx.reset(); + r.intenclr.write(|w| w.endrx().clear()); + + compiler_fence(Ordering::SeqCst); + + trace!("startrx"); + r.tasks_startrx.write(|w| unsafe { w.bits(1) }); + + while r.events_endrx.read().bits() == 0 {} + + compiler_fence(Ordering::SeqCst); + r.events_rxstarted.reset(); + + Ok(()) } } @@ -439,14 +493,7 @@ pub struct UarteWithIdle<'d, U: Instance, T: TimerInstance> { impl<'d, U: Instance, T: TimerInstance> UarteWithIdle<'d, U, T> { /// Creates the interface to a UARTE instance. /// Sets the baud rate, parity and assigns the pins to the UARTE peripheral. - /// - /// # Safety - /// - /// The returned API is safe unless you use `mem::forget` (or similar safe mechanisms) - /// on stack allocated buffers which which have been passed to [`send()`](Uarte::send) - /// or [`receive`](Uarte::receive). - #[allow(unused_unsafe)] - pub unsafe fn new( + pub fn new( uarte: impl Unborrow + 'd, timer: impl Unborrow + 'd, ppi_ch1: impl Unborrow + 'd, @@ -501,93 +548,119 @@ impl<'d, U: Instance, T: TimerInstance> UarteWithIdle<'d, U, T> { _ppi_ch2: ppi_ch2, } } -} -impl<'d, U: Instance, T: TimerInstance> ReadUntilIdle for UarteWithIdle<'d, U, T> { - type ReadUntilIdleFuture<'a> - where - Self: 'a, - = impl Future> + 'a; - fn read_until_idle<'a>(&'a mut self, rx_buffer: &'a mut [u8]) -> Self::ReadUntilIdleFuture<'a> { - async move { - let ptr = rx_buffer.as_ptr(); - let len = rx_buffer.len(); - assert!(len <= EASY_DMA_SIZE); + pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> { + self.ppi_ch1.disable(); + self.uarte.read(buffer).await + } - let r = U::regs(); - let s = U::state(); + pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error> { + self.uarte.write(buffer).await + } - let drop = OnDrop::new(|| { - trace!("read drop: stopping"); + pub fn blocking_read(&mut self, buffer: &mut [u8]) -> Result<(), Error> { + self.ppi_ch1.disable(); + self.uarte.blocking_read(buffer) + } - self.timer.stop(); + pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> { + self.uarte.blocking_write(buffer) + } - r.intenclr.write(|w| w.endrx().clear()); - r.events_rxto.reset(); - r.tasks_stoprx.write(|w| unsafe { w.bits(1) }); + pub async fn read_until_idle(&mut self, buffer: &mut [u8]) -> Result { + if buffer.len() == 0 { + return Err(Error::BufferZeroLength); + } + if buffer.len() > EASY_DMA_SIZE { + return Err(Error::BufferTooLong); + } - while r.events_endrx.read().bits() == 0 {} + let ptr = buffer.as_ptr(); + let len = buffer.len(); - trace!("read drop: stopped"); - }); + let r = U::regs(); + let s = U::state(); - r.rxd.ptr.write(|w| unsafe { w.ptr().bits(ptr as u32) }); - r.rxd.maxcnt.write(|w| unsafe { w.maxcnt().bits(len as _) }); + self.ppi_ch1.enable(); - r.events_endrx.reset(); - r.intenset.write(|w| w.endrx().set()); + let drop = OnDrop::new(|| { + trace!("read drop: stopping"); - compiler_fence(Ordering::SeqCst); - - trace!("startrx"); - r.tasks_startrx.write(|w| unsafe { w.bits(1) }); - - poll_fn(|cx| { - s.endrx_waker.register(cx.waker()); - if r.events_endrx.read().bits() != 0 { - return Poll::Ready(()); - } - Poll::Pending - }) - .await; - - compiler_fence(Ordering::SeqCst); - let n = r.rxd.amount.read().amount().bits() as usize; - - // Stop timer self.timer.stop(); - r.events_rxstarted.reset(); - drop.defuse(); + r.intenclr.write(|w| w.endrx().clear()); + r.events_rxto.reset(); + r.tasks_stoprx.write(|w| unsafe { w.bits(1) }); - Ok(n) - } + while r.events_endrx.read().bits() == 0 {} + + trace!("read drop: stopped"); + }); + + r.rxd.ptr.write(|w| unsafe { w.ptr().bits(ptr as u32) }); + r.rxd.maxcnt.write(|w| unsafe { w.maxcnt().bits(len as _) }); + + r.events_endrx.reset(); + r.intenset.write(|w| w.endrx().set()); + + compiler_fence(Ordering::SeqCst); + + r.tasks_startrx.write(|w| unsafe { w.bits(1) }); + + poll_fn(|cx| { + s.endrx_waker.register(cx.waker()); + if r.events_endrx.read().bits() != 0 { + return Poll::Ready(()); + } + Poll::Pending + }) + .await; + + compiler_fence(Ordering::SeqCst); + let n = r.rxd.amount.read().amount().bits() as usize; + + self.timer.stop(); + r.events_rxstarted.reset(); + + drop.defuse(); + + Ok(n) } -} -impl<'d, U: Instance, T: TimerInstance> Read for UarteWithIdle<'d, U, T> { - type ReadFuture<'a> - where - Self: 'a, - = impl Future> + 'a; - fn read<'a>(&'a mut self, rx_buffer: &'a mut [u8]) -> Self::ReadFuture<'a> { - async move { - self.ppi_ch1.disable(); - let result = self.uarte.read(rx_buffer).await; - self.ppi_ch1.enable(); - result + pub fn blocking_read_until_idle(&mut self, buffer: &mut [u8]) -> Result { + if buffer.len() == 0 { + return Err(Error::BufferZeroLength); + } + if buffer.len() > EASY_DMA_SIZE { + return Err(Error::BufferTooLong); } - } -} -impl<'d, U: Instance, T: TimerInstance> Write for UarteWithIdle<'d, U, T> { - type WriteFuture<'a> - where - Self: 'a, - = impl Future> + 'a; + let ptr = buffer.as_ptr(); + let len = buffer.len(); - fn write<'a>(&'a mut self, tx_buffer: &'a [u8]) -> Self::WriteFuture<'a> { - self.uarte.write(tx_buffer) + let r = U::regs(); + + self.ppi_ch1.enable(); + + r.rxd.ptr.write(|w| unsafe { w.ptr().bits(ptr as u32) }); + r.rxd.maxcnt.write(|w| unsafe { w.maxcnt().bits(len as _) }); + + r.events_endrx.reset(); + r.intenclr.write(|w| w.endrx().clear()); + + compiler_fence(Ordering::SeqCst); + + r.tasks_startrx.write(|w| unsafe { w.bits(1) }); + + while r.events_endrx.read().bits() == 0 {} + + compiler_fence(Ordering::SeqCst); + let n = r.rxd.amount.read().amount().bits() as usize; + + self.timer.stop(); + r.events_rxstarted.reset(); + + Ok(n) } } diff --git a/examples/nrf/src/bin/uart.rs b/examples/nrf/src/bin/uart.rs index 208961c8b..68ee3978a 100644 --- a/examples/nrf/src/bin/uart.rs +++ b/examples/nrf/src/bin/uart.rs @@ -7,7 +7,6 @@ mod example_common; use example_common::*; use embassy::executor::Spawner; -use embassy::traits::uart::{Read, Write}; use embassy_nrf::gpio::NoPin; use embassy_nrf::{interrupt, uarte, Peripherals}; diff --git a/examples/nrf/src/bin/uart_idle.rs b/examples/nrf/src/bin/uart_idle.rs index ec9a36026..76449c0e3 100644 --- a/examples/nrf/src/bin/uart_idle.rs +++ b/examples/nrf/src/bin/uart_idle.rs @@ -4,11 +4,9 @@ #[path = "../example_common.rs"] mod example_common; -use embassy_traits::uart::ReadUntilIdle; use example_common::*; use embassy::executor::Spawner; -use embassy::traits::uart::Write; use embassy_nrf::gpio::NoPin; use embassy_nrf::{interrupt, uarte, Peripherals}; @@ -19,11 +17,9 @@ async fn main(_spawner: Spawner, p: Peripherals) { config.baudrate = uarte::Baudrate::BAUD115200; let irq = interrupt::take!(UARTE0_UART0); - let mut uart = unsafe { - uarte::UarteWithIdle::new( - p.UARTE0, p.TIMER0, p.PPI_CH0, p.PPI_CH1, irq, p.P0_08, p.P0_06, NoPin, NoPin, config, - ) - }; + let mut uart = uarte::UarteWithIdle::new( + p.UARTE0, p.TIMER0, p.PPI_CH0, p.PPI_CH1, irq, p.P0_08, p.P0_06, NoPin, NoPin, config, + ); info!("uarte initialized!"); diff --git a/examples/nrf/src/bin/uart_split.rs b/examples/nrf/src/bin/uart_split.rs index 4b5dbb21f..a9c02e796 100644 --- a/examples/nrf/src/bin/uart_split.rs +++ b/examples/nrf/src/bin/uart_split.rs @@ -4,16 +4,15 @@ #[path = "../example_common.rs"] mod example_common; -use embassy::blocking_mutex::kind::Noop; -use embassy::channel::mpsc::{self, Channel, Sender}; -use embassy::util::Forever; -use embassy_nrf::peripherals::UARTE0; -use embassy_nrf::uarte::UarteRx; use example_common::*; +use embassy::blocking_mutex::kind::Noop; +use embassy::channel::mpsc::{self, Channel, Sender}; use embassy::executor::Spawner; -use embassy::traits::uart::{Read, Write}; +use embassy::util::Forever; use embassy_nrf::gpio::NoPin; +use embassy_nrf::peripherals::UARTE0; +use embassy_nrf::uarte::UarteRx; use embassy_nrf::{interrupt, uarte, Peripherals}; static CHANNEL: Forever> = Forever::new(); From df00c83984b99c5c87a1e90d042147eae7c75631 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Thu, 13 Jan 2022 23:05:31 +0100 Subject: [PATCH 7/9] nrf/qspi: expose all functionality as inherent methods. --- embassy-nrf/src/qspi.rs | 208 +++++++++++--------------- examples/nrf/src/bin/qspi.rs | 1 - examples/nrf/src/bin/qspi_lowpower.rs | 1 - 3 files changed, 88 insertions(+), 122 deletions(-) diff --git a/embassy-nrf/src/qspi.rs b/embassy-nrf/src/qspi.rs index 6afba4931..89262ac05 100644 --- a/embassy-nrf/src/qspi.rs +++ b/embassy-nrf/src/qspi.rs @@ -1,11 +1,9 @@ #![macro_use] -use core::future::Future; use core::marker::PhantomData; use core::ptr; use core::task::Poll; use embassy::interrupt::{Interrupt, InterruptExt}; -use embassy::traits::flash::{Error, Flash}; use embassy::util::Unborrow; use embassy_hal_common::drop::DropBomb; use embassy_hal_common::unborrow; @@ -58,6 +56,13 @@ impl Default for Config { } } +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[non_exhaustive] +pub enum Error { + // TODO add "not in data memory" error and check for it +} + pub struct Qspi<'d, T: Instance> { dpm_enabled: bool, phantom: PhantomData<&'d mut T>, @@ -240,6 +245,87 @@ impl<'d, T: Instance> Qspi<'d, T> { }) .await } + + pub async fn read(&mut self, address: usize, data: &mut [u8]) -> Result<(), Error> { + let bomb = DropBomb::new(); + + assert_eq!(data.as_ptr() as u32 % 4, 0); + assert_eq!(data.len() as u32 % 4, 0); + assert_eq!(address as u32 % 4, 0); + + let r = T::regs(); + + r.read + .src + .write(|w| unsafe { w.src().bits(address as u32) }); + r.read + .dst + .write(|w| unsafe { w.dst().bits(data.as_ptr() as u32) }); + r.read + .cnt + .write(|w| unsafe { w.cnt().bits(data.len() as u32) }); + + r.events_ready.reset(); + r.intenset.write(|w| w.ready().set()); + r.tasks_readstart.write(|w| w.tasks_readstart().bit(true)); + + self.wait_ready().await; + + bomb.defuse(); + + Ok(()) + } + + pub async fn write(&mut self, address: usize, data: &[u8]) -> Result<(), Error> { + let bomb = DropBomb::new(); + + assert_eq!(data.as_ptr() as u32 % 4, 0); + assert_eq!(data.len() as u32 % 4, 0); + assert_eq!(address as u32 % 4, 0); + + let r = T::regs(); + r.write + .src + .write(|w| unsafe { w.src().bits(data.as_ptr() as u32) }); + r.write + .dst + .write(|w| unsafe { w.dst().bits(address as u32) }); + r.write + .cnt + .write(|w| unsafe { w.cnt().bits(data.len() as u32) }); + + r.events_ready.reset(); + r.intenset.write(|w| w.ready().set()); + r.tasks_writestart.write(|w| w.tasks_writestart().bit(true)); + + self.wait_ready().await; + + bomb.defuse(); + + Ok(()) + } + + pub async fn erase(&mut self, address: usize) -> Result<(), Error> { + let bomb = DropBomb::new(); + + assert_eq!(address as u32 % 4096, 0); + + let r = T::regs(); + r.erase + .ptr + .write(|w| unsafe { w.ptr().bits(address as u32) }); + r.erase.len.write(|w| w.len()._4kb()); + + r.events_ready.reset(); + r.intenset.write(|w| w.ready().set()); + r.tasks_erasestart.write(|w| w.tasks_erasestart().bit(true)); + + self.wait_ready().await; + + bomb.defuse(); + + Ok(()) + } } impl<'d, T: Instance> Drop for Qspi<'d, T> { @@ -285,124 +371,6 @@ impl<'d, T: Instance> Drop for Qspi<'d, T> { } } -impl<'d, T: Instance> Flash for Qspi<'d, T> { - type ReadFuture<'a> - where - Self: 'a, - = impl Future> + 'a; - type WriteFuture<'a> - where - Self: 'a, - = impl Future> + 'a; - type ErasePageFuture<'a> - where - Self: 'a, - = impl Future> + 'a; - - fn read<'a>(&'a mut self, address: usize, data: &'a mut [u8]) -> Self::ReadFuture<'a> { - async move { - let bomb = DropBomb::new(); - - assert_eq!(data.as_ptr() as u32 % 4, 0); - assert_eq!(data.len() as u32 % 4, 0); - assert_eq!(address as u32 % 4, 0); - - let r = T::regs(); - - r.read - .src - .write(|w| unsafe { w.src().bits(address as u32) }); - r.read - .dst - .write(|w| unsafe { w.dst().bits(data.as_ptr() as u32) }); - r.read - .cnt - .write(|w| unsafe { w.cnt().bits(data.len() as u32) }); - - r.events_ready.reset(); - r.intenset.write(|w| w.ready().set()); - r.tasks_readstart.write(|w| w.tasks_readstart().bit(true)); - - self.wait_ready().await; - - bomb.defuse(); - - Ok(()) - } - } - - fn write<'a>(&'a mut self, address: usize, data: &'a [u8]) -> Self::WriteFuture<'a> { - async move { - let bomb = DropBomb::new(); - - assert_eq!(data.as_ptr() as u32 % 4, 0); - assert_eq!(data.len() as u32 % 4, 0); - assert_eq!(address as u32 % 4, 0); - - let r = T::regs(); - r.write - .src - .write(|w| unsafe { w.src().bits(data.as_ptr() as u32) }); - r.write - .dst - .write(|w| unsafe { w.dst().bits(address as u32) }); - r.write - .cnt - .write(|w| unsafe { w.cnt().bits(data.len() as u32) }); - - r.events_ready.reset(); - r.intenset.write(|w| w.ready().set()); - r.tasks_writestart.write(|w| w.tasks_writestart().bit(true)); - - self.wait_ready().await; - - bomb.defuse(); - - Ok(()) - } - } - - fn erase<'a>(&'a mut self, address: usize) -> Self::ErasePageFuture<'a> { - async move { - let bomb = DropBomb::new(); - - assert_eq!(address as u32 % 4096, 0); - - let r = T::regs(); - r.erase - .ptr - .write(|w| unsafe { w.ptr().bits(address as u32) }); - r.erase.len.write(|w| w.len()._4kb()); - - r.events_ready.reset(); - r.intenset.write(|w| w.ready().set()); - r.tasks_erasestart.write(|w| w.tasks_erasestart().bit(true)); - - self.wait_ready().await; - - bomb.defuse(); - - Ok(()) - } - } - - fn size(&self) -> usize { - 256 * 4096 // TODO - } - - fn read_size(&self) -> usize { - 4 // TODO - } - - fn write_size(&self) -> usize { - 4 // TODO - } - - fn erase_size(&self) -> usize { - 4096 // TODO - } -} - pub(crate) mod sealed { use embassy::waitqueue::AtomicWaker; diff --git a/examples/nrf/src/bin/qspi.rs b/examples/nrf/src/bin/qspi.rs index c7f9503bb..b2e6bfc15 100644 --- a/examples/nrf/src/bin/qspi.rs +++ b/examples/nrf/src/bin/qspi.rs @@ -7,7 +7,6 @@ mod example_common; use defmt::assert_eq; use embassy::executor::Spawner; -use embassy::traits::flash::Flash; use embassy_nrf::Peripherals; use embassy_nrf::{interrupt, qspi}; use example_common::*; diff --git a/examples/nrf/src/bin/qspi_lowpower.rs b/examples/nrf/src/bin/qspi_lowpower.rs index e9e1bac42..4e264ef2f 100644 --- a/examples/nrf/src/bin/qspi_lowpower.rs +++ b/examples/nrf/src/bin/qspi_lowpower.rs @@ -8,7 +8,6 @@ mod example_common; use core::mem; use embassy::executor::Spawner; use embassy::time::{Duration, Timer}; -use embassy::traits::flash::Flash; use embassy_nrf::Peripherals; use embassy_nrf::{interrupt, qspi}; use example_common::*; From 6eec3d8acca1a4c6a853d0b65e43ec0a0f5c5c27 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Thu, 13 Jan 2022 23:10:24 +0100 Subject: [PATCH 8/9] nrf/rng: expose all functionality as inherent methods. --- embassy-nrf/src/rng.rs | 131 ++++++++++++++++-------------------- examples/nrf/src/bin/rng.rs | 6 +- 2 files changed, 61 insertions(+), 76 deletions(-) diff --git a/embassy-nrf/src/rng.rs b/embassy-nrf/src/rng.rs index 6b36cbb88..98833c52b 100644 --- a/embassy-nrf/src/rng.rs +++ b/embassy-nrf/src/rng.rs @@ -1,5 +1,3 @@ -use core::convert::Infallible; -use core::future::Future; use core::marker::PhantomData; use core::ptr; use core::sync::atomic::AtomicPtr; @@ -7,13 +5,11 @@ use core::sync::atomic::Ordering; use core::task::Poll; use embassy::interrupt::InterruptExt; -use embassy::traits; use embassy::util::Unborrow; use embassy::waitqueue::AtomicWaker; use embassy_hal_common::drop::OnDrop; use embassy_hal_common::unborrow; use futures::future::poll_fn; -use rand_core::RngCore; use crate::interrupt; use crate::pac; @@ -39,7 +35,7 @@ struct State { /// A wrapper around an nRF RNG peripheral. /// -/// It has a non-blocking API, through `embassy::traits::Rng`, and a blocking api through `rand`. +/// It has a non-blocking API, and a blocking api through `rand`. pub struct Rng<'d> { irq: interrupt::RNG, phantom: PhantomData<(&'d mut RNG, &'d mut interrupt::RNG)>, @@ -146,72 +142,51 @@ impl<'d> Rng<'d> { pub fn bias_correction(&self, enable: bool) { RNG::regs().config.write(|w| w.dercen().bit(enable)) } -} -impl<'d> Drop for Rng<'d> { - fn drop(&mut self) { - self.irq.disable() - } -} - -impl<'d> traits::rng::Rng for Rng<'d> { - type Error = Infallible; - - type RngFuture<'a> - where - 'd: 'a, - = impl Future> + 'a; - - fn fill_bytes<'a>(&'a mut self, dest: &'a mut [u8]) -> Self::RngFuture<'a> { - async move { - if dest.len() == 0 { - return Ok(()); // Nothing to fill - } - - let range = dest.as_mut_ptr_range(); - // Even if we've preempted the interrupt, it can't preempt us again, - // so we don't need to worry about the order we write these in. - STATE.ptr.store(range.start, Ordering::Relaxed); - STATE.end.store(range.end, Ordering::Relaxed); - - self.enable_irq(); - self.start(); - - let on_drop = OnDrop::new(|| { - self.stop(); - self.disable_irq(); - - // The interrupt is now disabled and can't preempt us anymore, so the order doesn't matter here. - STATE.ptr.store(ptr::null_mut(), Ordering::Relaxed); - STATE.end.store(ptr::null_mut(), Ordering::Relaxed); - }); - - poll_fn(|cx| { - STATE.waker.register(cx.waker()); - - // The interrupt will never modify `end`, so load it first and then get the most up-to-date `ptr`. - let end = STATE.end.load(Ordering::Relaxed); - let ptr = STATE.ptr.load(Ordering::Relaxed); - - if ptr == end { - // We're done. - Poll::Ready(()) - } else { - Poll::Pending - } - }) - .await; - - // Trigger the teardown - drop(on_drop); - - Ok(()) + pub async fn fill_bytes(&mut self, dest: &mut [u8]) { + if dest.len() == 0 { + return; // Nothing to fill } - } -} -impl<'d> RngCore for Rng<'d> { - fn fill_bytes(&mut self, dest: &mut [u8]) { + let range = dest.as_mut_ptr_range(); + // Even if we've preempted the interrupt, it can't preempt us again, + // so we don't need to worry about the order we write these in. + STATE.ptr.store(range.start, Ordering::Relaxed); + STATE.end.store(range.end, Ordering::Relaxed); + + self.enable_irq(); + self.start(); + + let on_drop = OnDrop::new(|| { + self.stop(); + self.disable_irq(); + + // The interrupt is now disabled and can't preempt us anymore, so the order doesn't matter here. + STATE.ptr.store(ptr::null_mut(), Ordering::Relaxed); + STATE.end.store(ptr::null_mut(), Ordering::Relaxed); + }); + + poll_fn(|cx| { + STATE.waker.register(cx.waker()); + + // The interrupt will never modify `end`, so load it first and then get the most up-to-date `ptr`. + let end = STATE.end.load(Ordering::Relaxed); + let ptr = STATE.ptr.load(Ordering::Relaxed); + + if ptr == end { + // We're done. + Poll::Ready(()) + } else { + Poll::Pending + } + }) + .await; + + // Trigger the teardown + drop(on_drop); + } + + pub fn blocking_fill_bytes(&mut self, dest: &mut [u8]) { self.start(); for byte in dest.iter_mut() { @@ -223,24 +198,36 @@ impl<'d> RngCore for Rng<'d> { self.stop(); } +} + +impl<'d> Drop for Rng<'d> { + fn drop(&mut self) { + self.irq.disable() + } +} + +impl<'d> rand_core::RngCore for Rng<'d> { + fn fill_bytes(&mut self, dest: &mut [u8]) { + self.blocking_fill_bytes(dest); + } fn next_u32(&mut self) -> u32 { let mut bytes = [0; 4]; - self.fill_bytes(&mut bytes); + self.blocking_fill_bytes(&mut bytes); // We don't care about the endianness, so just use the native one. u32::from_ne_bytes(bytes) } fn next_u64(&mut self) -> u64 { let mut bytes = [0; 8]; - self.fill_bytes(&mut bytes); + self.blocking_fill_bytes(&mut bytes); u64::from_ne_bytes(bytes) } fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rand_core::Error> { - self.fill_bytes(dest); + self.blocking_fill_bytes(dest); Ok(()) } } -// TODO: Should `Rng` implement `CryptoRng`? It's 'suitable for cryptographic purposes' according to the specification. +impl<'d> rand_core::CryptoRng for Rng<'d> {} diff --git a/examples/nrf/src/bin/rng.rs b/examples/nrf/src/bin/rng.rs index 2f1a26993..a35a9fa85 100644 --- a/examples/nrf/src/bin/rng.rs +++ b/examples/nrf/src/bin/rng.rs @@ -5,9 +5,7 @@ #[path = "../example_common.rs"] mod example_common; -use defmt::unwrap; use embassy::executor::Spawner; -use embassy::traits::rng::Rng as _; use embassy_nrf::interrupt; use embassy_nrf::rng::Rng; use embassy_nrf::Peripherals; @@ -19,14 +17,14 @@ async fn main(_spawner: Spawner, p: Peripherals) { // Async API let mut bytes = [0; 4]; - unwrap!(rng.fill_bytes(&mut bytes).await); // nRF RNG is infallible + rng.fill_bytes(&mut bytes).await; defmt::info!("Some random bytes: {:?}", bytes); // Sync API with `rand` defmt::info!("A random number from 1 to 10: {:?}", rng.gen_range(1..=10)); let mut bytes = [0; 1024]; - unwrap!(rng.fill_bytes(&mut bytes).await); + rng.fill_bytes(&mut bytes).await; let zero_count: u32 = bytes.iter().fold(0, |acc, val| acc + val.count_zeros()); let one_count: u32 = bytes.iter().fold(0, |acc, val| acc + val.count_ones()); defmt::info!( From 7997687f3b4c8f679ae458ee28cd338ed9e44b2e Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Thu, 13 Jan 2022 23:56:25 +0100 Subject: [PATCH 9/9] nrf: impl embedded-hal 1.0 and embedded-hal-async traits. --- embassy-nrf/Cargo.toml | 8 +- embassy-nrf/src/buffered_uarte.rs | 14 +- embassy-nrf/src/gpio.rs | 229 +++++++++++++++-------- embassy-nrf/src/gpiote.rs | 147 +++++++++++++-- embassy-nrf/src/spim.rs | 264 ++++++++++++++++++++------ embassy-nrf/src/twim.rs | 297 ++++++++++++++++++++---------- embassy-nrf/src/uarte.rs | 203 ++++++++++++++++++++ examples/nrf/Cargo.toml | 1 - 8 files changed, 910 insertions(+), 253 deletions(-) diff --git a/embassy-nrf/Cargo.toml b/embassy-nrf/Cargo.toml index 3d0c171f3..c9bd2bc14 100644 --- a/embassy-nrf/Cargo.toml +++ b/embassy-nrf/Cargo.toml @@ -12,6 +12,9 @@ edition = "2018" # There are no plans to make this stable. unstable-pac = [] +# Implement embedded-hal 1.0 alpha and embedded-hal-async traits. +unstable-traits = ["embedded-hal-1", "embedded-hal-async"] + nrf52805 = ["nrf52805-pac", "_ppi"] nrf52810 = ["nrf52810-pac", "_ppi"] nrf52811 = ["nrf52811-pac", "_ppi"] @@ -47,11 +50,14 @@ embassy = { version = "0.1.0", path = "../embassy" } embassy-macros = { version = "0.1.0", path = "../embassy-macros", features = ["nrf"]} embassy-hal-common = {version = "0.1.0", path = "../embassy-hal-common" } +embedded-hal-02 = { package = "embedded-hal", version = "0.2.6" } +embedded-hal-1 = { package = "embedded-hal", version = "1.0.0-alpha.6", git = "https://github.com/embassy-rs/embedded-hal", branch = "embassy", optional = true} +embedded-hal-async = { version = "0.0.1", git = "https://github.com/embassy-rs/embedded-hal", branch = "embassy", optional = true} + defmt = { version = "0.3", optional = true } log = { version = "0.4.14", optional = true } cortex-m-rt = ">=0.6.15,<0.8" cortex-m = "0.7.3" -embedded-hal = "0.2.6" embedded-dma = "0.1.2" futures = { version = "0.3.17", default-features = false } critical-section = "0.2.5" diff --git a/embassy-nrf/src/buffered_uarte.rs b/embassy-nrf/src/buffered_uarte.rs index 45e8afc4b..2880c84f6 100644 --- a/embassy-nrf/src/buffered_uarte.rs +++ b/embassy-nrf/src/buffered_uarte.rs @@ -213,9 +213,6 @@ impl<'d, U: UarteInstance, T: TimerInstance> AsyncBufRead for BufferedUarte<'d, cx: &mut Context<'_>, ) -> Poll> { self.inner.with(|state| { - // Conservative compiler fence to prevent optimizations that do not - // take in to account actions by DMA. The fence has been placed here, - // before any DMA action has started compiler_fence(Ordering::SeqCst); trace!("poll_read"); @@ -265,9 +262,6 @@ impl<'d, U: UarteInstance, T: TimerInstance> AsyncWrite for BufferedUarte<'d, U, trace!("poll_write: queued {:?}", n); - // Conservative compiler fence to prevent optimizations that do not - // take in to account actions by DMA. The fence has been placed here, - // before any DMA action has started compiler_fence(Ordering::SeqCst); Poll::Ready(Ok(n)) @@ -347,9 +341,7 @@ impl<'a, U: UarteInstance, T: TimerInstance> PeripheralState for StateInner<'a, trace!(" irq_rx: buf {:?} {:?}", buf.as_ptr() as u32, buf.len()); // Start UARTE Receive transaction - r.tasks_startrx.write(|w| - // `1` is a valid value to write to task registers. - unsafe { w.bits(1) }); + r.tasks_startrx.write(|w| unsafe { w.bits(1) }); } break; } @@ -397,9 +389,7 @@ impl<'a, U: UarteInstance, T: TimerInstance> PeripheralState for StateInner<'a, unsafe { w.maxcnt().bits(buf.len() as _) }); // Start UARTE Transmit transaction - r.tasks_starttx.write(|w| - // `1` is a valid value to write to task registers. - unsafe { w.bits(1) }); + r.tasks_starttx.write(|w| unsafe { w.bits(1) }); } break; } diff --git a/embassy-nrf/src/gpio.rs b/embassy-nrf/src/gpio.rs index abda909f0..3f204d564 100644 --- a/embassy-nrf/src/gpio.rs +++ b/embassy-nrf/src/gpio.rs @@ -7,7 +7,6 @@ use core::marker::PhantomData; use cfg_if::cfg_if; use embassy::util::Unborrow; use embassy_hal_common::{unborrow, unsafe_impl_unborrow}; -use embedded_hal::digital::v2::{InputPin, OutputPin, StatefulOutputPin}; use gpio::pin_cnf::DRIVE_A; use crate::pac; @@ -57,18 +56,6 @@ impl<'d, T: Pin> Input<'d, T> { } } -impl<'d, T: Pin> InputPin for Input<'d, T> { - type Error = Infallible; - - fn is_high(&self) -> Result { - Ok(self.is_high()) - } - - fn is_low(&self) -> Result { - Ok(self.is_low()) - } -} - /// Digital input or output level. #[derive(Debug, Eq, PartialEq)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] @@ -142,28 +129,6 @@ impl<'d, T: Pin> Output<'d, T> { } } -impl<'d, T: Pin> OutputPin for Output<'d, T> { - type Error = Infallible; - - fn set_high(&mut self) -> Result<(), Self::Error> { - Ok(self.set_high()) - } - - fn set_low(&mut self) -> Result<(), Self::Error> { - Ok(self.set_low()) - } -} - -impl<'d, T: Pin> StatefulOutputPin for Output<'d, T> { - fn is_set_high(&self) -> Result { - Ok(self.is_set_high()) - } - - fn is_set_low(&self) -> Result { - Ok(self.is_set_low()) - } -} - /// GPIO flexible pin. /// /// This pin can either be a disconnected, input, or output pin. The level register bit will remain @@ -276,43 +241,6 @@ impl<'d, T: Pin> Drop for Flex<'d, T> { } } -/// Implement [`InputPin`] for [`Flex`]; -/// -/// If the pin is not in input mode the result is unspecified. -impl<'d, T: Pin> InputPin for Flex<'d, T> { - type Error = Infallible; - - fn is_high(&self) -> Result { - Ok(self.is_high()) - } - - fn is_low(&self) -> Result { - Ok(self.is_low()) - } -} - -impl<'d, T: Pin> OutputPin for Flex<'d, T> { - type Error = Infallible; - - fn set_high(&mut self) -> Result<(), Self::Error> { - Ok(self.set_high()) - } - - fn set_low(&mut self) -> Result<(), Self::Error> { - Ok(self.set_low()) - } -} - -impl<'d, T: Pin> StatefulOutputPin for Flex<'d, T> { - fn is_set_high(&self) -> Result { - Ok(self.is_set_high()) - } - - fn is_set_low(&self) -> Result { - Ok(self.is_set_low()) - } -} - pub(crate) mod sealed { use super::*; @@ -491,3 +419,160 @@ macro_rules! impl_pin { } }; } + +// ==================== + +mod eh02 { + use super::*; + + impl<'d, T: Pin> embedded_hal_02::digital::v2::InputPin for Input<'d, T> { + type Error = Infallible; + + fn is_high(&self) -> Result { + Ok(self.is_high()) + } + + fn is_low(&self) -> Result { + Ok(self.is_low()) + } + } + + impl<'d, T: Pin> embedded_hal_02::digital::v2::OutputPin for Output<'d, T> { + type Error = Infallible; + + fn set_high(&mut self) -> Result<(), Self::Error> { + Ok(self.set_high()) + } + + fn set_low(&mut self) -> Result<(), Self::Error> { + Ok(self.set_low()) + } + } + + impl<'d, T: Pin> embedded_hal_02::digital::v2::StatefulOutputPin for Output<'d, T> { + fn is_set_high(&self) -> Result { + Ok(self.is_set_high()) + } + + fn is_set_low(&self) -> Result { + Ok(self.is_set_low()) + } + } + + /// Implement [`InputPin`] for [`Flex`]; + /// + /// If the pin is not in input mode the result is unspecified. + impl<'d, T: Pin> embedded_hal_02::digital::v2::InputPin for Flex<'d, T> { + type Error = Infallible; + + fn is_high(&self) -> Result { + Ok(self.is_high()) + } + + fn is_low(&self) -> Result { + Ok(self.is_low()) + } + } + + impl<'d, T: Pin> embedded_hal_02::digital::v2::OutputPin for Flex<'d, T> { + type Error = Infallible; + + fn set_high(&mut self) -> Result<(), Self::Error> { + Ok(self.set_high()) + } + + fn set_low(&mut self) -> Result<(), Self::Error> { + Ok(self.set_low()) + } + } + + impl<'d, T: Pin> embedded_hal_02::digital::v2::StatefulOutputPin for Flex<'d, T> { + fn is_set_high(&self) -> Result { + Ok(self.is_set_high()) + } + + fn is_set_low(&self) -> Result { + Ok(self.is_set_low()) + } + } +} + +#[cfg(feature = "unstable-traits")] +mod eh1 { + use super::*; + + impl<'d, T: Pin> embedded_hal_1::digital::ErrorType for Input<'d, T> { + type Error = Infallible; + } + + impl<'d, T: Pin> embedded_hal_1::digital::blocking::InputPin for Input<'d, T> { + fn is_high(&self) -> Result { + Ok(self.is_high()) + } + + fn is_low(&self) -> Result { + Ok(self.is_low()) + } + } + + impl<'d, T: Pin> embedded_hal_1::digital::ErrorType for Output<'d, T> { + type Error = Infallible; + } + + impl<'d, T: Pin> embedded_hal_1::digital::blocking::OutputPin for Output<'d, T> { + fn set_high(&mut self) -> Result<(), Self::Error> { + Ok(self.set_high()) + } + + fn set_low(&mut self) -> Result<(), Self::Error> { + Ok(self.set_low()) + } + } + + impl<'d, T: Pin> embedded_hal_1::digital::blocking::StatefulOutputPin for Output<'d, T> { + fn is_set_high(&self) -> Result { + Ok(self.is_set_high()) + } + + fn is_set_low(&self) -> Result { + Ok(self.is_set_low()) + } + } + + impl<'d, T: Pin> embedded_hal_1::digital::ErrorType for Flex<'d, T> { + type Error = Infallible; + } + + /// Implement [`InputPin`] for [`Flex`]; + /// + /// If the pin is not in input mode the result is unspecified. + impl<'d, T: Pin> embedded_hal_1::digital::blocking::InputPin for Flex<'d, T> { + fn is_high(&self) -> Result { + Ok(self.is_high()) + } + + fn is_low(&self) -> Result { + Ok(self.is_low()) + } + } + + impl<'d, T: Pin> embedded_hal_1::digital::blocking::OutputPin for Flex<'d, T> { + fn set_high(&mut self) -> Result<(), Self::Error> { + Ok(self.set_high()) + } + + fn set_low(&mut self) -> Result<(), Self::Error> { + Ok(self.set_low()) + } + } + + impl<'d, T: Pin> embedded_hal_1::digital::blocking::StatefulOutputPin for Flex<'d, T> { + fn is_set_high(&self) -> Result { + Ok(self.is_set_high()) + } + + fn is_set_low(&self) -> Result { + Ok(self.is_set_low()) + } + } +} diff --git a/embassy-nrf/src/gpiote.rs b/embassy-nrf/src/gpiote.rs index f1104904b..a4c24058c 100644 --- a/embassy-nrf/src/gpiote.rs +++ b/embassy-nrf/src/gpiote.rs @@ -5,7 +5,6 @@ use core::task::{Context, Poll}; use embassy::interrupt::{Interrupt, InterruptExt}; use embassy::waitqueue::AtomicWaker; use embassy_hal_common::unsafe_impl_unborrow; -use embedded_hal::digital::v2::InputPin; use futures::future::poll_fn; use crate::gpio::sealed::Pin as _; @@ -216,18 +215,6 @@ impl<'d, C: Channel, T: GpioPin> InputChannel<'d, C, T> { } } -impl<'d, C: Channel, T: GpioPin> InputPin for InputChannel<'d, C, T> { - type Error = Infallible; - - fn is_high(&self) -> Result { - self.pin.is_high() - } - - fn is_low(&self) -> Result { - self.pin.is_low() - } -} - /// GPIOTE channel driver in output mode pub struct OutputChannel<'d, C: Channel, T: GpioPin> { ch: C, @@ -454,3 +441,137 @@ impl_channel!(GPIOTE_CH4, 4); impl_channel!(GPIOTE_CH5, 5); impl_channel!(GPIOTE_CH6, 6); impl_channel!(GPIOTE_CH7, 7); + +// ==================== + +mod eh02 { + use super::*; + + impl<'d, C: Channel, T: GpioPin> embedded_hal_02::digital::v2::InputPin for InputChannel<'d, C, T> { + type Error = Infallible; + + fn is_high(&self) -> Result { + self.pin.is_high() + } + + fn is_low(&self) -> Result { + self.pin.is_low() + } + } +} + +#[cfg(feature = "unstable-traits")] +mod eh1 { + use super::*; + use futures::FutureExt; + + impl<'d, C: Channel, T: GpioPin> embedded_hal_1::digital::ErrorType for InputChannel<'d, C, T> { + type Error = Infallible; + } + + impl<'d, C: Channel, T: GpioPin> embedded_hal_1::digital::blocking::InputPin + for InputChannel<'d, C, T> + { + fn is_high(&self) -> Result { + self.pin.is_high() + } + + fn is_low(&self) -> Result { + self.pin.is_low() + } + } + + impl<'d, T: GpioPin> embedded_hal_async::digital::Wait for Input<'d, T> { + type WaitForHighFuture<'a> + where + Self: 'a, + = impl Future> + 'a; + + fn wait_for_high<'a>(&'a mut self) -> Self::WaitForHighFuture<'a> { + self.wait_for_high().map(Ok) + } + + type WaitForLowFuture<'a> + where + Self: 'a, + = impl Future> + 'a; + + fn wait_for_low<'a>(&'a mut self) -> Self::WaitForLowFuture<'a> { + self.wait_for_low().map(Ok) + } + + type WaitForRisingEdgeFuture<'a> + where + Self: 'a, + = impl Future> + 'a; + + fn wait_for_rising_edge<'a>(&'a mut self) -> Self::WaitForRisingEdgeFuture<'a> { + self.wait_for_rising_edge().map(Ok) + } + + type WaitForFallingEdgeFuture<'a> + where + Self: 'a, + = impl Future> + 'a; + + fn wait_for_falling_edge<'a>(&'a mut self) -> Self::WaitForFallingEdgeFuture<'a> { + self.wait_for_falling_edge().map(Ok) + } + + type WaitForAnyEdgeFuture<'a> + where + Self: 'a, + = impl Future> + 'a; + + fn wait_for_any_edge<'a>(&'a mut self) -> Self::WaitForAnyEdgeFuture<'a> { + self.wait_for_any_edge().map(Ok) + } + } + + impl<'d, T: GpioPin> embedded_hal_async::digital::Wait for Flex<'d, T> { + type WaitForHighFuture<'a> + where + Self: 'a, + = impl Future> + 'a; + + fn wait_for_high<'a>(&'a mut self) -> Self::WaitForHighFuture<'a> { + self.wait_for_high().map(Ok) + } + + type WaitForLowFuture<'a> + where + Self: 'a, + = impl Future> + 'a; + + fn wait_for_low<'a>(&'a mut self) -> Self::WaitForLowFuture<'a> { + self.wait_for_low().map(Ok) + } + + type WaitForRisingEdgeFuture<'a> + where + Self: 'a, + = impl Future> + 'a; + + fn wait_for_rising_edge<'a>(&'a mut self) -> Self::WaitForRisingEdgeFuture<'a> { + self.wait_for_rising_edge().map(Ok) + } + + type WaitForFallingEdgeFuture<'a> + where + Self: 'a, + = impl Future> + 'a; + + fn wait_for_falling_edge<'a>(&'a mut self) -> Self::WaitForFallingEdgeFuture<'a> { + self.wait_for_falling_edge().map(Ok) + } + + type WaitForAnyEdgeFuture<'a> + where + Self: 'a, + = impl Future> + 'a; + + fn wait_for_any_edge<'a>(&'a mut self) -> Self::WaitForAnyEdgeFuture<'a> { + self.wait_for_any_edge().map(Ok) + } + } +} diff --git a/embassy-nrf/src/spim.rs b/embassy-nrf/src/spim.rs index e767bc703..cd43b26e6 100644 --- a/embassy-nrf/src/spim.rs +++ b/embassy-nrf/src/spim.rs @@ -1,15 +1,12 @@ #![macro_use] -use core::future::Future; use core::marker::PhantomData; use core::sync::atomic::{compiler_fence, Ordering}; use core::task::Poll; use embassy::interrupt::InterruptExt; -use embassy::traits; use embassy::util::Unborrow; use embassy_hal_common::unborrow; use futures::future::poll_fn; -use traits::spi::{FullDuplex, Read, Spi, Write}; use crate::gpio; use crate::gpio::sealed::Pin as _; @@ -18,7 +15,7 @@ use crate::interrupt::Interrupt; use crate::util::{slice_ptr_parts, slice_ptr_parts_mut}; use crate::{pac, util::slice_in_ram_or}; -pub use embedded_hal::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3}; +pub use embedded_hal_02::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3}; pub use pac::spim0::frequency::FREQUENCY_A as Frequency; #[derive(Debug, Clone, Copy, PartialEq, Eq)] @@ -267,59 +264,6 @@ impl<'d, T: Instance> Drop for Spim<'d, T> { } } -impl<'d, T: Instance> Spi for Spim<'d, T> { - type Error = Error; -} - -impl<'d, T: Instance> Read for Spim<'d, T> { - type ReadFuture<'a> - where - Self: 'a, - = impl Future> + 'a; - - fn read<'a>(&'a mut self, data: &'a mut [u8]) -> Self::ReadFuture<'a> { - self.read(data) - } -} - -impl<'d, T: Instance> Write for Spim<'d, T> { - type WriteFuture<'a> - where - Self: 'a, - = impl Future> + 'a; - - fn write<'a>(&'a mut self, data: &'a [u8]) -> Self::WriteFuture<'a> { - self.write(data) - } -} - -impl<'d, T: Instance> FullDuplex for Spim<'d, T> { - type WriteReadFuture<'a> - where - Self: 'a, - = impl Future> + 'a; - - fn read_write<'a>(&'a mut self, rx: &'a mut [u8], tx: &'a [u8]) -> Self::WriteReadFuture<'a> { - self.transfer(rx, tx) - } -} - -impl<'d, T: Instance> embedded_hal::blocking::spi::Transfer for Spim<'d, T> { - type Error = Error; - fn transfer<'w>(&mut self, words: &'w mut [u8]) -> Result<&'w [u8], Self::Error> { - self.blocking_transfer_in_place(words)?; - Ok(words) - } -} - -impl<'d, T: Instance> embedded_hal::blocking::spi::Write for Spim<'d, T> { - type Error = Error; - - fn write(&mut self, words: &[u8]) -> Result<(), Self::Error> { - self.blocking_write(words) - } -} - pub(crate) mod sealed { use embassy::waitqueue::AtomicWaker; @@ -363,3 +307,209 @@ macro_rules! impl_spim { } }; } + +// ==================== + +mod eh02 { + use super::*; + + impl<'d, T: Instance> embedded_hal_02::blocking::spi::Transfer for Spim<'d, T> { + type Error = Error; + fn transfer<'w>(&mut self, words: &'w mut [u8]) -> Result<&'w [u8], Self::Error> { + self.blocking_transfer_in_place(words)?; + Ok(words) + } + } + + impl<'d, T: Instance> embedded_hal_02::blocking::spi::Write for Spim<'d, T> { + type Error = Error; + + fn write(&mut self, words: &[u8]) -> Result<(), Self::Error> { + self.blocking_write(words) + } + } +} + +#[cfg(feature = "unstable-traits")] +mod eh1 { + use super::*; + use core::future::Future; + + impl embedded_hal_1::spi::Error for Error { + fn kind(&self) -> embedded_hal_1::spi::ErrorKind { + match *self { + Self::TxBufferTooLong => embedded_hal_1::spi::ErrorKind::Other, + Self::RxBufferTooLong => embedded_hal_1::spi::ErrorKind::Other, + Self::DMABufferNotInDataMemory => embedded_hal_1::spi::ErrorKind::Other, + } + } + } + + impl<'d, T: Instance> embedded_hal_1::spi::ErrorType for Spim<'d, T> { + type Error = Error; + } + + impl<'d, T: Instance> embedded_hal_1::spi::blocking::Read for Spim<'d, T> { + fn read(&mut self, words: &mut [u8]) -> Result<(), Self::Error> { + self.blocking_transfer(words, &[]) + } + + fn read_transaction(&mut self, words: &mut [&mut [u8]]) -> Result<(), Self::Error> { + for buf in words { + self.blocking_read(buf)? + } + Ok(()) + } + } + + impl<'d, T: Instance> embedded_hal_1::spi::blocking::Write for Spim<'d, T> { + fn write(&mut self, words: &[u8]) -> Result<(), Self::Error> { + self.blocking_write(words) + } + + fn write_transaction(&mut self, words: &[&[u8]]) -> Result<(), Self::Error> { + for buf in words { + self.blocking_write(buf)? + } + Ok(()) + } + + fn write_iter(&mut self, words: WI) -> Result<(), Self::Error> + where + WI: IntoIterator, + { + for w in words { + self.blocking_write(&[w])?; + } + Ok(()) + } + } + + impl<'d, T: Instance> embedded_hal_1::spi::blocking::ReadWrite for Spim<'d, T> { + fn transfer(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), Self::Error> { + self.blocking_transfer(read, write) + } + + fn transfer_in_place(&mut self, words: &mut [u8]) -> Result<(), Self::Error> { + self.blocking_transfer_in_place(words) + } + + fn transaction<'a>( + &mut self, + operations: &mut [embedded_hal_async::spi::Operation<'a, u8>], + ) -> Result<(), Self::Error> { + use embedded_hal_1::spi::blocking::Operation; + for o in operations { + match o { + Operation::Read(b) => self.blocking_read(b)?, + Operation::Write(b) => self.blocking_write(b)?, + Operation::Transfer(r, w) => self.blocking_transfer(r, w)?, + Operation::TransferInPlace(b) => self.blocking_transfer_in_place(b)?, + } + } + Ok(()) + } + } + + impl<'d, T: Instance> embedded_hal_async::spi::Read for Spim<'d, T> { + type ReadFuture<'a> + where + Self: 'a, + = impl Future> + 'a; + + fn read<'a>(&'a mut self, words: &'a mut [u8]) -> Self::ReadFuture<'a> { + self.read(words) + } + + type ReadTransactionFuture<'a> + where + Self: 'a, + = impl Future> + 'a; + + fn read_transaction<'a>( + &'a mut self, + words: &'a mut [&'a mut [u8]], + ) -> Self::ReadTransactionFuture<'a> { + async move { + for buf in words { + self.read(buf).await? + } + Ok(()) + } + } + } + + impl<'d, T: Instance> embedded_hal_async::spi::Write for Spim<'d, T> { + type WriteFuture<'a> + where + Self: 'a, + = impl Future> + 'a; + + fn write<'a>(&'a mut self, data: &'a [u8]) -> Self::WriteFuture<'a> { + self.write(data) + } + + type WriteTransactionFuture<'a> + where + Self: 'a, + = impl Future> + 'a; + + fn write_transaction<'a>( + &'a mut self, + words: &'a [&'a [u8]], + ) -> Self::WriteTransactionFuture<'a> { + async move { + for buf in words { + self.write(buf).await? + } + Ok(()) + } + } + } + + impl<'d, T: Instance> embedded_hal_async::spi::ReadWrite for Spim<'d, T> { + type TransferFuture<'a> + where + Self: 'a, + = impl Future> + 'a; + + fn transfer<'a>(&'a mut self, rx: &'a mut [u8], tx: &'a [u8]) -> Self::TransferFuture<'a> { + self.transfer(rx, tx) + } + + type TransferInPlaceFuture<'a> + where + Self: 'a, + = impl Future> + 'a; + + fn transfer_in_place<'a>( + &'a mut self, + words: &'a mut [u8], + ) -> Self::TransferInPlaceFuture<'a> { + self.transfer_in_place(words) + } + + type TransactionFuture<'a> + where + Self: 'a, + = impl Future> + 'a; + + fn transaction<'a>( + &'a mut self, + operations: &'a mut [embedded_hal_async::spi::Operation<'a, u8>], + ) -> Self::TransactionFuture<'a> { + use embedded_hal_1::spi::blocking::Operation; + async move { + for o in operations { + match o { + Operation::Read(b) => self.read(b).await?, + Operation::Write(b) => self.write(b).await?, + Operation::Transfer(r, w) => self.transfer(r, w).await?, + Operation::TransferInPlace(b) => self.transfer_in_place(b).await?, + } + } + Ok(()) + } + } + } +} diff --git a/embassy-nrf/src/twim.rs b/embassy-nrf/src/twim.rs index ab649c470..4cd47c897 100644 --- a/embassy-nrf/src/twim.rs +++ b/embassy-nrf/src/twim.rs @@ -11,12 +11,10 @@ use core::marker::PhantomData; use core::sync::atomic::{compiler_fence, Ordering::SeqCst}; use core::task::Poll; use embassy::interrupt::{Interrupt, InterruptExt}; -use embassy::traits; use embassy::util::Unborrow; use embassy::waitqueue::AtomicWaker; use embassy_hal_common::unborrow; use futures::future::poll_fn; -use traits::i2c::I2c; use crate::chip::{EASY_DMA_SIZE, FORCE_COPY_BUFFER_SIZE}; use crate::gpio; @@ -50,6 +48,22 @@ impl Default for Config { } } +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[non_exhaustive] +pub enum Error { + TxBufferTooLong, + RxBufferTooLong, + TxBufferZeroLength, + RxBufferZeroLength, + Transmit, + Receive, + DMABufferNotInDataMemory, + AddressNack, + DataNack, + Overrun, +} + /// Interface to a TWIM instance. pub struct Twim<'d, T: Instance> { phantom: PhantomData<&'d mut T>, @@ -506,101 +520,6 @@ impl<'a, T: Instance> Drop for Twim<'a, T> { } } -impl<'d, T> I2c for Twim<'d, T> -where - T: Instance, -{ - type Error = Error; - - type WriteFuture<'a> - where - Self: 'a, - = impl Future> + 'a; - type ReadFuture<'a> - where - Self: 'a, - = impl Future> + 'a; - type WriteReadFuture<'a> - where - Self: 'a, - = impl Future> + 'a; - - fn read<'a>(&'a mut self, address: u8, buffer: &'a mut [u8]) -> Self::ReadFuture<'a> { - self.read(address, buffer) - } - - fn write<'a>(&'a mut self, address: u8, buffer: &'a [u8]) -> Self::WriteFuture<'a> { - self.write(address, buffer) - } - - fn write_read<'a>( - &'a mut self, - address: u8, - wr_buffer: &'a [u8], - rd_buffer: &'a mut [u8], - ) -> Self::WriteReadFuture<'a> { - self.write_read(address, wr_buffer, rd_buffer) - } -} - -impl<'a, T: Instance> embedded_hal::blocking::i2c::Write for Twim<'a, T> { - type Error = Error; - - fn write<'w>(&mut self, addr: u8, bytes: &'w [u8]) -> Result<(), Error> { - if slice_in_ram(bytes) { - self.blocking_write(addr, bytes) - } else { - let buf = &mut [0; FORCE_COPY_BUFFER_SIZE][..]; - for chunk in bytes.chunks(FORCE_COPY_BUFFER_SIZE) { - buf[..chunk.len()].copy_from_slice(chunk); - self.blocking_write(addr, &buf[..chunk.len()])?; - } - Ok(()) - } - } -} - -impl<'a, T: Instance> embedded_hal::blocking::i2c::Read for Twim<'a, T> { - type Error = Error; - - fn read<'w>(&mut self, addr: u8, bytes: &'w mut [u8]) -> Result<(), Error> { - self.blocking_read(addr, bytes) - } -} - -impl<'a, T: Instance> embedded_hal::blocking::i2c::WriteRead for Twim<'a, T> { - type Error = Error; - - fn write_read<'w>( - &mut self, - addr: u8, - bytes: &'w [u8], - buffer: &'w mut [u8], - ) -> Result<(), Error> { - if slice_in_ram(bytes) { - self.blocking_write_read(addr, bytes, buffer) - } else { - self.blocking_copy_write_read(addr, bytes, buffer) - } - } -} - -#[derive(Debug, Copy, Clone, Eq, PartialEq)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -#[non_exhaustive] -pub enum Error { - TxBufferTooLong, - RxBufferTooLong, - TxBufferZeroLength, - RxBufferZeroLength, - Transmit, - Receive, - DMABufferNotInDataMemory, - AddressNack, - DataNack, - Overrun, -} - pub(crate) mod sealed { use super::*; @@ -642,3 +561,187 @@ macro_rules! impl_twim { } }; } + +// ==================== + +mod eh02 { + use super::*; + + impl<'a, T: Instance> embedded_hal_02::blocking::i2c::Write for Twim<'a, T> { + type Error = Error; + + fn write<'w>(&mut self, addr: u8, bytes: &'w [u8]) -> Result<(), Error> { + if slice_in_ram(bytes) { + self.blocking_write(addr, bytes) + } else { + let buf = &mut [0; FORCE_COPY_BUFFER_SIZE][..]; + for chunk in bytes.chunks(FORCE_COPY_BUFFER_SIZE) { + buf[..chunk.len()].copy_from_slice(chunk); + self.blocking_write(addr, &buf[..chunk.len()])?; + } + Ok(()) + } + } + } + + impl<'a, T: Instance> embedded_hal_02::blocking::i2c::Read for Twim<'a, T> { + type Error = Error; + + fn read<'w>(&mut self, addr: u8, bytes: &'w mut [u8]) -> Result<(), Error> { + self.blocking_read(addr, bytes) + } + } + + impl<'a, T: Instance> embedded_hal_02::blocking::i2c::WriteRead for Twim<'a, T> { + type Error = Error; + + fn write_read<'w>( + &mut self, + addr: u8, + bytes: &'w [u8], + buffer: &'w mut [u8], + ) -> Result<(), Error> { + if slice_in_ram(bytes) { + self.blocking_write_read(addr, bytes, buffer) + } else { + self.blocking_copy_write_read(addr, bytes, buffer) + } + } + } +} + +#[cfg(feature = "unstable-traits")] +mod eh1 { + use super::*; + + impl embedded_hal_1::i2c::Error for Error { + fn kind(&self) -> embedded_hal_1::i2c::ErrorKind { + match *self { + Self::TxBufferTooLong => embedded_hal_1::i2c::ErrorKind::Other, + Self::RxBufferTooLong => embedded_hal_1::i2c::ErrorKind::Other, + Self::TxBufferZeroLength => embedded_hal_1::i2c::ErrorKind::Other, + Self::RxBufferZeroLength => embedded_hal_1::i2c::ErrorKind::Other, + Self::Transmit => embedded_hal_1::i2c::ErrorKind::Other, + Self::Receive => embedded_hal_1::i2c::ErrorKind::Other, + Self::DMABufferNotInDataMemory => embedded_hal_1::i2c::ErrorKind::Other, + Self::AddressNack => embedded_hal_1::i2c::ErrorKind::NoAcknowledge( + embedded_hal_1::i2c::NoAcknowledgeSource::Address, + ), + Self::DataNack => embedded_hal_1::i2c::ErrorKind::NoAcknowledge( + embedded_hal_1::i2c::NoAcknowledgeSource::Data, + ), + Self::Overrun => embedded_hal_1::i2c::ErrorKind::Overrun, + } + } + } + + impl<'d, T: Instance> embedded_hal_1::i2c::ErrorType for Twim<'d, T> { + type Error = Error; + } + + impl<'d, T: Instance> embedded_hal_1::i2c::blocking::I2c for Twim<'d, T> { + fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Self::Error> { + self.blocking_read(address, buffer) + } + + fn write(&mut self, address: u8, buffer: &[u8]) -> Result<(), Self::Error> { + self.blocking_write(address, buffer) + } + + fn write_iter(&mut self, _address: u8, _bytes: B) -> Result<(), Self::Error> + where + B: IntoIterator, + { + todo!(); + } + + fn write_iter_read( + &mut self, + _address: u8, + _bytes: B, + _buffer: &mut [u8], + ) -> Result<(), Self::Error> + where + B: IntoIterator, + { + todo!(); + } + + fn write_read( + &mut self, + address: u8, + wr_buffer: &[u8], + rd_buffer: &mut [u8], + ) -> Result<(), Self::Error> { + self.blocking_write_read(address, wr_buffer, rd_buffer) + } + + fn transaction<'a>( + &mut self, + _address: u8, + _operations: &mut [embedded_hal_async::i2c::Operation<'a>], + ) -> Result<(), Self::Error> { + todo!(); + } + + fn transaction_iter<'a, O>( + &mut self, + _address: u8, + _operations: O, + ) -> Result<(), Self::Error> + where + O: IntoIterator>, + { + todo!(); + } + } + + impl<'d, T: Instance> embedded_hal_async::i2c::I2c for Twim<'d, T> { + type ReadFuture<'a> + where + Self: 'a, + = impl Future> + 'a; + + fn read<'a>(&'a mut self, address: u8, buffer: &'a mut [u8]) -> Self::ReadFuture<'a> { + self.read(address, buffer) + } + + type WriteFuture<'a> + where + Self: 'a, + = impl Future> + 'a; + + fn write<'a>(&'a mut self, address: u8, bytes: &'a [u8]) -> Self::WriteFuture<'a> { + self.write(address, bytes) + } + + type WriteReadFuture<'a> + where + Self: 'a, + = impl Future> + 'a; + + fn write_read<'a>( + &'a mut self, + address: u8, + wr_buffer: &'a [u8], + rd_buffer: &'a mut [u8], + ) -> Self::WriteReadFuture<'a> { + self.write_read(address, wr_buffer, rd_buffer) + } + + type TransactionFuture<'a> + where + Self: 'a, + = impl Future> + 'a; + + fn transaction<'a>( + &'a mut self, + address: u8, + operations: &mut [embedded_hal_async::i2c::Operation<'a>], + ) -> Self::TransactionFuture<'a> { + let _ = address; + let _ = operations; + async move { todo!() } + } + } +} diff --git a/embassy-nrf/src/uarte.rs b/embassy-nrf/src/uarte.rs index 07cec5d6b..b10e55a05 100644 --- a/embassy-nrf/src/uarte.rs +++ b/embassy-nrf/src/uarte.rs @@ -712,3 +712,206 @@ macro_rules! impl_uarte { } }; } + +// ==================== + +mod eh02 { + use super::*; + + impl<'d, T: Instance> embedded_hal_02::blocking::serial::Write for Uarte<'d, T> { + type Error = Error; + + fn bwrite_all(&mut self, buffer: &[u8]) -> Result<(), Self::Error> { + self.blocking_write(buffer) + } + + fn bflush(&mut self) -> Result<(), Self::Error> { + Ok(()) + } + } + + impl<'d, T: Instance> embedded_hal_02::blocking::serial::Write for UarteTx<'d, T> { + type Error = Error; + + fn bwrite_all(&mut self, buffer: &[u8]) -> Result<(), Self::Error> { + self.blocking_write(buffer) + } + + fn bflush(&mut self) -> Result<(), Self::Error> { + Ok(()) + } + } + + impl<'d, U: Instance, T: TimerInstance> embedded_hal_02::blocking::serial::Write + for UarteWithIdle<'d, U, T> + { + type Error = Error; + + fn bwrite_all(&mut self, buffer: &[u8]) -> Result<(), Self::Error> { + self.blocking_write(buffer) + } + + fn bflush(&mut self) -> Result<(), Self::Error> { + Ok(()) + } + } +} + +#[cfg(feature = "unstable-traits")] +mod eh1 { + use super::*; + use core::future::Future; + + impl embedded_hal_1::serial::Error for Error { + fn kind(&self) -> embedded_hal_1::serial::ErrorKind { + match *self { + Self::BufferTooLong => embedded_hal_1::serial::ErrorKind::Other, + Self::BufferZeroLength => embedded_hal_1::serial::ErrorKind::Other, + Self::DMABufferNotInDataMemory => embedded_hal_1::serial::ErrorKind::Other, + } + } + } + + // ===================== + + impl<'d, T: Instance> embedded_hal_1::serial::ErrorType for Uarte<'d, T> { + type Error = Error; + } + + impl<'d, T: Instance> embedded_hal_1::serial::blocking::Write for Uarte<'d, T> { + fn write(&mut self, buffer: &[u8]) -> Result<(), Self::Error> { + self.blocking_write(buffer) + } + + fn flush(&mut self) -> Result<(), Self::Error> { + Ok(()) + } + } + + impl<'d, T: Instance> embedded_hal_async::serial::Read for Uarte<'d, T> { + type ReadFuture<'a> + where + Self: 'a, + = impl Future> + 'a; + + fn read<'a>(&'a mut self, buffer: &'a mut [u8]) -> Self::ReadFuture<'a> { + self.read(buffer) + } + } + + impl<'d, T: Instance> embedded_hal_async::serial::Write for Uarte<'d, T> { + type WriteFuture<'a> + where + Self: 'a, + = impl Future> + 'a; + + fn write<'a>(&'a mut self, buffer: &'a [u8]) -> Self::WriteFuture<'a> { + self.write(buffer) + } + + type FlushFuture<'a> + where + Self: 'a, + = impl Future> + 'a; + + fn flush<'a>(&'a mut self) -> Self::FlushFuture<'a> { + async move { Ok(()) } + } + } + + // ===================== + + impl<'d, T: Instance> embedded_hal_1::serial::ErrorType for UarteTx<'d, T> { + type Error = Error; + } + + impl<'d, T: Instance> embedded_hal_1::serial::blocking::Write for UarteTx<'d, T> { + fn write(&mut self, buffer: &[u8]) -> Result<(), Self::Error> { + self.blocking_write(buffer) + } + + fn flush(&mut self) -> Result<(), Self::Error> { + Ok(()) + } + } + + impl<'d, T: Instance> embedded_hal_async::serial::Write for UarteTx<'d, T> { + type WriteFuture<'a> + where + Self: 'a, + = impl Future> + 'a; + + fn write<'a>(&'a mut self, buffer: &'a [u8]) -> Self::WriteFuture<'a> { + self.write(buffer) + } + + type FlushFuture<'a> + where + Self: 'a, + = impl Future> + 'a; + + fn flush<'a>(&'a mut self) -> Self::FlushFuture<'a> { + async move { Ok(()) } + } + } + + // ===================== + + impl<'d, T: Instance> embedded_hal_1::serial::ErrorType for UarteRx<'d, T> { + type Error = Error; + } + + impl<'d, T: Instance> embedded_hal_async::serial::Read for UarteRx<'d, T> { + type ReadFuture<'a> + where + Self: 'a, + = impl Future> + 'a; + + fn read<'a>(&'a mut self, buffer: &'a mut [u8]) -> Self::ReadFuture<'a> { + self.read(buffer) + } + } + + // ===================== + + impl<'d, U: Instance, T: TimerInstance> embedded_hal_1::serial::ErrorType + for UarteWithIdle<'d, U, T> + { + type Error = Error; + } + + impl<'d, U: Instance, T: TimerInstance> embedded_hal_async::serial::Read + for UarteWithIdle<'d, U, T> + { + type ReadFuture<'a> + where + Self: 'a, + = impl Future> + 'a; + + fn read<'a>(&'a mut self, buffer: &'a mut [u8]) -> Self::ReadFuture<'a> { + self.read(buffer) + } + } + + impl<'d, U: Instance, T: TimerInstance> embedded_hal_async::serial::Write + for UarteWithIdle<'d, U, T> + { + type WriteFuture<'a> + where + Self: 'a, + = impl Future> + 'a; + + fn write<'a>(&'a mut self, buffer: &'a [u8]) -> Self::WriteFuture<'a> { + self.write(buffer) + } + + type FlushFuture<'a> + where + Self: 'a, + = impl Future> + 'a; + + fn flush<'a>(&'a mut self) -> Self::FlushFuture<'a> { + async move { Ok(()) } + } + } +} diff --git a/examples/nrf/Cargo.toml b/examples/nrf/Cargo.toml index ca013f8b7..fa7286923 100644 --- a/examples/nrf/Cargo.toml +++ b/examples/nrf/Cargo.toml @@ -15,7 +15,6 @@ defmt-rtt = "0.3" cortex-m = "0.7.3" cortex-m-rt = "0.7.0" -embedded-hal = "0.2.6" panic-probe = { version = "0.3", features = ["print-defmt"] } futures = { version = "0.3.17", default-features = false, features = ["async-await"] } rand = { version = "0.8.4", default-features = false }