[求助] STM32的DMA应用于UART数据接收讨论

xg_qing   2012-10-19 17:28 楼主
STM32的UART不带FIFO,通讯速度高时不使用DMA开销太大(LM3S有16级深的FIFO可以7/8满触发中断,带超时功能,亮点啊)。打算用DMA配置成外设到内存的数据传输方式实现数据接收,实现下来确实有难度啊。
具体如下
配置DMA时,必须先指定接收BUF大小,DMA传输中断可选择为传输错误、半传输或传输完成时产生。

关键问题是实现通讯时事先不知道要接收的数据包大小,对端不同类型数据包发送完成时DMA传输进度也会各不相同(和配置的DMA buf深度没有没系),无法保证所有包会产生半传输或传输完成中断。考虑增加一个定时器发送消息提示DMA进度,但高速通讯时,定时器的开销也较大。不知道有没有更好的办法。

应用中需要高传输速度与快速响应。STM32似忽很难实现啊。

实现不行只能放弃使用DMA,直接中断处理了。

回复评论 (17)

你不知道数据包的大小所以无论无何不可能实时响应的,因为你不知道何时结束是吧

可以考虑在发包前先加上包大小然后在启动dma
点赞  2012-10-19 18:31
引用: 原帖由 huo_hu 于 2012-10-19 18:31 发表
你不知道数据包的大小所以无论无何不可能实时响应的,因为你不知道何时结束是吧

可以考虑在发包前先加上包大小然后在启动dma
想法不错,但实现也许不行。因为数据包是走协议的,要判断帧标志以及数据帧格式正确性,收到一个数据就认为是包大小抗干扰将会比较差,且一旦有干扰将无法给包定界。
点赞  2012-10-19 20:40

回复 板凳 xg_qing 的帖子

那就第一个包作沟通,第二个包传输数据好了
点赞  2012-10-21 11:54
既然你是有协议的,那都还好办的啊,例如modbus 地址判断完后有数据长度标识,然后把这个数据长度读入DMA 的长度。再做DMA 的读取。
       还有就是超时定义超时了就直接关闭DMA 读数据好了,一帧的时间不可能无限长的,只要是协议长数据帧一定会分有后继帧,后继帧虚等前一帧数处理完后回应才发后继帧的,所以这里定义一下最长长度帧的超时计时 就好了
点赞  2012-10-21 13:35
引用: 原帖由 虚V界 于 2012-10-21 13:35 发表
既然你是有协议的,那都还好办的啊,例如modbus 地址判断完后有数据长度标识,然后把这个数据长度读入DMA 的长度。再做DMA 的读取。
       还有就是超时定义超时了就直接关闭DMA 读数据好了,一帧的时间不可能无限 ...
目前使用包格式类似Modbus,帧标志+源地址+目标地址+功能码+数据区字节数+数据区+CRC16。数据区最大长度为250个字节。
大部分情况下每包数据在0~40个字节之间,只有文件读写时会达到最大值250,只数据区接收时使用DMA可能改善不大啊。

包超时的想法很妙呀!你的想法是在接收数据区长度时启动DMA,同时启动超时定时器吗?呵呵,高手,这个办法确实有效解决了数据接收时的CPU开销。协议前段处理CPU开销看起来很验省下来了。STM32确实有些美中不足啊。

TI的M3 UART做得比较好就是有一个16级深的FIFO,我可以选择在接收端满了7/8产生时产生中断,同时也不必担心对端数据已经发送完成接收FIFO还没满不能产生中断的情况,因为可以选择接收超时中断(32个位时间没数据就认为接收超时)。这样对端包发送完最多32个位时间内就可以得到处理,收到14个字节才需CPU中断处理一次,CPU开销降低了很多。
使用STM32真的感觉很难兼顾低CPU开销与快速处理, 呵呵,STM32才开始用,也许是我菜没找到完美的方法吧。
点赞  2012-10-21 18:38
引用: 原帖由 huo_hu 于 2012-10-21 11:54 发表
那就第一个包作沟通,第二个包传输数据好了
大部分情况下每包数据在0~40个字节之间,只有文件读写时会到260个之字节,第2个包时间省了,第一个包CPU要处理,还是有点治镖不治本啊。
点赞  2012-10-21 18:42
用中断方式接收,发送时使用DMA

这么高速,进度率有啥用处啊?眼睛观察不过来吧
点赞  2012-10-21 18:48
引用: 原帖由 kevinyzw 于 2012-10-21 18:48 发表
用中断方式接收,发送时使用DMA

这么高速,进度率有啥用处啊?眼睛观察不过来吧

发送是使用的DMA,数据传输速度如果大于1M,中断接收的开销就比较大了,毕竟CPU也才72M啊。
红色不明白。
点赞  2012-10-22 16:26
你可以采用DMA的乒乓模式进行接收,其中乒的时候,设置为接收一个字节,当收到一个字节后,切换到乓的模式进行接收,同时启动定时器。
定时器的时长根据能接收完所有数据的时间合理定义。
当定时器超时中断后,查询乓模式接收到的数据,如果数据量有变化,说明数据未接受完成,重新启动定时器,继续接收。
如果数据量不变,说明数据接收完成(模拟超时)。

合理的定义定时器的超时,可以提高接收效率。你可以试试看。
点赞  2012-10-24 14:02
引用: 原帖由 azhiking 于 2012-10-24 14:02 发表
你可以采用DMA的乒乓模式进行接收,其中乒的时候,设置为接收一个字节,当收到一个字节后,切换到乓的模式进行接收,同时启动定时器。
定时器的时长根据能接收完所有数据的时间合理定义。
当定时器超时中断后,查询 ...
兵乓模式类似6楼的实现,此时DMA启动不再是接收数据字节长度位置而是一旦接收到数据就启动定接收后续,并定义超时。理解没错吧?
虽然STM32不支持兵乓模式(LM3S系列才有),但也可以用中接接收一个数据再启动DMA与超时定时器来实现。

目前为止,就这个方案最高效了。。

LM3S UART接收没必要搞得这么麻烦不?FIFO加超时机制已经非常高效了, 发送倒时可以用,更高效,又简单。
点赞  2012-10-24 23:43

回复 11楼 xg_qing 的帖子

确实是这样,LM3S的DMA也不支持超时中断。

ATMEL的DMA是支持超时中断的,类似于LM3S的FIFO超时中断。

不过DMA收发的话,对MCU的资源占用是非常小的,这是UART+FIFO不可比拟的。
点赞  2012-10-25 08:42
引用: 原帖由 azhiking 于 2012-10-25 08:42 发表
确实是这样,LM3S的DMA也不支持超时中断。

ATMEL的DMA是支持超时中断的,类似于LM3S的FIFO超时中断。

不过DMA收发的话,对MCU的资源占用是非常小的,这是UART+FIFO不可比拟的。

使用DMA CPU负担轻多了,但针对这种不知道传输数据量的情况下DMA的实时性比UART+FIFO还是要差,ATMLE没用过,支持DMA超时的话那就是最完美的了。

有了上面各位的铺垫,我又想到了另一种实现。

简单的配置DMA接收数据,设置传输完成中断,同时,配置一个定时器中断,每次定时中断到来时检查DMA有没有数据到达,若有,手动挂起DMA中断处理数据,若无则不做任何处理。数据处理全部在DMA中断中完成,结构非常简单。

这样处理后,数据处理延时最坏情况下也就是定时器的中断时间,实时性较好。

例如,可以设计为1mS中断一次,对大部分系统来说,这个中断开销都是合适的,带操作系统时直接用Tick时钟就行了。
点赞  2012-10-25 11:37
官方有利用DMA用作FIFO的文档,不知道实际怎么做,没仔细看!!!
点赞  2012-10-26 22:49

回复 14楼 MouseCat 的帖子

到ST官网上查看了AP, 确实如你所说,AN3109有描述该问题及解决方案。它用两种方式实现了DMA超时处理。一种用定时器捕捉检测空闲,另一种用UART中断检测空闲。前一种更高效,但占用定时器资源。

两种方式都比我的要高效,且实时性和TI的FIFO加超时是一样的。看来该问题已经可以完结了。本来已经用自己的方试实现了,现在看来还得改了。以后要多去去官网看看。。。

多谢大家!
点赞  2012-10-27 10:53
DMA是可以实现,也可以单个字节接收放到一个环型缓存区中。空闲时就处理。应该没问题。
点赞  2012-10-29 15:57
“STM32的UART不带FIFO,通讯速度高时不使用DMA开销太大”
有多大开销?
接收到一个字节后进中断,中断服务中将其取出来后放到一个缓冲区中不就完了嘛!
115200的波特率,一个字节的完成时间约是100uS。
点赞  2012-11-1 09:00
UART IDLE中断
点赞  2014-1-21 14:24
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 京公网安备 11010802033920号
    写回复