From c15411d1bdbc54caa0e9879ea1de8c43025f2090 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Wed, 14 Apr 2021 16:37:10 +0200 Subject: [PATCH] Remove Pin from SPI --- embassy-nrf-examples/src/bin/spim.rs | 12 +++--- embassy-nrf/src/spim.rs | 61 +++++++++++++++++++--------- embassy-stm32/src/f4/spi.rs | 56 ++++++++++++------------- embassy-traits/src/spi.rs | 6 +-- 4 files changed, 76 insertions(+), 59 deletions(-) diff --git a/embassy-nrf-examples/src/bin/spim.rs b/embassy-nrf-examples/src/bin/spim.rs index 6d0fa93d..27486374 100644 --- a/embassy-nrf-examples/src/bin/spim.rs +++ b/embassy-nrf-examples/src/bin/spim.rs @@ -17,7 +17,6 @@ use embassy_nrf::{interrupt, spim}; use embassy_traits::spi::FullDuplex; use embedded_hal::digital::v2::*; use example_common::*; -use futures::pin_mut; #[embassy::main] async fn main(spawner: Spawner) { @@ -32,8 +31,7 @@ async fn main(spawner: Spawner) { }; let irq = interrupt::take!(SPIM3); - let spim = spim::Spim::new(p.SPIM3, irq, p.P0_29, p.P0_28, p.P0_30, config); - pin_mut!(spim); + let mut spim = spim::Spim::new(p.SPIM3, irq, p.P0_29, p.P0_28, p.P0_30, config); let mut ncs = Output::new(p.P0_31, Level::High, OutputDrive::Standard); @@ -44,7 +42,7 @@ async fn main(spawner: Spawner) { ncs.set_low().unwrap(); cortex_m::asm::delay(5); let tx = [0xFF]; - unwrap!(spim.as_mut().read_write(&mut [], &tx).await); + unwrap!(spim.read_write(&mut [], &tx).await); cortex_m::asm::delay(10); ncs.set_high().unwrap(); @@ -57,7 +55,7 @@ async fn main(spawner: Spawner) { ncs.set_low().unwrap(); cortex_m::asm::delay(5000); let tx = [0b000_11101, 0]; - unwrap!(spim.as_mut().read_write(&mut rx, &tx).await); + unwrap!(spim.read_write(&mut rx, &tx).await); cortex_m::asm::delay(5000); ncs.set_high().unwrap(); info!("estat: {=[?]}", rx); @@ -67,7 +65,7 @@ async fn main(spawner: Spawner) { ncs.set_low().unwrap(); cortex_m::asm::delay(5); let tx = [0b100_11111, 0b11]; - unwrap!(spim.as_mut().read_write(&mut rx, &tx).await); + unwrap!(spim.read_write(&mut rx, &tx).await); cortex_m::asm::delay(10); ncs.set_high().unwrap(); @@ -76,7 +74,7 @@ async fn main(spawner: Spawner) { ncs.set_low().unwrap(); cortex_m::asm::delay(5); let tx = [0b000_10010, 0]; - unwrap!(spim.as_mut().read_write(&mut rx, &tx).await); + unwrap!(spim.read_write(&mut rx, &tx).await); cortex_m::asm::delay(10); ncs.set_high().unwrap(); diff --git a/embassy-nrf/src/spim.rs b/embassy-nrf/src/spim.rs index 93ca52c6..bbe1eedf 100644 --- a/embassy-nrf/src/spim.rs +++ b/embassy-nrf/src/spim.rs @@ -1,10 +1,10 @@ use core::future::Future; use core::marker::PhantomData; -use core::pin::Pin; use core::sync::atomic::{compiler_fence, Ordering}; use core::task::Poll; +use embassy::interrupt::InterruptExt; use embassy::traits; -use embassy::util::{wake_on_interrupt, PeripheralBorrow}; +use embassy::util::{AtomicWaker, PeripheralBorrow}; use embassy_extras::unborrow; use futures::future::poll_fn; use traits::spi::FullDuplex; @@ -50,7 +50,7 @@ impl<'d, T: Instance> Spim<'d, T> { ) -> Self { unborrow!(spim, irq, sck, miso, mosi); - let r = spim.regs(); + let r = T::regs(); // Configure pins sck.conf().write(|w| w.dir().output().drive().h0h1()); @@ -122,12 +122,26 @@ impl<'d, T: Instance> Spim<'d, T> { // Disable all events interrupts r.intenclr.write(|w| unsafe { w.bits(0xFFFF_FFFF) }); + irq.set_handler(Self::on_interrupt); + irq.unpend(); + irq.enable(); + Self { peri: spim, irq, phantom: PhantomData, } } + + fn on_interrupt(_: *mut ()) { + let r = T::regs(); + let s = T::state(); + + if r.events_end.read().bits() != 0 { + s.end_waker.wake(); + r.intenclr.write(|w| w.end().clear()); + } + } } impl<'d, T: Instance> FullDuplex for Spim<'d, T> { @@ -140,20 +154,15 @@ impl<'d, T: Instance> FullDuplex for Spim<'d, T> { #[rustfmt::skip] type WriteReadFuture<'a> where Self: 'a = impl Future> + 'a; - fn read<'a>(self: Pin<&'a mut Self>, data: &'a mut [u8]) -> Self::ReadFuture<'a> { + fn read<'a>(&'a mut self, data: &'a mut [u8]) -> Self::ReadFuture<'a> { self.read_write(data, &[]) } - fn write<'a>(self: Pin<&'a mut Self>, data: &'a [u8]) -> Self::WriteFuture<'a> { + fn write<'a>(&'a mut self, data: &'a [u8]) -> Self::WriteFuture<'a> { self.read_write(&mut [], data) } - fn read_write<'a>( - self: Pin<&'a mut Self>, - rx: &'a mut [u8], - tx: &'a [u8], - ) -> Self::WriteReadFuture<'a> { + fn read_write<'a>(&'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)?; @@ -162,7 +171,8 @@ impl<'d, T: Instance> FullDuplex for Spim<'d, T> { // before any DMA action has started. compiler_fence(Ordering::SeqCst); - let r = this.peri.regs(); + let r = T::regs(); + let s = T::state(); // Set up the DMA write. r.txd @@ -194,15 +204,11 @@ impl<'d, T: Instance> FullDuplex for Spim<'d, T> { // Wait for 'end' event. poll_fn(|cx| { - let r = this.peri.regs(); - + s.end_waker.register(cx.waker()); 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; @@ -215,8 +221,21 @@ impl<'d, T: Instance> FullDuplex for Spim<'d, T> { mod sealed { use super::*; + pub struct State { + pub end_waker: AtomicWaker, + } + + impl State { + pub const fn new() -> Self { + Self { + end_waker: AtomicWaker::new(), + } + } + } + pub trait Instance { - fn regs(&self) -> &pac::spim0::RegisterBlock; + fn regs() -> &'static pac::spim0::RegisterBlock; + fn state() -> &'static State; } } @@ -227,9 +246,13 @@ pub trait Instance: sealed::Instance + 'static { macro_rules! impl_instance { ($type:ident, $irq:ident) => { impl sealed::Instance for peripherals::$type { - fn regs(&self) -> &pac::spim0::RegisterBlock { + fn regs() -> &'static pac::spim0::RegisterBlock { unsafe { &*pac::$type::ptr() } } + fn state() -> &'static sealed::State { + static STATE: sealed::State = sealed::State::new(); + &STATE + } } impl Instance for peripherals::$type { type Interrupt = interrupt::$irq; diff --git a/embassy-stm32/src/f4/spi.rs b/embassy-stm32/src/f4/spi.rs index bc73611f..65bf7287 100644 --- a/embassy-stm32/src/f4/spi.rs +++ b/embassy-stm32/src/f4/spi.rs @@ -214,14 +214,13 @@ where type ReadFuture<'a> = impl Future> + 'a; type WriteReadFuture<'a> = impl Future> + 'a; - fn read<'a>(self: Pin<&'a mut Self>, buf: &'a mut [u8]) -> Self::ReadFuture<'a> { - let this = unsafe { self.get_unchecked_mut() }; + fn read<'a>(&'a mut self, buf: &'a mut [u8]) -> Self::ReadFuture<'a> { #[allow(mutable_transmutes)] let static_buf: &'static mut [u8] = unsafe { mem::transmute(buf) }; async move { - let rx_stream = this.rx_stream.take().unwrap(); - let spi = this.spi.take().unwrap(); + let rx_stream = self.rx_stream.take().unwrap(); + let spi = self.spi.take().unwrap(); spi.cr2.modify(|_, w| w.errie().set_bit()); @@ -236,8 +235,8 @@ where .double_buffer(false), ); - let fut = InterruptFuture::new(&mut this.rx_int); - let fut_err = InterruptFuture::new(&mut this.spi_int); + let fut = InterruptFuture::new(&mut self.rx_int); + let fut_err = InterruptFuture::new(&mut self.spi_int); rx_transfer.start(|_spi| {}); future::select(fut, fut_err).await; @@ -245,21 +244,20 @@ where let (rx_stream, spi, _buf, _) = rx_transfer.free(); spi.cr2.modify(|_, w| w.errie().clear_bit()); - this.rx_stream.replace(rx_stream); - this.spi.replace(spi); + self.rx_stream.replace(rx_stream); + self.spi.replace(spi); Ok(()) } } - fn write<'a>(self: Pin<&'a mut Self>, buf: &'a [u8]) -> Self::WriteFuture<'a> { - let this = unsafe { self.get_unchecked_mut() }; + fn write<'a>(&'a mut self, buf: &'a [u8]) -> Self::WriteFuture<'a> { #[allow(mutable_transmutes)] let static_buf: &'static mut [u8] = unsafe { mem::transmute(buf) }; async move { - let tx_stream = this.tx_stream.take().unwrap(); - let spi = this.spi.take().unwrap(); + let tx_stream = self.tx_stream.take().unwrap(); + let spi = self.spi.take().unwrap(); // let mut tx_transfer = Transfer::init( // tx_stream, @@ -272,7 +270,7 @@ where // .double_buffer(false), // ); // - // let fut = InterruptFuture::new(&mut this.tx_int); + // let fut = InterruptFuture::new(&mut self.tx_int); // // tx_transfer.start(|_spi| {}); // fut.await; @@ -284,28 +282,26 @@ where nb::block!(write_sr(&spi, byte)); } - this.tx_stream.replace(tx_stream); - this.spi.replace(spi); + self.tx_stream.replace(tx_stream); + self.spi.replace(spi); Ok(()) } } fn read_write<'a>( - self: Pin<&'a mut Self>, + &'a mut self, read_buf: &'a mut [u8], write_buf: &'a [u8], ) -> Self::WriteReadFuture<'a> { - let this = unsafe { self.get_unchecked_mut() }; - #[allow(mutable_transmutes)] let write_static_buf: &'static mut [u8] = unsafe { mem::transmute(write_buf) }; let read_static_buf: &'static mut [u8] = unsafe { mem::transmute(read_buf) }; async move { - let tx_stream = this.tx_stream.take().unwrap(); - let rx_stream = this.rx_stream.take().unwrap(); - let spi_tx = this.spi.take().unwrap(); + let tx_stream = self.tx_stream.take().unwrap(); + let rx_stream = self.rx_stream.take().unwrap(); + let spi_tx = self.spi.take().unwrap(); let spi_rx: SPI = unsafe { mem::transmute_copy(&spi_tx) }; spi_rx @@ -334,9 +330,9 @@ where // .double_buffer(false), // ); // - // let tx_fut = InterruptFuture::new(&mut this.tx_int); - // let rx_fut = InterruptFuture::new(&mut this.rx_int); - // let rx_fut_err = InterruptFuture::new(&mut this.spi_int); + // let tx_fut = InterruptFuture::new(&mut self.tx_int); + // let rx_fut = InterruptFuture::new(&mut self.rx_int); + // let rx_fut_err = InterruptFuture::new(&mut self.spi_int); // // rx_transfer.start(|_spi| {}); // tx_transfer.start(|_spi| {}); @@ -352,7 +348,7 @@ where for i in 0..(read_static_buf.len() - 1) { let byte = write_static_buf[i]; loop { - let fut = InterruptFuture::new(&mut this.spi_int); + let fut = InterruptFuture::new(&mut self.spi_int); match write_sr(&spi_tx, byte) { Ok(()) => break, _ => {} @@ -361,7 +357,7 @@ where } loop { - let fut = InterruptFuture::new(&mut this.spi_int); + let fut = InterruptFuture::new(&mut self.spi_int); match read_sr(&spi_tx) { Ok(byte) => { read_static_buf[i] = byte; @@ -381,9 +377,9 @@ where .rxneie() .clear_bit() }); - this.rx_stream.replace(rx_stream); - this.tx_stream.replace(tx_stream); - this.spi.replace(spi_rx); + self.rx_stream.replace(rx_stream); + self.tx_stream.replace(tx_stream); + self.spi.replace(spi_rx); Ok(()) } @@ -421,7 +417,7 @@ macro_rules! spi { impl Instance for pac::$SPI { unsafe fn enable_clock() { const EN_BIT: u8 = $en; - // NOTE(unsafe) this reference will only be used for atomic writes with no side effects. + // NOTE(unsafe) self reference will only be used for atomic writes with no side effects. let rcc = &(*pac::RCC::ptr()); // Enable clock. bb::set(&rcc.$apbXenr, EN_BIT); diff --git a/embassy-traits/src/spi.rs b/embassy-traits/src/spi.rs index 9f08e740..771ebf2f 100644 --- a/embassy-traits/src/spi.rs +++ b/embassy-traits/src/spi.rs @@ -33,10 +33,10 @@ pub trait FullDuplex { where Self: 'a; - fn read<'a>(self: Pin<&'a mut Self>, data: &'a mut [Word]) -> Self::ReadFuture<'a>; - fn write<'a>(self: Pin<&'a mut Self>, data: &'a [Word]) -> Self::WriteFuture<'a>; + fn read<'a>(&'a mut self, data: &'a mut [Word]) -> Self::ReadFuture<'a>; + fn write<'a>(&'a mut self, data: &'a [Word]) -> Self::WriteFuture<'a>; fn read_write<'a>( - self: Pin<&'a mut Self>, + &'a mut self, read: &'a mut [Word], write: &'a [Word], ) -> Self::WriteReadFuture<'a>;