你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

【实战经验】串口工作在DMA模式下有时接收异常

[复制链接]
zero99 发布时间:2016-7-12 14:44
串口工作在DMA模式下有时接收异常
7 P  l3 o4 G" S! @6 ?2 ~; x
前言8 a$ p% c% I' I3 d3 n
客户反馈在使用STM32F205的串口工作在DMA模式时,有时能够接收数据,有时完全没有数据,但如果换成中断模式来接收又能100%正常收到数据。
  @4 d& B8 }$ _1 \1 m% U! m& r& J5 Q1 Y. ^: U
一 复现现象  g- ]$ m' X8 U. x' k
问题背景
( @; R0 g# I' Z, k7 r7 u$ R与客户沟通,客户使用的是STM32F2标准库V1.1.0,串口波特率为1.408Mbps,不经过串口RS232,直接连接主CPU和从MCU(STM32F205)的串口发送和接收引脚,如下图所示:! L. P; I( a' }, U7 H( }) \. G

/ b" g$ k0 Z* H# j 1.png ( q* R3 l" T+ n$ H; r
3 c* P2 y5 B% ]! Q% v3 T
尝试重现问题
) P  N( `6 e4 V* }6 c1 S! K) ~% L由于客户使用的是主从架构,实验采用两块STM3220G-EVAL评估板来重现现象。一块用来不间断发送串口数据,另一块采用串口DMA进行接收,直接通过杜邦线连接串口PIN脚并共地,不使用评估板上的RS232收发器。接收端使用STM32F2xx_StdPeriph_Examples\ USART\USART_TwoBoards的示例代码。代码片段如下: 4 f9 p. ~9 W# v) n
# T1 C0 O- D: ]' F% p$ b# l- f
2.png
, p3 A' X8 y: r  k! m$ t% _. g" ?, b+ I4 \, N1 n
3.png
. E* N' k! V3 x5 q0 ]0 d) ]* q( m) v* d
USART_Config()函数如下: : s0 @7 R/ [1 R% D/ r! u$ o

6 P# M$ ]7 _5 }* o, S" s. c* N 4.png & X7 r' R9 ?3 l7 y4 I& p, i

! N! U6 m! p. B1 U2 A) E# H+ o 5.png 1 s7 j0 q7 c+ L/ v& _

  K( {/ L& m/ X8 H0 w, P3 ]: ]4 a 6.png # Q1 t, V6 l0 g% t& b3 X, k

8 q5 y9 G7 h7 z& n9 N按如上代码,有如下现象:
3 G& P* I6 F3 @% {% ~& o- _/ @! [1 代码不做修改,若先启动接收端MCU再启动发送端MCU,接收端MCU的串口能正常接收。+ ~1 r2 T; S6 L
2代码不做修改,若先启动发送端MCU再启动接收端MCU,接收端MCU的串口100%接收异常。
5 M  a7 t7 h0 G8 @4 Z" ^4 g3 修改发送端代码,改为发送端MCU串口每1秒间隔发送一次,则无论启动顺序如何,接收端MCU的串口都能正常。) M4 o3 b) d/ ~: M  _8 e4 g" `
  C# c3 V% @, a: S, }2 f
二 程序分析
  F+ o5 ~6 v6 x2 r- p由上述代码可知,程序是先在USART_Config()函数函数内初始化串口并使能,然后再在接下来的main函数的while循环内初始化DMA并使能。这个是标准库内附带的示例代码,咋一看没什么问题,但仔细一想,针对用户的使用场景,这里就会产生一个问题:由于用户的主CPU有可能在从MCU启动之前就已经有可能启动,那么在这种情况下,在初始化完串口并使能后,到DMA使能之前这段时间内,若主CPU向从MCU发送串口数据,从MCU是否能正确接收?
" \" |  f4 b* i2 i" D* f; r6 E7 m  s. [' v. m5 o. W4 N2 Q
从上述测试代码的结果2可以得出,若在串口初始化并使能后到DMA使能之前有数据来,MCU是不能接收的,经进一步调试,发现此时数据寄存器USART_DR存在一个数据,且在状态寄存器USART_SR中ORE值1,由此可知,串口的接收寄存器中已经接收到一个数据,但是后面的数据又来了,由于数据寄存器中的数据没有及时转移走(此时DMA还没有开启),从而导致后面的数据无法存入,所以产生了上溢错误(ORE),而一旦产生上溢错误后,就无法再触发DAM请求,及时之后再启动DMA也不行,无法触发DMA请求就无法将数据寄存器内的数据及时转移走,如此陷入死锁,这就是串口无**常接收的原因。这时反观一下代码的结果3,这又将做如何解释?4 O4 c- J2 A- J, J- V
8 @4 F* W( D- G# m
仔细查看测试结果3,发现这个发送端每1秒间隔发送一次,那么就会存在这个一个概率,这个发送的时间点是否刚好在接收端MCU的串口初始化并使能和DMA使能之间还是之后,这个时间窗口非常关键,如果刚好在时间窗,那么串口接收就不正常,如果在这个时间窗之后,串口接收就能正常。由于测试代码采用的是1秒间隔,对于MCU来说这个是非常大的时间长度,还是很小概率能碰中这个时间窗的,因此,测试结果看起来是都能正常,实际严格来说,还是存在刚好碰中的可能。如果间隔时间缩短,那个碰中的几率就增大。由此看来,这也就能解释测试结果3了,也能解释客户提到的有时正常有时不正常的现象了。9 \1 s6 A. H! q5 Z9 f7 Y7 z" O

9 h  W* S/ w& j" @# ?+ Q三 问题处理
# Q% z& h, k; e# b处理有两种方法,第一种方法是在使能DMA后,及时将数据寄存器DR中的数据清除掉,如下代码所示:
% k- q: \6 m6 J5 T! k. C: X/ D1 ?, i* m) {+ e. l6 ]
7.png 8 e( Z0 e+ E$ t! S' t1 g2 j

0 u; ~6 t3 k2 ~: w这里是使用读DR的方法来清除的,从参考手册中也提到使用这种方法来清除ORE标志:
/ Q  X5 g& N  R
& N/ `3 L( J9 X% h3 K( s, |/ b 8.png % z& a; R' e% n2 |. f; `& L' Z4 a( t& T
% d8 w! K# x, E5 c) G: G
第一种方法类似于一种纠错措施,下面介绍另一种推荐的方法,如下代码所示:
+ Y1 ^$ S, F: ]6 A/ d* P$ P/ H! V( g' p7 e/ p
9.png
& F2 }) l8 z: |8 \/ _& o% B9 ~1 Q: Z& o0 @6 _' y
如上所示,可以先使能DMA再使能串口,这样就彻底不存在那个时间窗了,不管数据何时过来能能被DAM及时转走。这个是推荐的解决方法。
. G5 a! Q2 Q- |, _0 A' v% e4 ?& R! a
四 结论
( p/ b- ^3 e7 D1 V- R标准库中的示例代码一般来说只供参考,对于大部分情况来说都是能正常工作的,但偶尔也会出现不适用的情况,此时更需要我们针对问题进行思考分析,进一步找到原因才能解决问题。对于串口使用DMA来接收的情况,这里建议一定要先使能DMA,最后使能串口,这样就能避免类似问题出现了。+ f2 w& H7 [2 B$ N
5 `! }/ l/ d& q
) q  a# L( P' u  W' T: A
文档下载地址:# C& Q2 K' i; i% ^# G
https://www.stmcu.org.cn/document/detail/index/id-217182

2 |& y9 J% k7 K; B7 t9 h
9 s# @" c3 F9 S4 Q; H  g实战经验汇总:1 S! Y1 o* G( N- d% w
https://www.stmcu.org.cn/module/forum/thread-576401-1-1.html, |9 v9 I; B$ r* t2 y& a* i
" T1 Q# P4 Y" J: d! ~. N" ]9 f
收藏 4 评论7 发布时间:2016-7-12 14:44

举报

7个回答
leiyijing 回答时间:2017-3-24 17:47:42
我们也发现了同样的问题,既然ST知道了有问题,怎么不更新库文件呢?
faye1 回答时间:2017-7-17 13:30:20
厉害,基本也是类似的问题,搞了很久
Abners 回答时间:2017-9-27 18:31:02
我用的是103的片子,也遇到一个问题,不过是发送的,特定长度,最后一个字节不对!苦逼呀!!!
任风吹吹 回答时间:2018-5-9 10:09:34
leiyijing2003 发表于 2017-3-24 17:47
3 N# a# d% m6 ?$ {我们也发现了同样的问题,既然ST知道了有问题,怎么不更新库文件呢?
) h, R' l2 D, @/ C
这个属于应用层代码调用顺序问题,为什么要更新库?看懂了再说话
Nikola 回答时间:2018-11-22 09:53:39
不错,支持下
@LARRY@ 回答时间:2018-12-28 09:47:17
Abners 发表于 2017-9-27 18:31  q" S* J4 y9 c9 h, b1 y
我用的是103的片子,也遇到一个问题,不过是发送的,特定长度,最后一个字节不对!苦逼呀!!! ...
; V: w5 }6 d$ c: D  J5 S& k
你可以在DMA发送完成后检查一下串口是否空闲,因为DMA发送完了之后串口还要1到2个字节的时间,判断下串口发送完成标志位就好了
liudawei123 回答时间:2019-9-12 11:34:44
非常不错哦,支持下

所属标签

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版