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

实战经验 | STM32G474勘误手册中SRAM Write Error详解

[复制链接]
STMCU-管管 发布时间:2025-9-9 08:39

1. 勘误手册中的“SRAM Write Error”

在STM32G474的勘误手册ES0430的第2.2.7章节中提到SRAM Write Error问题,具体内容如下: image.png

▲ 图1. 勘误手册ES0430中对SRAM Write Error问题的说明

对于大于32kbytes的SRAM,它的每32kbytes空间对应一个SRAM状态机,对于SRAM独立空间但没有超过32kbytes的空间,比如SRAM2,CCM SRAM,都对应各自的一个SRAM状态机。正是由于这个原因,在workaround中需要对每个空间进行一次状态机的恢复操作。以确保每个SRAM状态机都能正常工作。

芯片复位系统起来后,即使存在“SRAM Write Error”,对SRAM的第一次读操作是没有问题的(对SRAM的读操作只能恢复对应这个地址段的SRAM的状态机,不影响其他地址段的SRAM状态机),并且这次读操作可以恢复属于这个地址段的有问题的SRAM状态机到正常状态;如果复位后的SRAM的第一次操作是写操作,则发生“SRAM Write Error”时对SRAM的第一次写操作会出错。但之后对SRAM的操作由于状态机的恢复都不会存在读写问题。

2. 怎样复现此问题

由于编译器生成的代码(startup code)会对全局变量进行初始化,因此要复现这个问题需要在编译器对全局变量进行初始化之前进行问题的复现。

发生“SRAM Write Error”问题的SRAM空间地址段即为对这个SRAM进行写入同时又异常复位的SRAM空间。

在软件工程文件中会有一个Startup code,比如STM32G474的IAR工程会有startup_stm32g474xx.s文件,处理器从复位起来后首先执行的是这部分代码: image.png

▲ 图2. 初始化代码

复现问题需要在Reset_Handler的开始就去对SRAM进行循环写入的动作,可以使用汇编代码或者是C代码,C代码可以放置在SystemInit函数中,但要注意不要进行函数的调用(函数调用会压栈,即对栈所在的32kbytes区域进行了写入,这部分空间对应的SRAM状态机会恢复到正常状态(存在问题的情况下),SRAM问题就不能复现了)。

在对SRAM进行写入的同时对MCU进行NRST的复位操作就可以复现问题,复现概率大概是千分之一左右,取决于代码运行主频、异常复位信号产生的频率等因素(这个NRST信号来自于另外一块开发板或是信号发生器)。

对写入数据的判断要放置在数据写入之后。

2.1. STM32G474的workaround代码

在ES0430 2.2.7章节中提到workaround,下面的代码就是处理器复位后需要首先执行的代码,放置Reset_Handler开始的地方:

UVISION---------------------------------------------------;SRAM addressMOV32 R0, #0x20000000;read accessLDR R1, [R0, #+0];next SRAM instanceMOV32 R0, #0x20008000;dummy read, no consequence on R1 valueLDR R1, [R0, #+0]MOV32 R0, #0x20010000LDR R1, [R0, #+0];the SRAM2 cutMOV32 R0, #0x20014000LDR R1, [R0, #+0];CCM SRAMMOV32 R0, #0x10000000LDR R1, [R0, #+0]

▲ UVISION工程使用的workaround代码

STM32CUBEIDE-----------------------------------------------movw r0, #0x0000 //SRAM addressmovt r0,#0x2000ldr r1, [R0, #+0] //read accessmovw r0, #0x8000 //next SRAM instancemovt r0,#0x2000ldr r1, [R0, #+0] //dummy read, no consequence on R1valuemovw r0, #0x0000 //next SRAM instancemovt r0,#0x2001ldr r1, [R0, #+0] //read accessmovw r0, #0x4000 //the SRAM2 cutmovt r0,#0x2001ldr r1, [R0, #+0]movw r0, #0x0000 // CCM SRAMmovt r0,#0x1000ldr r1, [R0, #+0]

▲ STM32CUBEIDE工程使用的workaround代码

IAR--------------------------------------------------MOV32 R0, #0x20000000 //SRAM addressLDR R1, [R0, #+0] //read accessMOV32 R0, #0x20008000 //next SRAM instanceLDR R1, [R0, #+0] //dummy read, no consequence on R1valueMOV32 R0, #0x20010000LDR R1, [R0, #+0]MOV32 R0, #0x20014000 //the SRAM2 cutLDR R1, [R0, #+0]MOV32 R0, #0x10000000 // CCM SRAMLDR R1, [R0, #+0]

▲ IAR 工程使用的workaround代码

3. 问题概率分析

正常情况下出现“SRAM Write Error”问题的概率是非常低的,因此很多客户只有出现问题后对问题进行分析时考虑。“SRAM Write Error”属于非常低的概率事件的具体原因如下:

  1. 正在运行的处理器发生异常复位的概率比较低。然后发生复位时SRAM正处于写入阶段的概率会更低一些,再者发生复位时SRAM正在写入并恰巧引发“SRAM Write Error”的概率又进一步降低。
  2. 对于一般的编译器,都有自动生成的Startup code,在这部分代码中会对不带初值的全局变量(SRAM地址空间)进行初始化(写0),使得有问题的SRAM状态机转为正常(“SRAM Write Error”恰巧出现在这部分地址段)。
  3. 在普通应用中,代码执行到main()函数之前要运行startup code,第一次压栈的数据直到代码运行到用户自己的main函数中时也永远不会有弹出的情况。因此即使第一次对栈空间进行写入发生SRAM write error造成写入错误,也不会对这部分SRAM地址段造成影响。
  4. 在167945(bugzilla)里,提到如下的问题复现概率:/the problem arises when the product is reset (NRST signal) during a phase of writing into SRAM. I had a nucleo board constantly writing into SRAM while other nucleo was toggling its NRST pin. The first board was logging the cases when the reset was causing the problem. The test rig counted 188571 resets of STM32G4 to get 100 errors./
  5. 下面3.1章节的一种情况会产生“SRAM Write Error”可能影响系统运行。在有些特殊情况下,比如在客户处发现的一个Keil工程,第一次对SRAM的写入动作出现在startup code代码中的一处压栈操作中,并且这个压栈的数据在跳转到main.c之前存在出栈操作,这样的压栈数据是有用的,“SRAM Write Error”问题的存在会对程序运行造成风险(客户代码和跟踪情况无法在此处展示)。

3.1. 实验一(IAR工程):为了验证上面的第2点、第3点和第5点,做了如下的实验

使用STM32G474开发板:Nucleo_G474RE PC

端编译调试软件:IAR 9.40.1

使用的软件工程为:…\STM32Cube_FW_G4_V1.5.0\Projects\NUCLEOG474RE\Examples\GPIO\GPIO_IOToggle

需要修改main.c代码如下: image.png

对于SRAM空间:0x20010000,属于不带初值的全局变量,startup code会进行写“0”操作。

对于CCM SRAM空间:0x10000500,属于带初值的全局变量。产生“SRAM Write Error”时,可能会有错误的初值。反汇编代码跟踪如下:

Trace information:由于存在断点,系统运行起来后会停在:“Reset_Handler”,此时栈指针指向0x20000428,然后先执行SystemInit: image.png

image.png

单步跟踪代码,发现第一次对SRAM的操作为压栈。见下图第一次压栈: image.png

单步运行一步后,栈指针为0x20000420,R0和R1中的数据入栈。请留意这是对SRAM的写操作,之后程序运行到main()函数后一直不会返回,这个值一直会在栈中,因此这个SRAM地址段即使发生了“SRAM Write Error”也不会对程序造成不好的影响,并且能使有问题的SRAM状态机恢复到正常状态: image.png

之后继续跟踪代码(代码在Startup code中),寻找每个SRAM状态机地址段的第一次读出或是写入的位置。

执行的代码流程大概如下:

如果对应的MCU有FPU,iar_program_start首先会调用iar_init_vfp对FPU进行初始化:然后iar_program_start会调用cmain: image.png

cmain首先会调用low_level_init:

cmain然后会调用iar_data_init3进行全局和静态变量的初始化: image.png

iar_data_init3首先会调用iar_zero_init3进行初始值为0的全局和静态变量的初始化:然后iar_data_init3会调用iar_copy_init3进行初始值为非0的全局和静态变量的初始化:最后__call_main会调用main函数跳转到main函数:

至此MCU从复位向量开始,运行启动代码之后就跳转到main函数,然后开始运行用户的代码:

跟踪代码对SRAM的操作,下面图片是对没有初始值的全局变量的初始化(写入0),此位置对应的SRAM状态机也能转为正常(如果存在 SRAM Write Error):

#pragma location=0x20010000 char Data1[16];

image.png

对0x20010000初始化完成后的情况(都清零): image.png

然后全速运行到对0x10000500的初始化(此案例中是运行到断点处),由于是带初值的,因此第一次对这个地址段的SRAM的操作为写入操作。

#pragma location=0x10000500 char Data4[4]= {0x11, 0x22, 0x33, 0x44};

image.png

单步运行: image.png

单步运行: image.png

单步运行: image.png image.png

单步运行: image.png

单步运行: image.png

单步运行: image.png

单步运行: image.png

单步运行: image.png

单步运行: image.png

由于之前的0x44332211已经写入,并且程序复位起来后仍然存在,在再次写入时会影响代码的跟踪和判断,因此我们先给它写入其它区别于0x44332211的值。直接在memory窗口中的0x10000500地址中写入0xaaaaaaaa: image.png

然后再激活反汇编窗口(使用鼠标在反汇编窗口中单击一下),并单步运行,就可以看到0x44332211被写入到地址为0x10000500的CCM SRAM中。

在这个工程中,对于CCM SRAM空间来说,属于第一次写入操作,如果存在“SRAM Write Error”问题,那么程序继续运行下去可能会运行不正常,因为一个全局变量拥有了异常的初始值。

如果之后程序跑飞并且客户开启了硬件看门狗,那么看门狗复位后程序才能正常运行(已经有了第一次写入动作,SRAM状态机已经正常了)。 image.png

然后程序继续运行,一直运行到Main();: image.png

我们可以看到,进入main函数后,之前压栈的数据是不会弹出的,在这个工程中main函数永远不会返回,因此对于处于此处栈空间的32kbytes地址段,即使存在“SRAM Write Error”问题,系统也能正常运行。

3.2. 实验二(Keil工程):使用Keil工程进行实验

使用STM32G474开发板:Nucleo_G474RE PC

端编译调试软件:Keil V5.40

使用的软件工程为:…\STM32Cube_FW_G4_V1.5.0\Projects\NUCLEOG474RE\Examples\GPIO\GPIO_IOToggle

Keil startup code运行情况,Keil工程比IAR工程存在“SRAM Write Error”的风险要高一些,因为Keil start up code会先对带初值的全局变量赋初值,之后才是全局变量的清零操作。如果栈空间和这个带初值的全局变量的空间不在同一个SRAM区间(32kbytes大小的空间),就会存在问题。https://developer.arm.com/documentation/100748/0618/Embedded-SoftwareDevelopment/Application-startup image.png

需要修改main.c代码如下: image.png

Keil软件工程的跟踪:*.map文件部分内容:Global Symbols image.png

在汇编窗口中跟踪代码运行,下图中程序从reset起来,刚开始运行: image.png

Keil第一次对SRAM进行写入的动作发生在压栈的时候。压栈之前: image.png

压栈完成的状态: image.png

之后继续跟踪代码: image.png

继续跟踪代码的运行: image.png

下来是进行test全局变量的加载:

如果这部分全局变量空间和栈空间不属于同一个32Kbytes SRAM空间,则在SRAM第一次写入如果出错,会造成代码运行问题。 image.png

image.png

image.png

继续跟踪代码,接下来是是包含对test0等的清零操作: image.png

很大的一块区域被清零: image.png

之后跳转到main.c中,之前压栈数据一直没有使用。在栈所处的32Kbytes SRAM空间,即使第一次SRAM写入出错,也不会有问题。 image.png

4. 应用代码建议

对于有些客户,代码已经稳定并不再修改,也通过了测试;在产品应用上也能接受看门狗复位(硬件看门狗),可以不添加workaround部分提到的代码。

对于不想添加这部分代码的客户,又担心存在“SRAM Write Error”问题对系统造成影响;可以结合*.map文件中全局变量在SRAM中的具体地址进行分析,并跟踪starup code代码的运行,看“SRAM Write Error”是否会对程序运行造成问题,如果没有问题,可以不添加workaround部分的代码。

对于安全性要求较高的应用,建议采用ES0430 2.2.7章节的workaround代码来提升系统的安全性。

对于使能了Parity check的SRAM,不管有没有可能出现“SRAM Write Error”都建议在代码开头用软件初始化整个SRAM内存,以避免读取未初始化的位置时出现奇偶校验错误。 image.png

▲ 使能了Parity check的SRAM区,

建议在程序运行开始处对整个SRAM区进行初始化

5. 小结

根据客户的实际使用情况,可以选择是否使用“SRAM Write Error”的workaround代码。但对于安全性要求较高的应用,还是建议使用SRAM状态机恢复代码(ES0430 2.2.7章节提到的workaround,或此文章的2.1章节),并对开启了Parity check的SRAM区在程序开始运行时进行初始化。

收藏 评论0 发布时间:2025-9-9 08:39

举报

0个回答

所属标签

相似分享

官网相关资源

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