打印
[STM32F1]

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

[复制链接]
605|8
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
yinxiangh|  楼主 | 2020-4-4 13:45 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
在使用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】开始存放。不知道大家有没有遇到过这种情况?

使用特权

评论回复
沙发
zhuww| | 2020-4-4 13:49 | 只看该作者
有一个方法可以实现

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

使用特权

评论回复
板凳
yinxiangh|  楼主 | 2020-4-4 13:52 | 只看该作者

但现在问题就在于是否从头开始接收无法控制,我实验的结果是,仅仅只是禁能再使能是不能让DMA模块从头开始接收的,要重新初始化一遍才可以。

使用特权

评论回复
地板
chuxh| | 2020-4-4 13:56 | 只看该作者
不用全部重新初始化,调用个API函数重新设置缓冲区就可以了

使用特权

评论回复
5
yinxiangh|  楼主 | 2020-4-4 13:59 | 只看该作者

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

使用特权

评论回复
6
zwll| | 2020-4-4 14:08 | 只看该作者

不是有启动dma的API吗
HAL_DAC_Start_DMA...

使用特权

评论回复
7
dingy| | 2020-4-4 14:12 | 只看该作者
如果不定长度呢

使用特权

评论回复
8
yinxiangh|  楼主 | 2020-4-4 14:16 | 只看该作者

嗯,预料中的结果,多谢大家啦

使用特权

评论回复
9
Prry| | 2020-11-26 00:02 | 只看该作者
使用“双缓存DMA接收”,即是乒乓缓冲区,DMA处理完一个buf通知cpu拷贝,然后DMA切换搬运到另一个buf。另外,DMA接收必须设置为连续模式;对于单次模式,数据多或者波特率高的话可能会丢数据。
参考STM32串口DMA收发实现,实测高速通信(1.5Mbps)不翻车:https://acuity.blog.csdn.net/article/details/108367512

使用特权

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

本版积分规则

723

主题

7134

帖子

2

粉丝