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

技术分享 | 初始化顺序为何会导致异常?

[复制链接]
STMCU-管管 发布时间:2019-12-4 11:09
一个因初始化顺序而导致异常的话题

9 |3 w  M1 U/ G& ^2 S
有STM32用户反映,他使用STM32F4系列芯片进行开发,通过STM32CubeMX配置初始化代码,使用了UART的DMA传输。但他发现DMA根本不工作。后来他无意中发现,是因为他在用户代码里不经意地调整过UART外设和DMA外设初始化代码的前后顺序,当他重新调整二者的先后顺序后就一切正常了。他想知道这个顺序是怎么影响DMA功能的。

: e4 \* r7 ?% x! R# ^/ `& b9 j4 Q' C
笔者顺手拿了块STM32F334的NUCLEO板,开启UART1/UART3的数据通信功能,使用DMA进行数据的循环传输。UART1 发送数据,UART3接收数据,均配置在异步双工模式。基于STM32CubeMX配置后生成初始化代码,添加用户代码。如下图所示:

: ^( |6 z% \% M5 ~" Z; p
11.png

- |5 A2 S; \- u
经测试验证,发现基于UART1/3的DMA传输功能是正常的。

7 z+ K! p( V; @- c
结合客户的反馈,我将DMA与UART初始化顺序前后调换下,如下图:
8 @2 p6 X' B5 @4 s- d* L
22.png
- I) E5 N# ?0 |; w
果然发现,DMA真的不工作了,UART1/UART3之间没有发生数据通信。通过调试发现,UART1/3的数据寄存器内容维持0值而没有任何变化,尤其作为发送端的UART1的数据寄存器也毫无动静。
' V$ y# O+ S9 M! g9 t3 c: q7 J
看来,DMA和UART的初始化代码的顺序的确影响到了二者的功能。也就是说如果代码是基于现有CubeMX生成的初始化代码,二者的初始化顺序不能随意调整,那到底怎么回事呢?

- R5 Q. V4 X* F1 B
首先自然是查看这两个初始化代码内容,试图找到蛛丝马迹。很遗憾,并未很快发现原因。当再次查看DMA初始化函数MX_DMA_Init();的具体内容时,发现其代码其实很简单,就两个动作,几行代码而已:
. K4 W. {8 b" n6 d9 H1 a5 H
33.png
3 N/ J5 c5 \! ^4 }6 _* z
一个开启DMA外设的时钟,另一个动作就是使能DMA相关的中断矢量控制。
/ X+ ]1 Y5 I) e# ^) {6 s$ e: z' s/ [
既然这样,我尝试将该DMA初始化函数体位置依然放在UART初始化代码的后面,但将DMA初始化函数里的那句开启DMA外设时钟的代码提取出来,并移到UART初始化代码之前,据此进行验证。这次,结果又一切正常了。

/ ?7 h2 p+ A( R5 {, t& K3 e
也就是说,基于现有初始化代码,这个DMA时钟的开启要放在UART初始化代码之前,那是为什么呢?感觉UART的配置跟DMA时钟并没有啥关系啊。
+ v% y! W9 A$ ?3 y7 z
再回头细看UART的初始化代码,在UART初始化函数的一个子函数HAL_UART_MspInit()那里发现了端倪。
! B- ^4 e6 d) t5 k  b8 r
MX_USART1_UART_Init()==》
HAL_UART_Init()==》
HAL_UART_MspInit();

3 k3 }3 d+ r" |, b+ y
因为我们开启了跟UART传输事件相关的DMA功能,在UART_MspInit();函数里不仅有对与UART相关的GPIO的复用功能配置,还有跟UART事件有关的DMA配置。看来UART的初始化还是跟DMA有关联的。【见如下截图】

7 q  {  i% b# Y9 ]; k! E' Y. n* [2 M
44.png
* F2 u- C0 X7 a9 @3 _5 c; o
结合前面提到的DMA初始化函数里的那句开启DMA外设时钟代码,到这里基本明白怎么回事了。
- Z0 Z* S: }6 t2 X3 X1 @& i1 A
因为我们在UART初始化代码里要做跟DMA有关的配置,如果不事先将DMA外设的时钟开启,【UART初始化函数里也没有开启DMA外设时钟的代码】,那么,在UART初始化代码进行有关DMA的配置操作就没法保证有效。

. J2 B7 r, f/ G2 [% D! f& _$ H, H  ^
到此,开篇中提到的因为DMA和UART初始化代码顺序影响DMA功能的原因应该说揭晓了。

$ v. d7 G5 ?2 |0 R2 v5 B% h. q
在做嵌入式开发过程中,很多的初始化配置都是基于硬件本身的,有些初始化顺序往往有硬件方面的配置时序要求,关于这些各个芯片手册中一般都会有描述和说明。我们在编写初始代码时须遵循相关规定或约定。当然,有些配置顺序可能还得结合具体应用,实际体会后而做灵活调整。

% T+ S. L& L1 }& j1 \/ h  @0 @0 b
具体到文中案例,本来STM32CubeMX在生成初始化代码时已经考虑到初始化时序这点了,只是用户在整理代码过程中无意调整了二者的初始化顺序而不自知,再加上我们对CubeMX生成的初始化代码本身往往缺乏足够的熟悉度,在开发过程中可能会因此陷入一时的困扰。关于这点,相信未来版本的STM32CubeMX会做进一步的调整与完善。
1 h2 d6 o9 _5 R& j" C$ I
资料下载>>! s9 B4 _$ Y. G) d7 C/ o
# X6 ?" [1 L. Q6 h  ]
赞 收藏 1 评论8 发布时间:2019-12-4 11:09

举报

8个回答
老牛洋车 回答时间:2019-12-4 11:13:18
看来CubeMX生成的代码顺序尽量不要去改变。
cloudcn 回答时间:2019-12-4 11:46:48
UART的DMA方式是依赖DMA的,DMA的EN不打开寄存器根本写不进去 ( F  x. [4 F! U# H1 B
先初始化UART时写DMA还没启用,写寄存器也白写,自然不好用
. X4 _2 o1 ]4 C, W/ |, K微控制器初始化的一般顺序是由内向外 先独立后复合
七哥 回答时间:2019-12-4 12:02:24
用ST芯片,记住一点,对某外设寄存器的操作时,必须开外设时钟,不然操作无效。
疯de_恒 回答时间:2019-12-4 16:44:17
更新HAL库,如果遇到需要操作的模块还没打开相应时钟,自动打开再配置。
qiangtech 回答时间:2019-12-4 17:26:43
す疯Ⅱ恒す 发表于 2019-12-4 16:44
- B5 M* Z2 w# b7 k- B& \! H" y% j/ d更新HAL库,如果遇到需要操作的模块还没打开相应时钟,自动打开再配置。

  H# ^  F6 d- E9 `0 }正解,大大提升了容错率。
wyxy163@126.com 回答时间:2019-12-4 20:10:19
提示: 作者被禁止或删除 内容自动屏蔽
慎微 回答时间:2019-12-5 16:18:33
MX_DMA_init() 相当于先分配内存空间啊。没分配空间就进行内存处理,异常在情理中。
lwg8458 回答时间:2019-12-7 09:55:10
所以HAL库没有标准库灵活
关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版