3、DMA传输类型:内存到内存、内存到外设、外设到内存、外设到外设
DMA(Direct Memory Access)传输的核心价值在于绕过CPU,直接在源地址与目标地址之间搬运数据。根据数据流向和参与对象的类型,DMA传输可划分为四种基本模式。理解这四种模式是配置DMA控制器、设计驱动程序以及优化系统性能的基础。
3.1 四种传输类型概述
下表从数据源、数据目标、典型应用场景和硬件路径四个维度,对四种DMA传输类型进行对比:
| 传输类型 | 数据源 | 数据目标 | 典型应用场景 | 硬件路径 |
|---|---|---|---|---|
| 内存到内存 (M2M) | 系统RAM | 系统RAM | 大块数据拷贝、内存清零、帧缓冲移动 | DMA控制器直接读写系统总线 |
| 内存到外设 (M2P) | 系统RAM | 外设FIFO/寄存器 | LCD显示刷新、音频播放、网络数据发送 | DMA控制器 → 外设总线 |
| 外设到内存 (P2M) | 外设FIFO/寄存器 | 系统RAM | 摄像头数据采集、音频录音、网络数据接收 | 外设总线 → DMA控制器 |
| 外设到外设 (P2P) | 外设A | 外设B | 硬件编解码器直连、数字信号处理链路 | 外设总线直连,DMA做桥接 |
关键区分:M2M传输通常需要DMA控制器支持“双地址”模式(源地址和目标地址均为内存地址);而M2P和P2M传输通常使用“单地址”模式,其中一个地址固定为外设的FIFO地址。
3.2 内存到内存 (M2M) 传输
M2M传输是最纯粹的DMA形式,用于在系统RAM的两个不同区域之间搬运数据。它完全在内存总线上进行,不涉及任何外设寄存器。
- 工作原理:DMA控制器从源内存地址读取数据,写入目标内存地址。传输完成后触发中断通知CPU。
- 优势:释放CPU,使其在数据拷贝期间可以执行其他计算任务。对于大块数据(如>1KB),效率远高于CPU的
memcpy()。 - 限制:会占用系统总线带宽,可能影响CPU访问内存的延迟。在Cache一致性方面需要特别注意(见后续章节)。
Linux内核API示例:
// 使用dmaengine API进行M2M传输
struct dma_chan *chan;
struct dma_device *dev;
struct dma_async_tx_descriptor *tx;
dma_cookie_t cookie;
// 1. 请求DMA通道
chan = dma_request_chan(dev, "memcpy");
// 2. 准备传输描述符
tx = dmaengine_prep_dma_memcpy(chan, dst_phys, src_phys, size, flags);
// 3. 提交并启动传输
cookie = dmaengine_submit(tx);
dma_async_issue_pending(chan);
3.3 内存到外设 (M2P) 传输
M2P传输是“数据输出”类驱动的核心。CPU将数据准备好放入内存缓冲区,DMA控制器负责将数据从内存搬运到外设的发送FIFO或数据寄存器。
- 典型流程:
- CPU在内存中填充数据缓冲区。
- CPU配置DMA控制器:源地址(内存缓冲区)、目标地址(外设FIFO)、传输长度。
- DMA控制器启动,每次传输一个数据单元(如32位字)到外设。
- 外设读取FIFO数据并发送到物理链路(如SPI、I2S、UART)。
- 传输完成,DMA触发中断,CPU准备下一批数据。
- 关键参数:外设地址必须配置为“固定地址”模式(不递增),而内存地址配置为“递增地址”模式。
避坑指南:在M2P传输中,如果外设的FIFO深度很小(如只有4字节),DMA的“突发传输”长度(burst size)必须与FIFO深度匹配,否则可能导致数据溢出或丢失。
3.4 外设到内存 (P2M) 传输
P2M传输是“数据输入”类驱动的基石。外设接收到数据后,DMA控制器自动将数据从外设的接收FIFO搬运到内存缓冲区,无需CPU逐字节读取。
- 典型流程:
- CPU分配并锁定内存缓冲区,配置DMA控制器:源地址(外设FIFO)、目标地址(内存缓冲区)、传输长度。
- 外设产生数据并放入FIFO,同时向DMA控制器发出请求信号。
- DMA控制器响应请求,从FIFO读取数据并写入内存。
- 当传输长度达到预设值或外设传输完成时,DMA触发中断。
- CPU从内存缓冲区中处理数据。
- 环形缓冲区(Ring Buffer)模式:许多高性能驱动(如网卡、音频)使用P2M传输配合环形缓冲区,DMA自动循环填充多个缓冲区,CPU处理已满的缓冲区,实现流水线操作。
3.5 外设到外设 (P2P) 传输
P2P传输是最复杂但延迟最低的模式。数据从一个外设直接传输到另一个外设,完全不经过系统内存。DMA控制器在此扮演“数据桥接”的角色。
- 应用场景:
- 硬件编解码器直连:摄像头传感器直接输出到图像信号处理器(ISP)。
- 数字音频路由:I2S接收接口直接连接到I2S发送接口,实现音频直通。
- 高速数据转发:两个SPI设备之间进行实时数据中继。
- 硬件要求:
- DMA控制器必须支持“双外设”通道,即源和目标地址均为外设地址空间。
- 两个外设必须共享同一个DMA控制器或通过DMA握手信号连接。
- 通常需要硬件流控信号(DREQ/DACK)来同步数据传输速率。
P2P传输的挑战:
- 数据宽度匹配:源外设输出8位数据,目标外设期望16位数据,需要DMA控制器支持数据打包/解包。
- 时钟域同步:两个外设可能运行在不同的时钟域,DMA控制器需要处理跨时钟域同步。
- 调试困难:数据不经过内存,无法通过内存dump来验证数据完整性,通常需要逻辑分析仪或硬件探针。
3.6 四种传输类型的系统架构对比
下面的SVG图展示了四种DMA传输类型在系统总线上的数据流向,帮助理解每种模式下的硬件路径差异。
3.7 传输类型选择决策树
在实际驱动开发中,选择哪种DMA传输类型取决于数据流方向和硬件能力。以下决策树可以帮助快速判断:
- 数据是否需要经过内存?
- 是 → 进入步骤2。
- 否 → 选择 外设到外设 (P2P) 传输。
- 数据源是什么?
- 内存 → 进入步骤3。
- 外设 → 选择 外设到内存 (P2M) 传输。
- 数据目标是什么?
- 内存 → 选择 内存到内存 (M2M) 传输。
- 外设 → 选择 内存到外设 (M2P) 传输。
性能提示:在Android多媒体系统中,P2P传输常用于相机ISP直连显示控制器,实现零拷贝的预览通路,显著降低功耗和延迟。但P2P传输对DMA控制器的硬件资源要求较高,并非所有SoC都支持。