一、基本概念回顾
什么是 DMA?
DMA(Direct Memory Access)允许外设和内存之间在不占用 CPU 的情况下直接进行数据传输。
DMA 的特性
一个 DMA 控制器包含多个通道或流。
每个通道在同一时间只能处理一个传输。
同一时刻,一个 DMA 控制器只处理一个通道任务,按优先级顺序执行。
可以设置为:
内存地址自增(常见)
外设地址固定(例如 USART 数据寄存器)
数据宽度:字节、半字、字
普通模式或循环模式(用于连续接收)
串口 DMA 的方向
发送:内存 ➝ 外设(USARTx->TDR)
接收:外设 ➝ 内存(USARTx->RDR)
二、串口 DMA 发送流程
配置并启动 DMA,设置源地址为内存,目标地址为串口发送寄存器(TDR)。
启动 DMA 传输,DMA 自动将数据一字节一字节写入 TDR。
传输完成后会触发 DMA 中断,间接触发 HAL_UART_TxCpltCallback 回调函数。
示例代码:使用 DMA 发送
uint8_t txData[] = "DMA Send Test";
HAL_UART_Transmit_DMA(&huart1, txData, sizeof(txData) - 1);
回调函数处理:
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart) {
if (huart->Instance == USART1) {
// DMA 发送完成后的处理逻辑
}
}
三、串口 DMA 接收流程
配置 DMA,从 USART 的 RDR 寄存器读取数据写入内存。
设置内存自增,外设地址固定。
当接收设定数量数据后触发 DMA 中断,调用 RxCpltCallback()。
示例代码:使用 DMA 接收
uint8_t rxBuffer[64];
HAL_UART_Receive_DMA(&huart1, rxBuffer, sizeof(rxBuffer));
回调函数处理:
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) {
if (huart->Instance == USART1) {
// 处理 rxBuffer 中接收到的数据
}
}
四、模式说明
循环模式常结合 IDLE 中断判断一次传输结束。
五、注意事项
DMA 使用中 CPU 不干预数据搬运,效率高。
DMA 通道冲突可能导致传输失败,需在 .ioc 或代码中妥善配置。
使用 DMA 依然存在中断(传输完成)!RxCpltCallback() 和 TxCpltCallback() 依然是由中断触发的!
若使用循环模式接收,需结合 USART 的 IDLE 中断 辨别帧尾。
六、总结
DMA 大幅度降低 CPU 开销,适合高速、大批量数据收发;
使用 HAL 库时,传输完成的回调函数依然需要正确书写;
DMA 配置时需注意内存自增、传输宽度、模式等细节;
可与中断方式互补使用,提升系统效率。
————————————————
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/hallo_zz/article/details/147376041
|