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