Remove Pin from SPI

This commit is contained in:
Dario Nieuwenhuis 2021-04-14 16:37:10 +02:00
parent 8b1ffb2cb7
commit c15411d1bd
4 changed files with 76 additions and 59 deletions

View File

@ -17,7 +17,6 @@ use embassy_nrf::{interrupt, spim};
use embassy_traits::spi::FullDuplex; use embassy_traits::spi::FullDuplex;
use embedded_hal::digital::v2::*; use embedded_hal::digital::v2::*;
use example_common::*; use example_common::*;
use futures::pin_mut;
#[embassy::main] #[embassy::main]
async fn main(spawner: Spawner) { async fn main(spawner: Spawner) {
@ -32,8 +31,7 @@ async fn main(spawner: Spawner) {
}; };
let irq = interrupt::take!(SPIM3); let irq = interrupt::take!(SPIM3);
let spim = spim::Spim::new(p.SPIM3, irq, p.P0_29, p.P0_28, p.P0_30, config); let mut 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, OutputDrive::Standard); 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(); ncs.set_low().unwrap();
cortex_m::asm::delay(5); cortex_m::asm::delay(5);
let tx = [0xFF]; let tx = [0xFF];
unwrap!(spim.as_mut().read_write(&mut [], &tx).await); unwrap!(spim.read_write(&mut [], &tx).await);
cortex_m::asm::delay(10); cortex_m::asm::delay(10);
ncs.set_high().unwrap(); ncs.set_high().unwrap();
@ -57,7 +55,7 @@ async fn main(spawner: Spawner) {
ncs.set_low().unwrap(); ncs.set_low().unwrap();
cortex_m::asm::delay(5000); cortex_m::asm::delay(5000);
let tx = [0b000_11101, 0]; 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); cortex_m::asm::delay(5000);
ncs.set_high().unwrap(); ncs.set_high().unwrap();
info!("estat: {=[?]}", rx); info!("estat: {=[?]}", rx);
@ -67,7 +65,7 @@ async fn main(spawner: Spawner) {
ncs.set_low().unwrap(); ncs.set_low().unwrap();
cortex_m::asm::delay(5); cortex_m::asm::delay(5);
let tx = [0b100_11111, 0b11]; 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); cortex_m::asm::delay(10);
ncs.set_high().unwrap(); ncs.set_high().unwrap();
@ -76,7 +74,7 @@ async fn main(spawner: Spawner) {
ncs.set_low().unwrap(); ncs.set_low().unwrap();
cortex_m::asm::delay(5); cortex_m::asm::delay(5);
let tx = [0b000_10010, 0]; 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); cortex_m::asm::delay(10);
ncs.set_high().unwrap(); ncs.set_high().unwrap();

View File

@ -1,10 +1,10 @@
use core::future::Future; use core::future::Future;
use core::marker::PhantomData; use core::marker::PhantomData;
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::interrupt::InterruptExt;
use embassy::traits; use embassy::traits;
use embassy::util::{wake_on_interrupt, PeripheralBorrow}; use embassy::util::{AtomicWaker, PeripheralBorrow};
use embassy_extras::unborrow; use embassy_extras::unborrow;
use futures::future::poll_fn; use futures::future::poll_fn;
use traits::spi::FullDuplex; use traits::spi::FullDuplex;
@ -50,7 +50,7 @@ impl<'d, T: Instance> Spim<'d, T> {
) -> Self { ) -> Self {
unborrow!(spim, irq, sck, miso, mosi); unborrow!(spim, irq, sck, miso, mosi);
let r = spim.regs(); let r = T::regs();
// Configure pins // Configure pins
sck.conf().write(|w| w.dir().output().drive().h0h1()); sck.conf().write(|w| w.dir().output().drive().h0h1());
@ -122,12 +122,26 @@ impl<'d, T: Instance> Spim<'d, T> {
// Disable all events interrupts // Disable all events interrupts
r.intenclr.write(|w| unsafe { w.bits(0xFFFF_FFFF) }); r.intenclr.write(|w| unsafe { w.bits(0xFFFF_FFFF) });
irq.set_handler(Self::on_interrupt);
irq.unpend();
irq.enable();
Self { Self {
peri: spim, peri: spim,
irq, irq,
phantom: PhantomData, 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<u8> for Spim<'d, T> { impl<'d, T: Instance> FullDuplex<u8> for Spim<'d, T> {
@ -140,20 +154,15 @@ impl<'d, T: Instance> FullDuplex<u8> for Spim<'d, T> {
#[rustfmt::skip] #[rustfmt::skip]
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>(&'a mut self, data: &'a mut [u8]) -> Self::ReadFuture<'a> {
self.read_write(data, &[]) 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) self.read_write(&mut [], data)
} }
fn read_write<'a>( fn read_write<'a>(&'a mut self, rx: &'a mut [u8], tx: &'a [u8]) -> Self::WriteReadFuture<'a> {
self: Pin<&'a mut Self>,
rx: &'a mut [u8],
tx: &'a [u8],
) -> 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)?;
@ -162,7 +171,8 @@ impl<'d, T: Instance> FullDuplex<u8> for Spim<'d, T> {
// before any DMA action has started. // before any DMA action has started.
compiler_fence(Ordering::SeqCst); compiler_fence(Ordering::SeqCst);
let r = this.peri.regs(); let r = T::regs();
let s = T::state();
// Set up the DMA write. // Set up the DMA write.
r.txd r.txd
@ -194,15 +204,11 @@ impl<'d, T: Instance> FullDuplex<u8> for Spim<'d, T> {
// Wait for 'end' event. // Wait for 'end' event.
poll_fn(|cx| { poll_fn(|cx| {
let r = this.peri.regs(); s.end_waker.register(cx.waker());
if r.events_end.read().bits() != 0 { if r.events_end.read().bits() != 0 {
r.events_end.reset();
return Poll::Ready(()); return Poll::Ready(());
} }
wake_on_interrupt(&mut this.irq, cx.waker());
Poll::Pending Poll::Pending
}) })
.await; .await;
@ -215,8 +221,21 @@ impl<'d, T: Instance> FullDuplex<u8> for Spim<'d, T> {
mod sealed { mod sealed {
use super::*; use super::*;
pub struct State {
pub end_waker: AtomicWaker,
}
impl State {
pub const fn new() -> Self {
Self {
end_waker: AtomicWaker::new(),
}
}
}
pub trait Instance { 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 { macro_rules! impl_instance {
($type:ident, $irq:ident) => { ($type:ident, $irq:ident) => {
impl sealed::Instance for peripherals::$type { impl sealed::Instance for peripherals::$type {
fn regs(&self) -> &pac::spim0::RegisterBlock { fn regs() -> &'static pac::spim0::RegisterBlock {
unsafe { &*pac::$type::ptr() } unsafe { &*pac::$type::ptr() }
} }
fn state() -> &'static sealed::State {
static STATE: sealed::State = sealed::State::new();
&STATE
}
} }
impl Instance for peripherals::$type { impl Instance for peripherals::$type {
type Interrupt = interrupt::$irq; type Interrupt = interrupt::$irq;

View File

@ -214,14 +214,13 @@ where
type ReadFuture<'a> = impl Future<Output = Result<(), Error>> + 'a; type ReadFuture<'a> = impl Future<Output = Result<(), Error>> + 'a;
type WriteReadFuture<'a> = impl Future<Output = Result<(), Error>> + 'a; type WriteReadFuture<'a> = impl Future<Output = Result<(), Error>> + 'a;
fn read<'a>(self: Pin<&'a mut Self>, buf: &'a mut [u8]) -> Self::ReadFuture<'a> { fn read<'a>(&'a mut self, buf: &'a mut [u8]) -> Self::ReadFuture<'a> {
let this = unsafe { self.get_unchecked_mut() };
#[allow(mutable_transmutes)] #[allow(mutable_transmutes)]
let static_buf: &'static mut [u8] = unsafe { mem::transmute(buf) }; let static_buf: &'static mut [u8] = unsafe { mem::transmute(buf) };
async move { async move {
let rx_stream = this.rx_stream.take().unwrap(); let rx_stream = self.rx_stream.take().unwrap();
let spi = this.spi.take().unwrap(); let spi = self.spi.take().unwrap();
spi.cr2.modify(|_, w| w.errie().set_bit()); spi.cr2.modify(|_, w| w.errie().set_bit());
@ -236,8 +235,8 @@ where
.double_buffer(false), .double_buffer(false),
); );
let fut = InterruptFuture::new(&mut this.rx_int); let fut = InterruptFuture::new(&mut self.rx_int);
let fut_err = InterruptFuture::new(&mut this.spi_int); let fut_err = InterruptFuture::new(&mut self.spi_int);
rx_transfer.start(|_spi| {}); rx_transfer.start(|_spi| {});
future::select(fut, fut_err).await; future::select(fut, fut_err).await;
@ -245,21 +244,20 @@ where
let (rx_stream, spi, _buf, _) = rx_transfer.free(); let (rx_stream, spi, _buf, _) = rx_transfer.free();
spi.cr2.modify(|_, w| w.errie().clear_bit()); spi.cr2.modify(|_, w| w.errie().clear_bit());
this.rx_stream.replace(rx_stream); self.rx_stream.replace(rx_stream);
this.spi.replace(spi); self.spi.replace(spi);
Ok(()) Ok(())
} }
} }
fn write<'a>(self: Pin<&'a mut Self>, buf: &'a [u8]) -> Self::WriteFuture<'a> { fn write<'a>(&'a mut self, buf: &'a [u8]) -> Self::WriteFuture<'a> {
let this = unsafe { self.get_unchecked_mut() };
#[allow(mutable_transmutes)] #[allow(mutable_transmutes)]
let static_buf: &'static mut [u8] = unsafe { mem::transmute(buf) }; let static_buf: &'static mut [u8] = unsafe { mem::transmute(buf) };
async move { async move {
let tx_stream = this.tx_stream.take().unwrap(); let tx_stream = self.tx_stream.take().unwrap();
let spi = this.spi.take().unwrap(); let spi = self.spi.take().unwrap();
// let mut tx_transfer = Transfer::init( // let mut tx_transfer = Transfer::init(
// tx_stream, // tx_stream,
@ -272,7 +270,7 @@ where
// .double_buffer(false), // .double_buffer(false),
// ); // );
// //
// let fut = InterruptFuture::new(&mut this.tx_int); // let fut = InterruptFuture::new(&mut self.tx_int);
// //
// tx_transfer.start(|_spi| {}); // tx_transfer.start(|_spi| {});
// fut.await; // fut.await;
@ -284,28 +282,26 @@ where
nb::block!(write_sr(&spi, byte)); nb::block!(write_sr(&spi, byte));
} }
this.tx_stream.replace(tx_stream); self.tx_stream.replace(tx_stream);
this.spi.replace(spi); self.spi.replace(spi);
Ok(()) Ok(())
} }
} }
fn read_write<'a>( fn read_write<'a>(
self: Pin<&'a mut Self>, &'a mut self,
read_buf: &'a mut [u8], read_buf: &'a mut [u8],
write_buf: &'a [u8], write_buf: &'a [u8],
) -> Self::WriteReadFuture<'a> { ) -> Self::WriteReadFuture<'a> {
let this = unsafe { self.get_unchecked_mut() };
#[allow(mutable_transmutes)] #[allow(mutable_transmutes)]
let write_static_buf: &'static mut [u8] = unsafe { mem::transmute(write_buf) }; let write_static_buf: &'static mut [u8] = unsafe { mem::transmute(write_buf) };
let read_static_buf: &'static mut [u8] = unsafe { mem::transmute(read_buf) }; let read_static_buf: &'static mut [u8] = unsafe { mem::transmute(read_buf) };
async move { async move {
let tx_stream = this.tx_stream.take().unwrap(); let tx_stream = self.tx_stream.take().unwrap();
let rx_stream = this.rx_stream.take().unwrap(); let rx_stream = self.rx_stream.take().unwrap();
let spi_tx = this.spi.take().unwrap(); let spi_tx = self.spi.take().unwrap();
let spi_rx: SPI = unsafe { mem::transmute_copy(&spi_tx) }; let spi_rx: SPI = unsafe { mem::transmute_copy(&spi_tx) };
spi_rx spi_rx
@ -334,9 +330,9 @@ where
// .double_buffer(false), // .double_buffer(false),
// ); // );
// //
// let tx_fut = InterruptFuture::new(&mut this.tx_int); // let tx_fut = InterruptFuture::new(&mut self.tx_int);
// let rx_fut = InterruptFuture::new(&mut this.rx_int); // let rx_fut = InterruptFuture::new(&mut self.rx_int);
// let rx_fut_err = InterruptFuture::new(&mut this.spi_int); // let rx_fut_err = InterruptFuture::new(&mut self.spi_int);
// //
// rx_transfer.start(|_spi| {}); // rx_transfer.start(|_spi| {});
// tx_transfer.start(|_spi| {}); // tx_transfer.start(|_spi| {});
@ -352,7 +348,7 @@ where
for i in 0..(read_static_buf.len() - 1) { for i in 0..(read_static_buf.len() - 1) {
let byte = write_static_buf[i]; let byte = write_static_buf[i];
loop { loop {
let fut = InterruptFuture::new(&mut this.spi_int); let fut = InterruptFuture::new(&mut self.spi_int);
match write_sr(&spi_tx, byte) { match write_sr(&spi_tx, byte) {
Ok(()) => break, Ok(()) => break,
_ => {} _ => {}
@ -361,7 +357,7 @@ where
} }
loop { loop {
let fut = InterruptFuture::new(&mut this.spi_int); let fut = InterruptFuture::new(&mut self.spi_int);
match read_sr(&spi_tx) { match read_sr(&spi_tx) {
Ok(byte) => { Ok(byte) => {
read_static_buf[i] = byte; read_static_buf[i] = byte;
@ -381,9 +377,9 @@ where
.rxneie() .rxneie()
.clear_bit() .clear_bit()
}); });
this.rx_stream.replace(rx_stream); self.rx_stream.replace(rx_stream);
this.tx_stream.replace(tx_stream); self.tx_stream.replace(tx_stream);
this.spi.replace(spi_rx); self.spi.replace(spi_rx);
Ok(()) Ok(())
} }
@ -421,7 +417,7 @@ macro_rules! spi {
impl Instance for pac::$SPI { impl Instance for pac::$SPI {
unsafe fn enable_clock() { unsafe fn enable_clock() {
const EN_BIT: u8 = $en; 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()); let rcc = &(*pac::RCC::ptr());
// Enable clock. // Enable clock.
bb::set(&rcc.$apbXenr, EN_BIT); bb::set(&rcc.$apbXenr, EN_BIT);

View File

@ -33,10 +33,10 @@ pub trait FullDuplex<Word> {
where where
Self: 'a; Self: 'a;
fn read<'a>(self: Pin<&'a mut Self>, data: &'a mut [Word]) -> Self::ReadFuture<'a>; fn read<'a>(&'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 write<'a>(&'a mut self, data: &'a [Word]) -> Self::WriteFuture<'a>;
fn read_write<'a>( fn read_write<'a>(
self: Pin<&'a mut Self>, &'a mut self,
read: &'a mut [Word], read: &'a mut [Word],
write: &'a [Word], write: &'a [Word],
) -> Self::WriteReadFuture<'a>; ) -> Self::WriteReadFuture<'a>;