Skip to content

Commit d9ff39e

Browse files
wdfk-progRbb666
authored andcommitted
fix:[STM32][SPI]Refactor spixfer to fix DMA reception bug, correct timeout calculation
1 parent 072cb3a commit d9ff39e

1 file changed

Lines changed: 60 additions & 92 deletions

File tree

  • bsp/stm32/libraries/HAL_Drivers/drivers

bsp/stm32/libraries/HAL_Drivers/drivers/drv_spi.c

Lines changed: 60 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@
1010
* 2019-01-03 zylx modify DMA initialization and spixfer function
1111
* 2020-01-15 whj4674672 Porting for stm32h7xx
1212
* 2020-06-18 thread-liu Porting for stm32mp1xx
13-
* 2020-10-14 PeakRacing Porting for stm32wbxx
13+
* 2020-10-14 Dozingfiretruck Porting for stm32wbxx
14+
* 2025-09-22 wdfk_prog Refactor spixfer to fix DMA reception bug, correct timeout calculation.
1415
*/
1516

1617
#include <rtthread.h>
@@ -323,7 +324,7 @@ static rt_ssize_t spixfer(struct rt_spi_device *device, struct rt_spi_message *m
323324
}
324325

325326
LOG_D("%s transfer prepare and start", spi_drv->config->bus_name);
326-
LOG_D("%s sendbuf: %X, recvbuf: %X, length: %d",
327+
LOG_D("%s sendbuf: 0x%08x, recvbuf: 0x%08x, length: %d",
327328
spi_drv->config->bus_name,
328329
(uint32_t)message->send_buf,
329330
(uint32_t)message->recv_buf, message->length);
@@ -357,96 +358,73 @@ static rt_ssize_t spixfer(struct rt_spi_device *device, struct rt_spi_message *m
357358
recv_buf = (rt_uint8_t *)message->recv_buf + already_send_length;
358359
}
359360

360-
rt_uint32_t* dma_aligned_buffer = RT_NULL;
361-
rt_uint32_t* p_txrx_buffer = RT_NULL;
361+
const rt_uint8_t *dma_send_buf = send_buf;
362+
rt_uint8_t *dma_recv_buf = recv_buf;
362363

363-
if ((spi_drv->spi_dma_flag & SPI_USING_TX_DMA_FLAG) && (send_length >= DMA_TRANS_MIN_LEN))
364+
rt_uint8_t *aligned_send_buf = RT_NULL;
365+
rt_uint8_t *aligned_recv_buf = RT_NULL;
366+
367+
const rt_bool_t dma_eligible = (send_length >= DMA_TRANS_MIN_LEN);
368+
const rt_bool_t use_tx_dma = dma_eligible && (spi_drv->spi_dma_flag & SPI_USING_TX_DMA_FLAG);
369+
const rt_bool_t use_rx_dma = dma_eligible && (spi_drv->spi_dma_flag & SPI_USING_RX_DMA_FLAG);
370+
371+
if (dma_eligible)
364372
{
365373
#if defined(SOC_SERIES_STM32H7) || defined(SOC_SERIES_STM32F7)
366-
if (RT_IS_ALIGN((rt_uint32_t)send_buf, 32) && send_buf != RT_NULL) /* aligned with 32 bytes? */
367-
{
368-
p_txrx_buffer = (rt_uint32_t *)send_buf; /* send_buf aligns with 32 bytes, no more operations */
369-
}
370-
else
371-
{
372-
/* send_buf doesn't align with 32 bytes, so creat a cache buffer with 32 bytes aligned */
373-
dma_aligned_buffer = (rt_uint32_t *)rt_malloc_align(send_length, 32);
374-
rt_memcpy(dma_aligned_buffer, send_buf, send_length);
375-
p_txrx_buffer = dma_aligned_buffer;
376-
}
377-
rt_hw_cpu_dcache_ops(RT_HW_CACHE_FLUSH, dma_aligned_buffer, send_length);
374+
const rt_uint8_t align_size = 32;
378375
#else
379-
if (RT_IS_ALIGN((rt_uint32_t)send_buf, 4) && send_buf != RT_NULL) /* aligned with 4 bytes? */
376+
const rt_uint8_t align_size = 4;
377+
#endif
378+
/* Prepare DMA buffers only if the corresponding DMA will be used */
379+
if (send_buf && use_tx_dma && !RT_IS_ALIGN((rt_uint32_t)send_buf, align_size))
380380
{
381-
p_txrx_buffer = (rt_uint32_t *)send_buf; /* send_buf aligns with 4 bytes, no more operations */
381+
aligned_send_buf = rt_malloc_align(send_length, align_size);
382+
if (aligned_send_buf == RT_NULL)
383+
{
384+
state = HAL_ERROR;
385+
LOG_E("malloc aligned_send_buf failed!");
386+
break;
387+
}
388+
rt_memcpy(aligned_send_buf, send_buf, send_length);
389+
dma_send_buf = aligned_send_buf;
382390
}
383-
else
391+
392+
if (recv_buf && use_rx_dma && !RT_IS_ALIGN((rt_uint32_t)recv_buf, align_size))
384393
{
385-
/* send_buf doesn't align with 4 bytes, so creat a cache buffer with 4 bytes aligned */
386-
dma_aligned_buffer = (rt_uint32_t *)rt_malloc(send_length); /* aligned with RT_ALIGN_SIZE (8 bytes by default) */
387-
rt_memcpy(dma_aligned_buffer, send_buf, send_length);
388-
p_txrx_buffer = dma_aligned_buffer;
394+
aligned_recv_buf = rt_malloc_align(send_length, align_size);
395+
if (aligned_recv_buf == RT_NULL)
396+
{
397+
state = HAL_ERROR;
398+
LOG_E("malloc aligned_recv_buf failed!");
399+
break;
400+
}
401+
dma_recv_buf = aligned_recv_buf;
389402
}
390-
#endif /* SOC_SERIES_STM32H7 || SOC_SERIES_STM32F7 */
391-
}
392-
else if ((spi_drv->spi_dma_flag & SPI_USING_RX_DMA_FLAG) && (send_length >= DMA_TRANS_MIN_LEN))
393-
{
403+
394404
#if defined(SOC_SERIES_STM32H7) || defined(SOC_SERIES_STM32F7)
395-
if (RT_IS_ALIGN((rt_uint32_t)recv_buf, 32) && recv_buf != RT_NULL) /* aligned with 32 bytes? */
396-
{
397-
p_txrx_buffer = (rt_uint32_t *)recv_buf; /* recv_buf aligns with 32 bytes, no more operations */
398-
}
399-
else
400-
{
401-
/* recv_buf doesn't align with 32 bytes, so creat a cache buffer with 32 bytes aligned */
402-
dma_aligned_buffer = (rt_uint32_t *)rt_malloc_align(send_length, 32);
403-
rt_memcpy(dma_aligned_buffer, recv_buf, send_length);
404-
p_txrx_buffer = dma_aligned_buffer;
405-
}
406-
rt_hw_cpu_dcache_ops(RT_HW_CACHE_FLUSH, dma_aligned_buffer, send_length);
407-
#else
408-
if (RT_IS_ALIGN((rt_uint32_t)recv_buf, 4) && recv_buf != RT_NULL) /* aligned with 4 bytes? */
409-
{
410-
p_txrx_buffer = (rt_uint32_t *)recv_buf; /* recv_buf aligns with 4 bytes, no more operations */
411-
}
412-
else
413-
{
414-
/* recv_buf doesn't align with 4 bytes, so creat a cache buffer with 4 bytes aligned */
415-
dma_aligned_buffer = (rt_uint32_t *)rt_malloc(send_length); /* aligned with RT_ALIGN_SIZE (8 bytes by default) */
416-
rt_memcpy(dma_aligned_buffer, recv_buf, send_length);
417-
p_txrx_buffer = dma_aligned_buffer;
418-
}
419-
#endif /* SOC_SERIES_STM32H7 || SOC_SERIES_STM32F7 */
405+
// D-Cache maintenance for buffers that will be used by DMA
406+
if (dma_send_buf) rt_hw_cpu_dcache_ops(RT_HW_CACHE_FLUSH, (void *)dma_send_buf, send_length);
407+
if (dma_recv_buf) rt_hw_cpu_dcache_ops(RT_HW_CACHE_FLUSH, dma_recv_buf, send_length);
408+
#endif
420409
}
421410

422-
/* start once data exchange in DMA mode */
411+
/* Start data exchange in full-duplex DMA mode. */
423412
if (message->send_buf && message->recv_buf)
424413
{
425-
if ((spi_drv->spi_dma_flag & SPI_USING_TX_DMA_FLAG) && (spi_drv->spi_dma_flag & SPI_USING_RX_DMA_FLAG) && (send_length >= DMA_TRANS_MIN_LEN))
426-
{
427-
state = HAL_SPI_TransmitReceive_DMA(spi_handle, (uint8_t *)p_txrx_buffer, (uint8_t *)p_txrx_buffer, send_length);
428-
}
429-
else if ((spi_drv->spi_dma_flag & SPI_USING_TX_DMA_FLAG) && (send_length >= DMA_TRANS_MIN_LEN))
414+
if (use_tx_dma && use_rx_dma)
430415
{
431-
/* same as Tx ONLY. It will not receive SPI data any more. */
432-
state = HAL_SPI_Transmit_DMA(spi_handle, (uint8_t *)p_txrx_buffer, send_length);
433-
}
434-
else if ((spi_drv->spi_dma_flag & SPI_USING_RX_DMA_FLAG) && (send_length >= DMA_TRANS_MIN_LEN))
435-
{
436-
state = HAL_ERROR;
437-
LOG_E("It shoule be enabled both BSP_SPIx_TX_USING_DMA and BSP_SPIx_TX_USING_DMA flag, if wants to use SPI DMA Rx singly.");
438-
break;
416+
state = HAL_SPI_TransmitReceive_DMA(spi_handle, (uint8_t *)dma_send_buf, dma_recv_buf, send_length);
439417
}
440418
else
441419
{
442-
state = HAL_SPI_TransmitReceive(spi_handle, (uint8_t *)send_buf, (uint8_t *)recv_buf, send_length, timeout_ms);
420+
state = HAL_SPI_TransmitReceive(spi_handle, (uint8_t *)send_buf, recv_buf, send_length, timeout_ms);
443421
}
444422
}
445423
else if (message->send_buf)
446424
{
447-
if ((spi_drv->spi_dma_flag & SPI_USING_TX_DMA_FLAG) && (send_length >= DMA_TRANS_MIN_LEN))
425+
if (use_tx_dma)
448426
{
449-
state = HAL_SPI_Transmit_DMA(spi_handle, (uint8_t *)p_txrx_buffer, send_length);
427+
state = HAL_SPI_Transmit_DMA(spi_handle, (uint8_t *)dma_send_buf, send_length);
450428
}
451429
else
452430
{
@@ -461,16 +439,16 @@ static rt_ssize_t spixfer(struct rt_spi_device *device, struct rt_spi_message *m
461439
}
462440
else if(message->recv_buf)
463441
{
464-
rt_memset((uint8_t *)recv_buf, 0xff, send_length);
465-
if ((spi_drv->spi_dma_flag & SPI_USING_RX_DMA_FLAG) && (send_length >= DMA_TRANS_MIN_LEN))
442+
rt_memset(dma_recv_buf, 0xFF, send_length);
443+
if (use_rx_dma)
466444
{
467-
state = HAL_SPI_Receive_DMA(spi_handle, (uint8_t *)p_txrx_buffer, send_length);
445+
state = HAL_SPI_Receive_DMA(spi_handle, dma_recv_buf, send_length);
468446
}
469447
else
470448
{
471449
/* clear the old error flag */
472450
__HAL_SPI_CLEAR_OVRFLAG(spi_handle);
473-
state = HAL_SPI_Receive(spi_handle, (uint8_t *)recv_buf, send_length, timeout_ms);
451+
state = HAL_SPI_Receive(spi_handle, recv_buf, send_length, timeout_ms);
474452
}
475453
}
476454
else
@@ -491,10 +469,7 @@ static rt_ssize_t spixfer(struct rt_spi_device *device, struct rt_spi_message *m
491469
LOG_D("%s transfer done", spi_drv->config->bus_name);
492470
}
493471

494-
/* For simplicity reasons, this example is just waiting till the end of the
495-
transfer, but application may perform other tasks while transfer operation
496-
is ongoing. */
497-
if ((spi_drv->spi_dma_flag & (SPI_USING_TX_DMA_FLAG | SPI_USING_RX_DMA_FLAG)) && (send_length >= DMA_TRANS_MIN_LEN))
472+
if (use_tx_dma || use_rx_dma)
498473
{
499474
/* blocking the thread,and the other tasks can run */
500475
if (rt_completion_wait(&spi_drv->cpt, timeout_tick) != RT_EOK)
@@ -522,21 +497,16 @@ static rt_ssize_t spixfer(struct rt_spi_device *device, struct rt_spi_message *m
522497
}
523498
}
524499

525-
if(dma_aligned_buffer != RT_NULL) /* re-aligned, so need to copy the data to recv_buf */
500+
if (state == HAL_OK && aligned_recv_buf != RT_NULL)
526501
{
527-
if(recv_buf != RT_NULL)
528-
{
529502
#if defined(SOC_SERIES_STM32H7) || defined(SOC_SERIES_STM32F7)
530-
rt_hw_cpu_dcache_ops(RT_HW_CACHE_INVALIDATE, p_txrx_buffer, send_length);
531-
#endif /* SOC_SERIES_STM32H7 || SOC_SERIES_STM32F7 */
532-
rt_memcpy(recv_buf, p_txrx_buffer, send_length);
533-
}
534-
#if defined(SOC_SERIES_STM32H7) || defined(SOC_SERIES_STM32F7)
535-
rt_free_align(dma_aligned_buffer);
536-
#else
537-
rt_free(dma_aligned_buffer);
538-
#endif /* SOC_SERIES_STM32H7 || SOC_SERIES_STM32F7 */
503+
rt_hw_cpu_dcache_ops(RT_HW_CACHE_INVALIDATE, aligned_recv_buf, send_length);
504+
#endif
505+
rt_memcpy(recv_buf, aligned_recv_buf, send_length);
539506
}
507+
508+
if (aligned_send_buf) rt_free_align(aligned_send_buf);
509+
if (aligned_recv_buf) rt_free_align(aligned_recv_buf);
540510
}
541511

542512
if (message->cs_release && !(device->config.mode & RT_SPI_NO_CS) && (device->cs_pin != PIN_NONE))
@@ -562,8 +532,6 @@ static rt_err_t spi_configure(struct rt_spi_device *device,
562532

563533
struct stm32_spi *spi_drv = rt_container_of(device->bus, struct stm32_spi, spi_bus);
564534
spi_drv->cfg = configuration;
565-
rt_kprintf("@spi_configure\n");
566-
567535
return stm32_spi_init(spi_drv, configuration);
568536
}
569537

0 commit comments

Comments
 (0)