DMAC 配置

DMA 一般配置流程如下:

  1. 初始化时钟:打开 DMA 控制器(DMAC)时钟

  2. 配置相关 DMA 通道

  1. 申请一个空闲的 DMA 通道

  2. 根据应用需求,配置通道控制参数

  1. 传输方向和流控:如内存到外设、外设到内存等,以及由源或目的外设、或 DMAC 控制传输请求和节奏

  2. 源端口和目的端口地址

  3. 传输宽度(1/2/4 Bytes)

  4. 突发长度 msize(1/4/8/16)

  5. 传输块大小(Block Size)

  6. 优先级设置

  1. 使能通道中断(如需传输完成/异常通知)

  2. 启动数据传输:打开通道使能位,启动 DMA 通道,外设/DMAC 发起 DMA 请求,启动数据搬运过程

  3. 结束与后处理

    1. DMA 传输完成后,产生中断

    2. 在中断服务函数中处理完成信号、释放资源等

DMA 参数示意图如下所示:

../../../_images/dmac_block_size_diagram.svg

通道申请和释放

DMA 通过以下两个 API 实现通道的申请和释放:

  • GDMA_ChnlAlloc() :按顺序从通道 0 开始分配

  • GDMA_ChnlFree() :按照指定的通道编号释放通道

通道申请过程中,可能出现两个 CPU 同时申请一个通道,这会导致程序运行异常。为解决该问题,在通道申请过程中,会使用硬件信号量来 保护。

传输方向和流控制器

目前共有四种传输方向和两种流控制器设置,共八种可用配置。

  • 当外设作为流控制器时,DMA 将根据外设发出的单次/突发请求进行数据传输。

  • 当 DMAC 作为流控制器时,所有来自外设的请求都将按照配置的请求进行处理。

CTLx.TT_FC[2:0](x为通道编号)

方向

流控制器

000

内存 到 内存

DMAC

001

内存 到 外设

DMAC

010

外设 到 内存

DMAC

011

外设 到 外设

DMAC

100

外设 到 内存

外设

101

外设 到 外设

源外设

110

内存 到 外设

外设

111

外设 到 外设

目的外设

流控制器配置原则:

  • 如果 block_ts 已知,使用 DMAC 作为流控制器。例如播放音乐、图片等,以及搬运内存数据。

  • 如果 block_ts 未知,使用外设作为流控制器。例如 UART 接收不定长数据,可以让 UART 做流控制器,每当有数据来临再请求传输。

警告

  • 仅当 DMAC 用作流控制器时,才能设置 block_ts 参数。

  • 使用外设作为流控制器,需要确保 IP 在硬件设计上支持触发 DMA 请求。详情可参考 握手 章节。

数据块大小

RTL8721Dx:

上图阐述了 DMAC 传输数据大小的设置。block_ts 表示将在单个数据块中传输的数据量,需要设置为 总数据量/SRC_TR_WIDTH,最大值是 {{IC_PARAM_GDMA_BLOCK_SIZE}}

事务模式和宽度

DMAC 传输时,单次传输事务(Transaction)的大小可配置:

  • msize > 1:突发传输

  • msize = 1:单次传输

CTLx.SRC_MSIZE[2:0]/DEST_MSIZE[2:0]

传输 msize

000

1

001

4

010

8

011

16

100 及以上

不支持

DMAC 支持以下传输宽度:

CTLx.SRC_TR_WIDTH[2:0]/DST_TR_WIDTH[2:0]

传输宽度/Byte

000

1

001

2

010

4

011 及以上

不支持

  • 当 DMAC 作为流控制器,单个数据块传输到最后,剩余的数据量不足以完成一次 Msize * Width 传输,但满足一次 1 * Width 传输,DMAC 将发起单次传输请求,完成传输。

  • 当外设作为流控制器,外设决定发出单次传输还是突发传输请求。

备注

  • 读写外设时: SRC_TR_WIDTH/DST_TR_WIDTH 根据外设的数据宽度决定。

  • 读写内存时:

    • 如果缓存被禁用,内存地址无需对齐,但需确保总数据量能被 SRC_TR_WIDTH 整除,以保证 block_ts 为整数。

    • 如果缓存被启用,内存地址必须满足缓冲区边界对齐,且需按缓存行对齐。

  • 当源或者目的是内存时(如 P2M、M2M 模式):硬件将强制 Memory 端的传输位宽为 4 Bytes,配置的 DST_TR_WIDTHSRC_TR_WIDTH 参数将被忽略。

  • 为防止 FIFO 溢出或下溢,要求 SRC_MSIZE * SRC_TR_WIDTH 必须等于 DST_MSIZE * DST_TR_WIDTH

传输类型

DMAC 支持以下传输类型:

  • Single Block: 仅包含一个数据块

  • Multi-Block:包含多个数据块

    • 自动重加载(Auto-reloading)模式

    • 链表(Link List)模式

    • 连续(Continuous)模式

各个模式使用场景及特点如下:

DMAC 各模式特点

模式

子模式

使用场景

特点

Single Block

地址空间连续且仅传输一次

  • 传输完成后 DMA 立即停止

Multi-Block

auto-reload

地址空间连续且源端或者目的端需要重复加载某一个数据块

  • 若开启块中断,每个块传输完成都会暂停,直到中断处理结束

Link List

地址空间非连续

  • 若开启块中断,每个块传输完成后触发中断,但将立即传输下一个块

  • 该模式下,即便进入中断也不会阻碍 DMA 数据传输

continuous

单个地址空间连续的数据块

  • 始终保持地址递增模式,若源和目的端均为 continuous 模式,则传输与 single block 相同

  • 通常用于仅一端为连续地址、另一端使用 auto-reload 或 Link List 模式的场景

Auto-reloading 模式

在 auto-reloading 模式下,源和目标可分别选择使用的方法。

Auto-reloading 传输类型

设置

说明

Src auto reload

PGDMA_InitTypeDef->GDMA_ReloadSrc = 1

PGDMA_InitTypeDef->GDMA_ReloadDst = 0

对多块传输(multi-block transfers),每块结束时SAR寄存器会从初始值自动重载,目的地址连续,如

Multi-Block 传输-源地址自动重载&目的地址连续 所示。

Dst auto reload

PGDMA_InitTypeDef->GDMA_ReloadSrc = 0

PGDMA_InitTypeDef->GDMA_ReloadDst = 1

对多块传输,每块结束时DAR寄存器会从初始值自动重载,源地址连续。

Src & Dst auto reload

PGDMA_InitTypeDef->GDMA_ReloadSrc = 1

PGDMA_InitTypeDef->GDMA_ReloadDst = 1

对多块传输,每块结束时SAR和DAR寄存器都会从初始值自动重载,如 Multi-Block 传输-源和目的地址均自动重载 所示。

../../../_images/mbd_source_auto_dest_cont.png

Multi-Block 传输-源地址自动重载&目的地址连续

../../../_images/mbd_source_dest_auto.png

Multi-Block 传输-源和目的地址均自动重载

地址递增类型

源地址递增

包含两种模式:

  • 递增(Increment):表示在每次源端传输时,源地址是否递增。递增操作用于对齐到下一个 CTLx.SRC_TR_WIDTH 边界。

  • 不变(No change):如果设备从具有固定地址的源外设 FIFO 读取数据,则应将该字段设置为"不变"。

目的地址递增

包含两种模式:

  • 递增(Increment):表示在每次目的端传输时,目的地址是否递增。递增操作用于对齐到下一个 CTLx.DST_TR_WIDTH 边界。

  • 不变(No change):如果设备将数据写入到具有固定地址的目的外设 FIFO,则应将该字段设置为"不变"。

配置原则:

  • 如果源端或者目的端为 Memory,地址模式一般设置为 Increment

  • 如果源端或者目的端为外设,地址模式一般设置为 No Change

FIFO

每个 DMAC 通道都有自己独立的 FIFO,且不同通道的 FIFO 大小不同。

RTL8721Dx:
FIFO Size

通道号

CH0

CH1

CH2~CH7

FIFO 大小/Bytes

128

128

32

中断类型

DMAC 支持多种中断类型,这些中断可独立使用或组合使用。

中断类型

说明

块中断

单个数据块传输完成触发

传输中断

所有数据块传输完毕时产生

错误中断

传输过程中发生错误

备注

  • 多块 auto-reload 模式下,块中断触发后将暂停传输,待中断处理函数执行完毕后再继续。

  • Link List 模式的传输完成条件为:最后一个数据块的下一数据块指针为空。

  • Link List 模式下,块中断不会暂停传输,下一个数据块将立即开始传输。

挂起和终止

DMAC 支持通道的挂起恢复和强制终止。

  • 挂起通道:直接配置 CFGx.CH_SUSP,但不保证当前数据传输已完成。需结合 CFGx.INACTIVE 状态检测,方可安全暂停且不丢失数据。

  • 恢复传输:清除 CFGx.CH_SUSP 即可继续进行数据传输。

  • 终止传输:需持续轮询 CFGx.INACTIVE 直至该位设为 1,方可终止传输。

备注

CFGx.INACTIVE 用于指示通道在 AXI 总线上是否处于空闲状态(1 = 非活跃,0 = 活跃)。可与 CFGx.CH_SUSP 配合使用,在目的端为外设时安全关闭通道。通道进入非活跃状态的场景:

  • DMAC 完成所有待写数据的内存写入操作后,CFGx.INACTIVE 自动置 1。

  • 外设数据宽度(如 4 字节)超出 DMAC FIFO 剩余空间(如 2 字节),无法发起写操作,CFGx.INACTIVE 立即置 1。

聚集和分散

RTL8721Dx:

不支持。

优先级

DMAC 支持两种通道优先级:

  • 软件:各通道优先级可通过 CFGx.CH_PRIOR 配置,有效值范围为 0 ~ (DMAC_NUM_CHANNELS-1)。其中, 0 为最高优先级, DMAC_NUM_CHANNELS-1 为最低优先级。

  • 硬件:若两个通道请求的软件优先级相同,或未配置软件优先级,通道编号较小的通道优先级更高(例如:通道 2 优先级高于通道 4)。

握手

DMAC 仅支持硬件握手,不支持软件握手。仅在与外设进行数据传输时,才需配置握手接口。所有硬件握手接口在 IC 设计阶段已固定,用户无法自行更改。 当前 IC 支持的硬件握手接口及其对应 IP 如下表所示:

RTL8721Dx:
DMAC 握手接口

功能

握手编号

说明

UART0 TX

0

UART0 RX

1

UART1 TX

2

UART1 RX

3

UART2 TX

4

UART2 RX

5

SPI0 TX

6

SPI0 RX

7

SPI1 TX

8

SPI1 RX

9

SPIC TX

10

SPIC RX

11

SPORT0 TX

12

两个FIFO,占用编号12和13

SPORT0 RX

14

两个FIFO,占用编号14和15

SPORT1 TX

16

两个FIFO,占用编号16和17

SPORT1 RX

18

两个FIFO,占用编号18和19

LEDC_TX

20

I2C0 TX

21

I2C0 RX

22

I2C1 TX

23

I2C1 RX

24

实时状态获取

DMAC 支持实时获取当前传输的源地址、目的地址和已传输数据量。

需调用对应 API 读取。

备注

若要获取已传输数据量,block_ts 必须至少大于 768,且不可在中断函数中读取;否则,获取的值始终为 0。

安全机制

默认情况下,DMAC 的安全传输功能处于关闭状态。当用户需要使用该功能时,需首先开启 Trustzone 功能

DMAC 支持针对每个通道独立配置安全传输功能。启用该功能后,DMAC 将通过 AXI 主机接口发起 Secure 访问请求。此时,DMAC 可以在安全和非安全的外设(或内存)之间传递数据。

  • 安全通道仅能在安全世界中配置,且安全通道可访问安全外设(内存)和非安全外设(内存);

  • 非安全通道仅能访问非安全外设(内存)。

要启用某通道的安全传输特性,可在 Secure 代码中配置 DMAC 参数时,设置如下结构体成员:

PGDMA_InitTypeDef->SecureTransfer = 1;