From 28c0023c9abbd4b3c353aa23becae52331a7ff2f Mon Sep 17 00:00:00 2001 From: Folkert Date: Sat, 5 Jun 2021 11:48:00 +0200 Subject: [PATCH] add distinct read and write functions --- embassy-nrf/src/twim.rs | 133 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 131 insertions(+), 2 deletions(-) diff --git a/embassy-nrf/src/twim.rs b/embassy-nrf/src/twim.rs index ecad58f3a..5eb1932e5 100644 --- a/embassy-nrf/src/twim.rs +++ b/embassy-nrf/src/twim.rs @@ -456,11 +456,138 @@ where 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.write_read(address, &[], buffer) + 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(); + let s = T::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(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(|cx| { + 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 + }) + .await; + + self.read_errorsrc()?; + + if r.rxd.amount.read().bits() != buffer.len() as u32 { + return Err(Error::Receive); + } + + Ok(()) + } } fn write<'a>(&'a mut self, address: u8, bytes: &'a [u8]) -> Self::WriteFuture<'a> { - self.write_read(address, bytes, &mut []) + 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(); + let s = T::state(); + + // 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)?; + } + + // 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(|cx| { + 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 + }) + .await; + + self.read_errorsrc()?; + + if r.txd.amount.read().bits() != bytes.len() as u32 { + return Err(Error::Transmit); + } + + Ok(()) + } } fn write_read<'a>( @@ -533,6 +660,8 @@ where }) .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;