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

【经验分享】一个因初始化顺序而导致异常的话题

[复制链接]
STMCU小助手 发布时间:2022-2-16 19:36
有 STM32 用户反映,他使用 STM32F4 系列芯片进行开发,通过 STM32CubeMx 配置初始化代码,使用了 UART 的 DMA 传输。但他发现 DMA 根本不工作。后来他无意中发现,是因为他在用户代码里不经意地调整过 UART 外设和 DMA 外设初始化代码的前后顺, }- Q8 K: W' l
序,当他重新调整二者的先后顺序后就一切正常了。他想知道这个顺序是怎么影响 DMA功能的。
1 L: t5 N$ Q7 R2 b" f# h$ K; s我顺手拿了块 STM32F334 的 Nucleo 板,开启 UART1/UART3 的数据通信功能,使用DMA 进行数据的循环传输。UART1 发送数据,UART3 接收数据,均配置在异步双工模式。基于 STM32CubeMx 配置后生成初始化代码,添加用户代码。如下图所示:2 F% r6 F/ e. s$ X7 `8 P' s; [

( o) W& r7 N: D% O4 v UH_HXO06U)40W5I4)F4EV_2.png
; _8 [. a1 ?; f# e$ w( i- D- w, s0 t9 q8 g* ~2 N( v; u
7 Y- z% v0 A; |, K0 T
经测试验证,发现基于 UART1/3 的 DMA 传输功能是正常的。3 D/ z6 {* v9 ~) p. Y, z
6 Y/ {# L$ C6 q$ L+ R4 w
结合客户的反馈,我将 DMA 与 UART 初始化顺序前后调换下,如下图:* T8 U" K3 S1 T

: K# n8 J$ C5 ^, R& W5 ~ }F1B({YB8Q(R_]WA8N7K9%3.png   `, ~$ z" @  y' g# i* R4 G: M
8 D+ c% g) T# J* Q
果然发现,DMA 真的不工作了,UART1/UART3 之间没有发生数据通信。通过调试发现,UART1/3 的数据寄存器内容维持 0 值而没有任何变化,尤其作为发送端的 UART1的数据寄存器也毫无动静。+ C! R7 n& _( W
3 C2 a2 }; @! I$ D3 X. ]
看来,DMA 和 UART 的初始化代码的顺序的确影响到了二者的功能。也就是说如果代码是基于现有 CubeMX 生成的初始化代码,二者的初始化顺序不能随意调整,那到底怎么回事呢?6 ]( I# {  h+ B# g: [7 c$ |. s

4 G( q; i0 u1 q( R, ~+ T! k, v7 I; [3 V
5 V8 n! w* u9 _& i; Q: E首先自然是查看这两个初始化代码内容,试图找到蛛丝马迹。很遗憾,并未很快发现原因。当再次查看 DMA 初始化函数 MX_DMA_Init();的具体内容时,发现其代码其实很简单,就两个动作,几行代码而已:8 J0 \* n5 q6 r1 Z0 T

& I) Y! k! G/ C( w2 P% x' V" X  Y0 N3 y$ I0 S
SUM]Z%W4F@1N8K@~F]JQ2PU.png
! [2 z* m7 U1 }+ H: O8 x
% O) |7 f3 ?6 E5 M& j6 J一个开启 DMA 外设的时钟,另一个动作就是使能 DMA 相关的中断矢量控制。6 o& ?! D0 D/ _, p7 l  v* o5 P

, ^- l5 F$ G- O9 y/ }% i8 ]既然这样,我尝试将该 DMA 初始化函数体位置依然放在 UART 初始化代码的后面,但将DMA 初始化函数里的那句开启 DMA 外设时钟的代码提取出来,并移到 UART 初始化代码之前,据此进行验证。这次,结果又一切正常了。9 B" f5 c3 l) \- c% ^9 D+ h! z

5 @4 a# o2 D' a9 e也就是说,基于现有初始化代码,这个 DMA 时钟的开启要放在 UART 初始化代码之前,那是为什么呢?感觉 UART 的配置跟 DMA 时钟并没有啥关系啊。
- e( M" O$ a% n0 s) Y1 J$ a" W: d5 v0 o! s0 `, N
再回头细看 UART 的初始化代码,在 UART 初始化函数的一个子函数HAL_UART_MspInit()那里发现了端倪。
" Y! y1 Z# d" D9 a. a# m# y; N% N
' R0 W) D" Q) D; L9 S$ u5 IMX_USART1_UART_Init()==》HAL_UART_Init()==》HAL_UART_MspInit();0 n; n! }! z# Z5 E2 y+ `+ H  K

1 u' S3 R8 \- Z1 h因为我们开启了跟 UART 传输事件相关的 DMA 功能,在 UART_MspInit();函数里不仅有对与 UART 相关的 GPIO 的复用功能配置,还有跟 UART 事件有关的 DMA 配置。看来UART 的初始化还是跟 DMA 有关联的。【见如下截图】
5 M& ~% X% O& U0 H6 ^( L4 z( U" `- S! n% P! P: A4 p
F8EAO7XC4PXXJ$U043S8.png
/ E* X7 K+ Q. u) l0 N4 M7 x" j$ `0 g, t/ Z, V1 ^- N
结合前面提到的 DMA 初始化函数里的那句开启 DMA 外设时钟代码,到这里基本明白怎么回事了。: \& m9 I( C4 N" ]& H* y& _
- m* _8 s+ Z7 J- f% t
因为我们在 UART 初始化代码里要做跟 DMA 有关的配置,如果不事先将 DMA 外设的时钟开启,【UART 初始化函数里也没有开启 DMA 外设时钟的代码】,那么,在 UART 初始化代码进行有关 DMA 的配置操作就没法保证有效。1 J# f# T" ]& e( \* r( t5 c* f

5 h+ A( D& Z# t" O0 M# f到此,开篇中提到的因为 DMA 和 UART 初始化代码顺序影响 DMA 功能的原因应该说揭晓了。, ~7 m  }/ p0 S/ i! u

3 K$ w  c: W. X在做嵌入式开发过程中,很多的初始化配置都是基于硬件本身的,有些初始化顺序往往有硬件方面的配置时序要求,关于这些各个芯片手册中一般都会有描述和说明。我们在编写初始代码时须遵循相关规定或约定。当然,有些配置顺序可能还得结合具体应用,实际体会后而做灵活调整。& L* {8 A! s/ s( d7 U3 R

2 ?" u, _! h/ t- i3 x具体到文中案例,本来 STM32CubeMx 在生成初始化代码时已经考虑到初始化时序这点了,只是用户在整理代码过程中无意调整了二者的初始化顺序而不自知,再加上我们对CubeMx 生成的初始化代码本身往往缺乏足够的熟悉度,在开发过程中可能会因此陷入一时的困扰。关于这点,相信未来版本的 STM32CubeMx 会做进一步的调整与完善。$ H- [9 R1 b) z: p$ O- k4 C( r: \
' Q( [+ i' m1 z  d+ W8 {
赞 收藏 评论0 发布时间:2022-2-16 19:36

举报

0个回答

所属标签

相似技术帖

官网相关资源

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