diff --git a/embassy-nrf-examples/src/bin/spim.rs b/embassy-nrf-examples/src/bin/spim.rs index 8eaac5e1..b7436332 100644 --- a/embassy-nrf-examples/src/bin/spim.rs +++ b/embassy-nrf-examples/src/bin/spim.rs @@ -6,7 +6,7 @@ #[path = "../example_common.rs"] mod example_common; -use embassy_nrf::gpio::{Level, Output}; +use embassy_nrf::gpio::{Level, Output, OutputDrive}; use embassy_nrf::peripherals::Peripherals; use embassy_traits::spi::FullDuplex; use example_common::*; @@ -37,7 +37,7 @@ async fn run() { let spim = spim::Spim::new(p.spim3, irq, p.p0_29, p.p0_28, p.p0_30, config); pin_mut!(spim); - let mut ncs = Output::new(p.p0_31, Level::High); + let mut ncs = Output::new(p.p0_31, Level::High, OutputDrive::Standard); // Example on how to talk to an ENC28J60 chip diff --git a/embassy-nrf/src/spim.rs b/embassy-nrf/src/spim.rs index 38cfa005..33005188 100644 --- a/embassy-nrf/src/spim.rs +++ b/embassy-nrf/src/spim.rs @@ -4,8 +4,7 @@ use core::pin::Pin; use core::sync::atomic::{compiler_fence, Ordering}; use core::task::Poll; use embassy::traits; -use embassy::util::{PeripheralBorrow, WakerRegistration}; -use embassy_extras::peripheral::{PeripheralMutex, PeripheralState}; +use embassy::util::{wake_on_interrupt, PeripheralBorrow}; use futures::future::poll_fn; use traits::spi::FullDuplex; @@ -26,13 +25,9 @@ pub enum Error { DMABufferNotInDataMemory, } -struct State { - spim: T, - waker: WakerRegistration, -} - pub struct Spim<'d, T: Instance> { - inner: PeripheralMutex>, + spim: T, + irq: T::Interrupt, phantom: PhantomData<&'d mut T>, } @@ -130,20 +125,11 @@ impl<'d, T: Instance> Spim<'d, T> { r.intenclr.write(|w| unsafe { w.bits(0xFFFF_FFFF) }); Self { - inner: PeripheralMutex::new( - State { - spim, - waker: WakerRegistration::new(), - }, - irq, - ), + spim, + irq, phantom: PhantomData, } } - - fn inner(self: Pin<&mut Self>) -> Pin<&mut PeripheralMutex>> { - unsafe { Pin::new_unchecked(&mut self.get_unchecked_mut().inner) } - } } impl<'d, T: Instance> FullDuplex for Spim<'d, T> { @@ -157,69 +143,69 @@ impl<'d, T: Instance> FullDuplex for Spim<'d, T> { type WriteReadFuture<'a> where Self: 'a = impl Future> + 'a; fn read<'a>(self: Pin<&'a mut Self>, data: &'a mut [u8]) -> Self::ReadFuture<'a> { - async move { todo!() } + self.read_write(data, &[]) } fn write<'a>(self: Pin<&'a mut Self>, data: &'a [u8]) -> Self::WriteFuture<'a> { - async move { todo!() } + self.read_write(&mut [], data) } fn read_write<'a>( - mut self: Pin<&'a mut Self>, + self: Pin<&'a mut Self>, rx: &'a mut [u8], tx: &'a [u8], ) -> Self::WriteReadFuture<'a> { async move { + let this = unsafe { self.get_unchecked_mut() }; slice_in_ram_or(rx, Error::DMABufferNotInDataMemory)?; slice_in_ram_or(tx, Error::DMABufferNotInDataMemory)?; - self.as_mut().inner().register_interrupt(); - self.as_mut().inner().with(|s, _irq| { - // 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); + // 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 = s.spim.regs(); + let r = this.spim.regs(); - // 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 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 _) }); + // 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()); + // 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) }); + // 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); - }); + // 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| { - self.as_mut().inner().with(|s, _irq| { - let r = s.spim.regs(); - if r.events_end.read().bits() != 0 { - return Poll::Ready(()); - } - s.waker.register(cx.waker()); - Poll::Pending - }) + let r = this.spim.regs(); + + if r.events_end.read().bits() != 0 { + r.events_end.reset(); + return Poll::Ready(()); + } + + wake_on_interrupt(&mut this.irq, cx.waker()); + + Poll::Pending }) .await; @@ -228,16 +214,6 @@ impl<'d, T: Instance> FullDuplex for Spim<'d, T> { } } -impl PeripheralState for State { - type Interrupt = U::Interrupt; - fn on_interrupt(&mut self) { - if self.spim.regs().events_end.read().bits() != 0 { - self.spim.regs().intenclr.write(|w| w.end().clear()); - self.waker.wake() - } - } -} - mod sealed { use super::*;