DMA(直接内存访问)数据传输是计算机系统中高效搬运数据的核心技术,其核心目标是通过硬件控制器绕过CPU直接操作内存与外设间的数据交换。以下是DMA数据传输的详细流程、模式及优化策略:
一、DMA数据传输基本流程
-
初始化配置
-
参数设置:CPU通过写DMA控制器的寄存器,定义传输参数:
- 源地址:数据起始位置(如内存地址
0x20000000
或外设寄存器USART_DR
)。 - 目标地址:数据目的地(如内存缓冲区或外设数据寄存器)。
- 传输方向:内存→外设、外设→内存或内存→内存。
- 传输长度:以字节、字或块为单位(如传输1024字节)。
- 地址自增:内存地址通常自增,外设地址固定(如串口数据寄存器)。
- 数据宽度:与外设寄存器对齐(如32位寄存器需4字节对齐)。
- 传输模式:单次(Normal)、循环(Circular)或请求(On-Demand)。
- 源地址:数据起始位置(如内存地址
-
示例代码(STM32配置UART发送DMA):
DMA_HandleTypeDef hdma_usart_tx; hdma_usart_tx.Instance = DMA1_Channel4; hdma_usart_tx.Init.Direction = DMA_MEMORY_TO_PERIPH; hdma_usart_tx.Init.PeriphInc = DMA_PINC_DISABLE; // 外设地址固定 hdma_usart_tx.Init.MemInc = DMA_MINC_ENABLE; // 内存地址自增 hdma_usart_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; hdma_usart_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE; hdma_usart_tx.Init.Mode = DMA_NORMAL; // 单次传输模式 HAL_DMA_Init(&hdma_usart_tx); __HAL_LINKDMA(&huart2, hdmatx, hdma_usart_tx); // 绑定DMA到UART
-
-
触发传输
- 硬件触发:外设(如UART、ADC)在数据就绪后,向DMA控制器发送请求信号(DREQ)。
- 软件触发:通过代码手动启动传输(如内存到内存复制)。
- 总线仲裁:DMA控制器向CPU发送HOLD信号请求总线控制权,CPU释放总线后回复HLDA信号。
-
数据传输
- 直接操作:DMA控制器接管总线,按配置参数逐字节(或按数据宽度)搬运数据。
- 突发传输(Burst):某些DMA支持连续传输多个数据单元(如一次传输4个字),减少总线占用次数。
-
传输完成处理
- 中断通知:DMA控制器触发中断,CPU处理后续任务(如解析数据、释放资源)。
- 状态检查:读取DMA状态寄存器,确认传输是否成功(如超时或地址错误标志位)。
二、DMA数据传输模式
模式 | 特点 | 适用场景 |
---|---|---|
单次传输 | 传输指定长度后停止,需手动重启 | 非连续任务(如单次文件读写) |
循环传输 | 自动重置地址和计数器,持续传输 | 实时数据流(音频、视频采集) |
请求传输 | 外设按需分批次请求传输 | 流控外设(如SPI从设备) |
内存到内存 | 不涉及外设,直接复制内存数据 | 大块数据快速拷贝(图像处理) |
分散-聚集 | 通过描述符链表管理非连续内存块传输 | 网络数据包分片、多缓冲区处理 |
双缓冲 | 交替使用两个缓冲区,实现传输与处理的并行 | 无延迟实时处理(音频播放) |
三、DMA数据传输优化策略
-
双缓冲机制(Double Buffering)
- 原理:
- Buffer A:DMA传输数据。
- Buffer B:CPU处理数据。
- 传输完成时自动切换缓冲区,避免处理延迟。
- 实现(以音频播放为例):
// 配置循环模式 + 双缓冲 hdma.Init.Mode = DMA_CIRCULAR; HAL_UART_Transmit_DMA(&huart2, buffer1, BUFFER_SIZE); // 中断回调中切换缓冲区 void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart) { if (huart->Instance == USART2) { // 处理buffer2,同时DMA传输buffer1 } }
- 原理:
-
分散-聚集(Scatter-Gather)
- 原理:使用描述符链表定义多个非连续内存块的传输规则。
- 优势:减少CPU配置次数,提升灵活性和效率。
- 示例(网络数据包接收):
- 数据包分片存储在多个内存块中,DMA按链表自动搬运。
-
缓存一致性管理
- 问题:CPU缓存与DMA操作的内存区域不一致。
- 解决方案:
- 手动刷新缓存(ARM Cortex-M7):
SCB_CleanDCache_by_Addr((uint32_t*)buffer, buffer_size); // 清理缓存 SCB_InvalidateDCache_by_Addr((uint32_t*)buffer, buffer_size); // 失效缓存
- 使用非缓存内存:通过MPU配置内存区域为
Non-Cacheable
。
- 手动刷新缓存(ARM Cortex-M7):
-
增大传输块大小
- 减少中断频率,降低CPU上下文切换开销(如一次性传输4KB数据)。
四、典型应用场景
-
UART串口通信
- 场景:接收GPS模块的连续定位数据流。
- 配置:
- 循环模式DMA,外设→内存传输。
- 双缓冲机制避免数据覆盖。
-
ADC连续采样
- 场景:实时采集温度传感器数据。
- 配置:
- 循环模式DMA,ADC结果寄存器→内存数组。
- 定时器触发采样,确保固定频率。
-
图像处理
- 场景:摄像头采集图像到内存,GPU处理后显示。
- 配置:
- 内存到内存DMA快速拷贝图像缓冲区。
- 分散-聚集模式处理非连续图像分块。
五、常见问题与调试
-
数据错位或丢失
- 原因:数据宽度或地址自增配置错误。
- 解决:检查外设寄存器与内存对齐方式是否匹配。
-
传输未完成
- 原因:DMA通道未使能、中断未配置或总线权限冲突。
- 解决:
- 确认DMA控制器时钟已开启。
- 检查HOLD/HLDA信号是否正常(逻辑分析仪捕获)。
-
缓存一致性问题
- 现象:CPU读取到旧数据或DMA写入的数据未生效。
- 解决:清理或失效缓存,或使用非缓存内存。
六、总结
DMA数据传输通过硬件控制器实现高效、低延迟的数据搬运,是提升系统性能的关键技术。开发者需掌握:
- 配置流程:初始化参数、触发方式及中断处理。
- 模式选择:根据场景选择单次、循环或双缓冲等模式。
- 优化技巧:双缓冲、分散-聚集、缓存一致性管理等。
深入理解DMA机制,可显著优化嵌入式系统、多媒体处理及高吞吐应用的性能与实时性。