编程指南
- 源端与终端地址需要 4Byte 对齐。
- data_width 需与外设 FIFO 位宽对齐。
- task_len 设置需要与 data_width 对齐。

外设到外设传输
- task_len、block_len:必须与 max(src_width,dst_width)对齐。
- src_type=io_multi(或 io_fast) 与 dst_type=io_multi(或 io_fast) :
- 源端外设与终端外设,其 GPDMA 通路对应的 FIFO 水位配置需保持一致。
- block_len =外设 GPDMA 通路对应的 FIFO 水位。
- 假设 UART2SPI: UART 的 periph_fifo_level=8Bytes,SPI 的 periph_fifo_level=4Bytes,SPI_fifo_size=6Bytes,task_len=10Bytes,不满足源端外设 periph_fifo_level 必须等于终端外设 periph_fifo_level 的要求,会导致 GPDMA 工作异常。假设 task_len=8Bytes,则会把 SPI 的 FIFO 写满,导致溢出。假设 task_len=4,则 GPDMA 会等待 UART 的请求,但 UART 因数据量不足无法发出请求,最终导致 GPDMA 卡死,因为 UART 需要 8 个数据才能发出请求,但此时只有 6Bytes 数据,导致 GPDMA 卡死。
- 当 src_type=io_multi(或 io_fast) 与 dst_type=io_single: block_len 必须等于源端外设其 GPDMA 通路对应的 FIFO 水位。
- 当 src_type=io_single 与 dst_type=io_multi(或 io_fast) : block_len 必须等于终端外设其 GPDMA 通路对应的 FIFO 水位。
- 当 src_type=io_single 与 dst_type=io_single : 推荐 block_len =max(GPDMA 的 fifo_size,源端 fifo_size/2,终端 fifo_size/2)。
| 对象 | 参数 | 配置值例 1 | 配置值例 2 | 配置值例 3 | 配置值例 4 | 配置值例 5 | 配置值例 6 |
|---|---|---|---|---|---|---|---|
| 源端 SPI0 | width | 8 | 8 | 8 | 8 | 8 | 8 |
| type | io_single | io_single | io_single | io_single | io_multi (或 io_fast) | io_multi (或 io_fast) | |
| 终端 SPI1 | width | 32 | 8 | 32 | 8 | 32 | 8 |
| type | io_single | io_single | io_multi (或 io_fast) | io_multi (或 io_fast) | io_multi (或 io_fast) | io_multi (或 io_fast) | |
| 要求 | task_len 与 block_len 对齐要求 | 4Byte 对齐 | 1Byte 对齐 | 4Byte 对齐 | 1Byte 对齐 | 4Byte 对齐 | 1Byte 对齐 |
| 源端:SPI0 水位 | - | - | - | - | block_len | block_len | |
| 终端:SPI1 水位 | - | - | block_len | block_len | block_len | block_len |
Task 配置参数
当 link_src_sel=0,GPDMA 从 task_addr 与 task_h8bits_addr 对应地址空间读取 Task 配置参数。
操作流程如下:首先需要把 Task 配置参数,写到 Memory 空间。刷 Cache。(由于是 CPU 写,GPDMA 读,存在 Cache 一致性问题,需要刷一下 Cache,让数据实际写到物理存储器中)。然后把 Memory 空间对应地址写到 task_addr 与 task_h8bits_addr 寄存器。然后启动 GPDMA
当 link_src_sel=1,GPDMA 从 GPDMA_LINK_ID 、GPDMA_TASK_CFG_1 、GPDMA_BLOCK_LEN 、GPDMA_SRC_ADDR 、GPDMA_DST_ADDR 、GPDMA_TASK_LEN 、GPDMA_TASK_CFG_2 与 GPDMA_NEXT_TASK_ADDR 寄存器获取 Task 配置参数。对比 link_src_sel=0,主要少了刷 Cache 的动作。
Task 参数配置流程
GPDMA_LINK_ID =0xa1c8_6688
GPDMA_TASK_CFG_1 :dst_data_width、dst_type 与 dst_id 参考设备重要配置信息,dst_burst=3。src_data_width、src_type 与 src_id 参考设备重要配置信息,src_burst=3
GPDMA_BLOCK_LEN :block_len=外设 FIFO 触发 GPDMA 水位(或 GPDMA_FIFO_SIZE) 。
GPDMA_SRC_ADDR: 根据需求填写源端地址
GPDMA_DST_ADDR: 根据需求填写终端地址
GPDMA_TASK_LEN : 根据需求填写 task_len
GPDMA_TASK_CFG_2 :当为最后一个 Task:next_task_h8_addr 设置为 0xFF,否则为 0x00
GPDMA_NEXT_TASK_ADDR :根据 Link 中下一个 Task 具体地址填写
GPDMA 编程说明
以下是以 SRAM 搬运数据到 SPI (SPI0) 为例的 GPDMA 配置步骤:
- 初始化参数。
表 2. GPDMA 编程初始化参数示例 源端 终端 SRAM (假设 src _width=32) src_width = 32src_type = memory
SPI (SPI0, id=8) dst_width = 32dst_type = io_multi
- 设置 block_len=16(Bytes)。
- 初始化 SPI ,并将 SPI 的 FIFO 水位设置为与 block_len 相等。此处设为 16
- 使能 GPDMA 模块时钟、释放 GPDMA 复位并使能 GPDMA 中断。
- 配置任务链表内容如下(链表存储器必须 4Bytes 对齐):
表 3. GPDMA 任务链表编程示例 地址 参数描述 备注 0xa1c8_6688 GPDMA_LINK_ID TASK_LINK_ID 需要与 SET 一致。 0x2288_2580
GPDMA_TASK_CFG_1 - 0x0000_0010 GPDMA_BLOCK_LEN - 0x9004_7444 GPDMA_SRC_ADDR 源端地址:sram 首地址 0x913f_0200 GPDMA_DST_ADDR 终端:SPI0 TX_FIFO 地址 0x0000_00f4 GPDMA_TASK_LEN - 0x55ff_0000 GPDMA_TASK_CFG_2 使用推荐值 0x55ff_0000。因为只有一个 task,故下一任务高 8bit 地址 =0xff 0xffff_fffc GPDMA_NEXT_TASK_ADDR 因为只有一个 task,故下一任务低 32bit 地址 =0xffff_fffc。下一任务高 8bit 地址 + 下一任务低 32bit 地址 =0xff_fffffffc,表示 GPDMA Link 结束。 - 把任务链表首地址 (0x900406e0),写到 GPDMA 所对应通道的 GPDMA_CH_TASK_ADD_1 寄存器中。
- 启动 GPDMA 传输,等待 GPDMA 传输完成中断。
