通常情况下单片机复位后会自动清零 SRAM 中的一些变量,本文以 ARM 单片机为例来说一说如何实现不清零。
在默认情况下,定义一个未初始化的数组:
uint8_t hardfault_info[256];
它会被分配到ZI 段中去。什么是ZI 段?
ZI(.bss) 即 zero-initialized ,它是在代码中未作初始化的需要在运行时被初始化为零的变量的集合。类似地还有 XO(execute-only )、RO(read-only,.text)只读的常量、RW(read-write,.data)在编译时被初始化了的可读写变量。
如果一个变量在代码中被初始化为 0 应该放在哪个段呢?试验了一下,如果定义的是初始化为 0 的数组,那么它被放到了 ZI 段。如果定义的是一个变量或小数组(小于 9 字节),它被放到了RW段,并且 ZI 段还有可能增大 4 个字节(不初始化为0的时候也有可能增加),这就不明白其中的道理了。
注:后来查了一下,这个现象应该可以通过 --bss_threshold=num 来控制,它是用来控制小的全局 ZI 数据应该放到什么段里(ZI/RW)。
所以,既然定义的未初始化的数组 hardfault_info 被分配到了 ZI 段,每次复位后在执行 __main 程序后会被重新初始化为零,复位前的值被全部抹去。
要实现不被初始化为 0 ,需要定义一个 RAM 执行区(execution region),属性设置为 UNINIT,来告诉编译器,在初始化的时候不要将该区域的 ZI 段初始化为 0。
以下两种方法是一致的:
方法 1:
RW_IRAM2 0x2000FF00 UNINIT 0x00000100 { ; RW data
.ANY (iram_uninit)
}
__attribute__((section("iram_uninit"), zero_init)) uint8_t hardfault_info[252];
方法 2:
RW_IRAM2 0x2000FF00 UNINIT 0x00000100 { ; RW data
.ANY (+RW +ZI)
}
__attribute__((at(0x2000FF00))) uint8_t hardfault_info[252];
|