nordic __noinit__变量使用
Noinit RAM是啥,用来做啥?
Noinit RAM,故名思意就是未被初始化的变量,我们编程的时候也知道,如果定义了一个常规的变量,一般编译器都会将其初始化成固定数值(一般是0xFF),系统每次复位的时候都赋值为一个固定的初始值。
但是有些场景下我们需要一些特定变量,这些变量在系统复位后也能保持复位前的值,不发生改变,Noinit RAM有用的地方就在这里。
应用场景的一些探讨:
- 在某些不掉电场景下代替flash存储达到变量的保持功能
这个功能可以配合flash存储,在短期内以Noinit RAM保持数据,在关键节点再将数据写进flash,以达到减少flash擦写次数的操作次数(特别是Nordic在协议栈操作下,flash写操作容易失败的情况下)。
- 系统的DEBUG定位
系统出现硬件错误的时候往往会进入到harfault中断服务线程,此时可以将系统进入harfault前的PC指针和一些详细的DEBUG信息写入Noinit RAM保存起来,等到复位启动后也可以将错误的DEBUG信息拿出来分析。
- 模拟RTC实时时钟的可记忆寄存器
这个用法下,RTC几乎可以不受复位的影响。
- 防止某些需要保持的数据在复位下不丢失
如果没有任何flash存储方式,可以尝试使用Noinit RAM代替其功能,在某些场景很实用
- 检测一个系统是否是人为复位还是意外硬件复位
人为复位之前,Nonit RAM写入某个非0xff的特定值,如果是人为操做复位,则复位后的变量是对应的特定值。如果是意外硬件复位,则就可以通过Nonit RAM检查出来
Noinit RAM的配置:
注:根据MCU本身的RAM地址去设置,本文是以nRF52832为例
RAM Start地址:0x20003AB8 RAM Stop地址:0x20010000 (协议栈已经占0x3AB8)
Start地址+IRAM1 Size = IRAM2地址;
IRAM2地址+IRAM2 Size = Stop地址;
程序使用:
//建议将Noinit RAM打包成一个结构体操作,就不需要定义多个__attribute__地址了,兼容性好
//NoInit掉电保持数据
typedef struct
{
uint32_t wake_flag;
uint32_t circle_count;
uint8_t last_battery_level;
uint16_t last_battery_value;
} noinit_data_t;
%将RAM映射到0x2000FFF0地址,也就是Noinit RAM部分
#define __noinit__ __attribute__((at(0x2000FFF0)))
__noinit__ noinit_data_t noinit_data;
int main()
{
if(noinit_data.wake_flag == 0xff)
{
//掉电复位,需要初始化一次数据
noinit_data.circle_count = 0;
}
else if(noinit_data.wake_flag == 0x01)
{
//人为复位
}
while(1)
{
//无需初始化,直接++
noinit_data.circle_count++;
}
}
特别注意:
对于Nordic来说,量产产品往往会有SoftDevice+BootLoader+APP三个部分,此时必须将BootLoader和APP的工程Noinit RAM设置设置一致才行,否则系统先运行BootLoader再跳转到APP,可能会发生不可控的事情