From da197b60165b74d05c3d12b046b5cfda0b9cb126 Mon Sep 17 00:00:00 2001
From: Dario Nieuwenhuis <dirbaio@dirbaio.net>
Date: Fri, 31 May 2024 21:43:03 +0200
Subject: [PATCH] stm32/spi: fix spiv1 rxonly hanging.

---
 embassy-stm32/src/spi/mod.rs   |  7 +--
 tests/stm32/build.rs           |  1 +
 tests/stm32/src/bin/spi_dma.rs | 97 ++++++++++++++--------------------
 3 files changed, 45 insertions(+), 60 deletions(-)

diff --git a/embassy-stm32/src/spi/mod.rs b/embassy-stm32/src/spi/mod.rs
index af8e3fc30..3729ed8de 100644
--- a/embassy-stm32/src/spi/mod.rs
+++ b/embassy-stm32/src/spi/mod.rs
@@ -148,9 +148,10 @@ impl<'d, M: PeriMode> Spi<'d, M> {
                 w.set_ssm(true);
                 w.set_crcen(false);
                 w.set_bidimode(vals::Bidimode::UNIDIRECTIONAL);
-                if mosi.is_none() {
-                    w.set_rxonly(vals::Rxonly::OUTPUTDISABLED);
-                }
+                // we're doing "fake rxonly", by actually writing one
+                // byte to TXDR for each byte we want to receive. if we
+                // set OUTPUTDISABLED here, this hangs.
+                w.set_rxonly(vals::Rxonly::FULLDUPLEX);
                 w.set_dff(<u8 as SealedWord>::CONFIG)
             });
         }
diff --git a/tests/stm32/build.rs b/tests/stm32/build.rs
index 176adff62..675115568 100644
--- a/tests/stm32/build.rs
+++ b/tests/stm32/build.rs
@@ -14,6 +14,7 @@ fn main() -> Result<(), Box<dyn Error>> {
         feature = "stm32c031c6",
         feature = "stm32wb55rg",
         feature = "stm32l073rz",
+        feature = "stm32h503rb",
         // wrong ram size in stm32-data
         feature = "stm32wl55jc",
         feature = "stm32u5a5zj",
diff --git a/tests/stm32/src/bin/spi_dma.rs b/tests/stm32/src/bin/spi_dma.rs
index 30e679f2a..92f741af5 100644
--- a/tests/stm32/src/bin/spi_dma.rs
+++ b/tests/stm32/src/bin/spi_dma.rs
@@ -6,34 +6,32 @@ mod common;
 use common::*;
 use defmt::assert_eq;
 use embassy_executor::Spawner;
+use embassy_stm32::gpio::{Level, Output, Speed};
 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 = 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_peri = peri!(p, SPI);
+    let mut sck = peri!(p, SPI_SCK);
+    let mut mosi = peri!(p, SPI_MOSI);
+    let mut miso = peri!(p, SPI_MISO);
+    let mut tx_dma = peri!(p, SPI_TX_DMA);
+    let mut rx_dma = peri!(p, SPI_RX_DMA);
 
     let mut spi_config = spi::Config::default();
     spi_config.frequency = Hertz(1_000_000);
 
     let mut spi = Spi::new(
-        spi_peri.reborrow(),
-        sck.reborrow(),  // Arduino D13
-        mosi.reborrow(), // Arduino D11
-        miso.reborrow(), // Arduino D12
-        tx_dma.reborrow(),
-        rx_dma.reborrow(),
+        &mut spi_peri,
+        &mut sck,  // Arduino D13
+        &mut mosi, // Arduino D11
+        &mut miso, // Arduino D12
+        &mut tx_dma,
+        &mut rx_dma,
         spi_config,
     );
 
@@ -85,51 +83,36 @@ async fn main(_spawner: Spawner) {
     core::mem::drop(spi);
 
     // test rx-only configuration
+    let mut spi = Spi::new_rxonly(
+        &mut spi_peri,
+        &mut sck,
+        &mut miso,
+        // SPIv1/f1 requires txdma even if rxonly.
+        #[cfg(not(any(
+            feature = "stm32h503rb",
+            feature = "stm32h563zi",
+            feature = "stm32h753zi",
+            feature = "stm32h755zi",
+            feature = "stm32h7a3zi",
+            feature = "stm32h7s3l8",
+            feature = "stm32u585ai",
+            feature = "stm32u5a5zj",
+            feature = "stm32wba52cg",
+        )))]
+        &mut tx_dma,
+        &mut rx_dma,
+        spi_config,
+    );
 
-    // stm32f207zg - spi_v1
-    // stm32f103c8 - spi_f1
-    // stm32g491re - spi_v2
-    // stm32h753zi - spi_v3
-    // stm32h563zi - spi_v4
-    // stm32wba52cg - spi_v5
+    let mut mosi = Output::new(&mut mosi, Level::Low, Speed::VeryHigh);
 
-    #[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,
-                )
-            }
-        };
+    mosi.set_high();
+    spi.read(&mut buf).await.unwrap();
+    assert_eq!(buf, [0xff; 9]);
 
-        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]);
-    };
+    mosi.set_low();
+    spi.read(&mut buf).await.unwrap();
+    assert_eq!(buf, [0x00; 9]);
 
     info!("Test OK");
     cortex_m::asm::bkpt();