DMA — Flash 到 SRAM 数据搬运
难度: ⭐⭐(理解 DMA 概念即可)
固件库: AT32F403A_407_Firmware_Library V2.2.2
源文件:project/at_start_f403a/examples/dma/flash_to_sram/src/main.c
这个实验是干嘛的?
DMA(Direct Memory Access,直接存储器访问)是 MCU 里最强大的"搬运工"。
没有 DMA 时:CPU 自己一个字节一个字节地从 Flash 复制到 SRAM,复制 128 字节就要执行 128 次循环,CPU 什么都干不了。
有了 DMA 时:你告诉 DMA “把这块数据从这里搬到那里”,DMA 硬件自动完成,CPU 空闲了。搬运完成后 DMA 发一个中断通知 CPU。
本实验用 DMA 的内存到内存模式,把 Flash 中的 32 个 32 位数据搬到 SRAM,搬运完成后触发中断,然后比对数据。
硬件准备
不需要任何外部硬件! 这是纯内部操作,Flash → SRAM。
DMA 核心概念
DMA 的三种搬运方向
| 方向 | 说明 | 典型用途 |
|---|---|---|
| 外设→内存 | 从外设读数据存到内存 | ADC 采样、串口接收 |
| 内存→外设 | 从内存取数据发到外设 | 串口发送、DAC 输出 |
| 内存→内存 | 内存之间复制数据 | 数据搬运、缓冲区拷贝 |
DMA 的关键参数
| 参数 | 含义 |
|---|---|
| 源地址 | 数据从哪来 |
| 目标地址 | 数据搬到哪去 |
| 数据宽度 | 每次搬运多少字节(字节/半字/字) |
| 地址递增 | 搬完一个后地址是否 +1 |
| 传输数量 | 总共搬多少个 |
| 循环模式 | 搬完后是否自动重新开始 |
完整代码
|
|
代码分段讲解
1. 源数据和目标缓冲区
|
|
const修饰 → 编译器把它放在 Flash 中(只读)- 没有
const→ 放在 SRAM 中(可读写) - DMA 就是从 Flash 的地址搬到 SRAM 的地址
2. DMA 方向
|
|
本实验是内存到内存模式。ADC+DMA 那个实验用的是外设到内存。
3. 地址递增
|
|
两个都要递增!因为我们要搬 32 个数据:
- 第 1 个:从
src[0]搬到dst[0] - 第 2 个:从
src[1]搬到dst[1] - …
- 第 32 个:从
src[31]搬到dst[31]
如果地址不递增,就会一直搬同一个位置的数据。
4. 中断通知
|
|
FDT = Full Data Transfer,全部数据传输完成。
中断服务函数中:
|
|
5. 等待完成
|
|
data_counter_end 初始值设为 1,中断把它清零。主循环在这里等待。
注意:这个变量必须用 volatile 修饰(__IO),否则编译器可能优化掉这个循环。
实验现象
- 3 个 LED 全部亮起 → DMA 搬运成功,数据一致
- LED 不亮 → 数据比对失败(不应该发生)
DMA 传输速度
DMA 搬运 32 个 32 位数据(128 字节)需要多少时间?
- DMA 时钟 = 系统时钟(240MHz)
- 每个字需要 2 个时钟周期(读 + 写)
- 32 个字 = 64 个时钟周期 = 64 / 240MHz ≈ 267ns
267 纳秒搬完 128 字节! 如果用 CPU 循环复制,至少需要 100+ 个时钟周期。
常见问题
Q: 数据比对失败?
- 检查源地址和目标地址是否正确
- 检查数据宽度是否匹配(本例用 32 位字)
- 检查 buffer_size 是否正确
Q: 中断不触发?
- 是否使能了 DMA 中断?
- NVIC 是否配置了优先级?
- 中断标志是否清除?
Q: 想用循环模式?
loop_mode_enable = TRUE:搬完后自动重新开始- 适合 ADC 连续采样:DMA 反复把 ADC 数据搬到缓冲区
小结
| 概念 | 说明 |
|---|---|
| DMA | 硬件自动搬运数据,不占 CPU |
| 内存到内存 | 最简单的 DMA 模式 |
| 地址递增 | 搬多个数据时必须使能 |
| FDT 中断 | 全部搬完后触发 |
| volatile | 防止编译器优化掉等待循环 |
学了 DMA 能做什么?
DMA 是"高性能嵌入式系统"的基石:
数据采集
| 项目 | 原理 | 难度 |
|---|---|---|
| 高速 ADC 采集 | 定时器触发 ADC + DMA 自动存储 | ⭐⭐⭐ |
| 音频录音 | I2S + DMA → 高速音频数据采集 | ⭐⭐⭐ |
| 示波器 | ADC + DMA + 双缓冲 → 连续波形采集 | ⭐⭐⭐⭐ |
| 多通道同步采集 | 多 ADC + DMA → 同时采集多路信号 | ⭐⭐⭐⭐ |
数据输出
| 项目 | 原理 | 难度 |
|---|---|---|
| DMA 波形生成 | DMA + DAC → 输出任意波形(正弦、三角) | ⭐⭐⭐ |
| LED 灯带驱动 | DMA + GPIO 精确时序 → WS2812 驱动 | ⭐⭐⭐ |
| 高速串口发送 | DMA + USART → 大数据量快速发送 | ⭐⭐ |
| LCD 刷屏 | DMA + SPI → 高速刷新屏幕 | ⭐⭐⭐ |
性能优化
| 项目 | 原理 | 难度 |
|---|---|---|
| 内存拷贝加速 | DMA 内存到内存 → 比 CPU 循环快 | ⭐⭐ |
| 双缓冲技术 | DMA 搬 A 缓冲时,CPU 处理 B 缓冲 | ⭐⭐⭐⭐ |
| 零拷贝通信 | DMA 直接在外设和内存之间搬运,不经过 CPU | ⭐⭐⭐⭐ |
核心思路:DMA 的价值在于解放 CPU。没有 DMA,CPU 要亲自搬运每一个字节,什么都干不了。有了 DMA,CPU 只需要"发号施令",然后去做更重要的事(计算、控制、通信)。在高速数据采集、音频处理、显示刷新等场景,DMA 是不可或缺的。
下一步:学会了 DMA,可以学 FLASH 读写,了解如何用内部 Flash 存储用户数据。