From f9324201b1d9375e12b4af9a6b2424fe3ff85d32 Mon Sep 17 00:00:00 2001
From: Alexandros Liarokapis <liarokapis.v@gmail.com>
Date: Mon, 27 May 2024 15:44:58 +0300
Subject: [PATCH 1/7] add proper rxonly support for spi_v3 and force tx dma
 stream requirement on others

---
 embassy-stm32/Cargo.toml      |   4 +-
 embassy-stm32/src/dma/util.rs |   1 +
 embassy-stm32/src/i2s.rs      |  12 +++-
 embassy-stm32/src/spi/mod.rs  | 121 ++++++++++++++++++++++++++++++++--
 4 files changed, 130 insertions(+), 8 deletions(-)

diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml
index 5ef2366d9..67c61a671 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<P = impl WsPin<T>> + 'd,
         ck: impl Peripheral<P = impl CkPin<T>> + 'd,
         mck: impl Peripheral<P = impl MckPin<T>> + 'd,
-        txdma: impl Peripheral<P = impl TxDma<T>> + 'd,
+        #[cfg(not(spi_v3))] txdma: impl Peripheral<P = impl TxDma<T>> + 'd,
         rxdma: impl Peripheral<P = impl RxDma<T>> + '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..0a0afafc6 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<P = T> + 'd,
         sck: impl Peripheral<P = impl SckPin<T>> + 'd,
         miso: impl Peripheral<P = impl MisoPin<T>> + 'd,
+        #[cfg(not(spi_v3))] tx_dma: impl Peripheral<P = impl TxDma<T>> + 'd,
         rx_dma: impl Peripheral<P = impl RxDma<T>> + '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(not(spi_v3))]
+            new_dma!(tx_dma),
+            #[cfg(spi_v3)]
             None,
             new_dma!(rx_dma),
             config,
@@ -584,11 +588,11 @@ impl<'d> Spi<'d, Async> {
     #[allow(dead_code)]
     pub(crate) fn new_internal<T: Instance>(
         peri: impl Peripheral<P = T> + 'd,
-        tx_dma: impl Peripheral<P = impl TxDma<T>> + 'd,
-        rx_dma: impl Peripheral<P = impl RxDma<T>> + 'd,
+        tx_dma: Option<ChannelAndRequest<'d>>,
+        rx_dma: Option<ChannelAndRequest<'d>>,
         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.
@@ -623,11 +627,114 @@ impl<'d> Spi<'d, Async> {
 
     /// SPI read, using DMA.
     pub async fn read<W: Word>(&mut self, data: &mut [W]) -> Result<(), Error> {
+        #[cfg(not(spi_v3))]
+        {
+            self.transmission_read(data).await
+        }
+        #[cfg(spi_v3)]
+        {
+            self.tsize_read(data).await
+        }
+    }
+
+    #[cfg(spi_v3)]
+    async fn tsize_read<W: Word>(&mut self, data: &mut [W]) -> Result<(), Error> {
+        if data.is_empty() {
+            return Ok(());
+        }
+
+        self.info.regs.cr1().modify(|w| {
+            w.set_spe(false);
+        });
+
+        let comm = self.info.regs.cfg2().modify(|w| {
+            let prev = w.comm();
+            w.set_comm(vals::Comm::RECEIVER);
+            prev
+        });
+
+        let i2scfg = self.info.regs.i2scfgr().modify(|w| {
+            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 tsize = self.info.regs.cr2().read().tsize();
+
+        let rx_src = self.info.regs.rx_ptr();
+
+        let mut read = 0;
+        let mut remaining = data.len();
+
+        loop {
+            self.set_word_size(W::CONFIG);
+            set_rxdmaen(self.info.regs, true);
+
+            let transfer_size = remaining.min(u16::max_value().into());
+
+            let transfer = unsafe {
+                self.rx_dma
+                    .as_mut()
+                    .unwrap()
+                    .read(rx_src, &mut data[read..(read + transfer_size)], Default::default())
+            };
+
+            self.info.regs.cr2().modify(|w| {
+                w.set_tsize(transfer_size as u16);
+            });
+
+            self.info.regs.cr1().modify(|w| {
+                w.set_spe(true);
+            });
+
+            self.info.regs.cr1().modify(|w| {
+                w.set_cstart(true);
+            });
+
+            transfer.await;
+
+            finish_dma(self.info.regs);
+
+            remaining -= transfer_size;
+
+            if remaining == 0 {
+                break;
+            }
+
+            read += transfer_size;
+        }
+
+        self.info.regs.cr1().modify(|w| {
+            w.set_spe(false);
+        });
+
+        self.info.regs.cfg2().modify(|w| {
+            w.set_comm(comm);
+        });
+
+        self.info.regs.cr2().modify(|w| {
+            w.set_tsize(tsize);
+        });
+
+        self.info.regs.i2scfgr().modify(|w| {
+            w.set_i2scfg(i2scfg);
+        });
+
+        Ok(())
+    }
+
+    #[cfg(not(spi_v3))]
+    async fn transmission_read<W: Word>(&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 +1014,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() {}
 

From 76fbec74da30c5cd04b441aa49414a286170a491 Mon Sep 17 00:00:00 2001
From: Alexandros Liarokapis <liarokapis.v@gmail.com>
Date: Mon, 27 May 2024 20:43:17 +0300
Subject: [PATCH 2/7] fix spi panic on read due to i2s configuration conversion
 check

---
 embassy-stm32/src/spi/mod.rs | 52 ++++++++++++++++++++----------------
 1 file changed, 29 insertions(+), 23 deletions(-)

diff --git a/embassy-stm32/src/spi/mod.rs b/embassy-stm32/src/spi/mod.rs
index 0a0afafc6..0b12bc9b6 100644
--- a/embassy-stm32/src/spi/mod.rs
+++ b/embassy-stm32/src/spi/mod.rs
@@ -643,36 +643,40 @@ impl<'d> Spi<'d, Async> {
             return Ok(());
         }
 
-        self.info.regs.cr1().modify(|w| {
+        let regs = self.info.regs;
+
+        regs.cr1().modify(|w| {
             w.set_spe(false);
         });
 
-        let comm = self.info.regs.cfg2().modify(|w| {
+        let comm = regs.cfg2().modify(|w| {
             let prev = w.comm();
             w.set_comm(vals::Comm::RECEIVER);
             prev
         });
 
-        let i2scfg = self.info.regs.i2scfgr().modify(|w| {
-            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 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 tsize = self.info.regs.cr2().read().tsize();
+        let tsize = regs.cr2().read().tsize();
 
-        let rx_src = self.info.regs.rx_ptr();
+        let rx_src = regs.rx_ptr();
 
         let mut read = 0;
         let mut remaining = data.len();
 
         loop {
             self.set_word_size(W::CONFIG);
-            set_rxdmaen(self.info.regs, true);
+            set_rxdmaen(regs, true);
 
             let transfer_size = remaining.min(u16::max_value().into());
 
@@ -683,21 +687,21 @@ impl<'d> Spi<'d, Async> {
                     .read(rx_src, &mut data[read..(read + transfer_size)], Default::default())
             };
 
-            self.info.regs.cr2().modify(|w| {
+            regs.cr2().modify(|w| {
                 w.set_tsize(transfer_size as u16);
             });
 
-            self.info.regs.cr1().modify(|w| {
+            regs.cr1().modify(|w| {
                 w.set_spe(true);
             });
 
-            self.info.regs.cr1().modify(|w| {
+            regs.cr1().modify(|w| {
                 w.set_cstart(true);
             });
 
             transfer.await;
 
-            finish_dma(self.info.regs);
+            finish_dma(regs);
 
             remaining -= transfer_size;
 
@@ -708,21 +712,23 @@ impl<'d> Spi<'d, Async> {
             read += transfer_size;
         }
 
-        self.info.regs.cr1().modify(|w| {
+        regs.cr1().modify(|w| {
             w.set_spe(false);
         });
 
-        self.info.regs.cfg2().modify(|w| {
+        regs.cfg2().modify(|w| {
             w.set_comm(comm);
         });
 
-        self.info.regs.cr2().modify(|w| {
+        regs.cr2().modify(|w| {
             w.set_tsize(tsize);
         });
 
-        self.info.regs.i2scfgr().modify(|w| {
-            w.set_i2scfg(i2scfg);
-        });
+        if let Some(i2scfg) = i2scfg {
+            regs.i2scfgr().modify(|w| {
+                w.set_i2scfg(i2scfg);
+            });
+        }
 
         Ok(())
     }

From 1d05015a1c6b79d9cf7f93d16718508f3f80fc7e Mon Sep 17 00:00:00 2001
From: Alexandros Liarokapis <liarokapis.v@gmail.com>
Date: Mon, 27 May 2024 20:42:29 +0300
Subject: [PATCH 3/7] broaden tsize read support to other spi versions

---
 embassy-stm32/src/spi/mod.rs | 24 +++++++-----------------
 1 file changed, 7 insertions(+), 17 deletions(-)

diff --git a/embassy-stm32/src/spi/mod.rs b/embassy-stm32/src/spi/mod.rs
index 0b12bc9b6..a3578dfde 100644
--- a/embassy-stm32/src/spi/mod.rs
+++ b/embassy-stm32/src/spi/mod.rs
@@ -508,7 +508,7 @@ impl<'d> Spi<'d, Async> {
         peri: impl Peripheral<P = T> + 'd,
         sck: impl Peripheral<P = impl SckPin<T>> + 'd,
         miso: impl Peripheral<P = impl MisoPin<T>> + 'd,
-        #[cfg(not(spi_v3))] tx_dma: impl Peripheral<P = impl TxDma<T>> + 'd,
+        #[cfg(any(spi_v1, spi_f1))] tx_dma: impl Peripheral<P = impl TxDma<T>> + 'd,
         rx_dma: impl Peripheral<P = impl RxDma<T>> + 'd,
         config: Config,
     ) -> Self {
@@ -517,9 +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(not(spi_v3))]
+            #[cfg(any(spi_v1, spi_f1))]
             new_dma!(tx_dma),
-            #[cfg(spi_v3)]
+            #[cfg(any(spi_v2, spi_v3, spi_v4, spi_v5))]
             None,
             new_dma!(rx_dma),
             config,
@@ -626,19 +626,8 @@ impl<'d> Spi<'d, Async> {
     }
 
     /// SPI read, using DMA.
+    #[cfg(any(spi_v2, spi_v3, spi_v4, spi_v5))]
     pub async fn read<W: Word>(&mut self, data: &mut [W]) -> Result<(), Error> {
-        #[cfg(not(spi_v3))]
-        {
-            self.transmission_read(data).await
-        }
-        #[cfg(spi_v3)]
-        {
-            self.tsize_read(data).await
-        }
-    }
-
-    #[cfg(spi_v3)]
-    async fn tsize_read<W: Word>(&mut self, data: &mut [W]) -> Result<(), Error> {
         if data.is_empty() {
             return Ok(());
         }
@@ -733,8 +722,9 @@ impl<'d> Spi<'d, Async> {
         Ok(())
     }
 
-    #[cfg(not(spi_v3))]
-    async fn transmission_read<W: Word>(&mut self, data: &mut [W]) -> Result<(), Error> {
+    /// SPI read, using DMA.
+    #[cfg(any(spi_v1, spi_f1))]
+    pub async fn read<W: Word>(&mut self, data: &mut [W]) -> Result<(), Error> {
         if data.is_empty() {
             return Ok(());
         }

From 9a6ed79ad124c8a22f6833c2c4f9637661a5bbdb Mon Sep 17 00:00:00 2001
From: Alexandros Liarokapis <liarokapis.v@gmail.com>
Date: Mon, 27 May 2024 20:51:50 +0300
Subject: [PATCH 4/7] remove rx-only support for new spi versions with missing
 I2SCFGR register

---
 embassy-stm32/src/spi/mod.rs | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/embassy-stm32/src/spi/mod.rs b/embassy-stm32/src/spi/mod.rs
index a3578dfde..d9b6f0003 100644
--- a/embassy-stm32/src/spi/mod.rs
+++ b/embassy-stm32/src/spi/mod.rs
@@ -508,7 +508,7 @@ impl<'d> Spi<'d, Async> {
         peri: impl Peripheral<P = T> + 'd,
         sck: impl Peripheral<P = impl SckPin<T>> + 'd,
         miso: impl Peripheral<P = impl MisoPin<T>> + 'd,
-        #[cfg(any(spi_v1, spi_f1))] tx_dma: impl Peripheral<P = impl TxDma<T>> + 'd,
+        #[cfg(any(spi_v1, spi_f1, spi_v4, spi_v5))] tx_dma: impl Peripheral<P = impl TxDma<T>> + 'd,
         rx_dma: impl Peripheral<P = impl RxDma<T>> + 'd,
         config: Config,
     ) -> Self {
@@ -517,9 +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))]
+            #[cfg(any(spi_v1, spi_f1, spi_v4, spi_v5))]
             new_dma!(tx_dma),
-            #[cfg(any(spi_v2, spi_v3, spi_v4, spi_v5))]
+            #[cfg(any(spi_v2, spi_v3))]
             None,
             new_dma!(rx_dma),
             config,
@@ -626,7 +626,7 @@ impl<'d> Spi<'d, Async> {
     }
 
     /// SPI read, using DMA.
-    #[cfg(any(spi_v2, spi_v3, spi_v4, spi_v5))]
+    #[cfg(any(spi_v2, spi_v3))]
     pub async fn read<W: Word>(&mut self, data: &mut [W]) -> Result<(), Error> {
         if data.is_empty() {
             return Ok(());
@@ -723,7 +723,7 @@ impl<'d> Spi<'d, Async> {
     }
 
     /// SPI read, using DMA.
-    #[cfg(any(spi_v1, spi_f1))]
+    #[cfg(any(spi_v1, spi_f1, spi_v4, spi_v5))]
     pub async fn read<W: Word>(&mut self, data: &mut [W]) -> Result<(), Error> {
         if data.is_empty() {
             return Ok(());

From 46fc15783d226d66aa93e38c0b36c8cac9b71700 Mon Sep 17 00:00:00 2001
From: Alexandros Liarokapis <liarokapis.v@gmail.com>
Date: Tue, 28 May 2024 12:50:24 +0300
Subject: [PATCH 5/7] add spi_v4 and spi_v5 support but block i2scfg rx-only
 configuration

---
 embassy-stm32/src/spi/mod.rs | 12 +++++++-----
 1 file changed, 7 insertions(+), 5 deletions(-)

diff --git a/embassy-stm32/src/spi/mod.rs b/embassy-stm32/src/spi/mod.rs
index d9b6f0003..109b2738b 100644
--- a/embassy-stm32/src/spi/mod.rs
+++ b/embassy-stm32/src/spi/mod.rs
@@ -508,7 +508,7 @@ impl<'d> Spi<'d, Async> {
         peri: impl Peripheral<P = T> + 'd,
         sck: impl Peripheral<P = impl SckPin<T>> + 'd,
         miso: impl Peripheral<P = impl MisoPin<T>> + 'd,
-        #[cfg(any(spi_v1, spi_f1, spi_v4, spi_v5))] tx_dma: impl Peripheral<P = impl TxDma<T>> + 'd,
+        #[cfg(any(spi_v1, spi_f1, spi_v2))] tx_dma: impl Peripheral<P = impl TxDma<T>> + 'd,
         rx_dma: impl Peripheral<P = impl RxDma<T>> + 'd,
         config: Config,
     ) -> Self {
@@ -517,9 +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_v4, spi_v5))]
+            #[cfg(any(spi_v1, spi_f1, spi_v2))]
             new_dma!(tx_dma),
-            #[cfg(any(spi_v2, spi_v3))]
+            #[cfg(any(spi_v3, spi_v4, spi_v5))]
             None,
             new_dma!(rx_dma),
             config,
@@ -626,7 +626,7 @@ impl<'d> Spi<'d, Async> {
     }
 
     /// SPI read, using DMA.
-    #[cfg(any(spi_v2, spi_v3))]
+    #[cfg(any(spi_v3, spi_v4, spi_v5))]
     pub async fn read<W: Word>(&mut self, data: &mut [W]) -> Result<(), Error> {
         if data.is_empty() {
             return Ok(());
@@ -644,6 +644,7 @@ impl<'d> Spi<'d, Async> {
             prev
         });
 
+        #[cfg(spi_v3)]
         let i2scfg = regs.i2scfgr().modify(|w| {
             w.i2smod().then(|| {
                 let prev = w.i2scfg();
@@ -713,6 +714,7 @@ impl<'d> Spi<'d, Async> {
             w.set_tsize(tsize);
         });
 
+        #[cfg(spi_v3)]
         if let Some(i2scfg) = i2scfg {
             regs.i2scfgr().modify(|w| {
                 w.set_i2scfg(i2scfg);
@@ -723,7 +725,7 @@ impl<'d> Spi<'d, Async> {
     }
 
     /// SPI read, using DMA.
-    #[cfg(any(spi_v1, spi_f1, spi_v4, spi_v5))]
+    #[cfg(any(spi_v1, spi_f1, spi_v2))]
     pub async fn read<W: Word>(&mut self, data: &mut [W]) -> Result<(), Error> {
         if data.is_empty() {
             return Ok(());

From 4d1fbcd9cd42ebc3169008e189fcd98dce1c427d Mon Sep 17 00:00:00 2001
From: Alexandros Liarokapis <liarokapis.v@gmail.com>
Date: Tue, 28 May 2024 13:38:27 +0300
Subject: [PATCH 6/7] address review comments

---
 embassy-stm32/src/spi/mod.rs | 23 +++++------------------
 1 file changed, 5 insertions(+), 18 deletions(-)

diff --git a/embassy-stm32/src/spi/mod.rs b/embassy-stm32/src/spi/mod.rs
index 109b2738b..7fb8da5ac 100644
--- a/embassy-stm32/src/spi/mod.rs
+++ b/embassy-stm32/src/spi/mod.rs
@@ -657,28 +657,23 @@ impl<'d> Spi<'d, Async> {
             })
         });
 
-        let tsize = regs.cr2().read().tsize();
-
         let rx_src = regs.rx_ptr();
 
-        let mut read = 0;
-        let mut remaining = data.len();
-
-        loop {
+        for mut chunk in data.chunks_mut(u16::max_value().into()) {
             self.set_word_size(W::CONFIG);
             set_rxdmaen(regs, true);
 
-            let transfer_size = remaining.min(u16::max_value().into());
+            let tsize = chunk.len();
 
             let transfer = unsafe {
                 self.rx_dma
                     .as_mut()
                     .unwrap()
-                    .read(rx_src, &mut data[read..(read + transfer_size)], Default::default())
+                    .read(rx_src, &mut chunk, Default::default())
             };
 
             regs.cr2().modify(|w| {
-                w.set_tsize(transfer_size as u16);
+                w.set_tsize(tsize as u16);
             });
 
             regs.cr1().modify(|w| {
@@ -692,14 +687,6 @@ impl<'d> Spi<'d, Async> {
             transfer.await;
 
             finish_dma(regs);
-
-            remaining -= transfer_size;
-
-            if remaining == 0 {
-                break;
-            }
-
-            read += transfer_size;
         }
 
         regs.cr1().modify(|w| {
@@ -711,7 +698,7 @@ impl<'d> Spi<'d, Async> {
         });
 
         regs.cr2().modify(|w| {
-            w.set_tsize(tsize);
+            w.set_tsize(0);
         });
 
         #[cfg(spi_v3)]

From 4f76f6b9df72c10f039911d0e35ca504be750564 Mon Sep 17 00:00:00 2001
From: Alexandros Liarokapis <liarokapis.v@gmail.com>
Date: Tue, 28 May 2024 15:24:05 +0300
Subject: [PATCH 7/7] add spi_dma rx-only test

---
 tests/stm32/src/bin/spi_dma.rs | 65 +++++++++++++++++++++++++++++++---
 1 file changed, 60 insertions(+), 5 deletions(-)

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();
 }