1. DMA基础概念
1.1 DMA工作原理
直接存储器访问(Direct Memory Access,DMA)是一种允许外设或存储器之间直接传输数据的硬件机制,无需CPU逐字节参与。DMA控制器作为独立的总线主机,在系统总线上与CPU并行工作,显著提升数据吞吐量并降低CPU负载。
核心工作流程: DMA传输由硬件状态机构成,通常包含以下四个阶段:
- 请求阶段: 外设(如ADC、SPI、UART)产生DMA请求信号,通知DMA控制器准备传输。
- 仲裁阶段: DMA控制器向总线仲裁器申请总线控制权,优先级高于CPU(在多数车载MCU架构中)。
- 传输阶段: DMA控制器直接驱动地址总线和数据总线,完成源地址到目的地址的数据搬运,每次传输一个字节/半字/字。
- 完成阶段: 传输计数器递减至零时,DMA控制器产生中断信号通知CPU,或自动重载配置进入循环模式。
| 传输阶段 | 总线操作 | 时钟周期数(典型) | CPU干预 |
|---|---|---|---|
| 请求与仲裁 | DMA控制器获取总线控制权 | 1~2 | 无 |
| 源地址读取 | 从外设数据寄存器或存储器读取数据 | 1~4(取决于总线等待状态) | 无 |
| 目的地址写入 | 将数据写入目标存储器或外设 | 1~4 | 无 |
| 地址更新与计数 | 源/目的地址递增或递减,传输计数器减1 | 0(并行于读写周期) | 无 |
关键理解: DMA传输的最小单位是beat(一次总线传输)。对于支持突发传输(burst transfer)的DMA控制器,一次请求可连续传输多个beat,大幅降低总线仲裁开销。
1.2 DMA在车载MCU中的角色
在车载嵌入式系统中,MCU需要同时处理多个实时外设的数据流——CAN收发、LIN通信、ADC采样、SPI传感器读取、PWM捕获等。DMA在这些场景中扮演着数据管道和CPU卸载引擎的双重角色。
| 车载应用场景 | 外设类型 | 数据速率 | DMA作用 |
|---|---|---|---|
| 电机控制电流采样 | ADC + SPI | 1~10 Msps | 将ADC结果直接搬运到PWM比较寄存器或RAM缓冲区 |
| CAN FD报文收发 | CAN控制器 | 最高8 Mbps | 自动将报文从RAM搬运到CAN Tx FIFO,或从Rx FIFO搬运到RAM |
| 传感器数据采集 | SPI / I²C | 1~50 Mbps | 多通道传感器数据连续采集,无需CPU逐字节读取 |
| 音频/语音处理 | I²S / SAI | 48~192 kHz | 双缓冲乒乓传输,保证音频流连续无断裂 |
| Bootloader固件升级 | UART / CAN | 115200 bps~1 Mbps | 大块固件数据从通信接口直接搬运到Flash编程缓冲区 |
车载安全关键性: 在ISO 26262 ASIL-B/D系统中,DMA传输必须配合ECC(纠错码)保护,防止单比特翻转导致数据损坏。部分车载MCU(如Infineon TC3xx、NXP S32K3)提供DMA传输的硬件CRC校验和地址保护机制。
1.3 DMA与CPU的数据搬运对比
理解DMA与CPU在数据搬运上的本质差异,是正确使用DMA的前提。下表从多个维度进行对比:
| 对比维度 | CPU搬运(轮询/中断) | DMA搬运 | 车载场景影响 |
|---|---|---|---|
| 执行主体 | CPU核心(取指、译码、执行) | DMA控制器(硬件状态机) | CPU可同时运行控制算法 |
| 每字节开销 | 10~50个CPU时钟周期(含循环、地址计算、中断压栈) | 1~4个总线时钟周期(纯硬件搬运) | 高数据速率场景下差异显著 |
| CPU负载 | 100%占用(轮询)或每次中断约50~200周期(上下文切换) | 仅初始化配置+完成中断(约0.1%~1% CPU负载) | 释放CPU用于安全监控和诊断 |
| 实时性 | 受中断优先级和任务调度影响,抖动大 | 硬件触发,确定性延迟(通常2~5个总线周期) | 满足车载硬实时要求 |
| 数据吞吐量 | 受限于CPU主频和指令效率 | 接近总线带宽上限 | 支持多通道并发采集 |
| 灵活性 | 可进行数据校验、格式转换、条件判断 | 仅搬运,部分DMA支持简单运算(加减、CRC) | 复杂处理仍需CPU介入 |
| 功耗 | 高(CPU全速运行+缓存活动) | 低(专用硬件,无取指开销) | 符合车载低功耗待机要求 |
性能量化示例: 以100 kHz采样率、16位精度的ADC为例,每秒需搬运200 KB数据。
- CPU轮询方式: 每次采样约消耗50周期 → 5 MHz CPU时间 → 在200 MHz MCU上占用2.5% CPU。
- DMA方式: 每次采样仅消耗2个总线周期 → 0.2 MHz总线时间 → 几乎零CPU占用,且支持双缓冲无丢失。
何时不应使用DMA? 对于单次、小数据量(如1~4字节)或需要逐字节判断/转换的场景,DMA的初始化开销可能超过直接CPU读取。典型例子:UART接收单字节命令、GPIO电平读取。此时使用中断或轮询更高效。