请选择 进入手机版 | 继续访问电脑版

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

基于STM32关闭SPI导致WRPERR错误经验分享

[复制链接]
STMCU小助手 发布时间:2023-8-13 14:06
01引言
! n. B' }: x0 e+ i+ D
在STM32的应用中,SPI算是用的比较多的外设了,也是单片机最常见外设之一。客户说它执行了关闭SPI的代码,竟然会导致Flash中的WRPERR标志置位,致使应用碰到一些问题。这就奇怪了,SPI和内部Flash看起来是风马牛不相及的事情,为什么会发生这种事呢?一起来看看吧。

0 `4 @7 r/ {1 U- X! @
02问题
2.1 问题起源

  Y( o: S3 F  w) \, E
客户在使用STM32L072RBT6的时候,使用STM32 CubeL0库,在程序编写时,发现执行关闭SPI代码时,会导致Flash的写保护错误标志WRPERR置位,导致其后面准备写EEPROM的时候,就无法对EEPROM写入了。

7 U5 e5 X2 G# I& C' ?  g
客户使用两个标志flag1和flag2,来观察WRPERR标志的变化。代码如图1所示。
7 H" |) X$ v2 `2 P0 M
微信图片_20230813140430.png
图1.用户测试代码

) h& ^9 ]7 G/ L- e$ N7 m
在执行这个代码时,前面flag1还等于0,执行到flag2那句,就变成flag2等于1了,同样地取了WRPERR标志位的值。所以客户就怀疑执行_HAL_SPI_DISABLE()会把Flash的WRPERR标志置1了。

, `! u5 x, |" m: H. Y' H
因为在对EEPROM编程中,需要先调用位于stm32l0xx_hal_flash.c中的FLASH_WaitForLastOperation()函数,此函数中,将会对Flash所有错误标志进行检查,如果出现了错误,它则返回HAL_ERROR,导致后续对EEPROM的编程不会被执行。

; X0 v$ w4 r" `0 |# y
2.2 问题重现
1 p& p: l9 Y4 a9 m; G/ p' K- ?/ a
使用NUCLEO-L053R8来验证客户的这个问题。在\STM32Cube_FW_L0_V1.10.0\Projects\STM32L052R8-Nucleo\Examples\SPI\SPI_FullDuplex_ComPolling例程中直接进行修改测试。

) K; Y9 b4 W. B( s5 V" k4 B  z
首先,把客户的测试代码加到例程中SPI初始化之后的位置。如图2所示。

9 @6 g" }" M7 p' f9 C7 o  J
微信图片_20230813140431_9.png
图2.测试代码1(位于SPI初始化之后)
+ O6 D  z' D" i& Z+ H2 G) Y
编译,并在线调试,发现并没有出现客户所描述的问题。如图3所示。

/ s* |% j4 U1 B1 v6 j4 ~
微信图片_20230813140431_8.png
图3.测试代码1结果(位于SPI初始化之后)

, F; H  A7 s+ I2 f7 X5 X
可以看到,WRPERR的值并没有被置1,Flag1和Flag2的值也都是0。那么,为什么客户说他那边会有这个问题呢?

1 R2 U: a/ f+ C8 M0 G
再回头仔细看一下客户的测试代码,发现客户的测试代码中并没有对SPI进行初始化,其_HAL_SPI_DISABLE()代码是放在其他外设初始化之后的。
' V' [/ y8 z8 |$ v& G( F# f
好,那么再来修改一下测试代码,把客户这三句测试代码挪动到SPI初始化之前,如图4所示。
" e' b# `# S9 J  W% V# r
微信图片_20230813140431_7.png
图4.测试代码2(位于SPI初始化之前)
8 |$ q9 W9 T) {+ n% s2 N
编译,并在线调试,这时,会惊奇地发现客户所描述地问题来了。其结果如图5所示。

& A. H) m- I5 ]( o
微信图片_20230813140431_6.png
图5.测试代码2结果(位于SPI初始化之前)
4 f0 _+ O  s( W0 G1 H
可以看到,这时Flash的WRPERR标志位置1了,测试代码中,flag2的值也跟flag1不同了。

- r) p7 E+ S( e, P
再做一个实验,将此处的HAL库写法,改成直接操作寄存器,来试一下。测试代码变成是图6这样的。

* }6 M. ^# B% T- b
微信图片_20230813140431_5.png
图6.测试代码3(位于SPI初始化之前,直接操作寄存器)
1 v- G/ ?: ]: w' A3 y, w( h
编译,在线调试,这次又惊喜地发现,问题不见了。结果如图7所示。

/ Y/ [, L& A0 b1 e' ^$ f
微信图片_20230813140431_4.png
图7.测试代码3结果(位于SPI初始化之前,直接操作寄存器)
2 G. L8 f# B; o/ c
三种操作,为什么只有第二种方式有问题呢?而且为什么错的偏偏是Flash的写保护错误标志WRPERR呢?接下来可以分析一下它们的反汇编代码,看看到底是哪里出问题了。

0 c$ v0 D: ]1 Y
2.3 反汇编分析

" E; U; F' v4 j% t+ d7 h4 V
对于三种情况,把反汇编拉出来看最清楚其操作过程了。

2 S1 X& g+ t; A+ Q$ y7 m
先分析第一种情况——测试代码位于SPI初始化之后。其反汇编如图8所示。

3 S" a$ q; ?  H+ `
微信图片_20230813140431_3.png
图8.测试代码1的反汇编(位于SPI初始化之后)

7 \$ G5 |6 O8 r: D' D
从之前的Watch窗口,知道flag1的地址为 0x2000000c,flag2的地址为0x2000000d。
1 z+ O8 f5 b9 a- F  `) {0 ]) ]  r4 Q3 P- z
现在对三句C语言测试语句的反汇编语句进行解析,如下:

- T- g. }8 F: I- I, z# {  ]
微信图片_20230813140431_1.png
微信图片_20230813140431_2.png

% F, p! K( q/ E9 A7 o
可以看到,这段汇编是一点问题都没有的。

" L3 V2 i( F5 o" s/ q+ E+ L
接下来,先分析第三种情况——也就是测试代码放在SPI初始化之前,但是使用直接操作寄存器的方式。其反汇编如图9所示。
* N# l7 I+ ~& H* N
微信图片_20230813140431.png
图9.测试代码3的反汇编(位于SPI初始化之前,直接操作寄存器)

0 ]& j/ }1 d7 z$ X' P
从之前的Watch窗口,知道flag1的地址为0x2000000c,flag2的地址为0x2000000d。
( [9 r  z9 c. g# [- z
现在对三句C语言测试语句的反汇编语句进行解析,如下:
8 ~) o' c- ^3 ^& D
微信图片_20230813140432_11.png
微信图片_20230813140432_10.png
可以看到,这段汇编也是一点问题都没有的。
( o- f8 S$ h9 m
最后,再来分析一下有问题的第二种情况,也就是测试代码放在SPI初始化之前,但是使用_HAL_SPI_DISABLE()关闭SPI的情况。其反汇编如图10所示。
' U; T; W2 t$ \# x4 x
微信图片_20230813140432_9.png
图10.测试代码2的反汇编(位于SPI初始化之前)
- w% n: \1 P. q; u( V2 Y
从之前的Watch窗口,知道flag1的地址为0x20000008,flag2的地址为0x20000009。

/ o6 z/ \+ g: U0 U3 C
现在对三句C语言测试语句的反汇编语句进行解析,如下:
% Y1 S% r; h5 J3 D  }% K% Z
微信图片_20230813140432_8.png
微信图片_20230813140432_7.png

- v3 F0 L! t/ [
可以看到,问题出在哪了?问题就出在“STR R3,[R 2]”这个语句上,这个语句在0x00000000这个位置写值,而0x00000000此时映射的是Flash的地址0x08000000,也就是Stack Pointer的位置。如图11和图12所示。
0 \; K0 [2 ^* b8 O: V
微信图片_20230813140432_6.png
图11.0x00000000地址的数据
2 {4 h) r! V6 `% |
微信图片_20230813140432_5.png
图12.0x08000000地址的数据

) ~( C1 P  a* N/ D4 y+ k! N
首先,这个位置本来就不应该被修改。

4 T$ l7 i& f. L
第二,因为没有对Flash程序存储器进行解锁,就往里边写值,就会造成写保护错误,导致WRPERR标志位置位。所以,可以明白为什么WRPERR会被置位了。
1 G; M1 h3 W+ T7 }% z# H: I( R4 Z
可是关键的问题在哪儿呢?在执行“LDR  R2,[R0,#4]”这条语句时,R2本来应该是SPI2_CR1的地址,但是它竟然是0x00000000!如图13所示。

7 u3 `4 c, @5 A: H: {; {
微信图片_20230813140432_4.png
图13.0x2000000c地址的数据
/ r9 `' H* ~( L
从Watch窗口来看一下SpiHandle的情况。如图14所示。

1 v! ]  n$ G  h% v9 y6 \
微信图片_20230813140432_3.png
图14.SpiHandle(未初始化)
3 K  e, |/ e5 g$ d. f5 _
从图14可以看到,其实刚才的0x2000000c地址就是SpiHandle结构体的地址,也是SpiHandle.Instance的地址,而SpiHandle.Instance的值为0。SpiHandle.Ins tance.CR1的地址为0x0,导致显示它装载的值是Stack pointer的值0x20000468,这里本应该是SPI2_CR1的地址和SPI2_CR1的值。
0 G5 Q8 L) J8 ?8 F
也就是因为这里的问题,才会导致了后面的WRPERR错误。

2 K8 \: d2 h4 k1 `) e* `' a* ]6 I: E
2.4 代码分析
5 a6 p# Z$ I# U! F0 K! U, U
再回到代码这边来看一下,有问题的代码究竟是有什么情况。客户的代码主要就是一句关闭SPI的语句“_HAL_SPI_DISABLE(&SpiHandle);”。
- ^+ M( o$ D1 y5 N# t$ Y5 E9 n+ u! w
这个语句是怎么解析的?它再stm32l0xx_hal_spi.h中解析,如图15所示。
9 L/ W4 Y5 D5 e  P
微信图片_20230813140432_2.png
图15._HAL_SPI_DISABLE函数

1 r: W/ ?; E' b8 Q0 {+ K* G& @
看到这个函数时,看到了重要的字眼——“Instance”!就明白是什么问题了,因为这个SpiHandle.Instance还没有被初始化呢!这也说明了为什么在图14中,看到的SpiHandle.Instance的值为0x0,而SpiHandle.Instance. CR2的值为0x20000468。关键就在于这个SpiHandle. Instance还没有初始化。

+ V. Q8 i: J) N' S4 S5 J* {, M% E
所以,把客户的测试代码放在SPI初始化代码之后没有问题,就是因为这个SpiHandle.Instance已经被初始化过了。所以,它不会有问题。

% D. |7 O# i! j( K1 E# Y
03: v* E4 `: F2 ?$ m3 ?. N
问题解决
9 {8 m& h* W7 A: |
本来客户的代码就没有必要这么写,因为SPI都没初始化,对它进行关闭并没有什么意义。

  P" l3 J9 u7 j& g. N+ ]. W$ @
如果非要在这里关闭SPI的话,那就要先对SpiHandle.Instance进行初始化才行。如图16所示。

1 F" l4 c; D0 y! f' U$ E- ^
微信图片_20230813140432_1.png
图16._HAL_SPI_DISABLE函数
; _4 ~; O$ @* h% w8 U. k5 F8 u  c
加了“SpiHandle.Instance=SPIx;”初始化后,再跑这段代码,就不会出现客户所说的问题了。
! {3 a8 R: z  M+ W5 @' H( X" v2 ]! n. y% o
现在再来看一下SpiHandle的情况。
& N7 x) ^* P+ d: J* z' z; ]
微信图片_20230813140432.png
图17.SpiHandle(SpiHandle.Instance已初始化)
  \* v& X6 Z  m' G; h
经过对SpiHandle.Instance的初始化,这里就可以看到SpiHandle.Instance的值为0x40003800了,为SPI2外设寄存器的基地址,而且可以看到SpiHandle.Instance. CR1的地址就是SPI2_CR1的地址0x40003800,值也是SPI2_CR1的值0x0了。

6 r" [/ ^* l" z6 w$ U0 N2 H
04小结

9 K; l1 r* k* D' `( T  `
在用户代码中,SpiHandle只是定义了SPI_HandleTypeDef结构体,其各种参数并还没有进行实际初始化。在没有初始化的前提下,对其进行操作时不对的,也是危险的,应该在写代码的时候引起重视。
) A9 o- _: f) q" ^6 {5 h  _
使用HAL库的时候,如果要对一个外设进行任何的操作,请务必记得它是被初始化过的。否则,出了问题可能都不一定知道。

, b7 e5 ]" a6 l5 b% y
转载自: STM32单片机
如有侵权请联系删除
: t3 j4 k. X0 b' n8 j, z
- |7 q7 ]! P' e, i0 V" d9 ]
收藏 评论0 发布时间:2023-8-13 14:06

举报

0个回答
关于意法半导体
我们是谁
投资者关系
意法半导体可持续发展举措
创新和工艺
招聘信息
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
关注我们
st-img 微信公众号
st-img 手机版