打印
[STM32F1]

DMA接收不定时、不定长UART数据的问题

[复制链接]
749|16
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
yinxiangh|  楼主 | 2023-1-6 18:41 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
在使用UART接收串口数据时,如果使用接收中断来处理,那么每当RXNE为1时就会中断一次,接收1000个字节的数据就要进中断1000次,很占用CPU时间。举例一种比较常见的应用场景,单片机与GPS模块通讯进行串口通讯,GPS模块每1秒通过串口对外发送报文,单片机接收到完整报文后再一并解析。前述中断的方法显然效率不高,这时想到用DMA来提升效率。假如GPS每秒发送的最大报文长度不会超过1000个字节,此时定义数组GpsRxBuf【1000】来存放GPS模块发来的数据。在配置DMA时,将DMA的源地址设置为单片机所使用的UART的DR寄存器,目的地址设置为&GpsRxBuf[0],传输长度(CNDTR寄存器)设置为1000,模式是非循环模式。这样,DMA模块在每收到1个字节的数据后自动将相应UART的DR寄存器中的值搬移到GpsRxBuf数组中去,第一个字节搬移到GpsRxBuf【0】、此时CNDTR寄存器减1,变为999,第二个字节搬移到GpsRxBuf【1】,CNDTR再减1,变为998……,假如接收到的最后一个字节是第100个字节,此时第100个字节被搬移到GpsRxBuf【99】中,CNDTR减为900。由于此时是最后一个字节,此时会进入UART的IDLE中断(需先配置),程序读出当前DMA的CNDTR的值,此时是900,那么就说明单片机本次从GPS模块接收了(1000 - 900),也就是100个字节的数据,此时禁能DMA,将DMA的CNDTR再次设置为1000,再使能DMA,准备下次接收。但这时有个问题存在,就是再次使能DMA的时候,虽然CNDTR已被重设为1000,只代表下次DMA传输的最大字节数改为1000,但DMA模块内部的目的地址指针并未变,也就是说在下一次收到一个字节数据时,DMA会将数据搬移到GpsRxBuf[100]的位置,而不是GpsRxBuf【0】的位置。但我们所希望的是下一秒再收GPS模块发来的数据,是从头开始,也就是从GpsRxBuf【0】开始存放。不知道大家有没有遇到过这种情况?

使用特权

评论回复
沙发
dingy| | 2023-1-6 18:43 | 只看该作者
有一个方法可以实现

启动DMA接收,指定缓冲区地址,然后定时查询已接收DMA数据长度。。。处理数据。。。当DMA中断时再启动从头开始接收

使用特权

评论回复
板凳
yinxiangh|  楼主 | 2023-1-6 18:46 | 只看该作者
但现在问题就在于是否从头开始接收无法控制,我实验的结果是,仅仅只是禁能再使能是不能让DMA模块从头开始接收的,要重新初始化一遍才可以。

使用特权

评论回复
地板
jiajs| | 2023-1-6 18:47 | 只看该作者
不用全部重新初始化,调用个API函数重新设置缓冲区就可以了

使用特权

评论回复
5
yinxiangh|  楼主 | 2023-1-6 18:49 | 只看该作者

谢谢解答。
您指的“重新设置缓冲区”指的是重新设置DMA_CPARx寄存器吗?

使用特权

评论回复
6
stly| | 2023-1-6 18:51 | 只看该作者
不是有启动dma的API吗
HAL_DAC_Start_DMA...

使用特权

评论回复
7
renyaq| | 2023-1-6 18:54 | 只看该作者
如果不定长度呢

使用特权

评论回复
8
zhenykun| | 2023-1-6 18:57 | 只看该作者
使用“双缓存DMA接收”,即是乒乓缓冲区,DMA处理完一个buf通知cpu拷贝,然后DMA切换搬运到另一个buf。

使用特权

评论回复
9
dengdc| | 2023-1-6 19:35 | 只看该作者
另外,DMA接收必须设置为连续模式;对于单次模式,数据多或者波特率高的话可能会丢数据。

使用特权

评论回复
10
jiahy| | 2023-1-6 19:37 | 只看该作者
参考STM32串口DMA收发实现,实测高速通信(1.5Mbps)不翻车:https://acuity.blog.csdn.net/article/details/108367512

使用特权

评论回复
11
yinxiangh|  楼主 | 2023-1-6 19:40 | 只看该作者
嗯,预料中的结果,多谢大家啦

使用特权

评论回复
12
tpgf| | 2023-2-5 11:38 | 只看该作者
接收数据的底层能自己识别是否已经接收完成了吗

使用特权

评论回复
13
paotangsan| | 2023-2-6 09:03 | 只看该作者
看的我好累啊 是不是数据大端小端的问题啊

使用特权

评论回复
14
renzheshengui| | 2023-2-6 09:26 | 只看该作者
yinxiangh 发表于 2023-1-6 18:46
但现在问题就在于是否从头开始接收无法控制,我实验的结果是,仅仅只是禁能再使能是不能让DMA模块从头开始 ...

我也存在这个问题 必须重新初始化才好使

使用特权

评论回复
15
wakayi| | 2023-2-6 10:20 | 只看该作者
jiajs 发表于 2023-1-6 18:47
不用全部重新初始化,调用个API函数重新设置缓冲区就可以了

这个问题就是缓冲区出现问题了是吗 那如果我已经完全读取完成数据了还存在这个问题吗

使用特权

评论回复
16
wowu| | 2023-2-6 10:28 | 只看该作者
完全没有必要每个字节中断啊  可以把一包数据都接收完一次的

使用特权

评论回复
17
xiaoqizi| | 2023-2-6 10:50 | 只看该作者
jiajs 发表于 2023-1-6 18:47
不用全部重新初始化,调用个API函数重新设置缓冲区就可以了

难道每次都需要对缓冲区重新设置吗

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

723

主题

7134

帖子

2

粉丝