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 + '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;
+ }
+}