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

基于STM32的数据意外变化导致条件判断流程异常

[复制链接]
攻城狮Melo 发布时间:2023-12-7 15:29
01问题描述
+ |3 Q) ^$ B8 j3 j用户使用的 MCU 型号是 STM32H750VB。 6 j2 |/ Q  \) V3 O- v6 y9 v
* |! z3 a! `5 a% }$ X! n
在客户的代码中有多个条件语句,在条件里面的变量数值没有变化的情况下执行了条件里面的逻辑。有点类似如下 C 语句 :6 j8 X% t3 I6 K4 {
9 _/ @) S) Z" E7 E2 D6 ]
微信图片_20231207152903.jpg
, u' {9 w5 p! y; D( h
4 v6 x1 J8 M  [
即变量 A 在明明没有变化且条件不满足的情况下, 程序运行时偏偏执行了条件内部的代码. 很奇怪的现象。一时很难判断是编译器的问题还是芯片问题.
, f, c  J0 m. F; G; s% r9 R+ O$ e7 d0 j
了解到客户的代码中使用了第三方库, xx.o 文件, 像这样的条件有 80 多个, 每次出现问题的具体变量并不是固定哪一个, 但是在大概 10 分钟内肯定会有其中一个出现执行逻辑问题。随意动一下代码问题就不出现, 或者出现的位置发生变化 ; 用 KEIL 编译器去设置断点, 想看该变量信息, 也会导致问题不再出现。
6 Y8 ]: ]) C# x7 g# C0 h! n$ l3 y. ?8 }
02问题分析' l% b$ ]7 m  A0 C
一开始查看 errta sheet, 看到以下相关内容 :. m* ?0 p" J$ s7 f) Y; Z9 C
微信图片_20231207152900.jpg
: M/ z" [3 a: K9 T* B; k7 c8 x: M

+ U/ B# M( J; `& \即怀疑问题跟 AXI SRAM 相关. 查看客户的这些变量, 确实是存放在 AXI SRAM 中. 由于任何修改代码都可能导致问题不再出现, 因此所有尝试须建立在不修改代码的基础上, 不然无法说明问题。
2 W/ V2 Z, r0 U  c3 E  j/ |/ i$ u4 e; I6 s
于是让客户用 STM32CubeProgrammer 以 hot plug 模式连接 MCU, 按照勘误手册中 2.2.9 节所描述的 workaround 方式将 AXI_TARG7_FN_MOD 寄存器的 READ_ISS_OVERRIDE 位通过地址的方式直接修改 :/ y. I9 d( w" P; `  S6 P
8 z& |* w; q* b
微信图片_20231207152856.jpg   T0 L0 u7 u/ d- G- R4 p) N
: {4 o- E& n& Z
结果发现并没什么效果. 于是排除了这种可能性. ' j# z& R3 W2 P  U2 |6 y. d! v9 v
5 ^3 f& [* S+ P3 x' R: W& S
一开始也怀疑问题可能跟 Cache 有关, 于是测试下关闭 Cahce 会怎么样. 通过 KEIL 调试模式下,暂停住 CPU 运行, 然后手动关闭 D-Cache :
: N# p+ n! a% `, h, ~9 n3 P; H
* }( y8 z- n/ ]' r% g) r
微信图片_20231207152853.jpg
. I. P* K% y4 H

7 i0 O: `7 _; h$ x1 }. R; \& \2 ^结果发现问题消失不见 ! 说明问题肯定跟 Cache 有关.
7 Q& U/ s; ]0 R7 d/ \8 j5 |$ W7 ^. g: F* ]8 Q- U; p
但客户的代码最终肯定是不能关闭 Cache 的, 想到内核中有一个寄存器可以打开全局 Cache 的write throght 模式, 如下编程手册中的 CACR 寄存器的 FORCEWT 位 :
2 q: k5 z! ?' |; s3 ~( b: A  [# c3 Z3 [2 [/ A. S& Q
微信图片_20231207152849.jpg
8 \/ D2 f7 |) [$ S  G+ @( h+ J: n5 m
' \, X8 p5 ]0 Q4 {, ~; b" x1 O3 |结果发现, 客户的代码本身就已经打开 :
6 M: ]; c8 s+ y6 s6 }+ P+ o( [" ^4 `* z' g! a! E9 {- m! T! u) i
微信图片_20231207152846.jpg 2 h& H. Y! S+ u
% [# O. [5 X! e8 A
看样子此模式与此问题无关. 得换个思路. & \4 G7 E  a9 k4 q6 a+ A
0 H% Z# e6 F* Y5 R/ A5 m+ v
考虑到问题跟内存数据有关, 代码又不能动. 但是得想办法让内存中数据的位置动动, 看看会有什么效果 ?* q8 r/ x2 u5 y0 I; @7 w

* l4 X% p8 v9 J3 L+ C通过修改 KEIL 的链接配置文件.sct 文件, 将变量随意动动, 结果发现问题也会消失不见 ! 这说明,数据的地址跟问题绝对有关联.那么具体是哪些数据呢 ?
$ R6 h& N, P$ w% [# q6 r

. X: {5 C4 g4 B8 q6 p2 w0 L为了精确定位到与哪些变量有关, 查看 KEIL 生成的 map 文件, 按地址倒序将每个程序中所用到的.o 的对应变量逐个挪移动 DTCM RAM 中.' h: u) k: m0 X( N$ T2 b
5 m7 R0 |8 P/ j$ O6 }
微信图片_20231207152843.jpg
2 B$ v- n' I) N4 y
- z* Z: `8 W1 B. |( r( R
为什么要倒序呢? 主要是因为, 假如先挪低地址的变量, 肯定会导致高地址的变量向低地址移动.这好比, 如果先抽掉下面的砖头, 那么上面的砖头会自动移动下面去. 假如先抽掉上面的砖头情况就不一样了, 下面的砖头还会保持不动. 这就是为什么先挪移上面的砖头的意义, 也就是所谓的倒序.
" R$ K: q' {( @+ u! q7 B

/ g2 M6 [" v$ l通过这种方式, 最终定位到问题跟 heap_4.o 文件以及用户使用到的第三方提供的 xx.o 文件中的ZI 数据有关. 只要保持这两种数据位置不变, 那么问题就可以稳定触发, 一旦其中任何一个位置有所变动, 问题就消失不见.
) B4 l7 B( S: j) Y6 o0 Q2 J  k: d
微信图片_20231207152840.jpg
0 c5 ^; `& f" N( u$ n
% ~( ^) ?4 a8 f( X5 b
现在我们知道规律了, 那么只要固定好这两种 ZI 数据位置不变的情况下, 再去尝试修改代码, 结果发现, 此时修改代码不再会对结果产生影响! 换句话说, 现在可以自由修改代码了.
8 A' v5 V; O2 I8 V6 v* v% D) m9 W  ?( {) u2 w% d# ^' z8 B
考虑到此问题与 Cache 有关, 于是接下来通过 MPU 设置将 heap_4.o 所在区域的 Cache 功能关闭, 结果发现问题消失.
% I1 n) E* P" _0 u
% t# C9 h" U5 R; s2 L6 y% i
微信图片_20231207152836.jpg * T7 x$ t; C$ k

2 z1 `: M1 t: d# \5 p4 ]  A/ ^ 微信图片_20231207152833.jpg % `+ r, d) k4 T; V: E6 d
% N3 K  `/ k1 b5 W1 C
Heap_4.o 的 ZI 数据是存放在 SRAM2 中的 0x3002 E050 位置.
4 K+ d6 S* H" [0 ~/ Z
2 h' o+ }! D- M  \% H& G( h
微信图片_20231207152830.jpg % w2 _6 A% J7 M+ Y/ A
微信图片_20231207152819.jpg
  ?% F4 L1 _! [. A
+ z9 j8 ~: A! j+ y3 w7 c
现在的现象是,Heap_4.o 的 ZI 数据只需要固定在这个位置, 问题就能稳定重现,只不过将其对应的cache 关闭, 问题则消失.7 Y, b1 S5 J" {# w9 O

# d) R* P! w& C9 ~  l那么此区域默认的 Cache 属性是怎么样的呢? 这个在 AN4839 中可以找到其默认属性:
8 P7 K! k% \  @  p! h" n2 @# K  H. I6 f* z1 H; R: X
微信图片_20231207152816.jpg
! ~, f1 P& g. k3 P# F. N: \: V0 l8 L1 G
于是我们通过代码, 将其 MPU 属性再次配置其默认属性:- e0 S# F/ J1 @9 ?

) s8 o' u4 y! j9 \9 \2 r( F

! N0 h: e9 c$ w: s. R
" G& u& ^/ m# t 微信图片_20231207152809.jpg
( z- J+ w! O* H+ i9 E6 K% B
: X2 v" d( a+ j& A* d, M1 Z6 Q结果问题可以重现. 这再次说明, cache 属性对结果有影响.
" E7 ]- @, G7 u
; H5 g- Z/ i# ~! m& P
但是此时还无法对其产生的过程细节进行解释.5 l$ s7 d6 }* n) W
% a# S" I3 o$ {/ F' K2 ]4 l
与此同时, 尝试关闭客户使用第三方库 xx.o 文件中的数据 cache, 问题也同样会消失。这说明, 此问题跟客户所使用的第三方库是有关系的, 其数据在 cache 中产生了一致性问题.
1 F+ h" D* P+ S9 `( l/ a

$ y' x$ h1 R4 o( r# a于是询问客户这个第三方库是如何来的? 他们回复是一家欧洲公司提供的, 且是以 M4 内核编译的.6 I5 g( r" D1 W8 I  a8 Q

& [& v7 [- C% M; [很明显, 在使用原则上, M4 编译出来的.o 文件, 就不应该用在 H7 工程上. # e% f; D: ~9 C+ G7 M/ O
, ~& a  L- i, v! d- K: P6 N
以 M4 为内核编译的.o 文件放到 M7 工程中会产生什么样的影响? 虽然理论上, M7 内核的指令集是向下兼容的, 但是也需要考虑 M7 内核相关的一些特性, 比如 Cache, memory barrier 等等. 不能完全确保不会出问题, 最保险就是重新以 M7 内核编译这个.o 文件. ( K; `2 ^) ?/ v: D) ?9 M% {

/ U8 a- V, R" G由于这个第三方.o 文件客户自己也是无法知道其内部是如何实现的, 因此, 问题的具体产生过程是没办法进一步调查了. 但定位到这个.o 文件已经是当前能得到的最终结果./ G' u2 d6 K" u# r' F. K

: J5 o( E( z; z1 V% H6 ?" @8 G03小结) C+ v2 c$ \/ y6 Q
本文最终问题的真相虽有点匪夷所思, 但这正反映了当前国内软件应用上的混乱情况. 本文所描述的问题根本原因虽然很另类, 但所涉及到的方法却对开发者有一定的参考意义, 在不能动代码的情况下, 需要挪动数据的位置, 这就必须对编译器有一定的了解. 虽也不至于太难, 但对很多开发都来说, 对编译器的了解未必很深, 因此, 一开始很多人就会卡住。另外, 对 MPU 的了解也是一大门槛. 因此, 特奉上此文, 以供参考.
9 {- I; U5 A# y. _* O6 b0 D) z% ?
  J0 J/ ]! N& i1 N/ o# {$ o& o9 D转载自: STM32单片机* s9 c( S2 l5 ~1 B/ o6 O
如有侵权请联系删除
7 Y# }7 T1 q3 _4 j4 z8 W7 C
* u2 W3 v" ^9 P5 O. \
* U* @8 G/ F8 o# B
微信图片_20231207152812.jpg
收藏 评论0 发布时间:2023-12-7 15:29

举报

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