高质量程序是怎么写出来的?串口DMA机制

💡 原文中文,约19200字,阅读约需46分钟。
📝

内容提要

本文介绍了串口的DMA功能及其作用,包括低速通信场景下不需要使用DMA,但对于大数据量和高波特率的情况,使用DMA可以提高串口性能。文章详细介绍了串口DMA接收和发送的实现方式,并提供了配置代码和处理方法。最后,给出了完整的源码和压力测试结果。

🔎

延伸解读

DMA并非总是必要:低速场景的权衡

文章指出,串口在波特率≤115200bps且数据量小时,使用DMA并不能充分发挥作用。高波特率下,循环发送会阻塞线程,中断发送则需频繁响应中断(如115200bps下约每69微秒一次),消耗大量CPU资源。因此,是否采用DMA应基于实际波特率和数据量评估,避免过度设计。

接收双缓冲:规避数据覆盖风险

许多教程仅用“空闲中断+DMA传输完成中断”接收数据,但DMA搬运不受CPU控制,CPU拷贝时新数据可能覆盖缓冲区。文章强调需做双缓冲(乒乓缓存),STM32F0虽不支持硬件双缓存,但可利用半满中断模拟:半满时拷贝前半部分,溢满时拷贝后半部分,交替进行,确保数据安全。

发送配置:每次重新初始化DMA通道

串口DMA发送需将通道设为单次模式,每次发送前重新配置所有参数。文章特别提醒,仅修改发送buf大小的做法在数据量大时会导致发送失败且不触发完成中断。此外,发送状态标识必须在启动DMA前置位,否则在数据量少时可能因中断先执行而误判状态,导致标识无法清除。

压力测试验证:1.5Mbps下的稳定表现

文章在STM32F030C8T6平台(48MHz主频)上进行了压力测试:1.5Mbps波特率下,串口助手每毫秒发送1KB数据,STM32F0通过DMA接收并回传,毫无压力;还进行了大文件传输比对。这表明该实现方案在高波特率、大数据量场景下具有可靠性,但需注意USB转TTL工具和串口助手需支持高波特率。

❓

Q&A

串口在什么情况下需要使用DMA?

当数据量较大或波特率较高时,使用DMA是必要的。高波特率下,循环发送会阻塞线程消耗CPU,中断发送会频繁响应中断消耗资源;接收时传统中断模式也会因频繁中断消耗大量CPU。低速通信(波特率≤115200bps且数据量小)则不需要DMA。

STM32串口DMA接收为什么要用双缓冲或半满中断机制?

因为DMA传输不受CPU控制,当DMA传输完成时CPU开始拷贝数据,若串口继续有数据进来,DMA会继续搬运数据到buf,可能覆盖尚未处理的数据。使用双缓冲(乒乓缓存)或利用STM32F0的buf半满中断,可以让CPU和DMA交替访问不同内存区域,避免数据覆盖风险。

STM32串口DMA接收需要处理哪些中断场景?

需要处理三种中断场景:DMA通道buf溢满(传输完成)中断、DMA通道buf半满中断、串口空闲中断。前两者用于在DMA搬运数据到一半或全部完成时通知CPU拷贝数据;串口空闲中断用于处理数据量小于buf或非整数倍buf的情况,在串口一段时间无数据后触发。

串口DMA发送时如何配置DMA通道?

发送时DMA通道工作模式设为单次模式(正常模式),每次需要发送数据时重新配置DMA通道所有参数(包括内存地址、数据大小等),使能传输完成中断,启动前清空相关状态标识。不能仅修改buf大小,否则数据量大时可能导致发送失败且不触发完成中断。

串口DMA发送处理函数应该在什么时机调用?

可以在主线程任务中调用(需确保线程不被阻塞)、定时器中断中调用、或DMA传输完成中断中调用。原则是及时查询发送fifo,当fifo数据量大于等于DMA发送buf大小时填满buf并启动传输,以充分利用DMA性能并兼顾实时性。

STM32F0系列串口DMA的压力测试结果如何?

在1.5Mbps波特率下,串口助手每毫秒发送1k字节数据,STM32F0使用DMA接收并回传,毫无压力;也可稳定传输大文件,将接收数据保存为文件与源文件比较一致。测试需USB转TTL工具和串口助手支持高波特率,推荐CP2102、FT232芯片。

🏷️

标签

➡️

继续阅读