Memory to Memory - Multi Block
This sample uses the multi block feature of GDMA to achieve data transfer from memory to memory.
When the total size of the data to be transferred exceeds 65535, the multi block feature needs to be used.
In this sample, the multi block feature uses a block link list for transmission, which can divide larger data into several link list items for transfer, ensuring that the data amount of each link list item does not exceed 65535.
Users can modify some GDMA settings through relevant macro configurations, including the types of interrupts enabled, channel configuration, and data transfer length. For detailed explanations of specific macro configuration items, please refer to Configurations.
Requirements
For hardware requirements, please refer to the Requirements.
Configurations
The following macros can be configured to modify the GDMA data transfer length.
#define GDMA_TRANSFER_SIZE 200 /*< Set this macro to modify the transfer size. */ #define GDMA_MULTIBLOCK_SIZE 12 /*< Set this macro to modify the block size. */
The following macros represent the parameter configurations of the allocated GDMA channel.
#define MULTI_BLOCK_DMA_CHANNEL_NUM multi_block_dma_ch_num #define MULTI_BLOCK_DMA_CHANNEL DMA_CH_BASE(multi_block_dma_ch_num) #define MULTI_BLOCK_DMA_IRQ DMA_CH_IRQ(multi_block_dma_ch_num)
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_multiblock_demo();
Building and Downloading
For building and downloading, please refer to the Building and Downloading.
Experimental Verification
Press the Reset button on the EVB.
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.
multi_block_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\multiblock\dma_multiblock_demo.c
.
Initialization
The initialization flow for peripherals can refer to Initialization Flow.
In this sample, data is transferred from memory to memory, so there is no need to set PAD and PINMUX.
Call
RCC_PeriphClockCmd()
to enable the GDMA clock.Call
GDMA_channel_request
to request a free GDMA channel and register the GDMA interrupt handler.Initialize the GDMA peripheral:
Define a
GDMA_InitTypeDef
typeGDMA_InitStruct
, and callGDMA_StructInit()
to pre-fillGDMA_InitStruct
with default values.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
MULTI_BLOCK_DMA_CHANNEL_NUM
Transfer Direction
Buffer Size
GDMA_TRANSFER_SIZE
Source Address Increment or Decrement
Destination Address Increment or Decrement
Source Data Size
Destination Data Size
Source Burst Transaction Length
Destination Burst Transaction Length
Source Address
GDMA_SendBuffer
Destination Address
GDMA_RecvBuffer
Multi-block Enable
1
Multi-block Mode
Multi-block Struct
GDMA_LLIStruct
Configure the information of the LLI structure.
Configure
GDMA_LLIDef::SAR
as the source address for each block transfer, and configureGDMA_LLIDef::DAR
as the destination address for each block transfer.Configure
GDMA_LLIDef::LLP
as a pointer to the LLI structure corresponding to the next block, to link the next transfer unit in multi-block transfers.Configure
GDMA_LLIDef::CTL_LOW
with the basic information of the GDMA transfer; refer to the sample for specific configuration.Configure
GDMA_LLIDef::CTL_HIGH
with the amount of data transferred for each block, with its value beingGDMA_InitTypeDef::GDMA_BufferSize
.
for (int i = 0; i < GDMA_MULTIBLOCK_SIZE; i++) { if (i == (GDMA_MULTIBLOCK_SIZE - 1)) { //GDMA_LLIStruct[i].LLP=0; GDMA_LLIStruct[i].SAR = (uint32_t)GDMA_SendBuffer[i]; GDMA_LLIStruct[i].DAR = (uint32_t)GDMA_RecvBuffer[i]; GDMA_LLIStruct[i].LLP = 0; /* configure low 32 bit of CTL register */ GDMA_LLIStruct[i].CTL_LOW = BIT(0) | (GDMA_InitStruct.GDMA_DestinationDataSize << 1) | (GDMA_InitStruct.GDMA_SourceDataSize << 4) | (GDMA_InitStruct.GDMA_DestinationInc << 7) | (GDMA_InitStruct.GDMA_SourceInc << 9) | (GDMA_InitStruct.GDMA_DestinationMsize << 11) | (GDMA_InitStruct.GDMA_SourceMsize << 14) | (GDMA_InitStruct.GDMA_DIR << 20); /* configure high 32 bit of CTL register */ GDMA_LLIStruct[i].CTL_HIGH = GDMA_InitStruct.GDMA_BufferSize; } else { GDMA_LLIStruct[i].SAR = (uint32_t)GDMA_SendBuffer[i]; GDMA_LLIStruct[i].DAR = (uint32_t)GDMA_RecvBuffer[i]; GDMA_LLIStruct[i].LLP = (uint32_t)&GDMA_LLIStruct[i + 1]; /* configure low 32 bit of CTL register */ GDMA_LLIStruct[i].CTL_LOW = BIT(0) | (GDMA_InitStruct.GDMA_DestinationDataSize << 1) | (GDMA_InitStruct.GDMA_SourceDataSize << 4) | (GDMA_InitStruct.GDMA_DestinationInc << 7) | (GDMA_InitStruct.GDMA_SourceInc << 9) | (GDMA_InitStruct.GDMA_DestinationMsize << 11) | (GDMA_InitStruct.GDMA_SourceMsize << 14) | (GDMA_InitStruct.GDMA_DIR << 20) | (GDMA_InitStruct.GDMA_Multi_Block_Mode & LLP_SELECTED_BIT); /* configure high 32 bit of CTL register */ GDMA_LLIStruct[i].CTL_HIGH = GDMA_InitStruct.GDMA_BufferSize; } }
Call
GDMA_Init()
to initialize the GDMA peripheral.Configure the GDMA block transfer completion interrupt:
GDMA_INT_Block
and NVIC. For NVIC-related configuration, refer to Interrupt Configuration.
Call
GDMA_Cmd()
to enable GDMA channel for transmission.
Functional Implementation
After enabling GDMA, GDMA begins transferring data from
GDMA_SendBuffer
toGDMA_RecvBuffer
. A block Transfer Complete interruptGDMA_INT_Block
will be triggered whenever a block transfer is completed. Within the interrupt handler, record the number of blocks that have been transferred. When the number of transmitted blocks equals the set value, compare whether the sent data is equal to the received data.GDMA_ClearAllTypeINT(MULTI_BLOCK_DMA_CHANNEL_NUM); block_cnt++; if (block_cnt == GDMA_MULTIBLOCK_SIZE) { /* Compare whether the destination data which transported by GDMA is equal to the source data*/ for (uint32_t i = 0; i < GDMA_MULTIBLOCK_SIZE; i++) { for (uint32_t j = 0; j < GDMA_TRANSFER_SIZE; j++) { if (GDMA_SendBuffer[i][j] != GDMA_RecvBuffer[i][j]) { IO_PRINT_ERROR4("multi_block_dma_handler: Data transmission error! index %d %d GDMA_SendBuffer = %d, GDMA_RecvBuffer = %d", i, j, GDMA_SendBuffer[i][j], GDMA_RecvBuffer[i][j]); } } } IO_PRINT_INFO0("multi_block_dma_handler: Data transmission completion!"); }