3、DMA基础回顾:DMA控制器工作原理、DMA传输类型与描述符链
直接存储器访问(DMA)是嵌入式系统中实现高速数据传输的关键硬件机制。它允许外设或内存块之间直接交换数据,而无需CPU逐字节干预。理解DMA控制器的工作原理、传输类型以及描述符链结构,是后续分析Cache失效导致DMA传输故障的前提。
3.1 DMA控制器工作原理
DMA控制器本质上是一个专用的状态机,负责在总线矩阵上扮演“总线主控”角色。其核心工作流程包含以下阶段:
- 请求阶段:外设(如UART、ADC、定时器)或软件通过硬件信号线向DMA控制器发出传输请求。
- 仲裁阶段:当多个DMA通道同时请求时,仲裁器根据优先级(固定或可编程)选择当前服务通道。
- 源地址读取:DMA从源地址寄存器指向的内存或外设数据寄存器中读取数据。
- 目的地址写入:将读取的数据写入目的地址寄存器指向的目标位置。
- 计数更新与结束判断:传输计数器减1,若计数器归零则触发完成中断,否则等待下一请求。
关键指标: DMA传输延迟通常由“请求到仲裁延迟 + 总线获取延迟 + 单次传输时钟数”决定。在Cache失效场景下,若DMA直接访问内存而Cache中存有脏数据,将导致数据不一致。
3.2 DMA传输类型
根据源和目的地址的归属,DMA传输主要分为以下三种类型。每种类型对Cache一致性的影响不同。
| 传输类型 | 源地址 | 目的地址 | 典型应用 | Cache失效风险 |
|---|---|---|---|---|
| 内存到内存 | 内存缓冲区A | 内存缓冲区B | 数据搬移、帧缓冲拷贝 | 高:源/目的都可能被Cache缓存 |
| 外设到内存 | 外设数据寄存器 | 内存缓冲区 | ADC采样、UART接收 | 中:目的内存可能被Cache缓存 |
| 内存到外设 | 内存缓冲区 | 外设数据寄存器 | DAC输出、UART发送 | 中:源内存可能被Cache缓存 |
故障排查要点: 在“内存到内存”传输中,若CPU在DMA传输前写入了源缓冲区,但数据仅停留在Cache中(写回策略),DMA直接从物理内存读取时将拿到旧数据。这是最常见的Cache一致性问题。
3.3 DMA描述符链
描述符链(Descriptor Chain)是高级DMA控制器支持的一种链表式传输管理机制。每个描述符包含本次传输的配置信息,并通过指针链接到下一个描述符,形成链式结构。DMA控制器自动遍历链表,完成多段不连续传输。
典型描述符结构(以32位系统为例):
struct dma_descriptor {
uint32_t src_addr; // 源地址
uint32_t dst_addr; // 目的地址
uint32_t control; // 控制字(传输大小、中断使能、传输类型等)
uint32_t next_desc; // 下一个描述符指针(NULL表示链尾)
};
描述符链的工作流程:
- 初始化:软件在内存中构建描述符数组,设置每个描述符的地址和传输参数,并将最后一个描述符的
next_desc置为NULL。 - 启动:将第一个描述符的地址写入DMA控制器的描述符基址寄存器,然后使能通道。
- 自动遍历:DMA完成当前描述符后,自动读取
next_desc指针,加载下一个描述符,继续传输。 - 完成中断:当DMA遇到
next_desc == NULL或传输计数器归零时,触发完成中断。
工程实践建议: 在配置DMA描述符链时,务必确保描述符结构体在内存中对齐到4字节或8字节边界。同时,对于描述符链所在的内存区域,建议使用
mmap或链接脚本将其放置在非Cache段,或使用硬件Cache维护指令(如ARM的DCache_CleanInvalidate)在修改描述符后执行刷新操作。