本帖最后由 IFXNaZhang 于 2024-7-10 10:18 编辑
在默认情况下,编译器会将变量存放在RAM中,并在启动时对其进行初始化。但是有些时候,当芯片复位(不含上电复位)时,我们希望变量在复位后不被初始化, 保存复位前的一些信息。比如将系统进入hardfault前的PC指针和一些详细的DEBUG信息写入Noinit RAM保存起来,等到复位启动后可以将错误的DEBUG信息拿出来分析。实际上,由于变量是存储在RAM中的,只要不掉电,变量的数值是不会改变的,所以只要不让系统在复位时进行初始化操作即可。对此,不同的编译环境有不同的设置方法,下面就来讲讲在Keil、 IAR、ModusToolbox编译环境下,实现该功能的方法。 1. IAR 实现变量不初始化的方法 在IAR Embedded Workbench中,__no_init是一个特殊的关键字,用于指示编译器不要对变量进行初始化操作,可参考IAR帮助文件中的相关内容: 即在IAR中“__no_init”可以直接使用,类似下面定义一个不被初始化的变量: __no_init uint16_t Test_NoInit;
在这个例子中,关键字“__no_init”用于告诉编译器,这个变量不需要在复位时进行初始化。为了验证是否执行成功,可以考虑周期性地让系统复位,观察变量的变化,比如下面的示例程序定义一个复位后初始化的变量和一个不被初始化的变量,系统周期复位,会发现每次Test_NoInit 数据都是在上次数据基础上增加10,而不是像Test_Init那样每次是被初始化后的数据增加10。 2. Keil 实现变量不被初始化方法 Keil MDK (Microcontroller Development Kit) 使用的编译器是 ARM 公司推出的 ARM Compiler。编译器说明文档中没有专门的关键字,解决方法是需要自己开辟一个UNINIT的段,再把不需要初始化的变量定义到这个段里面。 首先需要手动修改分散加载文件: 打开Options for Target对话框,选择Linker标签页,不勾选Use Memory Layout from Target Dialog。这个选项的意思是使用Target标签进行链接设置,所以在其勾选的情况下,分散加载文件是不能进行手动编辑的。当该选项不勾选时,就可以点Edit进行分散加载文件的设置了。 分散加载文件如下: 定义了一个 UNINIT 段,并指定它不被初始化。 注意:在 Arm Compiler 6 中使用的是 ".bss.NoInit",而在 Arm Compiler 5 中使用的是 zero_init。 定义变量:
验证代码同IAR,可进行复位后初始化的变量和不被初始化的变量的观察。 3. ModusToolbox 实现变量不被初始化方法 在ModusToolbox中可以使用GNU Arm Embedded Compiler。操作与Keil中类似,需要修改linker.ld文件。linker.ld文件的路径一般如下: MTB生成的工程中,变量SystemCoreClock就是定义在不被初始化的区域,如需加入更多变量,可在linker文件中修改no_init_size大小,利用该部分区域。 在linker文件中关于不被初始化区域的描述:
定义变量到这个不被初始化的区域:
验证代码同IAR。
|
学习了!