From 18287ea63d8b9cdd081218ead022ad68e32f6bd5 Mon Sep 17 00:00:00 2001 From: Raphael Coeffic Date: Wed, 14 May 2025 01:48:18 +0200 Subject: [PATCH] fix(f4): SPI DMA transfers (#6221) --- .../targets/common/arm/stm32/stm32_spi.cpp | 112 ++++++++++-------- 1 file changed, 64 insertions(+), 48 deletions(-) diff --git a/radio/src/targets/common/arm/stm32/stm32_spi.cpp b/radio/src/targets/common/arm/stm32/stm32_spi.cpp index ca32e5645..db9f057f4 100644 --- a/radio/src/targets/common/arm/stm32/stm32_spi.cpp +++ b/radio/src/targets/common/arm/stm32/stm32_spi.cpp @@ -237,10 +237,8 @@ static uint16_t _scratch_byte __DMA_NO_CACHE; static uint8_t _scratch_buffer[512] __DMA_NO_CACHE; #if defined(STM32F4) -extern uint32_t _sram; -extern uint32_t _eram; #define _IS_DMA_BUFFER(addr) \ - ((intptr_t)(addr) >= (intptr_t)&_sram && (intptr_t)(addr) <= (intptr_t)&_eram) + (((intptr_t)(addr) & 0xF0000000) != CCMDATARAM_BASE) #else #define _IS_DMA_BUFFER(addr) (true) #endif @@ -266,33 +264,40 @@ uint32_t stm32_spi_dma_receive_bytes(const stm32_spi_t* spi, uint8_t* data, } bool use_scratch_buffer = !_IS_DMA_BUFFER(data) || !_IS_ALIGNED(data); - if (use_scratch_buffer) { - _dma_enable_stream(spi->DMA, spi->rxDMA_Stream, _scratch_buffer, length); - } else { - _dma_enable_stream(spi->DMA, spi->rxDMA_Stream, data, length); - } - LL_SPI_EnableDMAReq_RX(spi->SPIx); + uint32_t max_xfer_len = use_scratch_buffer ? sizeof(_scratch_buffer) : length; - _scratch_byte = 0xFFFF; - LL_DMA_SetMemoryIncMode(spi->DMA, spi->txDMA_Stream, LL_DMA_MEMORY_NOINCREMENT); - _dma_enable_stream(spi->DMA, spi->txDMA_Stream, &_scratch_byte, length); - LL_SPI_EnableDMAReq_TX(spi->SPIx); + uint32_t xfer_len = length; + while (xfer_len > 0) { + uint32_t single_xfer_len = (xfer_len > max_xfer_len) ? max_xfer_len : xfer_len; + const void* xfer_data = use_scratch_buffer ? _scratch_buffer : data; - // Wait for end of DMA transfer - while(!stm32_dma_check_tc_flag(spi->DMA, spi->rxDMA_Stream)); + _dma_enable_stream(spi->DMA, spi->rxDMA_Stream, xfer_data, single_xfer_len); + LL_SPI_EnableDMAReq_RX(spi->SPIx); - // Wait for TXE=1 - while (!LL_SPI_IsActiveFlag_TXE(spi->SPIx)); + _scratch_byte = 0xFFFF; + LL_DMA_SetMemoryIncMode(spi->DMA, spi->txDMA_Stream, LL_DMA_MEMORY_NOINCREMENT); + _dma_enable_stream(spi->DMA, spi->txDMA_Stream, &_scratch_byte, single_xfer_len); + LL_SPI_EnableDMAReq_TX(spi->SPIx); + + // Wait for end of DMA transfer + while(!stm32_dma_check_tc_flag(spi->DMA, spi->rxDMA_Stream)); + + // Wait for TXE=1 + while (!LL_SPI_IsActiveFlag_TXE(spi->SPIx)); - // Wait for BSY=0 - while(LL_SPI_IsActiveFlag_BSY(spi->SPIx)); + // Wait for BSY=0 + while(LL_SPI_IsActiveFlag_BSY(spi->SPIx)); - // Disable SPI TX/RX DMA requests - LL_SPI_DisableDMAReq_TX(spi->SPIx); - LL_SPI_DisableDMAReq_RX(spi->SPIx); + // Disable SPI TX/RX DMA requests + LL_SPI_DisableDMAReq_TX(spi->SPIx); + LL_SPI_DisableDMAReq_RX(spi->SPIx); - if (use_scratch_buffer) { - memcpy(data, _scratch_buffer, length); + if (use_scratch_buffer) { + memcpy(data, _scratch_buffer, single_xfer_len); + } + + xfer_len -= single_xfer_len; + data += single_xfer_len; } return length; @@ -310,32 +315,43 @@ uint32_t stm32_spi_dma_transmit_bytes(const stm32_spi_t* spi, } bool use_scratch_buffer = !_IS_DMA_BUFFER(data) || !_IS_ALIGNED(data); - if (use_scratch_buffer) { - memcpy(_scratch_buffer, data, length); - data = _scratch_buffer; + uint32_t max_xfer_len = use_scratch_buffer ? sizeof(_scratch_buffer) : length; + + uint32_t xfer_len = length; + while (xfer_len > 0) { + uint32_t single_xfer_len = (xfer_len > max_xfer_len) ? max_xfer_len : xfer_len; + const void* xfer_data = data; + + if (use_scratch_buffer) { + memcpy(_scratch_buffer, data, single_xfer_len); + xfer_data = _scratch_buffer; + } + + LL_DMA_SetMemoryIncMode(spi->DMA, spi->txDMA_Stream, LL_DMA_MEMORY_INCREMENT); + _dma_enable_stream(spi->DMA, spi->txDMA_Stream, xfer_data, single_xfer_len); + LL_SPI_EnableDMAReq_TX(spi->SPIx); + + // Wait for end of DMA transfer + while (!stm32_dma_check_tc_flag(spi->DMA, spi->txDMA_Stream)); + + // Wait for TXE=1 + while (!LL_SPI_IsActiveFlag_TXE(spi->SPIx)); + + // Wait for BSY=0 + while (LL_SPI_IsActiveFlag_BSY(spi->SPIx)); + + // Clear data register + if (LL_SPI_IsActiveFlag_RXNE(spi->SPIx)) { + (void)LL_SPI_ReceiveData8(spi->SPIx); + } + + // Disable SPI TX DMA requests + LL_SPI_DisableDMAReq_TX(spi->SPIx); + + xfer_len -= single_xfer_len; + data += single_xfer_len; } - LL_DMA_SetMemoryIncMode(spi->DMA, spi->txDMA_Stream, LL_DMA_MEMORY_INCREMENT); - _dma_enable_stream(spi->DMA, spi->txDMA_Stream, data, length); - LL_SPI_EnableDMAReq_TX(spi->SPIx); - - // Wait for end of DMA transfer - while (!stm32_dma_check_tc_flag(spi->DMA, spi->txDMA_Stream)); - - // Wait for TXE=1 - while (!LL_SPI_IsActiveFlag_TXE(spi->SPIx)); - - // Wait for BSY=0 - while (LL_SPI_IsActiveFlag_BSY(spi->SPIx)); - - // Clear data register - if (LL_SPI_IsActiveFlag_RXNE(spi->SPIx)) { - (void)LL_SPI_ReceiveData8(spi->SPIx); - } - - // Disable SPI TX DMA requests - LL_SPI_DisableDMAReq_TX(spi->SPIx); - return length; #else return stm32_spi_transfer_bytes(spi, data, 0, length);