一、简介
本篇以SimpleBLEPeripheral工程为例,介绍SNV的使用。
二、实验平台
协议栈版本:BLE-CC254x-1.4.0
编译软件:IAR 8.20.2
硬件平台:Smart RF开发板
三、版权声明
博主:甜甜的大香瓜
声明:喝水不忘挖井人,转载请注明出处。
原文地址:http://blog.csdn.net/feilusia
联系方式:[email protected]
技术交流QQ群:127442605
四、CC2541的SNV简介
1、SNV是什么?
答:
NV就是从内部flash划分出来的一块专用于存储数据的flash。
NV就是Non-Volatile (非易挥发),香瓜在文档中看到的都是NV,很长一段时间困惑为什么大家都叫它SNV。
详细阅读OSAL API.pdf(位于C:\Texas Instruments\BLE-CC254x-1.4.0\Documents\osal)后发现,该文档第10章讲解的是NV,第11章则讲述的是SNV(Simple Non-Volatile)。
2541的协议栈用的是SNV(8位ID),而不是NV(16位ID)。
由这个线索,将我心中的各种百度不到的SNV的疑问也都迎刃而解了。
注:详细了解SNV后才发现我低估它了,并不像多数SNV资料中写的那么简单,因此本篇增加了大篇幅来解析SNV是怎么一回事。
2、SNV有多大?
答:
1)在C:\Texas Instruments\BLE-CC254x-1.4.0\Projects\ble\common\cc2540\ti_51ew_cc2540b.xcl中有这么两段代码:
// Setup of CODE banks // ------------------- // -D_BANK0_START=0x00000 // Note: Unconventional bank numbering on this part: -D_BANK0_END=0x07FFF // "BANK0" is the root bank/common area! // -D_BANK1_START=0x18000 -D_BANK1_END=0x1FFFF // -D_BANK2_START=0x28000 -D_BANK2_END=0x2FFFF // -D_BANK3_START=0x38000 -D_BANK3_END=0x3FFFF // -D_BANK4_START=0x48000 -D_BANK4_END=0x4FFFF // -D_BANK5_START=0x58000 -D_BANK5_END=0x5FFFF // -D_BANK6_START=0x68000 -D_BANK6_END=0x6FFFF // -D_BANK7_START=0x78000 // End of code space has to match that of OSAL NV page start. // Note that in this way, we'll be wasting last page spaced by NV pages, // but in order not to overwrite NV pages when downloading new image, the waste // is inevitable. // New OSAL NV driver will move the NV pages to the last pages not wasting // last page itself. -D_BANK7_END=(_BLENV_ADDRESS_SPACE_START-1)上面这段代码说明256K的flash被分为8个BANK,每块BANK为32K。
在第8块BANK的末尾分出了一块flash,用于NV。
// Internal flash used for NV address space. // --------------------------- // // Address range for HAL_FLASH_PAGE_SIZE == 2048 -D_BLENV_ADDRESS_SPACE_START=0x7E800 -D_BLENV_ADDRESS_SPACE_END=0x7F7FF // // Address range for HAL_FLASH_PAGE_SIZE == 4096 //-D_BLENV_ADDRESS_SPACE_START=0x7D000 //-D_BLENV_ADDRESS_SPACE_END=0x7EFFF // -Z(CODE)BLENV_ADDRESS_SPACE=_BLENV_ADDRESS_SPACE_START-_BLENV_ADDRESS_SPACE_END
上面这段代码说明NV的起始地址是0x7E800,终止地址是0x7F7FF。实际上NV也就是保存在这两页flash里,每页2048字节。
这个NV大小我们可以根据需要来改变,当然NV的flash大了、放代码的flash就小了。
3、SNV的接口资料哪里有?
答:OSAL API.pdf(位于C:\Texas Instruments\BLE-CC254x-1.4.0\Documents\osal)
4、使用SNV有什么需要注意的?
答:
在OSAL API.pdf的文档中提到了几个注意点:
1)写SNV会耗时百毫秒级,尽可能在写的时候关闭中断。
2)尽可能地少写SNV,因为它耗时耗电。
3)如果SNV的存储结构改变,或者协议栈版本升级了,有必要重新擦除和初始化SNV内存数据,否则读写时会出错。
4)尽量不要把SNV的代码放到中断函数里。
香瓜也补充一个很重要的注意点:
IAR的debug仿真时默认是全片擦除,因此会擦除flash中的code、NV。
所以经常有群友来回仿真调试时发现自己写的掉电保存数据没了,不知所以然,问题就出在这里。
解决办法:
(具体我也不知道该怎么填,大家自行百度或实验吧)
5、SNV的哪些ID是可以用的?
答:
在bcomdef.h中已经定义了一些我们不能用的SNV的ID:
/** @defgroup BLE_NV_IDS BLE Non-volatile IDs * @{ */ // Device NV Items - Range 0 - 0x1F #define BLE_NVID_IRK 0x02 //!< The Device's IRK #define BLE_NVID_CSRK 0x03 //!< The Device's CSRK #define BLE_NVID_SIGNCOUNTER 0x04 //!< The Device's Sign Counter // Bonding NV Items - Range 0x20 - 0x5F - This allows for 10 bondings #define BLE_NVID_GAP_BOND_START 0x20 //!< Start of the GAP Bond Manager's NV IDs #define BLE_NVID_GAP_BOND_END 0x5f //!< End of the GAP Bond Manager's NV IDs Range // GATT Configuration NV Items - Range 0x70 - 0x79 - This must match the number of Bonding entries #define BLE_NVID_GATT_CFG_START 0x70 //!< Start of the GATT Configuration NV IDs #define BLE_NVID_GATT_CFG_END 0x79 //!< End of the GATT Configuration NV IDs /** @} End BLE_NV_IDS */
实际上上面的ID所在的区域,本来就不是我们该使用的,我们适合用的ID是在0x80~0xFE:
注:这张表要看OSAL API.pdf的第十一章的SNV,别看错到第十章的NV。
五、测试代码
1、添加头文件(simpleBLEPeripheral.c)
#include "osal_snv.h"
static uint8 write_time = 0; //擦写次数 #define SNV_TEST_ID 0x80 static void simpleBLEPeripheral_HandleKeys( uint8 shift, uint8 keys ) { VOID shift; // Intentionally unreferenced parameter uint8 data[252]; uint8 ret; //UP 读SNV if ( keys & HAL_KEY_SW_1 ) { ret = osal_snv_read(SNV_TEST_ID, sizeof(data), data); if(ret == NV_OPER_FAILED) { //未保存过,设置出厂数据 //osal_memset(data, 0x55, sizeof(data)); //作为发送缓冲区,写0x55 for(uint8 i = 0; i < 252; i++) { data[i] = i; } osal_snv_write(SNV_TEST_ID, sizeof(data), data); osal_memset(data, 0, sizeof(data)); //清空缓冲区后,作为接收缓冲区 ret = osal_snv_read(SNV_TEST_ID, sizeof(data), data); } } //DOWN 写SNV if ( keys & HAL_KEY_SW_3 ) { write_time++; osal_memset(data, write_time, sizeof(data)); osal_snv_write(0x80, sizeof(data), data); } }
1)当写入252字节到SNV、并读出252字节SNV时,读写正常。
2)当写入253字节到SNV、并读出253字节SNV时,读写异常。
六、本篇仍存在的疑问
1、本篇实验结果252、253字节为SNV正常与否的分界线,看起来有些异常。也有可能是堆栈溢出导致的,暂不明白,望大家测试后告知我你们的实验结果。
(后续,已有两个群友表示他们的测试结果与我一样)
2、0x80与0xFE的ID是否都能写252字节?待验证。