打印
[STM32F1]

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

[复制链接]
2238|6
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
素心之剑|  楼主 | 2018-8-17 12:16 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 素心之剑 于 2018-8-17 12:20 编辑

在使用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】开始存放。不知道大家有没有遇到过这种情况?

沙发
ayb_ice| | 2018-8-17 13:12 | 只看该作者
有一个方法可以实现

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

使用特权

评论回复
板凳
素心之剑|  楼主 | 2018-8-17 13:29 | 只看该作者
ayb_ice 发表于 2018-8-17 13:12
有一个方法可以实现

启动DMA接收,指定缓冲区地址,然后定时查询已接收DMA数据长度。。。处理数据。 ...

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

使用特权

评论回复
地板
ayb_ice| | 2018-8-17 14:52 | 只看该作者
素心之剑 发表于 2018-8-17 13:29
谢谢解答。
但现在问题就在于是否从头开始接收无法控制,我实验的结果是,仅仅只是禁能再使能是不能让DMA ...

不用全部重新初始化,调用个API函数重新设置缓冲区就可以了

使用特权

评论回复
5
素心之剑|  楼主 | 2018-8-17 15:10 | 只看该作者
ayb_ice 发表于 2018-8-17 14:52
不用全部重新初始化,调用个API函数重新设置缓冲区就可以了

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

使用特权

评论回复
6
ayb_ice| | 2018-8-17 15:58 | 只看该作者
素心之剑 发表于 2018-8-17 15:10
谢谢解答。
您指的“重新设置缓冲区”指的是重新设置DMA_CPARx寄存器吗?

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

使用特权

评论回复
7
renzheshengui| | 2018-8-18 15:43 | 只看该作者
如果不定长度呢

使用特权

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

本版积分规则

9

主题

17

帖子

1

粉丝