nrf/spim: do not use PeripheralMutex

This commit is contained in:
Dario Nieuwenhuis 2021-03-20 03:38:21 +01:00
parent ba6e0a4058
commit f36cbe5e0c
2 changed files with 49 additions and 73 deletions

View File

@ -6,7 +6,7 @@
#[path = "../example_common.rs"] #[path = "../example_common.rs"]
mod example_common; mod example_common;
use embassy_nrf::gpio::{Level, Output}; use embassy_nrf::gpio::{Level, Output, OutputDrive};
use embassy_nrf::peripherals::Peripherals; use embassy_nrf::peripherals::Peripherals;
use embassy_traits::spi::FullDuplex; use embassy_traits::spi::FullDuplex;
use example_common::*; 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); let spim = spim::Spim::new(p.spim3, irq, p.p0_29, p.p0_28, p.p0_30, config);
pin_mut!(spim); 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 // Example on how to talk to an ENC28J60 chip

View File

@ -4,8 +4,7 @@ use core::pin::Pin;
use core::sync::atomic::{compiler_fence, Ordering}; use core::sync::atomic::{compiler_fence, Ordering};
use core::task::Poll; use core::task::Poll;
use embassy::traits; use embassy::traits;
use embassy::util::{PeripheralBorrow, WakerRegistration}; use embassy::util::{wake_on_interrupt, PeripheralBorrow};
use embassy_extras::peripheral::{PeripheralMutex, PeripheralState};
use futures::future::poll_fn; use futures::future::poll_fn;
use traits::spi::FullDuplex; use traits::spi::FullDuplex;
@ -26,13 +25,9 @@ pub enum Error {
DMABufferNotInDataMemory, DMABufferNotInDataMemory,
} }
struct State<T: Instance> {
spim: T,
waker: WakerRegistration,
}
pub struct Spim<'d, T: Instance> { pub struct Spim<'d, T: Instance> {
inner: PeripheralMutex<State<T>>, spim: T,
irq: T::Interrupt,
phantom: PhantomData<&'d mut T>, 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) }); r.intenclr.write(|w| unsafe { w.bits(0xFFFF_FFFF) });
Self { Self {
inner: PeripheralMutex::new( spim,
State { irq,
spim,
waker: WakerRegistration::new(),
},
irq,
),
phantom: PhantomData, phantom: PhantomData,
} }
} }
fn inner(self: Pin<&mut Self>) -> Pin<&mut PeripheralMutex<State<T>>> {
unsafe { Pin::new_unchecked(&mut self.get_unchecked_mut().inner) }
}
} }
impl<'d, T: Instance> FullDuplex<u8> for Spim<'d, T> { impl<'d, T: Instance> FullDuplex<u8> for Spim<'d, T> {
@ -157,69 +143,69 @@ impl<'d, T: Instance> FullDuplex<u8> for Spim<'d, T> {
type WriteReadFuture<'a> where Self: 'a = impl Future<Output = Result<(), Self::Error>> + 'a; type WriteReadFuture<'a> where Self: 'a = impl Future<Output = Result<(), Self::Error>> + 'a;
fn read<'a>(self: Pin<&'a mut Self>, data: &'a mut [u8]) -> Self::ReadFuture<'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> { 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>( fn read_write<'a>(
mut self: Pin<&'a mut Self>, self: Pin<&'a mut Self>,
rx: &'a mut [u8], rx: &'a mut [u8],
tx: &'a [u8], tx: &'a [u8],
) -> Self::WriteReadFuture<'a> { ) -> Self::WriteReadFuture<'a> {
async move { async move {
let this = unsafe { self.get_unchecked_mut() };
slice_in_ram_or(rx, Error::DMABufferNotInDataMemory)?; slice_in_ram_or(rx, Error::DMABufferNotInDataMemory)?;
slice_in_ram_or(tx, Error::DMABufferNotInDataMemory)?; slice_in_ram_or(tx, Error::DMABufferNotInDataMemory)?;
self.as_mut().inner().register_interrupt(); // Conservative compiler fence to prevent optimizations that do not
self.as_mut().inner().with(|s, _irq| { // take in to account actions by DMA. The fence has been placed here,
// Conservative compiler fence to prevent optimizations that do not // before any DMA action has started.
// take in to account actions by DMA. The fence has been placed here, compiler_fence(Ordering::SeqCst);
// 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. // Set up the DMA write.
r.txd r.txd
.ptr .ptr
.write(|w| unsafe { w.ptr().bits(tx.as_ptr() as u32) }); .write(|w| unsafe { w.ptr().bits(tx.as_ptr() as u32) });
r.txd r.txd
.maxcnt .maxcnt
.write(|w| unsafe { w.maxcnt().bits(tx.len() as _) }); .write(|w| unsafe { w.maxcnt().bits(tx.len() as _) });
// Set up the DMA read. // Set up the DMA read.
r.rxd r.rxd
.ptr .ptr
.write(|w| unsafe { w.ptr().bits(rx.as_mut_ptr() as u32) }); .write(|w| unsafe { w.ptr().bits(rx.as_mut_ptr() as u32) });
r.rxd r.rxd
.maxcnt .maxcnt
.write(|w| unsafe { w.maxcnt().bits(rx.len() as _) }); .write(|w| unsafe { w.maxcnt().bits(rx.len() as _) });
// Reset and enable the event // Reset and enable the event
r.events_end.reset(); r.events_end.reset();
r.intenset.write(|w| w.end().set()); r.intenset.write(|w| w.end().set());
// Start SPI transaction. // Start SPI transaction.
r.tasks_start.write(|w| unsafe { w.bits(1) }); r.tasks_start.write(|w| unsafe { w.bits(1) });
// Conservative compiler fence to prevent optimizations that do not // Conservative compiler fence to prevent optimizations that do not
// take in to account actions by DMA. The fence has been placed here, // take in to account actions by DMA. The fence has been placed here,
// after all possible DMA actions have completed. // after all possible DMA actions have completed.
compiler_fence(Ordering::SeqCst); compiler_fence(Ordering::SeqCst);
});
// Wait for 'end' event. // Wait for 'end' event.
poll_fn(|cx| { poll_fn(|cx| {
self.as_mut().inner().with(|s, _irq| { let r = this.spim.regs();
let r = s.spim.regs();
if r.events_end.read().bits() != 0 { if r.events_end.read().bits() != 0 {
return Poll::Ready(()); r.events_end.reset();
} return Poll::Ready(());
s.waker.register(cx.waker()); }
Poll::Pending
}) wake_on_interrupt(&mut this.irq, cx.waker());
Poll::Pending
}) })
.await; .await;
@ -228,16 +214,6 @@ impl<'d, T: Instance> FullDuplex<u8> for Spim<'d, T> {
} }
} }
impl<U: Instance> PeripheralState for State<U> {
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 { mod sealed {
use super::*; use super::*;