diff --git a/embassy-rp/src/spi.rs b/embassy-rp/src/spi.rs index c8589dd7..a91a1fd1 100644 --- a/embassy-rp/src/spi.rs +++ b/embassy-rp/src/spi.rs @@ -3,6 +3,7 @@ use core::marker::PhantomData; use embassy_embedded_hal::SetConfig; use embassy_hal_common::{into_ref, PeripheralRef}; pub use embedded_hal_02::spi::{Phase, Polarity}; +use futures::future::join; use crate::dma::{AnyChannel, Channel}; use crate::gpio::sealed::Pin as _; @@ -64,10 +65,8 @@ fn calc_prescs(freq: u32) -> (u8, u8) { } impl<'d, T: Instance, M: Mode> Spi<'d, T, M> { - pub fn new( + pub fn new_blocking( inner: impl Peripheral

+ 'd, - tx_dma: Option>, - rx_dma: Option>, clk: impl Peripheral

+ 'd> + 'd, mosi: impl Peripheral

+ 'd> + 'd, miso: impl Peripheral

+ 'd> + 'd, @@ -76,8 +75,8 @@ impl<'d, T: Instance, M: Mode> Spi<'d, T, M> { into_ref!(clk, mosi, miso); Self::new_inner( inner, - tx_dma, - rx_dma, + None, + None, Some(clk.map_into()), Some(mosi.map_into()), Some(miso.map_into()), @@ -262,6 +261,81 @@ impl<'d, T: Instance, M: Mode> Spi<'d, T, M> { } } +impl<'d, T: Instance> Spi<'d, T, Async> { + pub fn new( + inner: impl Peripheral

+ 'd, + tx_dma: impl Peripheral

+ 'd, + rx_dma: impl Peripheral

+ 'd, + clk: impl Peripheral

+ 'd> + 'd, + mosi: impl Peripheral

+ 'd> + 'd, + miso: impl Peripheral

+ 'd> + 'd, + config: Config, + ) -> Self { + into_ref!(tx_dma, rx_dma, clk, mosi, miso); + Self::new_inner( + inner, + Some(tx_dma.map_into()), + Some(rx_dma.map_into()), + Some(clk.map_into()), + Some(mosi.map_into()), + Some(miso.map_into()), + None, + config, + ) + } + + pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error> { + let ch = self.tx_dma.as_mut().unwrap(); + let transfer = unsafe { + self.inner.regs().dmacr().modify(|reg| { + reg.set_txdmae(true); + }); + // If we don't assign future to a variable, the data register pointer + // is held across an await and makes the future non-Send. + crate::dma::write(ch, buffer, self.inner.regs().dr().ptr() as *mut _, T::TX_DREQ) + }; + transfer.await; + Ok(()) + } + + pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> { + let ch = self.rx_dma.as_mut().unwrap(); + let transfer = unsafe { + self.inner.regs().dmacr().modify(|reg| { + reg.set_rxdmae(true); + }); + // If we don't assign future to a variable, the data register pointer + // is held across an await and makes the future non-Send. + crate::dma::read(ch, self.inner.regs().dr().ptr() as *const _, buffer, T::RX_DREQ) + }; + transfer.await; + Ok(()) + } + + pub async fn transfer(&mut self, rx_buffer: &mut [u8], tx_buffer: &[u8]) -> Result<(), Error> { + let tx_ch = self.tx_dma.as_mut().unwrap(); + let tx_transfer = unsafe { + self.inner.regs().dmacr().modify(|reg| { + reg.set_txdmae(true); + }); + // If we don't assign future to a variable, the data register pointer + // is held across an await and makes the future non-Send. + crate::dma::write(tx_ch, tx_buffer, self.inner.regs().dr().ptr() as *mut _, T::TX_DREQ) + }; + let rx_ch = self.rx_dma.as_mut().unwrap(); + let rx_transfer = unsafe { + self.inner.regs().dmacr().modify(|reg| { + reg.set_rxdmae(true); + }); + // If we don't assign future to a variable, the data register pointer + // is held across an await and makes the future non-Send. + crate::dma::read(rx_ch, self.inner.regs().dr().ptr() as *const _, rx_buffer, T::RX_DREQ) + }; + join(tx_transfer, rx_transfer).await; + Ok(()) + } +} + mod sealed { use super::*; diff --git a/examples/rp/src/bin/spi.rs b/examples/rp/src/bin/spi.rs index 88003ee1..e50297ae 100644 --- a/examples/rp/src/bin/spi.rs +++ b/examples/rp/src/bin/spi.rs @@ -4,7 +4,7 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_rp::spi::Spi; +use embassy_rp::spi::{Blocking, Spi}; use embassy_rp::{gpio, spi}; use gpio::{Level, Output}; use {defmt_rtt as _, panic_probe as _}; @@ -24,7 +24,7 @@ async fn main(_spawner: Spawner) { // create SPI let mut config = spi::Config::default(); config.frequency = 2_000_000; - let mut spi = Spi::new(p.SPI1, clk, mosi, miso, config); + let mut spi: Spi<'_, _, Blocking> = Spi::new_blocking(p.SPI1, clk, mosi, miso, config); // Configure CS let mut cs = Output::new(touch_cs, Level::Low); diff --git a/examples/rp/src/bin/spi_async.rs b/examples/rp/src/bin/spi_async.rs new file mode 100644 index 00000000..f21377ed --- /dev/null +++ b/examples/rp/src/bin/spi_async.rs @@ -0,0 +1,31 @@ +#![no_std] +#![no_main] +#![feature(type_alias_impl_trait)] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_rp::spi::{Async, Spi}; +use embassy_rp::{gpio, spi}; +use embassy_time::{Duration, Timer}; +use gpio::{Level, Output}; +use {defmt_rtt as _, panic_probe as _}; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = embassy_rp::init(Default::default()); + info!("Hello World!"); + + let miso = p.PIN_12; + let mosi = p.PIN_11; + let clk = p.PIN_10; + + let mut spi: Spi<'_, _, Async> = Spi::new(p.SPI1, p.DMA_CH0, p.DMA_CH1, clk, mosi, miso, spi::Config::default()); + + loop { + let tx_buf = [1_u8, 2, 3, 4, 5, 6]; + let mut rx_buf = [0_u8; 6]; + spi.transfer(&mut rx_buf, &tx_buf).await.unwrap(); + info!("{:?}", rx_buf); + Timer::after(Duration::from_secs(1)).await; + } +}