这一章在干嘛?
DMA 实验:DMA 控制器架构、通道映射、数据流 vs FIFO、Memory-to-Memory 与外设到内存模式、UART DMA 收发。从此 CPU 从搬运工解放出来。
25.1 DMA 简介
DMA(Direct Memory Access)= 直接存储器访问。
- 硬件在 RAM 与外设之间直接搬运数据;
- 不经过 CPU,不打断程序运行;
- 传输完成触发中断。
F407 有 2 个 DMA 控制器,共 16 个数据流,每个数据流 8 个通道。
| DMAx | 数据流 | 用途 |
|---|---|---|
| DMA1 | 0~7 | USART/RCC/ADC/TIM/I2C/SPI 等 |
| DMA2 | 0~7 | USART/SDIO/ADC/DCMI/Hash 等 |
原书图 25.1.1:DMA 控制器框图
通道优先级:软件 4 档(低/中/高/超高),相同时硬件编号小优先。
DMA ≠ 中断:中断需要 CPU 保存现场恢复现场;DMA 完全在硬件完成,CPU 完全可以睡大觉。
25.2 硬件设计
本实验:USART1 DMA 发送一段字符串,DMA 接收固定长度数据。
25.3 程序设计
25.3.1 CubeMX 配置
- USART1 → DMA Settings → Add
- RX: DMA1 Stream0, Channel 4 (USART1_RX)
- TX: DMA1 Stream7, Channel 4 (USART1_TX)
- NVIC: USART1 global interrupt + DMA1 stream0 global interrupt
25.3.2 关键代码
// 启动 DMA 接收
HAL_UART_Receive_DMA(&huart1, rx_buf, RX_LEN);
// 发送一段数据
HAL_UART_Transmit_DMA(&huart1, tx_buf, TX_LEN);
// 接收完成回调
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) {
if (huart->Instance == USART1) {
// 处理 rx_buf
HAL_UART_Receive_DMA(&huart1, rx_buf, RX_LEN); // 重启
}
}
原书图 25.3.2.1:USART DMA 收发流程图
原书图 25.3.3.1:DMA 数据流通道映射
25.3.3 Memory-to-Memory
DMA 也可在 RAM 内部搬运(如 memcpy 加速):
HAL_DMA_Start(&hdma, src, dst, len);
HAL_DMA_PollForTransfer(&hdma, HAL_DMA_FULL_TRANSFER, 100);
25.4 下载验证
串口助手输入字符串 → MCU 自动 DMA 接收 → 回环发送;同时开发板 LCD 显示 DMA 进度条。
原书图 25.4.1:DMA 串口回环测试
DMA 的核心优势?
不占用 CPU,硬件自动搬运。
USART1_RX 应该在哪个数据流哪个通道?
DMA1 Stream0 Channel 4。
DMA 接收完成后为什么要重启?
DMA 中断模式只触发一次,需要重新开启才能继续接收。