DMA控制器架构:内部模块、通道与描述符
大家好,我是你们的芯片架构课讲师。今天我们来聊聊DMA控制器的内部架构。说实话,很多工程师用DMA用了好几年,但真问起它内部怎么工作的,往往就卡壳了。我当年刚入行时也是这样,直到亲手调过一个挂死的DMA,才彻底搞明白。
一、DMA控制器的内部模块划分
一个典型的DMA控制器,内部可以拆成几个关键模块。我习惯把它想象成一个「微型处理器」——它有自己的指令集、执行单元和总线接口。
| 模块名称 | 功能描述 | 我踩过的坑 |
|---|---|---|
| 总线主控接口 | 负责向系统总线发起读写请求 | 曾经因为总线仲裁优先级设错,导致视频数据丢帧 |
| 通道控制器 | 管理多个DMA通道的调度与切换 | 多通道并发时,仲裁策略选错会死锁 |
| 描述符获取单元 | 从内存中读取描述符链表 | 描述符地址没对齐,直接总线错误 |
| 地址生成器 | 计算源地址和目标地址的递增逻辑 | 二维搬运时地址回绕算错过一次 |
| 传输控制器 | 控制单次传输的启动、暂停和终止 | 中断清除顺序不对,导致重复触发 |
这些模块协同工作,说白了就是:描述符获取单元从内存拿到任务,通道控制器分配执行资源,地址生成器算好每一步的地址,总线主控接口去搬数据,传输控制器盯着别出错。
核心要点:DMA控制器本质上是一个「专用状态机」,不是CPU。它不需要取指令译码,只需要按描述符的配置机械执行。这个区别很重要——你想想看,CPU跑飞了还能复位,DMA跑飞了,数据就乱套了。
二、通道(Channel)的概念
通道是什么?我个人的理解是:通道就是DMA控制器内部的一条独立数据通路。每个通道都有自己的寄存器组、状态机和缓冲逻辑。
为什么需要多个通道?举个例子。我在做一款AI加速芯片时,需要同时搬运三路数据:输入特征图、权重参数、输出特征图。如果只有一个通道,就得排队等,性能直接腰斩。多通道就是让这些搬运任务「并行跑」。
通道的核心属性包括:
- 通道号:0到N-1,每个通道有唯一ID
- 优先级:高优先级通道可以抢占低优先级通道的总线使用权
- 状态:空闲、忙碌、暂停、完成、错误
- 绑定描述符:当前正在执行的描述符指针
个人经验:通道数不是越多越好。我曾经设计过一个32通道的DMA,结果大部分通道常年空闲,反而增加了芯片面积和功耗。一般嵌入式场景4-8个通道就够用了,除非你做的是数据中心级别的数据搬运。
通道的调度策略也很关键。常见的有:
- 固定优先级:通道0永远优先。简单粗暴,但低优先级通道可能饿死
- 轮询调度:每个通道轮流获得总线使用权。公平,但实时性差
- 加权轮询:给高带宽通道更多时间片。我比较推荐这个
三、描述符(Descriptor)的作用
描述符,说白了就是DMA的「任务单」。CPU不需要一次次告诉DMA「去搬这个,再去搬那个」,而是把任务清单写在内存里,DMA自己照着清单干活。
一个典型的描述符结构长这样:
struct dma_descriptor {
uint32_t src_addr; // 源地址
uint32_t dst_addr; // 目标地址
uint32_t transfer_size; // 传输字节数
uint32_t next_desc; // 下一个描述符的地址(链表指针)
uint32_t ctrl_flags; // 控制标志:中断使能、地址递增模式等
uint32_t status; // 状态:完成/错误/进行中
};
描述符最妙的地方在于链表结构。每个描述符里有个next_desc字段,指向下一个描述符。这样就能形成一个描述符链,DMA搬完一个任务,自动去取下一个。CPU只需要把链头地址告诉DMA,剩下的全自动。
避坑指南:我曾经犯过一个低级错误——描述符链表的最后一个节点,next_desc没有置为NULL。结果DMA搬完所有数据后,继续读取垃圾地址,直接触发总线错误,整个系统挂死。记住:链表结尾必须显式标记终止。
描述符还有几个变种,我简单列一下:
- 线性描述符:最简单的,源地址和目标地址连续递增
- 二维描述符:支持行/列跳跃,适合图像数据搬运
- 链式描述符:上面说的链表结构,适合批量任务
- 循环描述符:链表首尾相连,适合环形缓冲区
四、整体架构图
下面我用一张SVG图来展示DMA控制器的内部架构。这张图是我自己画的,把上面讲的模块、通道和描述符串起来了。
从这张图可以看得很清楚:描述符链表在内存中,描述符获取单元通过总线去读,然后交给通道控制器分配通道,地址生成器算地址,传输控制器盯着执行。整个流程环环相扣。
五、总结
嗯,这一章的内容就这些。我最后再啰嗦几句:
- 模块划分:总线接口、描述符获取、通道控制、地址生成、传输控制,缺一不可
- 通道:独立的数据通路,多通道实现并行搬运,但别贪多
- 描述符:DMA的任务单,链表结构让批量搬运自动化
我个人觉得,理解DMA架构最好的方法就是去读一份真实的DMA控制器手册,比如ARM的PL080或者Xilinx的AXI DMA。边读边对照我讲的这些模块,你会发现——哦,原来就是这么回事。
一句话记住:DMA控制器 = 一个会自己读任务清单、自己分配资源、自己搬数据、自己汇报结果的「智能搬运工」。