1. 课程导论:UART通信基础、DMA与中断协同的意义、课程目标与学习路径
1.1 UART通信基础回顾
UART(Universal Asynchronous Receiver/Transmitter,通用异步收发器)是嵌入式系统中最基础、最广泛使用的串行通信协议之一。它通过两根信号线(TX 发送、RX 接收)实现设备间的全双工通信,无需共享时钟信号,依靠双方预先约定的波特率(Baud Rate)进行数据采样。
一个标准的UART数据帧结构如下:
| 字段 | 起始位 | 数据位(5~8位) | 校验位(可选) | 停止位(1/1.5/2位) |
|---|---|---|---|---|
| 电平 | 拉低(逻辑0) | LSB先发 | 奇/偶/无 | 拉高(逻辑1) |
| 作用 | 同步接收时钟 | 有效载荷 | 检错 | 帧结束 |
在Linux内核中,UART驱动通常位于 drivers/tty/serial/ 目录下,通过 struct uart_port 和 struct uart_ops 抽象硬件差异。传统驱动模式中,CPU每接收或发送一个字节都会触发一次中断,这在低速场景下尚可接受,但在高速率(如 3Mbps、5Mbps)或大数据量传输时,频繁的中断将严重消耗CPU资源。
1.2 为什么需要DMA与中断协同?
在纯中断驱动的UART传输模式下,每个字节的收发都会产生中断请求(IRQ)。假设波特率为 115200 bps,每字节 10 位(8N1),则每秒产生约 11520 次接收中断。CPU每次进入中断服务程序(ISR)都需要保存/恢复上下文、读取/写入数据寄存器,这种“字节级中断”在高吞吐场景下会导致严重的 中断风暴,CPU 有效利用率大幅下降。
DMA(Direct Memory Access,直接存储器访问) 控制器可以接管UART与内存之间的数据传输,无需CPU逐字节干预。CPU只需配置好DMA描述符(源地址、目的地址、传输长度),DMA硬件会自动完成数据搬运,仅在整批传输完成时产生一次完成中断。
下表对比了三种UART传输模式的性能差异:
| 传输模式 | CPU干预粒度 | 中断频率 | CPU利用率(高负载) | 适用场景 |
|---|---|---|---|---|
| 纯轮询(Polling) | 字节级 | 无中断 | 极高(忙等) | 调试、低吞吐 |
| 纯中断(Interrupt) | 字节级 | 极高 | 30%~60% | 中低速、简单系统 |
| DMA + 中断协同 | 数据块级 | 极低(每批一次) | <10% | 高速、大数据量、实时系统 |
1.3 课程目标
本课程旨在帮助嵌入式Linux驱动开发者系统掌握UART驱动中DMA与中断协同工作的设计与实现方法。完成本课程后,学员将具备以下能力:
- 理解UART硬件层与DMA控制器的交互机制:包括DMA请求线、流控信号、传输粒度对齐。
- 掌握Linux内核DMA引擎(dmaengine)框架:能够编写DMA slave驱动,配置描述符链。
- 设计中断与DMA的协同调度策略:包括环形缓冲区管理、超时中断、错误处理。
- 实现高性能UART驱动:在真实硬件平台上达到接近线速的收发性能,CPU占用率低于10%。
- 调试与优化:使用tracepoint、perf、DMA调试fs节点分析传输瓶颈。
1.4 学习路径与章节规划
本课程共30章,分为五个阶段,循序渐进地从基础概念深入到实战优化:
| 阶段 | 章节范围 | 核心内容 | 实践产出 |
|---|---|---|---|
| 基础篇 | 第1~6章 | UART协议、Linux串口框架、中断机制、DMA引擎基础 | 搭建实验环境,编写轮询UART驱动 |
| DMA篇 | 第7~14章 | dmaengine API、DMA描述符链、环形缓冲区、SG列表 | 实现DMA-only收发驱动 |
| 协同篇 | 第15~22章 | 中断与DMA协同调度、超时机制、流控、电源管理 | 实现完整DMA+中断协同驱动 |
| 进阶篇 | 第23~27章 | 多实例、虚拟化、RT-Linux、性能调优 | 驱动性能基准测试与优化 |
| 实战篇 | 第28~30章 | 真实硬件平台移植、问题排查、社区提交 | 提交内核补丁或发布驱动 |
1.5 实验环境准备
本课程所有驱动代码均在以下环境中验证:
- 内核版本:Linux 6.6 LTS(长期支持版)
- 硬件平台:ARM64(Raspberry Pi 4 / QEMU virt 机器)
- 交叉编译工具链:aarch64-linux-gnu-gcc 12+
- 调试工具:kgdb、trace-cmd、perf、devmem2
setup_env.sh 脚本一键搭建环境。