这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » 嵌入式开发 » STM32 » 细说BSS段SRAM清零与否

共15条 1/2 1 2 跳转至

细说BSS段SRAM清零与否

院士
2026-09-03 15:08:27   被打赏 45 分(兑奖)     打赏

细说BSS段SRAM清零与否

在大多数项目里面,我们并不需要关心变量在SRAM中的状态。当MCU每次上电复位后,我们编写的程序也都会给全局变量进行初始化,防止SRAM中的脏数据污染了我们的变量,导致程序异常跑飞等。不是这个技术知识点不重要,而是Keil等编译工具链已经为我们准备好了一套常用、稳定的SRAM内存初始化策略。不过,也有一些时候,我们更希望SRAM的使用更贴近项目,依项目背景而定制!这也是本帖子的分享目的。

Keil中的BSS段

在Keil编译环境下,BSS段在编译后记录着”未初始化或显式初始化为0的全局变量与静态变量“。这些内容需要在MCU上电复位后由MCU进行清零操作,以保证获得确定的0值。

Keil启动流程

我们以我平时常用的STM32F407VET6芯片为例。它在上电复位后,第一步的操作是初始化堆栈指针,然后就开始跑SystemInit(),紧接着就是跳转到__main()函数。而在__main()函数里面会把所有RAM清空,再加载全局变量和静态变量,之后MCU才会跑到我们自已编写的main()函数里面。我们查看startup_stm32f407xx.s文件就可以在复位回调函数里面看到:

; Reset handler
Reset_Handler    PROC
                 EXPORT  Reset_Handler             [WEAK]
        IMPORT  SystemInit
        IMPORT  __main

                 LDR     R0, =SystemInit
                 BLX     R0
                 LDR     R0, =__main
                 BX      R0
                 ENDP

Keil中的BSS段不被清零的方法

在默认情况下,BSS段在上电复位的时候会被MCU清零,但项目需求要求在上电复位时无需清零,这时该怎么办呢?Keil编译工具提供了两种方法来定制化解决这个问题。

编译器GUI设置

打开Keil编译器Option设置,将IRAM区域中的NoInit勾选,即表示在__main函数中此块IRAM区域不会被强制初始化为零。

Keil选项IRAM配置01.jpg

我这里为示意,把全部的IRAM空间都列为了”非初始化“,大家按自已的项目需求而设定。

特别注意:

  1. 用此种方法需要勾选Use Memory Layout from Target Dialog选项,否则无效。后面我们也会讲到。

  2. RAM1-3是片外RAM,下方的IRAM1-2才是片上RAM。不要设置错误与混淆。

sct分散加载文件

刚刚的GUI配置方法设置非常简单,但它有它的局限性——它只能配置两块IRAM区域。这在我们实际项目应用中,很难满足定制化与复杂的项目需求。这时就需要依靠sct分散加载文件了。

对于修改sct文件来关闭RAM初始化清零的操作也非常简单,只需要在RAM的定义声明上面添加UNINIT关键字即可。

; *************************************************************
; *** Scatter-Loading Description File generated by uVision ***
; *************************************************************

LR_IROM1 0x08005000 0x0001B000  {    ; load region size_region
  ER_IROM1 0x08005000 0x0001B000  {  ; load address = execution address
   *.o (RESET, +First)
   *(InRoot$$Sections)
   .ANY (+RO)
   .ANY (+XO)
  }
  RW_IRAM1 0x20002000 UNINIT 0x00020000  {  ; RW data
   .ANY (+RW +ZI)
  }
}

特别注意:

  1. 如果使用sct分散文件加载的方式,一定要把Use Memory Layout from Target Dialog选项勾选掉

Keil选项IRAM配置02.jpg

实验验证

有了理论基础,又有硬件环境,所以一定要上手验证一下。于是我编写了下述代码:

uint8_t txbuf[16] = {0};    /* 全局变量数组 */

int main(void)
{
    uint32_t i;
    hw_init();
    NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_3);
    SysTick_Config(SystemCoreClock / 1000);

    debug_out(txbuf, 16);

    time_tick = 1000;
    while(time_tick > 0)
    {
        ;
    }

    for (i = 0; i < 16; i++)
    {
        txbuf[i] = i;
    }

    debug_out(txbuf, 16);

    while (1)
    {

    }
}

上述代码的执行逻辑如下:

  1. 先打印全局变量数组txbuf[16]的16字节数据内容

  2. 等待1秒时间间隔

  3. 再将全局变量数组txbuf[16]依次写入0-15

  4. 再打印全局变量数组txbuf[16]的16字节数据内容

根据上面的理论学习,如果我未勾选NoInit的话,全局数组txbuf[16]应该会在上电复位后由编译器对其清零操作。而勾选NoInit后,全局数组txbuf[16]在上电复位后极可能是脏数据。实验结果会与结论保持一致吗?一起来看看我的串口打印内容

Keil选项IRAM配置03.jpg

串口打印内容一共分为6行:

  1. 第1行为未勾选NoInit时的上电打印数据,可以看到全部为0,即编译器已经将其做了清零操作;

  2. 第2行为手动初始化后打印的结果,也符合预期;

  3. 第3行为勾选NoInit时的上电打印数据,果然没有初始化清零操作了,看上去就是脏数据;

  4. 第4行为手动初始化后打印的结果,符合预期;

  5. 第5行为按reset按键后程序重新运行的打印数据。可以看到是上一次初始化的结果,再次验证了编译器未清零操作;

  6. 第6行为手动初始化后打印的结果,符合预期;

总结

在一些无须清零RAM的应用场景,或者需要保留RAM的应用场景下,Keil提供给了程序员控制BSS段的RAM清零与否的有效手段。大家根据自已的项目需求而参与设计实现吧!




关键词: BSS     BSS段     清零    

工程师
2026-09-04 11:08:14     打赏
2楼

这是打开了一个新世界啊


菜鸟
2026-09-07 10:03:01   被打赏 35 分(兑奖)     打赏
3楼

这是没断电上电情况吧---也就是只适合软件复位的情况,断电上电应该还是会清除RAM的数据,按这么搞的话,上电得到的是脏数据了吧


菜鸟
2026-09-07 11:17:01   被打赏 20 分(兑奖)     打赏
4楼

正常reset之后就得memset bss 0和memcpy data;如果触发了看门狗,在执行reset之前,可以把重要信息存到flash中,方便后续查看异常原因。


助工
2026-09-07 12:25:50   被打赏 25 分(兑奖)     打赏
5楼

不清零的情况适用于多个启动阶段需要共享数据的情况,但是mcu的场景下我还真没想过。


工程师
2026-09-07 15:37:50   被打赏 35 分(兑奖)     打赏
6楼

很少用这个功能,关键参数还是存到eeprom里,掉电存,上电读


高工
2026-09-07 15:38:54   被打赏 35 分(兑奖)     打赏
7楼

Keil 下要把一段变量分配到到no_init,bss 里面大佬可以介绍一波


助工
2026-09-07 15:55:11   被打赏 40 分(兑奖)     打赏
8楼

分几种情况,不是所有情况都需要清零。 1。如果做retention那种,复位恢复现场,这个的确不需要清零,但是这个bss段是在retention内存上的  。2。某些场景也需要一些前面若干十几字节或者若干字节不清除保存上次软复位发生了什么,比如看门狗现场


菜鸟
2026-09-07 16:03:12   被打赏 35 分(兑奖)     打赏
9楼

有些要求功能安全的特殊场景,异常复位后(比如看门狗)要求继续跑,比如一些特种设备,这个时候要求bss段,或者特定的一些运行参数指定到的特殊段,就不能清零,并且启动获取”启动方式“后,接管重启前的状态继续跑。


高工
2026-09-07 17:47:44   被打赏 30 分(兑奖)     打赏
10楼

这个功能开起来应用场景比较少,但是在线升级的情况下就可以用到。将新程序不需要但是在程序更换时可以用到的数据保存在IRAM中,而不用像之前那样保存在Flash中。这样可以节省Flash的空间。不知道双核能不能用到,现在感觉芯片厂商发布新的芯片大多数都宣称是双核的。


共15条 1/2 1 2 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]