本篇继 [[ZZZ-14-串口通讯UART]]、 [[ZZZ-15-串口通讯中断接收]],[[ZZZ-15-串口通讯中断接收]] 中应用到了 DMA,这节就来学习 DMA
1. 为什么要用 DMA?(从“搬砖”中解放 Boss)
在没有 DMA 之前,所有的数据搬运都必须经过 CPU。
场景:串口收到 100 字节数据
- 非 DMA 模式(CPU 模式): 每收到一个字节,串口就拍拍 CPU 的肩膀说:“老板,来货了,快把它搬到内存里!” CPU 必须放下手头正在算的数学题,跑过去搬一个字节,然后再回来算题。100 个字节,CPU 就得被打断 100 次。
- DMA 模式: CPU 告诉 DMA:“快递员,一会儿串口那边有 100 件货,你直接帮我搬到 0x2000… 这个地址的仓库(内存)里,搬完了再通知我。” 于是,CPU 继续心无旁骛地算题,DMA 在后台默默搬运。
2. DMA 在硬件体系中的位置
在 STM32 的内部,DMA 就像是一条“高速旁路”。它拥有访问内存(SRAM)和外设(如 UART, ADC, SPI)的权利。
graph TD
subgraph "STM32 内部总线架构"
CPU[Cortex-M3 内核
'大Boss'] DMA[DMA 控制器
'搬运工'] BusMatrix{总线矩阵
'交通枢纽'} SRAM[SRAM 内存
'仓库'] Flash[Flash 闪存
'代码库'] Peripherals[外设: UART/ADC/SPI
'码头'] end CPU --> BusMatrix DMA --> BusMatrix BusMatrix --- SRAM BusMatrix --- Flash BusMatrix --- Peripherals style CPU fill:#f96,stroke:#333 style DMA fill:#bbf,stroke:#333 style BusMatrix fill:#eee,stroke:#333
'大Boss'] DMA[DMA 控制器
'搬运工'] BusMatrix{总线矩阵
'交通枢纽'} SRAM[SRAM 内存
'仓库'] Flash[Flash 闪存
'代码库'] Peripherals[外设: UART/ADC/SPI
'码头'] end CPU --> BusMatrix DMA --> BusMatrix BusMatrix --- SRAM BusMatrix --- Flash BusMatrix --- Peripherals style CPU fill:#f96,stroke:#333 style DMA fill:#bbf,stroke:#333 style BusMatrix fill:#eee,stroke:#333
关键点:DMA 和 CPU 是并列的,它们共享总线。当 DMA 在搬运数据时,只要不发生“抢车道(总线竞争)”,CPU 完全可以在处理别的事情。
3. DMA 的“三要素”(快递单怎么填)
要让 DMA 工作,你(CPU)只需要在初始化时填好这张“快递单”:
- 从哪搬?(Source):比如外设的寄存器地址(串口的数据寄存器)。
- 搬到哪?(Destination):比如你定义的数组地址(内存)。
- 搬多少?(Direction & Size):搬运的方向、搬多少个字节、每次搬 8 位还是 16 位。
4. 结合上节的“串口空闲中断”案例
我们来看看 DMA 在那个案例里具体干了什么:
sequenceDiagram
participant PC as 电脑 (发送端)
participant UART as 串口外设 (码头)
participant DMA as DMA 搬运工
participant RAM as 接收数组 (仓库)
participant CPU as CPU (老板)
Note over CPU, RAM: 1. CPU 设置 DMA: '搬到数组里,搬完叫我'
PC->>UART: 发送数据 'H'
UART->>DMA: 货到了,快搬走
DMA->>RAM: 自动存入数组[0]
PC->>UART: 发送数据 'e'
UART->>DMA: 货又到了
DMA->>RAM: 自动存入数组[1]
Note right of PC: ...一段时间不发数据了...
UART->>CPU: 触发 IDLE (空闲中断)
CPU->>RAM: 老板起床处理整串数据 "He..."
5. DMA 的重要特性:通道 (Channel)
你在 CubeIDE 里看到 DMA1 Channel 1, Channel 2…
- 通道就像是独立的传送带。
- 串口接收需要一条通道,ADC 采集需要一条通道。
- STM32F103C8T6 内部通常有两个 DMA 控制器(DMA1 和 DMA2),每个控制器有 5-7 个通道。
6. 为什么要配合“空闲中断”?
- DMA 的弱点:它很“死板”,它只管搬运,直到搬满你设定的数量(比如 100 字节)。如果对方只发了 10 个字节就停了,DMA 就会一直等下去,不告诉 CPU。
- 空闲中断的强项:它很“机灵”,只要线上一没动静,它就叫醒 CPU。
- 强强联手:DMA 负责默默搬运不累着 CPU,空闲中断负责在关键时刻提醒 CPU 结账。
总结:DMA 的好处
- 极大地减轻 CPU 负担:CPU 不再需要为每一个字节的传输而中断。
- 提高实时性:在高速通信(如 SPI 驱动屏幕)中,DMA 能跑满带宽,而 CPU 搬运可能跟不上速度。
- 降低功耗:CPU 可以在 DMA 搬运时进入低功耗模式。