Transmit and Recieve - DMA

该示例使用 UARTDMA 与PC终端进行数据通信。
MCU使用DMA将数据发送到PC终端程序(如PUTTY或UartAssist),DMA将数据从Memory传输到UART TX FIFO外设。
MCU使用DMA接收PC终端输入的数据,GDMA将数据从UART RX FIFO 外设传输到Memory。
一旦DMA传输完成,MCU将缓冲数据发送回PC终端。

环境需求

该示例支持以下开发套件:

开发套件

Hardware Platforms

Board Name

RTL87x2G HDK

RTL87x2G EVB

更多信息请参考 快速入门

硬件连线

连接P3_0和RX,P3_1和TX。

编译和下载

该示例的工程路径如下:

Project file: samples\peripheral\uart\trx_gdma\proj\rtl87x2g\mdk

Project file: samples\peripheral\uart\trx_gdma\proj\rtl87x2g\gcc

请按照以下步骤操作构建并运行该示例:

  1. 打开工程文件。

  2. 按照 快速入门编译APP Image 给出的步骤构建目标文件。

  3. 编译成功后,在路径 mdk\bingcc\bin 下会生成 app bin app_MP_xxx.bin 文件。

  4. 按照 快速入门MPTool 给出的步骤将app bin烧录至EVB内。

  5. 按下复位按键,开始运行。

测试验证

准备阶段

  1. 启动 PuTTY 或 UartAssist 等PC终端,连接到使用的COM端口,并进行以下UART设置:

  • 波特率: 115200

  • 8 数据位

  • 1 停止位

  • 无校验

  • 无硬件流控

测试阶段

  1. 当EVB启动后,在DebugAnalyzer工具内观察如下LOG。

    Start uart tx rx by gdma test!
    
  2. 该示例开始发送 ### Uart trx gdma sample\r\n ,观察PC终端上出现的字符串。

  3. MCU向PC终端发送29个十六机制数(该示例TX Block size UART_TX_GDMA_BUFFER_SIZE 设置为29): 10 11 12 ... 2C, 观察PC终端上显示这29个十六进制数。

  4. 在PC终端上输入超过29个字符(该示例RX Block size UART_RX_GDMA_BUFFER_SIZE 设置为29)。观察PC终端上是否显示相同的字符。

代码介绍

该章节分为以下几个部分:

  1. 源码路径

  2. 初始化函数将在 初始化 章节介绍。

  3. 初始化后的功能实现将在 功能实现 章节介绍。

源码路径

  • 工程路径: sdk\samples\peripheral\uart\trx_gdma\proj

  • 源码路径: sdk\samples\peripheral\uart\trx_gdma\src

该工程的工程文件代码结构如下:

└── Project: output_toggle
    └── secure_only_app
        └── Device                   includes startup code
            ├── startup_rtl.c
            └── system_rtl.c
        ├── CMSIS                    includes CMSIS header files
        ├── CMSE Library             Non-secure callable lib
        ├── lib                      includes all binary symbol files that user application is built on
            └── rtl87x2g_io.lib
        ├── peripheral               includes all peripheral drivers and module code used by the application
            ├── rtl_gdma.c
            ├── rtl_nvic.c
            ├── rtl_pinmux.c
            ├── rtl_rcc.c
            └── rtl_uart.c
        └── APP                      includes the ble_peripheral user application implementation
            ├── io_uart.c
            └── main_ns.c

初始化

初始化流程包括了 board_uart_initdriver_uart_init


board_uart_init 中包含了PAD与PINMUX设置:

  1. 配置PAD:设置引脚、PINMUX模式、PowerOn、内部上拉。

  2. 配置PINMUX:分配引脚分别为UART3_TX、UART3_RX功能。


driver_uart_init 包含了对uart外设的初始化:

  1. 使能PCC时钟源。

  2. 设置波特率为115200,校验位为无奇偶校验,停止位为1位,数据长度为8bits。

  3. 使能UART DMA传输。

  4. 设置UART_TxWaterLevel为1,推荐设置为 GDMA_MSize

  5. 设置UART_RxWaterLevel为1,推荐设置为 GDMA_MSize

  6. 使能UART TX DMA, RX DMA。

RCC_PeriphClockCmd(APBPeriph_UART3, APBPeriph_UART3_CLOCK, ENABLE);
...
UART_InitStruct.UART_Div            = BaudRate_Table[BAUD_RATE_115200].div;
UART_InitStruct.UART_Ovsr           = BaudRate_Table[BAUD_RATE_115200].ovsr;
UART_InitStruct.UART_OvsrAdj        = BaudRate_Table[BAUD_RATE_115200].ovsr_adj;
...
UART_InitStruct.UART_DmaEn          = UART_DMA_ENABLE;
UART_InitStruct.UART_TxWaterLevel   = 1; /* Better to equal: GDMA_MSize */
UART_InitStruct.UART_RxWaterLevel   = 1; /* Better to equal: GDMA_MSize */
UART_InitStruct.UART_TxDmaEn        = ENABLE;
UART_InitStruct.UART_RxDmaEn        = ENABLE;

执行 UART_SendDataByGDMA ,初始化GDMA发送数据。

  1. 使用GDMA通道3。

  2. GDMA传输方向为 内存外设 传输。

  3. 源端地址设置为 GDMA_SendData_Buffer ,目的端地址设置为 (&(UART_DEMO->UART_RBR_THR))

  4. 使能GDMA通道3传输完成中断 GDMA_INT_Transfer

  5. 使能GDMA通道3传输。

GDMA_InitStruct.GDMA_ChannelNum       = UART_TX_GDMA_CHANNEL_NUM;
GDMA_InitStruct.GDMA_DIR              = GDMA_DIR_MemoryToPeripheral;
...
GDMA_InitStruct.GDMA_SourceAddr       = (uint32_t)GDMA_SendData_Buffer;
GDMA_InitStruct.GDMA_DestinationAddr  = (uint32_t)(&(UART_DEMO->UART_RBR_THR));
...
GDMA_INTConfig(UART_TX_GDMA_CHANNEL_NUM, GDMA_INT_Transfer, ENABLE);
...
GDMA_Cmd(UART_TX_GDMA_CHANNEL_NUM, ENABLE);

执行 UART_ReceiveDataByGDMA ,初始化GDMA接收数据。

  1. 使用GDMA通道4。

  2. GDMA传输方向为 外设内存 传输。

  3. 源端地址设置为 (&(UART_DEMO->RB_THR)) ,目的端地址设置为 GDMA_ReceiveData_Buffer

  4. 使能GDMA通道4传输完成中断 GDMA_INT_Transfer

  5. 使能GDMA通道4传输。

GDMA_InitStruct.GDMA_ChannelNum       = UART_RX_GDMA_CHANNEL_NUM;
GDMA_InitStruct.GDMA_DIR              = GDMA_DIR_PeripheralToMemory;
...
GDMA_InitStruct.GDMA_SourceAddr       = (uint32_t)(&(UART_DEMO->UART_RBR_THR));
GDMA_InitStruct.GDMA_DestinationAddr  = (uint32_t)GDMA_ReceiveData_Buffer;
...
GDMA_INTConfig(UART_RX_GDMA_CHANNEL_NUM, GDMA_INT_Transfer, ENABLE);
...
GDMA_Cmd(UART_RX_GDMA_CHANNEL_NUM, ENABLE);

功能实现

  1. 执行 uart_senddata_continuous ,发送 ### Uart trx gdma sample ###\r\n 到PC终端。

  2. 执行 GDMA_Cmd() 即开始GDMA从Memory向UART TX FIFO传输数据,当GDMA传输完成时,会触发 GDMA_INT_Transfer 中断,进入中断处理函数 UART_TX_GDMA_Handler

    1. 清除GDMA通道3 GDMA_INT_Transfer 中断标志位。

    2. 打印GDMA传输发送数据完成信息。

GDMA_ClearINTPendingBit(UART_TX_GDMA_CHANNEL_NUM, GDMA_INT_Transfer);

DBG_DIRECT("UART_TX_GDMA_Handler, Data transmission completion!");
  1. 在PC终端输入字符,即开始GDMA从UART RX FIFO向Memory传输数据,当输入字符超过29个字符(1 Block)时,触发 GDMA_INT_Transfer 中断,进入中断处理函数 UART_RX_GDMA_Handler

    1. 清除GDMA通道1 GDMA_INT_Transfer 中断标志位。

    2. 执行 uart_senddata_continuous ,将GDMA收到的数据发回PC终端。

    3. 打印GDMA传输完成信息。

GDMA_ClearINTPendingBit(UART_RX_GDMA_CHANNEL_NUM, GDMA_INT_Transfer);

DBG_DIRECT("UART_RX_GDMA_Handler, Data transmission completion!");

uart_senddata_continuous(UART_DEMO, GDMA_ReceiveData_Buffer, UART_RX_GDMA_BUFFER_SIZE);