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,可能会发生不可控的事情

posted @ 2020-11-20 17:15  -青云  阅读(839)  评论(0编辑  收藏  举报