From eb10dc8f591fa2cb88dd30564430680ea420cd58 Mon Sep 17 00:00:00 2001 From: ALTracer <11005378+ALTracer@users.noreply.github.com> Date: Tue, 1 Oct 2024 19:10:56 +0300 Subject: [PATCH 1/6] spi: blackpill-f4: Implement spi_xfer_block for faster reads * Existing implementation has to walk up and down the function stack per byte, which is fine for commands and general poking * 256-byte long page reads and writes can be accelerated because the length is known ahead of time * Keep a byte in flight on stm32f1/f4 SPI (this is simpler than IRQ or DMA) --- src/include/platform_support.h | 1 + .../common/blackpill-f4/blackpill-f4.c | 42 +++++++++++++++++++ src/target/spi.c | 8 ++++ 3 files changed, 51 insertions(+) diff --git a/src/include/platform_support.h b/src/include/platform_support.h index 5e04ceb332b..91aa6463af0 100644 --- a/src/include/platform_support.h +++ b/src/include/platform_support.h @@ -77,6 +77,7 @@ bool platform_spi_deinit(spi_bus_e bus); bool platform_spi_chip_select(uint8_t device_select); uint8_t platform_spi_xfer(spi_bus_e bus, uint8_t value); +void platform_spi_xfer_block(spi_bus_e bus, uint8_t *const data, size_t count); #endif #ifdef PLATFORM_IDENT_DYNAMIC diff --git a/src/platforms/common/blackpill-f4/blackpill-f4.c b/src/platforms/common/blackpill-f4/blackpill-f4.c index 1e26b875770..0f0f49993e7 100644 --- a/src/platforms/common/blackpill-f4/blackpill-f4.c +++ b/src/platforms/common/blackpill-f4/blackpill-f4.c @@ -291,6 +291,48 @@ uint8_t platform_spi_xfer(const spi_bus_e bus, const uint8_t value) } } +void platform_spi_xfer_block(const spi_bus_e bus, uint8_t *const data, const size_t count) +{ + uint32_t spi_base = OB_SPI; + switch (bus) { + case SPI_BUS_INTERNAL: + spi_base = OB_SPI; + break; + case SPI_BUS_EXTERNAL: + spi_base = EXT_SPI; + break; + default: + return; + } + +#if 0 + /* Put a byte on MOSI, wait entire transfer, grab the byte from MOSI into buffer, repeat. */ + for (size_t i = 0; i < count; i++) { + uint8_t resp = spi_xfer(spi_base, data[i]); + data[i] = resp; + } +#else + CM_ATOMIC_CONTEXT(); + /* + * Start the waveform by putting first MOSI byte into TXDR + * from which it falls immediately into the shadow register + * (pipelined polling version with inter-byte-gaps removed, no IRQ, no DMA) + */ + spi_write(spi_base, data[0]); + /* + * Put the next MOSI byte into TXDR, + * wait for previous byte from MOSI to appear in RXDR and copy it into buffer, + * repeat N-2 times + */ + for (size_t i = 0; i < count - 1; i++) { + spi_send(spi_base, data[i + 1]); + data[i] = spi_read(spi_base); + } + /* Once the last MOSI byte comes out, grab the last MISO byte */ + data[count - 1] = spi_read(spi_base); +#endif +} + int platform_hwversion(void) { return 0; diff --git a/src/target/spi.c b/src/target/spi.c index 872c68f4451..2c1b3e5eeb6 100644 --- a/src/target/spi.c +++ b/src/target/spi.c @@ -67,9 +67,13 @@ void bmp_spi_read(const spi_bus_e bus, const uint8_t device, const uint16_t comm bmp_spi_setup_xfer(bus, device, command, address); /* Now read back the data that elicited */ uint8_t *const data = (uint8_t *const)buffer; +#if 0 for (size_t i = 0; i < length; ++i) /* Do a write to read */ data[i] = platform_spi_xfer(bus, 0); +#else + platform_spi_xfer_block(bus, data, length); +#endif /* Deselect the Flash */ platform_spi_chip_select(device); } @@ -81,9 +85,13 @@ void bmp_spi_write(const spi_bus_e bus, const uint8_t device, const uint16_t com bmp_spi_setup_xfer(bus, device, command, address); /* Now write out back the data requested */ const uint8_t *const data = (const uint8_t *)buffer; +#if 0 for (size_t i = 0; i < length; ++i) /* Do a write to read */ platform_spi_xfer(bus, data[i]); +#else + platform_spi_xfer_block(bus, data, length); +#endif /* Deselect the Flash */ platform_spi_chip_select(device); } From 26dd5d862cc3555b5cb1a76a19045757c84b709a Mon Sep 17 00:00:00 2001 From: ALTracer <11005378+ALTracer@users.noreply.github.com> Date: Sat, 26 Oct 2024 19:13:01 +0300 Subject: [PATCH 2/6] spi: blackpill-f4: Split out const-qualified tx_buf --- src/include/platform_support.h | 2 +- .../common/blackpill-f4/blackpill-f4.c | 27 ++++++++++++++----- src/target/spi.c | 4 +-- 3 files changed, 23 insertions(+), 10 deletions(-) diff --git a/src/include/platform_support.h b/src/include/platform_support.h index 91aa6463af0..afd74c15f69 100644 --- a/src/include/platform_support.h +++ b/src/include/platform_support.h @@ -77,7 +77,7 @@ bool platform_spi_deinit(spi_bus_e bus); bool platform_spi_chip_select(uint8_t device_select); uint8_t platform_spi_xfer(spi_bus_e bus, uint8_t value); -void platform_spi_xfer_block(spi_bus_e bus, uint8_t *const data, size_t count); +void platform_spi_xfer_block(spi_bus_e bus, const uint8_t *const tx_buf, uint8_t *const rx_buf, size_t count); #endif #ifdef PLATFORM_IDENT_DYNAMIC diff --git a/src/platforms/common/blackpill-f4/blackpill-f4.c b/src/platforms/common/blackpill-f4/blackpill-f4.c index 0f0f49993e7..e488abdd759 100644 --- a/src/platforms/common/blackpill-f4/blackpill-f4.c +++ b/src/platforms/common/blackpill-f4/blackpill-f4.c @@ -291,7 +291,15 @@ uint8_t platform_spi_xfer(const spi_bus_e bus, const uint8_t value) } } -void platform_spi_xfer_block(const spi_bus_e bus, uint8_t *const data, const size_t count) +/** + * @brief Run a full-duplex SPI transfer + * @param bus Which BMP SPI bus to use (internal/external) + * @param tx_buf Transmit data buffer of at least `count` size (nonempty) + * @param rx_buf Receive data buffer of same size (can alias, can be NULL) + * @param count Byte count for the transfer, and each buffer size. + */ +void platform_spi_xfer_block( + const spi_bus_e bus, const uint8_t *const tx_buf, uint8_t *const rx_buf, const size_t count) { uint32_t spi_base = OB_SPI; switch (bus) { @@ -308,8 +316,9 @@ void platform_spi_xfer_block(const spi_bus_e bus, uint8_t *const data, const siz #if 0 /* Put a byte on MOSI, wait entire transfer, grab the byte from MOSI into buffer, repeat. */ for (size_t i = 0; i < count; i++) { - uint8_t resp = spi_xfer(spi_base, data[i]); - data[i] = resp; + uint8_t resp = spi_xfer(spi_base, tx_buf[i]); + if (rx_buf) + rx_buf[i] = resp; } #else CM_ATOMIC_CONTEXT(); @@ -318,18 +327,22 @@ void platform_spi_xfer_block(const spi_bus_e bus, uint8_t *const data, const siz * from which it falls immediately into the shadow register * (pipelined polling version with inter-byte-gaps removed, no IRQ, no DMA) */ - spi_write(spi_base, data[0]); + spi_write(spi_base, tx_buf[0]); /* * Put the next MOSI byte into TXDR, * wait for previous byte from MOSI to appear in RXDR and copy it into buffer, * repeat N-2 times */ for (size_t i = 0; i < count - 1; i++) { - spi_send(spi_base, data[i + 1]); - data[i] = spi_read(spi_base); + spi_send(spi_base, tx_buf[i + 1]); + uint8_t resp = spi_read(spi_base); + if (rx_buf) + rx_buf[i] = resp; } /* Once the last MOSI byte comes out, grab the last MISO byte */ - data[count - 1] = spi_read(spi_base); + uint8_t resp = spi_read(spi_base); + if (rx_buf) + rx_buf[count - 1] = resp; #endif } diff --git a/src/target/spi.c b/src/target/spi.c index 2c1b3e5eeb6..15e69c33a25 100644 --- a/src/target/spi.c +++ b/src/target/spi.c @@ -72,7 +72,7 @@ void bmp_spi_read(const spi_bus_e bus, const uint8_t device, const uint16_t comm /* Do a write to read */ data[i] = platform_spi_xfer(bus, 0); #else - platform_spi_xfer_block(bus, data, length); + platform_spi_xfer_block(bus, data, data, length); #endif /* Deselect the Flash */ platform_spi_chip_select(device); @@ -90,7 +90,7 @@ void bmp_spi_write(const spi_bus_e bus, const uint8_t device, const uint16_t com /* Do a write to read */ platform_spi_xfer(bus, data[i]); #else - platform_spi_xfer_block(bus, data, length); + platform_spi_xfer_block(bus, data, NULL, length); #endif /* Deselect the Flash */ platform_spi_chip_select(device); From 1430564e712360bd5d977c45eaad5d11c90339ef Mon Sep 17 00:00:00 2001 From: ALTracer <11005378+ALTracer@users.noreply.github.com> Date: Sat, 26 Oct 2024 19:29:07 +0300 Subject: [PATCH 3/6] native: Implement spi_xfer_block for faster reads --- src/platforms/native/platform.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/platforms/native/platform.c b/src/platforms/native/platform.c index e889527e872..392a128b117 100644 --- a/src/platforms/native/platform.c +++ b/src/platforms/native/platform.c @@ -519,6 +519,19 @@ uint8_t platform_spi_xfer(const spi_bus_e bus, const uint8_t value) return spi_xfer(bus == SPI_BUS_EXTERNAL ? EXT_SPI : AUX_SPI, value); } +void platform_spi_xfer_block( + const spi_bus_e bus, const uint8_t *const tx_buf, uint8_t *const rx_buf, const size_t count) +{ + const uint32_t spi_base = bus == SPI_BUS_EXTERNAL ? EXT_SPI : AUX_SPI; + + /* Put a byte on MOSI, wait entire transfer, grab the byte from MOSI into buffer, repeat. */ + for (size_t i = 0; i < count; i++) { + uint8_t resp = spi_xfer(spi_base, tx_buf[i]); + if (rx_buf) + rx_buf[i] = resp; + } +} + void exti15_10_isr(void) { uint32_t usb_vbus_port; From 6a88dbf674792ed0cbc2b49c6c6181ecdffad8ce Mon Sep 17 00:00:00 2001 From: ALTracer <11005378+ALTracer@users.noreply.github.com> Date: Sat, 26 Oct 2024 19:34:02 +0300 Subject: [PATCH 4/6] stlink, swlink: Add no-op stubs for spi_xfer_block --- src/platforms/stlink/platform.c | 10 ++++++++++ src/platforms/swlink/platform.c | 10 ++++++++++ 2 files changed, 20 insertions(+) diff --git a/src/platforms/stlink/platform.c b/src/platforms/stlink/platform.c index 4a423ff6039..71627b917c7 100644 --- a/src/platforms/stlink/platform.c +++ b/src/platforms/stlink/platform.c @@ -209,3 +209,13 @@ uint8_t platform_spi_xfer(const spi_bus_e bus, const uint8_t value) (void)bus; return value; } + +void platform_spi_xfer_block( + const spi_bus_e bus, const uint8_t *const tx_buf, uint8_t *const rx_buf, const size_t count) +{ + (void)bus; + (void)tx_buf; + (void)rx_buf; + (void)count; + return; +} diff --git a/src/platforms/swlink/platform.c b/src/platforms/swlink/platform.c index bff34040943..cff93831fd0 100644 --- a/src/platforms/swlink/platform.c +++ b/src/platforms/swlink/platform.c @@ -215,3 +215,13 @@ uint8_t platform_spi_xfer(const spi_bus_e bus, const uint8_t value) (void)bus; return value; } + +void platform_spi_xfer_block( + const spi_bus_e bus, const uint8_t *const tx_buf, uint8_t *const rx_buf, const size_t count) +{ + (void)bus; + (void)tx_buf; + (void)rx_buf; + (void)count; + return; +} From 845ecb8152169d1ad6afcf0de2d8b23100515f2a Mon Sep 17 00:00:00 2001 From: ALTracer <11005378+ALTracer@users.noreply.github.com> Date: Fri, 22 Nov 2024 20:42:31 +0300 Subject: [PATCH 5/6] fixup! spi: blackpill-f4: Implement spi_xfer_block for faster reads --- src/platforms/common/blackpill-f4/blackpill-f4.c | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/platforms/common/blackpill-f4/blackpill-f4.c b/src/platforms/common/blackpill-f4/blackpill-f4.c index e488abdd759..a4dc8585a2f 100644 --- a/src/platforms/common/blackpill-f4/blackpill-f4.c +++ b/src/platforms/common/blackpill-f4/blackpill-f4.c @@ -313,14 +313,6 @@ void platform_spi_xfer_block( return; } -#if 0 - /* Put a byte on MOSI, wait entire transfer, grab the byte from MOSI into buffer, repeat. */ - for (size_t i = 0; i < count; i++) { - uint8_t resp = spi_xfer(spi_base, tx_buf[i]); - if (rx_buf) - rx_buf[i] = resp; - } -#else CM_ATOMIC_CONTEXT(); /* * Start the waveform by putting first MOSI byte into TXDR @@ -343,7 +335,6 @@ void platform_spi_xfer_block( uint8_t resp = spi_read(spi_base); if (rx_buf) rx_buf[count - 1] = resp; -#endif } int platform_hwversion(void) From 8fb69b8c5b448b3ca8ee13953a6ba96e773fe670 Mon Sep 17 00:00:00 2001 From: ALTracer <11005378+ALTracer@users.noreply.github.com> Date: Fri, 22 Nov 2024 20:48:36 +0300 Subject: [PATCH 6/6] fixup! spi: blackpill-f4: Split out const-qualified tx_buf --- src/include/platform_support.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/include/platform_support.h b/src/include/platform_support.h index afd74c15f69..fdb519bc33c 100644 --- a/src/include/platform_support.h +++ b/src/include/platform_support.h @@ -77,7 +77,7 @@ bool platform_spi_deinit(spi_bus_e bus); bool platform_spi_chip_select(uint8_t device_select); uint8_t platform_spi_xfer(spi_bus_e bus, uint8_t value); -void platform_spi_xfer_block(spi_bus_e bus, const uint8_t *const tx_buf, uint8_t *const rx_buf, size_t count); +void platform_spi_xfer_block(spi_bus_e bus, const uint8_t *tx_buf, uint8_t *rx_buf, size_t count); #endif #ifdef PLATFORM_IDENT_DYNAMIC