Edit online

编程指南

注:
  • 源端与终端地址需要 4Byte 对齐。
  • data_width 需与外设 FIFO 位宽对齐。
  • task_len 设置需要与 data_width 对齐。

dma_flow1

1. GPDMA 编程指南

外设到外设传输

  • 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)。
以 SPI 为例,源端为 SPI0,终端为 SPI1。SPI 的 width 支持 8 或者 32。
1. 外设与外设传输编程示例
对象 参数 配置值例 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 配置步骤:

  1. 初始化参数。
    2. GPDMA 编程初始化参数示例
    源端 终端
    SRAM (假设 src _width=32)
    • src_width = 32
    • src_type = memory
    SPI (SPI0, id=8)
    • dst_width = 32
    • dst_type = io_multi
  2. 设置 block_len=16(Bytes)。
  3. 初始化 SPI ,并将 SPI 的 FIFO 水位设置为与 block_len 相等。此处设为 16
  4. 使能 GPDMA 模块时钟、释放 GPDMA 复位并使能 GPDMA 中断。
  5. 配置任务链表内容如下(链表存储器必须 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 结束。
  6. 把任务链表首地址 (0x900406e0),写到 GPDMA 所对应通道的 GPDMA_CH_TASK_ADD_1 寄存器中。
  7. 启动 GPDMA 传输,等待 GPDMA 传输完成中断。