diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml
index fde5b4786..4f0d7356d 100644
--- a/embassy-stm32/Cargo.toml
+++ b/embassy-stm32/Cargo.toml
@@ -72,7 +72,7 @@ rand_core = "0.6.3"
sdio-host = "0.5.0"
critical-section = "1.1"
#stm32-metapac = { version = "15" }
-stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-34c0188a682b32c32ff147d377e0629b1ebe8318" }
+stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-ad633a3e266151ea4d8fad630031a075ee02ab34" }
vcell = "0.1.3"
nb = "1.0.0"
@@ -97,7 +97,7 @@ proc-macro2 = "1.0.36"
quote = "1.0.15"
#stm32-metapac = { version = "15", default-features = false, features = ["metadata"]}
-stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-34c0188a682b32c32ff147d377e0629b1ebe8318", default-features = false, features = ["metadata"]}
+stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-ad633a3e266151ea4d8fad630031a075ee02ab34", default-features = false, features = ["metadata"]}
[features]
default = ["rt"]
diff --git a/embassy-stm32/src/dma/util.rs b/embassy-stm32/src/dma/util.rs
index 962ea2501..5aaca57c9 100644
--- a/embassy-stm32/src/dma/util.rs
+++ b/embassy-stm32/src/dma/util.rs
@@ -48,6 +48,7 @@ impl<'d> ChannelAndRequest<'d> {
Transfer::new_write_raw(&mut self.channel, self.request, buf, peri_addr, options)
}
+ #[allow(dead_code)]
pub unsafe fn write_repeated<'a, W: Word>(
&'a mut self,
repeated: &'a W,
diff --git a/embassy-stm32/src/i2s.rs b/embassy-stm32/src/i2s.rs
index c78810a38..9c0bbbb87 100644
--- a/embassy-stm32/src/i2s.rs
+++ b/embassy-stm32/src/i2s.rs
@@ -169,7 +169,7 @@ impl<'d> I2S<'d> {
ws: impl Peripheral
> + 'd,
ck: impl Peripheral
> + 'd,
mck: impl Peripheral
> + 'd,
- txdma: impl Peripheral
> + 'd,
+ #[cfg(not(spi_v3))] txdma: impl Peripheral
> + 'd,
rxdma: impl Peripheral
> + 'd,
freq: Hertz,
config: Config,
@@ -190,7 +190,15 @@ impl<'d> I2S<'d> {
let mut spi_cfg = SpiConfig::default();
spi_cfg.frequency = freq;
- let spi = Spi::new_internal(peri, txdma, rxdma, spi_cfg);
+ let spi = Spi::new_internal(
+ peri,
+ #[cfg(not(spi_v3))]
+ new_dma!(txdma),
+ #[cfg(spi_v3)]
+ None,
+ new_dma!(rxdma),
+ spi_cfg,
+ );
// TODO move i2s to the new mux infra.
//#[cfg(all(rcc_f4, not(stm32f410)))]
diff --git a/embassy-stm32/src/spi/mod.rs b/embassy-stm32/src/spi/mod.rs
index 5fc8691ac..7fb8da5ac 100644
--- a/embassy-stm32/src/spi/mod.rs
+++ b/embassy-stm32/src/spi/mod.rs
@@ -508,6 +508,7 @@ impl<'d> Spi<'d, Async> {
peri: impl Peripheral
+ 'd,
sck: impl Peripheral
> + 'd,
miso: impl Peripheral
> + 'd,
+ #[cfg(any(spi_v1, spi_f1, spi_v2))] tx_dma: impl Peripheral
> + 'd,
rx_dma: impl Peripheral
> + 'd,
config: Config,
) -> Self {
@@ -516,6 +517,9 @@ impl<'d> Spi<'d, Async> {
new_pin!(sck, AFType::OutputPushPull, Speed::VeryHigh, config.sck_pull_mode()),
None,
new_pin!(miso, AFType::Input, Speed::VeryHigh),
+ #[cfg(any(spi_v1, spi_f1, spi_v2))]
+ new_dma!(tx_dma),
+ #[cfg(any(spi_v3, spi_v4, spi_v5))]
None,
new_dma!(rx_dma),
config,
@@ -584,11 +588,11 @@ impl<'d> Spi<'d, Async> {
#[allow(dead_code)]
pub(crate) fn new_internal(
peri: impl Peripheral + 'd,
- tx_dma: impl Peripheral
> + 'd,
- rx_dma: impl Peripheral
> + 'd,
+ tx_dma: Option>,
+ rx_dma: Option>,
config: Config,
) -> Self {
- Self::new_inner(peri, None, None, None, new_dma!(tx_dma), new_dma!(rx_dma), config)
+ Self::new_inner(peri, None, None, None, tx_dma, rx_dma, config)
}
/// SPI write, using DMA.
@@ -622,12 +626,100 @@ impl<'d> Spi<'d, Async> {
}
/// SPI read, using DMA.
+ #[cfg(any(spi_v3, spi_v4, spi_v5))]
+ pub async fn read(&mut self, data: &mut [W]) -> Result<(), Error> {
+ if data.is_empty() {
+ return Ok(());
+ }
+
+ let regs = self.info.regs;
+
+ regs.cr1().modify(|w| {
+ w.set_spe(false);
+ });
+
+ let comm = regs.cfg2().modify(|w| {
+ let prev = w.comm();
+ w.set_comm(vals::Comm::RECEIVER);
+ prev
+ });
+
+ #[cfg(spi_v3)]
+ let i2scfg = regs.i2scfgr().modify(|w| {
+ w.i2smod().then(|| {
+ let prev = w.i2scfg();
+ w.set_i2scfg(match prev {
+ vals::I2scfg::SLAVERX | vals::I2scfg::SLAVEFULLDUPLEX => vals::I2scfg::SLAVERX,
+ vals::I2scfg::MASTERRX | vals::I2scfg::MASTERFULLDUPLEX => vals::I2scfg::MASTERRX,
+ _ => panic!("unsupported configuration"),
+ });
+ prev
+ })
+ });
+
+ let rx_src = regs.rx_ptr();
+
+ for mut chunk in data.chunks_mut(u16::max_value().into()) {
+ self.set_word_size(W::CONFIG);
+ set_rxdmaen(regs, true);
+
+ let tsize = chunk.len();
+
+ let transfer = unsafe {
+ self.rx_dma
+ .as_mut()
+ .unwrap()
+ .read(rx_src, &mut chunk, Default::default())
+ };
+
+ regs.cr2().modify(|w| {
+ w.set_tsize(tsize as u16);
+ });
+
+ regs.cr1().modify(|w| {
+ w.set_spe(true);
+ });
+
+ regs.cr1().modify(|w| {
+ w.set_cstart(true);
+ });
+
+ transfer.await;
+
+ finish_dma(regs);
+ }
+
+ regs.cr1().modify(|w| {
+ w.set_spe(false);
+ });
+
+ regs.cfg2().modify(|w| {
+ w.set_comm(comm);
+ });
+
+ regs.cr2().modify(|w| {
+ w.set_tsize(0);
+ });
+
+ #[cfg(spi_v3)]
+ if let Some(i2scfg) = i2scfg {
+ regs.i2scfgr().modify(|w| {
+ w.set_i2scfg(i2scfg);
+ });
+ }
+
+ Ok(())
+ }
+
+ /// SPI read, using DMA.
+ #[cfg(any(spi_v1, spi_f1, spi_v2))]
pub async fn read(&mut self, data: &mut [W]) -> Result<(), Error> {
if data.is_empty() {
return Ok(());
}
self.set_word_size(W::CONFIG);
+
self.info.regs.cr1().modify(|w| {
w.set_spe(false);
});
@@ -907,7 +999,13 @@ fn finish_dma(regs: Regs) {
while regs.sr().read().ftlvl().to_bits() > 0 {}
#[cfg(any(spi_v3, spi_v4, spi_v5))]
- while !regs.sr().read().txc() {}
+ {
+ if regs.cr2().read().tsize() == 0 {
+ while !regs.sr().read().txc() {}
+ } else {
+ while !regs.sr().read().eot() {}
+ }
+ }
#[cfg(not(any(spi_v3, spi_v4, spi_v5)))]
while regs.sr().read().bsy() {}
diff --git a/tests/stm32/src/bin/spi_dma.rs b/tests/stm32/src/bin/spi_dma.rs
index 5d46726dd..30e679f2a 100644
--- a/tests/stm32/src/bin/spi_dma.rs
+++ b/tests/stm32/src/bin/spi_dma.rs
@@ -8,27 +8,33 @@ use defmt::assert_eq;
use embassy_executor::Spawner;
use embassy_stm32::spi::{self, Spi};
use embassy_stm32::time::Hertz;
+use embassy_stm32::{into_ref, Peripheral as _};
#[embassy_executor::main]
async fn main(_spawner: Spawner) {
let p = embassy_stm32::init(config());
info!("Hello World!");
- let spi = peri!(p, SPI);
+ let spi_peri = peri!(p, SPI);
let sck = peri!(p, SPI_SCK);
let mosi = peri!(p, SPI_MOSI);
let miso = peri!(p, SPI_MISO);
let tx_dma = peri!(p, SPI_TX_DMA);
let rx_dma = peri!(p, SPI_RX_DMA);
+ into_ref!(spi_peri, sck, mosi, miso, tx_dma, rx_dma);
+
let mut spi_config = spi::Config::default();
spi_config.frequency = Hertz(1_000_000);
let mut spi = Spi::new(
- spi, sck, // Arduino D13
- mosi, // Arduino D11
- miso, // Arduino D12
- tx_dma, rx_dma, spi_config,
+ spi_peri.reborrow(),
+ sck.reborrow(), // Arduino D13
+ mosi.reborrow(), // Arduino D11
+ miso.reborrow(), // Arduino D12
+ tx_dma.reborrow(),
+ rx_dma.reborrow(),
+ spi_config,
);
let data: [u8; 9] = [0x00, 0xFF, 0xAA, 0x55, 0xC0, 0xFF, 0xEE, 0xC0, 0xDE];
@@ -76,6 +82,55 @@ async fn main(_spawner: Spawner) {
spi.blocking_read(&mut buf).unwrap();
spi.write(&buf).await.unwrap();
+ core::mem::drop(spi);
+
+ // test rx-only configuration
+
+ // stm32f207zg - spi_v1
+ // stm32f103c8 - spi_f1
+ // stm32g491re - spi_v2
+ // stm32h753zi - spi_v3
+ // stm32h563zi - spi_v4
+ // stm32wba52cg - spi_v5
+
+ #[cfg(any(stm32f207zg, stm32f103c8, stm32g491re, stm32h753zi, stm32h563zi, stm32wba52cg))]
+ {
+ let mut spi = {
+ #[cfg(stm32f207zg, stm32f103c8, stm32g491re)]
+ {
+ Spi::new_rxonly(
+ spi_peri.reborrow(),
+ sck.reborrow(),
+ miso.reborrow(),
+ tx_dma.reborrow(),
+ rx_dma.reborrow(),
+ spi_config,
+ )
+ }
+ #[cfg(stm32h753zi, stm32h563zi, stm32wba52cg)]
+ {
+ Spi::new_rxonly(
+ spi_peri.reborrow(),
+ sck.reborrow(),
+ miso.reborrow(),
+ rx_dma.reborrow(),
+ spi_config,
+ )
+ }
+ };
+
+ use embassy_stm32::gpio;
+ let mut mosi = gpio::Output::new(mosi.reborrow(), gpio::Level::Low, gpio::Speed::Low);
+
+ mosi.set_high();
+ spi.read(&mut buf).await.unwrap();
+ assert_eq!(buf, [0xff; 9]);
+
+ mosi.set_low();
+ spi.read(&mut buf).await.unwrap();
+ assert_eq!(buf, [0x00; 9]);
+ };
+
info!("Test OK");
cortex_m::asm::bkpt();
}