如何在 hid device 例程中实现非掉电保存相应的 RAM 数据

关键字 :NXPQN9080RAM

一、概述

在支持客户过程中,客户的业务代码可能需要实现在不掉电复位时保存某些 RAM 用户数据的功能,例如在 NXP QN9080 使用 NVDS 修改蓝牙地址的数据后需要通过软件重启来实现修改蓝牙地址,这导致有部分 SRAM 的数据丢失。或者是在客户设计Bootloader

代码和暂存用户数据时,常用来保存一些敏感信息,特殊应用场合下的不能被复位的数据或者做复位判断标志等数据,也需要用到文中所讲的内容。下面我们则以 MCUXpresso、IAR 以及 KEIL 这三个 IDE 开发,以 NXP QN9080 MCU 为例子去展开这部分。



二、实现方法

NXP QN9080 共 128KB SRAM 可供用户使用,我们可以使用局部的 RAM 区域用来保存一些特定数据。


图一

需要注意 SRAM 存储块的数量以及大小分配:


图二

以下则以 MCUXpresso、IAR、KEIL 这三个 IDE 上如何实现保存特定 RAM 数据分别进行讲解:

  • MCUXpresso IDE:

通常,应用代码中的全局变量会以链接的应用中的“.data”(初始化)或“.bss”(初始化为零)数据部分结尾。在应用开始执行时,启动代码会自动将“.data”部分的初始值从 FLASH 复制到 RAM,并直接在 RAM 中将“.bss”数据部分初始化为零“.bss“数

据的主要作用是存放程序中未初始化的全局变量和静态变量。这些变量在编译时没有明确赋初值,因此在程序加载到内存时,系统会自动将“.bss”数据的内存空间清零,以保证变量在使用前具备确定的初值。MCUXpresso IDE 可支持应用中使用“.noinit”数

据,这些数据与“.bss”数据类似,但它们不会在启动期间初始化为零。在使用“.noinit”数据时必须谨慎,保证应用代码对此类数据的初始值不做任何假设,这通常意味着应用代码必须先明确设置此数据,然后再使用,否则,这类全局变量的初始值基本上是随

机的(例如,会由系统启动时刚好存储在 RAM 中的值决定的)。但需要注意的是,这类数据在初始化时,只能够初始化为零,不可以是其他非零值,否则编译无法通过。

对于特定的 RAM 内存块,会先放入所有的“.data”项,然后放入“.bss”项,再放入“.noinit”项。在“cr_section_macros.h“头文件中定义可用于将全局变量放入到合适的“.noinit”部分的宏,首先,需要包括这个头文件:#include "cr_section_macros.h"


图三

如果你想将“.noinit”数据放入默认的 RAM 库中,你可以使用 __NOINIT_DEF 宏,例如:// create a noinit integer variable in the main block of RAM__NOINIT_DEF int noinit_var;

当然,你也可以使用 __NOINIT 宏,把你所需要的数据放到你所分配的 RAM 区域:// create a 128 bytes noinit buffer in RAM2__NOINT(RAM2) char noinit_buffer[128];

 

  • IAR

在默认情况下,编译器会将其变量存放在主 RAM 中,并在启动时对其进行初始化。同样的,在 IAR 中也可以设置 noinit 数据,__no_init 类型修饰符使编译器把变量放在非易失 RAM 区中,在启动时也不对它们进行初始化。也就是说 __no_init 在系统启动时不初

始化变量,可以直接使用 __no_init 这个定义,IAR 可自动识别到,例如:// create a noinit integer variable in the main block of RAM__no_init int noinit_var;

  • KEIL

KEIL 中没有其他两个 IDE 的关键词定义,需要在映射文件(.scf)中进行修改,在 SRAM 中开辟出一部分空间。


图四

然后在将需要保存的参数定义到这一部分的空间中:uint8_t test_data[20] __attribute__((at(0x401F000)));从而实现非掉电重启后能够保存数据的功能。



三、例程展示

我们今天测试的是蓝牙例程 hid device,以便于大家测试和验证结果。

  • MCUXpresso

测试代码示例如下:




图五

__NOINIT_DEF uint8_t test_data[20] = {0}; 为要保存的对应 RAM 变量,需初始化为 0,否则可能会随机派发值。ContrastNumber 为全局变量参照对比值。查看编译完成后的 .map 映射文件


图六

如下图,可以看到 test_data[0] 初始值被随机成 d9,ContrastNumber 初始化是 0,在后续的软件复位中,test_data[0] 会进行加一操作,而 ContrastNumber在每次复位后,都会重新被初始化成 0,说明测试通过。


图七

  • IAR

测试代码示例如下:

 


图八

__no_init uint8_t test_data[20];为所需的不初始化的 RAM 变量,ContrastNumber 为全局变量参照对比值。

测试结果如下:查看编译完成后的 .map 映射文件


图九

 


图十

可以看到 test_data[0] 初始值被随机成 bc,ContrastNumber 初始化是 0,在后续的软件复位中,test_data[0] 会进行加一操作,而 ContrastNumber在每次复位后,都会重新被初始化成 0,说明测试通过。

  • KEIL

先在映射文件 .scf 中预留出 4K 的 RAM 空间,作为特定数据存储。


图十一

测试代码示例如下:

uint8_t test_data[20] __attribute__((at(0x401F000))); 为所需的不初始化的 RAM 变量,变量起始位置为 0x401F000,长度为 20 Bytes。

uint8_t ContrastNumber = 0;为对比参照全局变量。


图十二

编译完成后映射文件 .map 如下:


图十三

测试结果如下:


图十四

KEIL 中 .data 为可寻址片内 RAM,可以看到 test_data[0] 初始值为 0,ContrastNumber 初始化是 0,在后续的软件复位中,test_data[0] 会进行加一操作,而 ContrastNumber 在每次复位后,都会重新被初始化成 0,说明测试通过。


四、总结

 以上则是如何分别讲了三种不同的 IDE 下在 hid device 例程中实现非掉电保存相应的 RAM 数据的过程,大家可以也在其他 Cortex-M MCU 中进行尝试。



五、参考资料

【1】QN908X_DS.pdf

【2】MCUXpreeso_IDE_User_Guide.pdf

★博文内容均由个人提供,与平台无关,如有违法或侵权,请与网站管理员联系。

★文明上网,请理性发言。内容一周内被举报5次,发文人进小黑屋喔~

评论