fix(f4): SPI DMA transfers (#6221)

This commit is contained in:
Raphael Coeffic
2025-05-14 09:48:18 +10:00
committed by GitHub
parent 2f074239dc
commit 18287ea63d
@@ -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);