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

基于STM32关闭SPI会导致WRPERR错误的问题分析

[复制链接]
STMCU小助手 发布时间:2023-8-18 13:03
01引言

. `/ c9 M% b% O
在STM32的应用中,SPI算是用的比较多的外设了,也是单片机最常见外设之一。客户说它执行了关闭SPI的代码,竟然会导致Flash中的WRPERR标志置位,致使应用碰到一些问题。这就奇怪了,SPI和内部Flash看起来是风马牛不相及的事情,为什么会发生这种事呢?一起来看看吧。

  b" k5 D, I* z7 C8 j- }
02问题
- S9 K/ j* y6 _% u+ I4 d0 R8 |
2.1 问题起源

, Q4 [& y) i' K) M" E  x9 c8 b; N
客户在使用STM32L072RBT6的时候,使用STM32 CubeL0库,在程序编写时,发现执行关闭SPI代码时,会导致Flash的写保护错误标志WRPERR置位,导致其后面准备写EEPROM的时候,就无法对EEPROM写入了。

0 z% v  s, n2 w" d
客户使用两个标志flag1和flag2,来观察WRPERR标志的变化。代码如图1所示。
7 E6 U+ D% _( _3 n9 [. P
微信图片_20230818130228_6.png
图1.用户测试代码
- F6 ^& ^1 I3 p: N8 O( i
在执行这个代码时,前面flag1还等于0,执行到flag2那句,就变成flag2等于1了,同样地取了WRPERR标志位的值。所以客户就怀疑执行_HAL_SPI_DISABLE()会把Flash的WRPERR标志置1了。
! ^. i( f& N3 c3 u- y4 y: o% X
因为在对EEPROM编程中,需要先调用位于stm32l0xx_hal_flash.c中的FLASH_WaitForLastOperation()函数,此函数中,将会对Flash所有错误标志进行检查,如果出现了错误,它则返回HAL_ERROR,导致后续对EEPROM的编程不会被执行。

- F$ K- q  N' k& I( V2 z7 p
2.2 问题重现
" c7 p6 o2 t3 w5 B; E) A8 s
使用NUCLEO-L053R8来验证客户的这个问题。在\STM32Cube_FW_L0_V1.10.0\Projects\STM32L052R8-Nucleo\Examples\SPI\SPI_FullDuplex_ComPolling例程中直接进行修改测试。
* z4 }6 [: _3 I: c
首先,把客户的测试代码加到例程中SPI初始化之后的位置。如图2所示。

& b9 k8 f; T1 e5 a: p& S1 f# `
微信图片_20230818130228_5.png
图2.测试代码1(位于SPI初始化之后)

% }$ e8 R8 a' p6 {8 L/ U- [
编译,并在线调试,发现并没有出现客户所描述的问题。如图3所示。
. g1 p# S/ K2 g. V# ^% B9 |+ \$ z
微信图片_20230818130228_4.png
图3.测试代码1结果(位于SPI初始化之后)

) G/ \: E" f* f$ x4 v* B  A! [
可以看到,WRPERR的值并没有被置1,Flag1和Flag2的值也都是0。那么,为什么客户说他那边会有这个问题呢?

: d0 f7 F# @& J. ^" O, r
再回头仔细看一下客户的测试代码,发现客户的测试代码中并没有对SPI进行初始化,其_HAL_SPI_DISABLE()代码是放在其他外设初始化之后的。
: V. p! ]3 K5 Q2 z2 S0 A
好,那么再来修改一下测试代码,把客户这三句测试代码挪动到SPI初始化之前,如图4所示。

+ k' L1 e5 a1 a3 ?  L2 _
微信图片_20230818130228_3.png
图4.测试代码2(位于SPI初始化之前)
) O' u6 l- V4 [- B( {
编译,并在线调试,这时,会惊奇地发现客户所描述地问题来了。其结果如图5所示。
: _( O4 u) u/ S6 i# Z
微信图片_20230818130228_2.png
图5.测试代码2结果(位于SPI初始化之前)

# Q8 y) J; L1 r& r- F) M
可以看到,这时Flash的WRPERR标志位置1了,测试代码中,flag2的值也跟flag1不同了。
( i8 T. ~! @7 b' o' ^2 I
再做一个实验,将此处的HAL库写法,改成直接操作寄存器,来试一下。测试代码变成是图6这样的。
3 G7 @( v; P) D, @, l3 Y% g: M, [
微信图片_20230818130228_1.png
图6.测试代码3(位于SPI初始化之前,直接操作寄存器)
2 ?9 e9 o* P3 c. R2 h
编译,在线调试,这次又惊喜地发现,问题不见了。结果如图7所示。
2 `5 G2 @4 k! D0 p/ Y$ ~; X
微信图片_20230818130228.png
图7.测试代码3结果(位于SPI初始化之前,直接操作寄存器)

1 p0 x7 h, N8 h# t. T9 H
三种操作,为什么只有第二种方式有问题呢?而且为什么错的偏偏是Flash的写保护错误标志WRPERR呢?接下来可以分析一下它们的反汇编代码,看看到底是哪里出问题了。
1 T, S* G# w- r9 @. X
2.3 反汇编分析

# ~2 Y: N" I( D. J! y  n: K+ k
对于三种情况,把反汇编拉出来看最清楚其操作过程了。

7 N" u- a9 I9 B4 P- M% b
先分析第一种情况——测试代码位于SPI初始化之后。其反汇编如图8所示。
+ \6 {" @( I0 {$ f/ P0 g2 {, q
微信图片_20230818130229_7.png
图8.测试代码1的反汇编(位于SPI初始化之后)
! S5 n6 g! x5 `4 D: E
从之前的Watch窗口,知道flag1的地址为 0x2000000c,flag2的地址为0x2000000d。

4 N2 D+ _; a3 H) F# m- M9 P
现在对三句C语言测试语句的反汇编语句进行解析,如下:
) v0 L% ~2 D' D8 d# g: y9 k
微信图片_20230818130229_6.png
微信图片_20230818130229_5.png

+ H6 s9 ^5 l+ P
可以看到,这段汇编是一点问题都没有的。
7 x2 B" W1 o9 B4 s8 f4 ]
接下来,先分析第三种情况——也就是测试代码放在SPI初始化之前,但是使用直接操作寄存器的方式。其反汇编如图9所示。
/ l8 j! K+ r( l  o: d4 c7 z
微信图片_20230818130229_4.png
图9.测试代码3的反汇编(位于SPI初始化之前,直接操作寄存器)

: R% B) j! S4 q: N) G( D7 [
从之前的Watch窗口,知道flag1的地址为0x2000000c,flag2的地址为0x2000000d。

# w6 j% g2 U' v/ o
现在对三句C语言测试语句的反汇编语句进行解析,如下:

) C/ R! C9 P7 l- U  r
微信图片_20230818130229_3.png
微信图片_20230818130229_2.png
可以看到,这段汇编也是一点问题都没有的。

5 J$ M1 N/ I4 t+ @, l
最后,再来分析一下有问题的第二种情况,也就是测试代码放在SPI初始化之前,但是使用_HAL_SPI_DISABLE()关闭SPI的情况。其反汇编如图10所示。

6 y2 v* ~! h2 C2 k- S5 i
微信图片_20230818130229_1.png
图10.测试代码2的反汇编(位于SPI初始化之前)

- m' s: f1 c/ b/ r" Z( B% J$ A
从之前的Watch窗口,知道flag1的地址为0x20000008,flag2的地址为0x20000009。

! J2 G0 Q! L/ `# J3 ~2 P/ f# H+ X
现在对三句C语言测试语句的反汇编语句进行解析,如下:
# V6 B. l: X& g( e
微信图片_20230818130229.png
微信图片_20230818130230_7.png

- x4 O, D- R" u# F; V7 V
可以看到,问题出在哪了?问题就出在“STR R3,[R 2]”这个语句上,这个语句在0x00000000这个位置写值,而0x00000000此时映射的是Flash的地址0x08000000,也就是Stack Pointer的位置。如图11和图12所示。
5 O! L% ~/ M: S; y0 p! g- }
微信图片_20230818130230_6.png
图11.0x00000000地址的数据

7 c6 }' F5 {0 H8 y5 g+ N; t
微信图片_20230818130230_5.png
图12.0x08000000地址的数据
* T' l; _: C, [; L
首先,这个位置本来就不应该被修改。
6 q7 i* D, Y) W
第二,因为没有对Flash程序存储器进行解锁,就往里边写值,就会造成写保护错误,导致WRPERR标志位置位。所以,可以明白为什么WRPERR会被置位了。
" m* z/ J: X& P
可是关键的问题在哪儿呢?在执行“LDR  R2,[R0,#4]”这条语句时,R2本来应该是SPI2_CR1的地址,但是它竟然是0x00000000!如图13所示。
- i) R! [2 p& o6 T8 I
微信图片_20230818130230_4.png
图13.0x2000000c地址的数据

, S7 J1 H& U4 A( Q- V
从Watch窗口来看一下SpiHandle的情况。如图14所示。

* [  z! e+ X9 F0 I6 s. e0 W
微信图片_20230818130230_3.png
图14.SpiHandle(未初始化)

9 q1 t# v0 ~  L1 s) y
从图14可以看到,其实刚才的0x2000000c地址就是SpiHandle结构体的地址,也是SpiHandle.Instance的地址,而SpiHandle.Instance的值为0。SpiHandle.Ins tance.CR1的地址为0x0,导致显示它装载的值是Stack pointer的值0x20000468,这里本应该是SPI2_CR1的地址和SPI2_CR1的值。

5 |; U6 u0 _& g2 s
也就是因为这里的问题,才会导致了后面的WRPERR错误。
( k! R' @1 |2 `" D: s+ n; x% X
2.4 代码分析

# \3 t4 Y/ e7 q7 v: v3 `
再回到代码这边来看一下,有问题的代码究竟是有什么情况。客户的代码主要就是一句关闭SPI的语句“_HAL_SPI_DISABLE(&SpiHandle);”。

6 E" C8 I/ v' t$ R7 x- h) `' R
这个语句是怎么解析的?它再stm32l0xx_hal_spi.h中解析,如图15所示。
7 O$ B& i% y+ Z' f
微信图片_20230818130230_2.png
图15._HAL_SPI_DISABLE函数

, _2 {3 J! U1 _0 @" K( H
看到这个函数时,看到了重要的字眼——“Instance”!就明白是什么问题了,因为这个SpiHandle.Instance还没有被初始化呢!这也说明了为什么在图14中,看到的SpiHandle.Instance的值为0x0,而SpiHandle.Instance. CR2的值为0x20000468。关键就在于这个SpiHandle. Instance还没有初始化。

( N6 T: e" U- q5 z! M# |5 N
所以,把客户的测试代码放在SPI初始化代码之后没有问题,就是因为这个SpiHandle.Instance已经被初始化过了。所以,它不会有问题。

6 x- W: G) m3 B1 t: ~9 @
03问题解决
* O( B& e- s" k3 [
本来客户的代码就没有必要这么写,因为SPI都没初始化,对它进行关闭并没有什么意义。

/ N7 c6 f% K2 B# D. j9 w
如果非要在这里关闭SPI的话,那就要先对SpiHandle.Instance进行初始化才行。如图16所示。
, ]9 q- f  X5 `3 w. p" i
微信图片_20230818130230_1.png
图16._HAL_SPI_DISABLE函数

7 g5 p2 E) g- d& |) n
加了“SpiHandle.Instance=SPIx;”初始化后,再跑这段代码,就不会出现客户所说的问题了。
3 r. {! m, I) o
现在再来看一下SpiHandle的情况。

" R& g+ Z" Q( _: I
微信图片_20230818130230.png
图17.SpiHandle(SpiHandle.Instance已初始化)

' x, @5 `! v( H: }, q8 n
经过对SpiHandle.Instance的初始化,这里就可以看到SpiHandle.Instance的值为0x40003800了,为SPI2外设寄存器的基地址,而且可以看到SpiHandle.Instance. CR1的地址就是SPI2_CR1的地址0x40003800,值也是SPI2_CR1的值0x0了。

5 r# x1 ]7 F  Q5 ]9 q1 I' ?3 ~" X0 Z
04小结

% H, V# j# _/ a6 S- n
在用户代码中,SpiHandle只是定义了SPI_HandleTypeDef结构体,其各种参数并还没有进行实际初始化。在没有初始化的前提下,对其进行操作时不对的,也是危险的,应该在写代码的时候引起重视。

5 r% J) ?$ _& A5 }" X2 ^1 f+ _
使用HAL库的时候,如果要对一个外设进行任何的操作,请务必记得它是被初始化过的。否则,出了问题可能都不一定知道。

( A8 s% Z: ^6 {$ O. C1 r
转载自: STM32单片机
如有侵权请联系删除

- \5 }9 Y- X- U) S# }% _
" _* R. |* A3 k3 m3 Q$ ?
收藏 评论0 发布时间:2023-8-18 13:03

举报

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