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

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

[复制链接]
STMCU小助手 发布时间:2023-8-13 14:06
01引言
4 y8 u; U: D5 X" M
在STM32的应用中,SPI算是用的比较多的外设了,也是单片机最常见外设之一。客户说它执行了关闭SPI的代码,竟然会导致Flash中的WRPERR标志置位,致使应用碰到一些问题。这就奇怪了,SPI和内部Flash看起来是风马牛不相及的事情,为什么会发生这种事呢?一起来看看吧。
4 a$ ^. v- a2 z7 G( k2 ^
02问题
2.1 问题起源
3 e8 _1 |8 G, [. F( i8 t$ j& i) Q
客户在使用STM32L072RBT6的时候,使用STM32 CubeL0库,在程序编写时,发现执行关闭SPI代码时,会导致Flash的写保护错误标志WRPERR置位,导致其后面准备写EEPROM的时候,就无法对EEPROM写入了。

* K" q8 R1 k& ^0 s, _
客户使用两个标志flag1和flag2,来观察WRPERR标志的变化。代码如图1所示。
( F7 H: I  q9 f) e% ^  e
微信图片_20230813140430.png
图1.用户测试代码
! b) U- N1 c$ p5 u3 a% x9 x
在执行这个代码时,前面flag1还等于0,执行到flag2那句,就变成flag2等于1了,同样地取了WRPERR标志位的值。所以客户就怀疑执行_HAL_SPI_DISABLE()会把Flash的WRPERR标志置1了。
7 r$ Y/ N5 d0 r% Y
因为在对EEPROM编程中,需要先调用位于stm32l0xx_hal_flash.c中的FLASH_WaitForLastOperation()函数,此函数中,将会对Flash所有错误标志进行检查,如果出现了错误,它则返回HAL_ERROR,导致后续对EEPROM的编程不会被执行。

+ p8 E) r+ p5 _' a# ?- E8 N& b
2.2 问题重现

* G) M3 L! P+ r$ M6 h7 s1 L+ F* `
使用NUCLEO-L053R8来验证客户的这个问题。在\STM32Cube_FW_L0_V1.10.0\Projects\STM32L052R8-Nucleo\Examples\SPI\SPI_FullDuplex_ComPolling例程中直接进行修改测试。

& C2 I6 Q$ R5 W& a, L! e/ ?
首先,把客户的测试代码加到例程中SPI初始化之后的位置。如图2所示。

5 H' q' j& F3 h/ S& Q
微信图片_20230813140431_9.png
图2.测试代码1(位于SPI初始化之后)
$ W: }7 W: E- V, J+ K( ~
编译,并在线调试,发现并没有出现客户所描述的问题。如图3所示。
9 W$ k+ F% f; O) [6 c+ z. i
微信图片_20230813140431_8.png
图3.测试代码1结果(位于SPI初始化之后)
( z( x! Z7 J7 p) J
可以看到,WRPERR的值并没有被置1,Flag1和Flag2的值也都是0。那么,为什么客户说他那边会有这个问题呢?
! u2 v0 O6 E- a; h: I6 I
再回头仔细看一下客户的测试代码,发现客户的测试代码中并没有对SPI进行初始化,其_HAL_SPI_DISABLE()代码是放在其他外设初始化之后的。

) r" c" i. u* F' y9 i( p$ N! t
好,那么再来修改一下测试代码,把客户这三句测试代码挪动到SPI初始化之前,如图4所示。
$ U% G4 n$ s/ d
微信图片_20230813140431_7.png
图4.测试代码2(位于SPI初始化之前)

" S9 T3 W0 l% w. \" R+ k2 {
编译,并在线调试,这时,会惊奇地发现客户所描述地问题来了。其结果如图5所示。
* R7 x) @& H/ ~
微信图片_20230813140431_6.png
图5.测试代码2结果(位于SPI初始化之前)
0 p& o& [; m7 s, w4 H3 f# Z
可以看到,这时Flash的WRPERR标志位置1了,测试代码中,flag2的值也跟flag1不同了。

7 n( `" g4 {- Y+ r
再做一个实验,将此处的HAL库写法,改成直接操作寄存器,来试一下。测试代码变成是图6这样的。
& y# P, C  l% J
微信图片_20230813140431_5.png
图6.测试代码3(位于SPI初始化之前,直接操作寄存器)
! Z! U3 n7 d1 w$ L+ E
编译,在线调试,这次又惊喜地发现,问题不见了。结果如图7所示。

% F( @* i1 h# j7 o+ C
微信图片_20230813140431_4.png
图7.测试代码3结果(位于SPI初始化之前,直接操作寄存器)
5 X* L1 f# U7 b8 ?) U
三种操作,为什么只有第二种方式有问题呢?而且为什么错的偏偏是Flash的写保护错误标志WRPERR呢?接下来可以分析一下它们的反汇编代码,看看到底是哪里出问题了。
3 s4 k/ I8 k8 z- V; ~, `! t7 Y, u# J
2.3 反汇编分析
8 Y0 `! F' ^! Y2 ^# q
对于三种情况,把反汇编拉出来看最清楚其操作过程了。
; L, C& [$ [+ @, R4 }5 j
先分析第一种情况——测试代码位于SPI初始化之后。其反汇编如图8所示。
7 Z- l" p+ {0 P# J
微信图片_20230813140431_3.png
图8.测试代码1的反汇编(位于SPI初始化之后)

+ r1 d+ h3 ^) M% i8 E- r' T
从之前的Watch窗口,知道flag1的地址为 0x2000000c,flag2的地址为0x2000000d。
. g/ o. K3 R) }0 n6 q8 w
现在对三句C语言测试语句的反汇编语句进行解析,如下:
& a; ?7 l8 D- X
微信图片_20230813140431_1.png
微信图片_20230813140431_2.png
' p- L. A6 f* v1 w2 L  k' N
可以看到,这段汇编是一点问题都没有的。

3 u, k6 F7 P' k! `7 b
接下来,先分析第三种情况——也就是测试代码放在SPI初始化之前,但是使用直接操作寄存器的方式。其反汇编如图9所示。
+ `" n" E% ?8 k: u; {4 Y
微信图片_20230813140431.png
图9.测试代码3的反汇编(位于SPI初始化之前,直接操作寄存器)
# B$ p) g* E! e2 X0 _7 ?1 \
从之前的Watch窗口,知道flag1的地址为0x2000000c,flag2的地址为0x2000000d。
4 u5 [  X% A1 j: {# A0 F
现在对三句C语言测试语句的反汇编语句进行解析,如下:
6 {6 X- ~5 K  b9 W7 N2 d+ p0 H
微信图片_20230813140432_11.png
微信图片_20230813140432_10.png
可以看到,这段汇编也是一点问题都没有的。

; J7 U1 T  u& r
最后,再来分析一下有问题的第二种情况,也就是测试代码放在SPI初始化之前,但是使用_HAL_SPI_DISABLE()关闭SPI的情况。其反汇编如图10所示。

7 }5 F) Z* G5 q1 X8 H+ _- h
微信图片_20230813140432_9.png
图10.测试代码2的反汇编(位于SPI初始化之前)

( I5 u8 u2 R% Q. C6 Z
从之前的Watch窗口,知道flag1的地址为0x20000008,flag2的地址为0x20000009。

$ S  h* i) s0 }5 {5 v
现在对三句C语言测试语句的反汇编语句进行解析,如下:
3 N$ b; r' ~& r4 Q
微信图片_20230813140432_8.png
微信图片_20230813140432_7.png

  _4 j" [6 N9 ~0 H# F$ S
可以看到,问题出在哪了?问题就出在“STR R3,[R 2]”这个语句上,这个语句在0x00000000这个位置写值,而0x00000000此时映射的是Flash的地址0x08000000,也就是Stack Pointer的位置。如图11和图12所示。

4 w7 i- C7 O! b; }8 f
微信图片_20230813140432_6.png
图11.0x00000000地址的数据
- k! r# n( o2 A
微信图片_20230813140432_5.png
图12.0x08000000地址的数据
; R& n1 U' H6 a! {5 C
首先,这个位置本来就不应该被修改。
6 P. n- X' [# V
第二,因为没有对Flash程序存储器进行解锁,就往里边写值,就会造成写保护错误,导致WRPERR标志位置位。所以,可以明白为什么WRPERR会被置位了。
# b$ O; `3 y  g# w2 j
可是关键的问题在哪儿呢?在执行“LDR  R2,[R0,#4]”这条语句时,R2本来应该是SPI2_CR1的地址,但是它竟然是0x00000000!如图13所示。
: ^0 _  E% B5 ~6 @4 @. {
微信图片_20230813140432_4.png
图13.0x2000000c地址的数据

* e9 K/ D8 B9 g4 ^, ~( p( J* Y
从Watch窗口来看一下SpiHandle的情况。如图14所示。

$ F# X, {. h( x  A0 @
微信图片_20230813140432_3.png
图14.SpiHandle(未初始化)

9 l4 f2 E) S8 f" @* x5 _
从图14可以看到,其实刚才的0x2000000c地址就是SpiHandle结构体的地址,也是SpiHandle.Instance的地址,而SpiHandle.Instance的值为0。SpiHandle.Ins tance.CR1的地址为0x0,导致显示它装载的值是Stack pointer的值0x20000468,这里本应该是SPI2_CR1的地址和SPI2_CR1的值。
) z! H4 k  ^7 [+ J
也就是因为这里的问题,才会导致了后面的WRPERR错误。
4 u' n) Y  x1 e9 F2 c: K, ]3 b2 S
2.4 代码分析
9 ]& K. K- c% B6 Q0 C+ r
再回到代码这边来看一下,有问题的代码究竟是有什么情况。客户的代码主要就是一句关闭SPI的语句“_HAL_SPI_DISABLE(&SpiHandle);”。

/ s* z% a8 Y( g& z( ]
这个语句是怎么解析的?它再stm32l0xx_hal_spi.h中解析,如图15所示。

6 H- O5 m* ]' f& i' Z# f6 w
微信图片_20230813140432_2.png
图15._HAL_SPI_DISABLE函数
) c+ J2 k. D5 F0 \# t
看到这个函数时,看到了重要的字眼——“Instance”!就明白是什么问题了,因为这个SpiHandle.Instance还没有被初始化呢!这也说明了为什么在图14中,看到的SpiHandle.Instance的值为0x0,而SpiHandle.Instance. CR2的值为0x20000468。关键就在于这个SpiHandle. Instance还没有初始化。

* X: Z; T) @3 _6 T- k0 {4 N; R9 s
所以,把客户的测试代码放在SPI初始化代码之后没有问题,就是因为这个SpiHandle.Instance已经被初始化过了。所以,它不会有问题。
* r& ]3 ]8 q" v8 e: S& ~; h- A$ m
03
( }0 n" R* C# R
问题解决
5 H* ~- N" O4 }! \
本来客户的代码就没有必要这么写,因为SPI都没初始化,对它进行关闭并没有什么意义。
- t9 M( M6 L6 j7 F* C9 z
如果非要在这里关闭SPI的话,那就要先对SpiHandle.Instance进行初始化才行。如图16所示。

" z; s! B$ \  b8 ?6 V
微信图片_20230813140432_1.png
图16._HAL_SPI_DISABLE函数

( L7 G/ f5 ]  \) ~1 ~9 R
加了“SpiHandle.Instance=SPIx;”初始化后,再跑这段代码,就不会出现客户所说的问题了。

5 w' j$ T# c- y/ s7 ^) ?  J" t
现在再来看一下SpiHandle的情况。
) L/ d, ^% H; p# c+ m
微信图片_20230813140432.png
图17.SpiHandle(SpiHandle.Instance已初始化)
: y0 I0 m# M+ Q) a& p" H
经过对SpiHandle.Instance的初始化,这里就可以看到SpiHandle.Instance的值为0x40003800了,为SPI2外设寄存器的基地址,而且可以看到SpiHandle.Instance. CR1的地址就是SPI2_CR1的地址0x40003800,值也是SPI2_CR1的值0x0了。
+ \* V$ [4 {3 O, {
04小结
2 E& Y# E" `' z2 X. f3 c. y. Y
在用户代码中,SpiHandle只是定义了SPI_HandleTypeDef结构体,其各种参数并还没有进行实际初始化。在没有初始化的前提下,对其进行操作时不对的,也是危险的,应该在写代码的时候引起重视。
' Q) R' g) T! c$ E% [5 M
使用HAL库的时候,如果要对一个外设进行任何的操作,请务必记得它是被初始化过的。否则,出了问题可能都不一定知道。
  K' Y* X4 x8 b2 b1 b7 O: O0 ]
转载自: STM32单片机
如有侵权请联系删除
. N0 O' z' h& s  N
( J( }9 }, k# w8 B+ |
收藏 评论0 发布时间:2023-8-13 14:06

举报

0个回答

所属标签

相似技术帖

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版