Memory to Memory - Scatter/Gather

This sample uses the GDMA scatter/gather function to achieve memory-to-memory data transfer.

Users can modify some GDMA settings, including channel configuration and data transfer length, through related macro configurations. For detailed descriptions of specific macro configuration items, please refer to Configuration.

Requirements

For hardware requirements, please refer to the Requirements.

Configurations

  1. The following macros can be used to configure whether to use the gather function or the scatter function.

    #define USE_GATHER      0       /*< Set this macro to 1 to use gather function. */
    #define USE_SCATTER     1       /*< Set this macro to 1 to use scatter function. */
    
  2. The following macros can be used to configure the parameters for gather or scatter.

    #define SCATTER_GATHER_BUFFER_SIZE              (20)
    #define SCATTER_GATHER_COUNT                    (4)
    #define SCATTER_GATHER_INTERVAL                 (1)
    
  1. The following macros represent the parameter configurations of the allocated GDMA channel.

    #define SCATTER_GATHER_DMA_CHANNEL_NUM     scatter_gather_dma_ch_num
    #define SCATTER_GATHER_DMA_CHANNEL         DMA_CH_BASE(scatter_gather_dma_ch_num)
    #define SCATTER_GATHER_DMA_IRQ             DMA_CH_IRQ(scatter_gather_dma_ch_num)
    
  2. The entry function is as follows, call this function in main() to run this sample code. For more details, please refer to the Initialization.

    dma_scrgar_demo();
    

Building and Downloading

For building and downloading, please refer to the Building and Downloading.

Experimental Verification

  1. Press the Reset button on the EVB.

  2. After initialization is complete, the GDMA begins transferring data. Once the GDMA completes the data transfer, it will trigger an interrupt. Observe the data transfer completion message displayed in the Debug Analyzer.

    scatter_gather_dma_handler: Data transmission completion!
    

Note

If an error is detected in the transferred data, observe the error information in the Debug Analyzer.

Code Overview

This section introduces the code and process description for initialization and corresponding function implementation in the sample.

Source Code Directory

The directory for project file and source code are as follows:

  • For project directory, please refer to Source Code Directory.

  • Source code directory: sdk\src\sample\io_demo\gdma\scatter_gather\dma_scrgar_demo.c.

Initialization

The initialization flow for peripherals can refer to Initialization Flow.

  1. In this sample, data is transferred from memory to memory, so there is no need to set PAD and PINMUX.

  2. Call RCC_PeriphClockCmd() to enable the GDMA clock.

  3. Call GDMA_channel_request to request a free GDMA channel and register the GDMA interrupt handler.

  4. Initialize the GDMA peripheral:

    1. Define a GDMA_InitTypeDef type GDMA_InitStruct, and call GDMA_StructInit() to pre-fill GDMA_InitStruct with default values.

    2. Modify the GDMA_InitStruct parameters as needed. The initialization parameters for the GDMA channel are configured as shown in the table below.

    GDMA Initialization Parameters

    GDMA Hardware Parameters

    Setting in the GDMA_InitStruct

    GDMA

    Channel Num

    GDMA_InitTypeDef::GDMA_ChannelNum

    SCATTER_GATHER_DMA_CHANNEL_NUM

    Transfer Direction

    GDMA_InitTypeDef::GDMA_DIR

    GDMA_DIR_MemoryToMemory

    Buffer Size

    GDMA_InitTypeDef::GDMA_BufferSize

    SCATTER_GATHER_BUFFER_SIZE

    Source Address Increment or Decrement

    GDMA_InitTypeDef::GDMA_SourceInc

    DMA_SourceInc_Inc

    Destination Address Increment or Decrement

    GDMA_InitTypeDef::GDMA_DestinationInc

    DMA_DestinationInc_Inc

    Source Data Size

    GDMA_InitTypeDef::GDMA_SourceDataSize

    GDMA_DataSize_Byte

    Destination Data Size

    GDMA_InitTypeDef::GDMA_DestinationDataSize

    GDMA_DataSize_Byte

    Source Burst Transaction Length

    GDMA_InitTypeDef::GDMA_SourceMsize

    GDMA_Msize_1

    Destination Burst Transaction Length

    GDMA_InitTypeDef::GDMA_DestinationMsize

    GDMA_Msize_1

    Source Address

    GDMA_InitTypeDef::GDMA_SourceAddr

    GDMA_SendBuffer

    Destination Address

    GDMA_InitTypeDef::GDMA_DestinationAddr

    GDMA_RecvBuffer

    Scatter Enable

    GDMA_InitTypeDef::GDMA_Scatter_En

    ENABLE

    Scatter Count

    GDMA_InitTypeDef::GDMA_ScatterCount

    SCATTER_GATHER_COUNT

    Scatter Interval

    GDMA_InitTypeDef::GDMA_ScatterInterval

    SCATTER_GATHER_INTERVAL

    Gather Enable

    GDMA_InitTypeDef::GDMA_Gather_En

    ENABLE

    Gather Count

    GDMA_InitTypeDef::GDMA_GatherCount

    SCATTER_GATHER_COUNT

    Gather Interval

    GDMA_InitTypeDef::GDMA_GatherInterval

    SCATTER_GATHER_INTERVAL

    1. Call GDMA_Init() to initialize the GDMA peripheral.

    2. Configure the GDMA total transfer completion interrupt: GDMA_INT_Transfer and NVIC. For NVIC-related configuration, refer to Interrupt Configuration.

  5. Call GDMA_Cmd() to enable GDMA channel for transmission.

Functional Implementation

  1. After enabling GDMA, GDMA begins transferring data from GDMA_SendBuffer to GDMA_RecvBuffer.

  2. If USE_SCATTER is set to 1, GDMA will scatter the data from the GDMA_SendBuffer into the GDMA_RecvBuffer, as shown in the figure below.

    ../../../_images/scatter.png

    GDMA Scatter Function

    Once the data transfer is completed, a GDMA total transfer completion interrupt GDMA_INT_Transfer interrupt is triggered. Within the interrupt handler, GDMA channel is closed, the GDMA channel interrupt flag is cleared, and it is checked whether the sent data is identical to the received data.

    uint32_t scatter_cnt = SCATTER_GATHER_BUFFER_SIZE / SCATTER_GATHER_COUNT;
    uint8_t send_value = 0;
    uint8_t recv_value = 0;
    
    for (uint32_t i = 0; i < scatter_cnt; i++)
    {
        for (uint32_t j = 0; j < SCATTER_GATHER_COUNT; j++)
        {
            send_value = GDMA_SendBuffer[i * SCATTER_GATHER_COUNT + j];
            recv_value = GDMA_RecvBuffer[i * (SCATTER_GATHER_COUNT + SCATTER_GATHER_INTERVAL) + j];
    
            if (send_value != recv_value)
            {
                IO_PRINT_ERROR4("scatter_gather_check_data: scatter check data failed i %d j %d source %d dest %d", i, j, send_value,
                               recv_value);
            }
        }
    }
    
  3. If USE_GATHER is set to 1, GDMA will gather the data scattered in the GDMA_SendBuffer into the GDMA_RecvBuffer, as shown in the figure below.

    ../../../_images/gather.png

    GDMA Gather Function

    Once the data transfer is completed, a GDMA total transfer completion interrupt GDMA_INT_Transfer interrupt is triggered. Within the interrupt handler, GDMA channel is closed, the GDMA channel interrupt flag is cleared, and it is checked whether the sent data is identical to the received data.

    uint32_t gather_cnt = SCATTER_GATHER_BUFFER_SIZE / SCATTER_GATHER_COUNT;
    uint8_t send_value = 0;
    uint8_t recv_value = 0;
    
    for (uint32_t i = 0; i < gather_cnt; i++)
    {
        for (uint32_t j = 0; j < SCATTER_GATHER_COUNT; j++)
        {
            send_value = GDMA_SendBuffer[i * (SCATTER_GATHER_COUNT + SCATTER_GATHER_INTERVAL) + j];
            recv_value = GDMA_RecvBuffer[i * SCATTER_GATHER_COUNT + j];
    
            if (send_value != recv_value)
            {
                IO_PRINT_ERROR4("scatter_gather_check_data: gather check data failed i %d j %d source %d dest %d", i, j, send_value,
                            recv_value);
            }
        }
    }