xf2016的个人空间 https://blog.eetop.cn/?1536195 [收藏] [复制] [分享] [RSS]

日志

使用AHB dmac的关键问题详细解释

已有 62 次阅读| 2025-9-18 14:49 |个人分类:AMBA|系统分类:芯片设计| AHB, DMAC

在 DW_ahb_dmac 的语境中,一个 “Block” 通常指的是一次 DMA 传输事务(Transaction)中,不可分割的一组连续数据传输。它是由控制器硬件自动完成的一个完整数据块移动操作。

为了更好地理解,我们可以将其分解:

1. Block 的核心概念

一个 Block 是 DMA 控制器配置和执行的一个基本传输单元。当您启动一次 DMA 传输时,您通常是在请求控制器移动一个“Block”的数据。

  • 它不是软件中的“函数”或“代码块”,而是硬件操作的一个数据块。

  • 它通常对应一次 AHB 总线上的 Burst 传输序列。AHB 总线高效的原因之一就是支持 Burst(突发)传输,可以在一次地址握手后连续传输多个数据。一个 Block 通常就由这样的一个 Burst 序列构成。

2. Block 的构成:如何定义一个大小的 Block?

一个 Block 的大小和行为是由 DMA 通道的寄存器配置决定的,主要包括:

  • 传输宽度 (CTLx.SRC_TR_WIDTH & CTLx.DST_TR_WIDTH):决定一次传输操作的基本单位是字节(8bit)、半字(16bit)还是字(32bit)。

  • Block 传输大小 (CTLx.BLOCK_TS):这是定义 Block 大小的核心寄存器。它指定了在这个 Block 中,要进行多少次“基本传输单位”的传输。

    • 例如:如果传输宽度设置为字(32位/4字节),且       BLOCK_TS = 10,那么这个 Block 将传输 10 * 4字节 = 40字节 的数据。

  • 源和目标地址 (SARx, DARx):定义了 Block 传输的起始地址。

  • 地址控制 (CTLx.SRC_INC, CTLx.DST_INC):决定每传输一个“基本单位”后,地址是递增、递减还是保持不变。

                                               


 

3. 一个具体的例子

假设我们配置 DMA 通道如下:

  • SRC_TR_WIDTH      = 2 (代表 32位,即      1 Word = 4 Bytes)

  • DST_TR_WIDTH      = 2 (代表 32位,即      1 Word = 4 Bytes)

  • BLOCK_TS = 4      (表示这个 Block 要传输 4 个 “Word”)

  • SRC_INC = 1 (源地址递增)

  • DST_INC = 1 (目标地址递增)

那么这次 Block 传输的过程将是:

  1. cpu 启动 DMA 传输。

  2. DMA 控制器成为一个 AHB 总线主设备,并发起一次      Burst 传输。

  3. 控制器会连续从源地址      (SARx) 读取 4 次数据,每次读取 32 位(1 Word)。

  4. 每读一次,源地址自动增加 4 字节(因为宽度是 32位)。

  5. 同时,控制器将读到的数据连续写入目标地址 (DARx) 4 次。

  6. 每写一次,目标地址自动增加 4 字节。

  7. 传输完 4 个 Word(共 16 字节)后,整个 Block 传输完成。控制器可能会产生一个中断(如果配置了),并等待下一次触发。

4. Block、LLI(链表项)和 Multi-block Transfer

DW_ahb_dmac 更强大的功能在于支持链表模式 (Linked List),这就引入了多 Block 传输的概念:

  • 单一 Block 传输:配置好寄存器后启动一次,传输一个 Block 后停止。

  • 多 Block 传输 (使用 LLI):您可以创建一个链表(LinkedList),其中每个节点(称为 LLI - Linked List Item)都包含了一组完整的寄存器配置(如 SAR, DAR, BLOCK_TS 等),用来描述一个 Block 如何传输。

    • 控制器会自动完成当前       Block(即当前 LLI 所描述的传输),然后无需软件干预,自动从下一个内存中的 LLI 节点加载配置,开始传输下一个 Block。

    • 这样,通过一个链表,DMA       控制器就可以将多个不连续的内存块(每个都是一个 Block)组织成一次连续的传输流,极大地提高了效率,减轻了 CPU 负担。

总结

DW_ahb_dmac 中:

  • 一个 Block 是 DMA 传输的核心操作单元,由 CTLx.BLOCK_TS 等寄存器定义其大小。

  • 它通常对应于 AHB 总线上的一次      Burst 传输,是硬件自动完成的一组连续数据的移动

  • 通过链表      (LLI) 结构,可以实现多个 Block 的自动、连续传输,用于处理分散/聚集(Scatter/Gather)等复杂数据搬移任务。

 

 

您提供的文档中“Example 5”和“2.9.1.5.1 Hardware Realignment of SAR/DAR Registers”章节完美地解释了这种情况。我将结合文档内容为您梳理清楚。

核心原则

1.  流控制器决定块大小:块的大小(总字节数)由流控制器(Flow Controller)决定。在大多数情况下,当 SRC_TR_WIDTH != DST_TR_WIDTH时,DMAC 是流控制器(CTLx.TT_FC设置为 000, 001, 010, 011)。

2.  BLOCK_TS始终以源端数据项数量为单位:无论目标端宽度如何,CTLx.BLOCK_TS寄存器编程的值始终代表需要从源端读取的“数据项”的数量。一个“数据项”的宽度由 CTLx.SRC_TR_WIDTH定义。

3.  总字节数计算:整个 Block 传输的总字节数(blk_size_bytes)由源端配置决定。

blk_size_bytes = CTLx.BLOCK_TS * (CTLx.SRC_TR_WIDTH / 8)

这个值必须与目标端的需求匹配,否则需要软件进行干预和计算。

 

场景分析 & 计算示例

让我们用文档中的 Example 5 作为基础,并扩展另一个例子。

示例 1:源端宽度 < 目标端宽度 (8-bit -> 64-bit)

这是文档中的 Example 5,也是最复杂的情况,可能涉及 fifo 刷新(Flush)。

·       配置:

o   CTLx.SRC_TR_WIDTH = 3‘b000(8-bit)

o   CTLx.DST_TR_WIDTH = 3’b011(64-bit)

o   CTLx.BLOCK_TS = 44

o   DMAC 是流控制器。

·       计算:

1.   Block 总字节数:

blk_size_bytes = 44 * (8/8) = 44 bytes

这意味着 DMAC 需要从源端读取 44 个字节

2.   目标端传输次数:

理想情况下,DMAC 希望每次以 64-bit (8-byte) 为单位写入目标。

44 bytes / 8 bytes = 5.5

这表示无法用整数次 64-bit 传输完成。前 5 次传输将写入 5 * 8 = 40字节。

·       会发生什么?

0.   DMAC 会先进行 5 次 64-bit 的 AHB 突发传输,消耗掉 40 字节的数据。

1.   此时,FIFO 中还剩 44 - 40 = 4字节数据需要写入,但无法凑成一个 64-bit 传输。

2.   此时,DW_ahb_dmac 会自动进入 “FIFO Flush Mode”

3.   在 Flush 模式下,控制器会临时改变目标端的传输宽度,将其从配置的 64-bit 切换为与源端相同的 8-bit

4.   然后,DMAC 发起 4 次 8-bit 的 AHB 单次传输,将剩余的 4 字节数据写完。

5.   特别注意:由于最后一次传输改变了地址对齐方式(从 64-bit 边界变成了 8-bit 边界),如果下一个 Block 是连续地址传输,硬件会自动对 DARx进行重新对齐(Realignment),使其回到 DST_TR_WIDTH对应的边界上,以保证下一个 Block 的正确开始。

示例 2:源端宽度 > 目标端宽度 (32-bit -> 16-bit)

这种情况相对简单。

·       配置:

o   CTLx.SRC_TR_WIDTH = 3‘b010(32-bit)

o   CTLx.DST_TR_WIDTH = 3’b001(16-bit)

o   CTLx.BLOCK_TS = 10// 要从源端读 10 个 32-bit 数据

o   DMAC 是流控制器。

·       计算:

1.   Block 总字节数:

blk_size_bytes = 10 * (32/8) = 10 * 4 = 40 bytes

这意味着 DMAC 需要从源端读取 40 个字节

2.   目标端传输次数:

DMAC 需要以 16-bit (2-byte) 为单位写入目标。

40 bytes / 2 bytes = 20

这意味着需要 20 16-bit 的 AHB 传输才能完成整个 Block。

·       会发生什么?

DMAC 的内部 FIFO 会进行数据打包和解包。

0.   它从源端进行一次 32-bit 读取,收到 4 字节数据。

1.   然后,它需要发起 2 16-bit 的写入,才能将这 4 字节数据送出。

2.   对于 BLOCK_TS=10,它总共需要进行 10 次源端读取和 20 次目标端写入。

这个过程对程序员是透明的,你只需要关心从源端读取多少個数据项 (BLOCK_TS)。

 

总结与编程指南

场景

BLOCK_TS的含义

总字节数计算

关键行为

SRC_TR_WIDTH == DST_TR_WIDTH

从源端读取的数据项数,也是向目标端写入的数据项数。

BLOCK_TS *   (SRC_TR_WIDTH/8)

最直接的情况,一一对应。

SRC_TR_WIDTH <   DST_TR_WIDTH

从源端读取的数据项数。

BLOCK_TS *   (SRC_TR_WIDTH/8)

可能触发   FIFO Flush。目标端最后可能用更小的位宽传输剩余数据。硬件负责地址重对齐。

SRC_TR_WIDTH >   DST_TR_WIDTH

从源端读取的数据项数。

BLOCK_TS *   (SRC_TR_WIDTH/8)

DMAC 自动进行多次目标端传输来完成一次源端读取。内部 FIFO 处理数据拆包。

给程序员的黄金法则:

1.  永远以源端视角编程 BLOCK_TS:你只需要告诉 DMAC “从源设备读取多少个数据项”。数据项的宽度就是 SRC_TR_WIDTH

2.  确保总字节数有效:计算 BLOCK_TS * (SRC_TR_WIDTH/8),确保这个总字节数对于目标设备是合理且可接受的。例如,如果目标设备期望接收 100 字节,而源端是 8-bit,那么 BLOCK_TS就应该设为 100。

3.  小心宽度不匹配的边界:特别是当源端较窄时,要意识到最后可能会有一段“零头”数据,但 DMAC 硬件会处理它。

因此,在您提供的配置中,BLOCK_TS的计算与 DST_TR_WIDTH无关。它的值直接由您想要搬运的数据总量源端传输宽度决定:BLOCK_TS = desired_total_bytes / (SRC_TR_WIDTH / 8)

 

 

 

 

 

由谁作为流控制器(Flow Controller) 决定了 DMA 传输的发起和控制方式,直接影响系统架构和软件复杂度。

根据文档DW_ahb_dmac(特别是 Chapter 2.2 和 Table 2-1),选择流控制器的核心原则可以归结为一条:

在 DMA 通道启动之时,由谁(软件/DMAC 或 外设)知道本次传输的“块(Block)”的确切大小?

下面我们详细分解这个原则,并阐述如何做出选择。

 

核心选择原则

流控制器

核心问题

适用场景

配置方法 (CTLx.TT_FC)

DMAC

软件是否在传输前就知道要传输多少数据?

传输固定大小的数据块。例如:
  - 搬运一块已知长度的内存数据
  - 从外设(如ADC)读取预定数量的采样点
  - 向显存搬运一个定长图像帧

000: Mem-Mem
  001:   Mem-Periph
  010:   Periph-Mem
  011:   Periph-Periph

源外设 (Source Peripheral)

源设备是否在数据传输过程中才能确定块何时结束?

源设备产生数据流,其长度未知。例如:
  - 从UART接收一个数据包(包长度由起始位/终止位决定,而非软件)
  - 从以太网MAC接收一个帧
  - 从传感器读取可变长度的数据

101: Periph-Periph (Src FC)

目标外设 (Destination Peripheral)

目标设备是否在接收数据过程中才能确定块何时结束?

目标设备处理数据流,其所需长度未知。例如:
  - 向一个音频编码器发送数据,由其决定何时处理完一个音频帧
  - 向一个加密引擎发送数据,加密引擎有固定的块处理大小

100: Periph-Mem (Periph FC)
  111:   Periph-Periph (Dst FC)

注:110(Mem-Periph with Peripheral FC) 模式较少见,可能用于目标外设有严格FIFO限制等特殊场景。

 

两种模式的详细工作机制与区别

为了更直观地理解,下图展示了两种模式下的主要工作流程与关键区别:

flow controller.PNG

 

1. DMAC 作为流控制器

·       工作机制

1.  软件配置:软件在启动 DMA 前,精确计算并写入 CTLx.BLOCK_TS寄存器。该值表示需要从源端读取的“数据项”数量。

2.  硬件执行:DMAC 内部有一个计数器,从 BLOCK_TS开始递减。

3.  传输结束:当计数器减到零时,DMAC 知道一个 Block 传输完毕,它会自动停止通道(如果未使能多块传输)并产生相应的中断(如 IntBlock)。

4.  外设角色:外设通过握手信号(dma_req, dma_single)仅用于事务级(Transaction) 的流控,即“我准备好发送/接收一个或一组数据了”,而不知道整个块何时结束。

·       优点:效率高,软件控制力强,逻辑简单。

·       缺点:要求数据长度在传输前已知。

2. 外设作为流控制器

·       工作机制

1.  软件配置:软件无需也无法设置 BLOCK_TS(其值无效)。它只需启动 DMA 通道。

2.  硬件执行:DMAC 会持续响应外设的传输请求,不断搬移数据。

3.  传输结束:当外设决定传输结束时(例如,UART 检测到停止位,或 FIFO 达到特定状态),它会通过握手接口的 dma_last 信号通知 DMAC。

4.  结束通知:DMAC 在当前事务传输完成后,接收到 dma_last信号,便知道整个 Block 传输完毕,随后停止通道并产生中断。

5.  数据预取风险:当目标外设是流控制器时,需要特别注意 CFGx.FCMODE位。

§  FCMODE=0(预取):DMAC 会积极地从源端读取数据,可能造成数据丢失(如果目标提前结束,源端多读的数据会被丢弃)。适用于源端是内存等非敏感设备。

§  FCMODE=1(非预取):DMAC 只在目标端请求数据时才去源端读取,保证数据不丢失。适用于源端是 FIFO 等“读敏感”设备。

·       优点:能处理未知长度的数据流,适应性强。

·       缺点:需要外设支持相应的握手协议(提供 dma_last),逻辑更复杂。

 

总结与决策流程

选择流控制器的决策流程可以归纳为以下几步:

1.  明确数据源和目的地:是内存到外设?外设到内存?还是外设到外设?

2.  询问关键问题:“在点击‘开始’按钮的那一刻,我知道这次要传多少字节数据吗?

o   答案是“我知道”:例如,“我要传 1024 字节”,“这个 ADC 缓冲区是 256 个采样点”。 -> 选择 DMAC 作为流控制器 (TT_FC= 000, 001, 010, 011)。

o   答案是“我不知道,取决于外设”:例如,“要等串口收到回车符才算完”,“要等网络包尾”。 -> 选择外设作为流控制器 (TT_FC= 100, 101, 111)。

3.  特殊情况处理:如果选择了目标外设作为流控制器,并且源端是类似 FIFO 的敏感设备,务必设置 CFGx.FCMODE = 1来禁用数据预取,防止数据丢失。

遵循这个原则,您就能为 DW_ahb_dmac 的每个通道做出正确的流控制器选择。

 

 

 

 



点赞

评论 (0 个评论)

facelist

您需要登录后才可以评论 登录 | 注册

  • 0

    周排名
  • 0

    月排名
  • 10

    总排名
  • 0

    关注
  • 6

    粉丝
  • 4

    好友
  • 20

    获赞
  • 4

    评论
  • 46

    访问数
关闭

站长推荐 上一条 /1 下一条


手机版| 小黑屋| 关于我们| 联系我们| 隐私声明| EETOP 创芯网
( 京ICP备:10050787号 京公网安备:11010502037710 )

GMT+8, 2025-9-18 23:01 , Processed in 0.016163 second(s), 8 queries , Gzip On, Redis On.

eetop公众号 创芯大讲堂 创芯人才网
返回顶部