3. UART 与 DMA 结合:为什么需要 DMA 及典型应用场景
在嵌入式系统中,UART(通用异步收发器)是最常用的串行通信接口之一。当波特率较低、数据量较小时,CPU 可以直接通过中断或轮询方式处理每个字节。然而,随着通信速率提升至数 Mbps 或数据包长度达到 KB 级别,传统的中断驱动模式会带来严重的 CPU 开销,甚至导致数据丢失。此时,DMA(直接存储器访问)成为解决性能瓶颈的关键技术。
3.1 为什么 UART 需要 DMA
UART 每传输一个字节都会触发一次中断。假设波特率为 3 Mbps,每个字节包含 10 位(1 起始位 + 8 数据位 + 1 停止位),则每秒传输约 300,000 字节。CPU 每 3.3 µs 就要响应一次中断,执行上下文保存、寄存器读写、缓冲区更新等操作。这种高频中断会严重挤占 CPU 处理其他任务的时间。
DMA 控制器接管 UART 数据搬运工作后,CPU 只需在传输开始前配置好源/目的地址和传输长度,在传输完成后通过完成中断获知结果。中间的数据搬运完全由 DMA 硬件完成,不占用 CPU 周期。
| 对比维度 | 中断驱动模式 | DMA 模式 |
|---|---|---|
| 每字节 CPU 干预 | 是,每次传输触发 ISR | 否,DMA 硬件自动搬运 |
| CPU 利用率(3 Mbps) | 约 60% ~ 80% | 约 5% ~ 15% |
| 数据吞吐量上限 | 受中断响应延迟限制 | 接近 UART 硬件极限 |
| 缓冲区管理 | 需在 ISR 中逐字节处理 | DMA 直接填充/读取内存 |
| 错误处理复杂度 | ISR 中即时检测 | 需结合完成中断与状态寄存器 |
3.2 UART + DMA 的典型应用场景
UART 与 DMA 的结合主要面向高波特率、大数据量、低延迟要求的通信场景。以下列出三种最典型的应用场景。
3.2.1 高波特率连续数据流
例如工业现场总线(RS-485/RS-422)以 1 Mbps ~ 10 Mbps 速率传输传感器数据或控制指令。DMA 可以连续接收数百字节的报文,CPU 仅在完整报文到达后执行解析。
3.2.2 大块数据批量传输
如固件升级、日志导出、文件传输。数据量可达数 KB 甚至数 MB。DMA 的块传输模式(Burst Transfer)能充分利用总线带宽,减少传输时间。
3.2.3 低功耗物联网设备
在电池供电设备中,CPU 大部分时间处于休眠状态。DMA 可以在 CPU 休眠时独立完成 UART 数据收发,仅在传输完成或出错时唤醒 CPU,显著降低系统功耗。
3.3 UART + DMA 的软件架构层次
在 Linux 内核中,UART + DMA 的驱动通常分为三层:
- UART 控制器驱动层(tty/serial):负责寄存器配置、波特率设置、流控管理,提供
uart_ops回调。 - DMA 引擎驱动层(dmaengine):提供统一的 DMA 传输 API,如
dmaengine_prep_slave_sg()、dmaengine_submit()。 - DMA 传输完成回调与错误处理层:在 DMA 完成中断或错误中断中,调用 UART 驱动的回调函数,更新环形缓冲区、唤醒等待队列。
3.4 关键配置参数对比
| 参数 | 说明 | 典型值 | 影响 |
|---|---|---|---|
| DMA 传输宽度 | 单次传输的数据位宽 | 8 位 / 16 位 / 32 位 | 匹配 UART 数据寄存器宽度 |
| DMA 突发长度 | 连续传输的数据项数 | 4 / 8 / 16 | 影响总线占用与传输效率 |
| 环形缓冲区大小 | DMA 接收缓冲区容量 | 512 / 1024 / 2048 字节 | 决定抗压能力与丢包风险 |
| 超时阈值 | 帧间隔超时时间 | 3 ~ 5 字符时间 | 影响短帧实时性 |
| DMA 通道优先级 | 多通道时的仲裁优先级 | 高 / 中 / 低 | 影响多外设并发时的响应 |
3.5 小结
UART 与 DMA 的结合是解决高波特率、大数据量通信性能瓶颈的核心手段。DMA 将 CPU 从逐字节中断处理中解放出来,使 CPU 专注于协议解析与业务逻辑。典型应用场景包括工业总线、固件升级、低功耗物联网等。在驱动开发中,需要合理配置 DMA 传输参数,并处理好完成中断与帧边界检测的关系,才能充分发挥硬件性能。