Zstack中关于NV的几个问题

本文转自:http://bbs.feibit.com/thread-366-1-1.html

原文是一篇pdf文档,我给复制出来的。

我是 zigbee 的新手,嘎嘎新的新手,目前学习 CC2430+Z-stack1.4.3 那一套东西呢,至今对协议栈也是一知半解。不过在学习过程中看资料总是提到NV这个事儿, NV者, Non Volatile 也,就是掉电不丢失的存储器呗, EEPROM, FLASH其实都是掉电不丢失,都可以称为NV。这个 NV的作用呢,无非就是用来存储需要掉电不丢失的一些系统参数罢,要不然每次上电都要重新弄参数,这是相当恶心的事情。 
在 CC2430+Zstack 系统中,是在片内 flash 中专门划出来一块空间来做为系统参数存储空间,我想如果外扩一个 IIC 总线的 EEPROM,也能干这个事儿,但是要做 N 多工作来修改协议栈中用到 NV 的地方,想想就害怕,还是别惹麻烦了。 
那位同学说了:“说那么多干嘛,赶紧说正事儿,你提到的几个问题是哪几个”?做人要厚道啊,实话实说,写到这里的时候我还没想好有哪几个,反正有好几个。写到哪里算哪里好了。 

第一个问题:  协议栈如何定义和操作NV? 
既然 NV不过是存储器而已,那么用脚趾头想想都能想象操作存储器必然要有 read和write这两件事吧。那么函数在哪里啊?协议栈挨个文件夹翻看翻看,在 OSAL 文件夹下有 OSAL_Nv.c 耶!有时间就逐个慢慢研究函数好了,我是没时间,看多了有大海的感觉。看协议栈安装路径下 documents 文件夹,OSAL API_F8W ………….pdf文档,发现实际上要操作 NV,关键只有三个函数。分别是: 
uint8 osal_nv_item_init( uint16 id, uint16 len, void *buf ) 
            初始化的,据说每次操作NV之前都得这么干; 
uint8 osal_nv_write( uint16 id, uint16 ndx, uint16 len, void *buf ) 
            写 NV的; 
uint8 osal_nv_read( uint16 id, uint16 ndx, uint16 len, void *buf ) 
            读 NV的。 

关于这几个函数的参数定义,可以看上面提到的pdf文档好了。不过几个函数的第一个参数是什么(后面几个参数很容易理解,我不说了。如果理解不了,去把谭浩强老师的那本C语言程序设计学习学习再来)?pdf文档给出来了: id – User-defined item ID.我们翻译成用户定义的条目吧。这个条目又是什么?就是用户定义的某个地址空间的一个名字,#define 出来的常数。Pdf 文档还给出 


来了一个系统预分配的编号,上面这个表就是了。从这个表看,原来协议栈各个层用到 NV的地方都有固定的定义,那么显然我们不能改啊。那么确实要自己添加几个参数存储的地方,怎么办?嗯,仔细看,上面表中有给 Application用的条目取值范围0x201~0xFFF,乖乖,你有多少参数都够用了吧。 
那么,在哪里添加哦?打开文件 ZComDef.h,往下看,再往下……… 

// OSAL NV item IDs 
#define ZCD_NV_EXTADDR                     0x0001 
#define ZCD_NV_BOOTCOUNTER               0x0002 
#define ZCD_NV_STARTUP_OPTION             0x0003 
#define ZCD_NV_START_DELAY                0x0004 
到了,就是这里,从这之后一路下去就是按照上面那个表定义的一些常量,其实是一个编号呗。继续往后看,依次是协议栈各个层用的 NV条目定义…... 
// NV Items Reserved for applications (user applications) 
// 0x0201 ?0x0FFF 
看到没?就是这里,user applications用的,可以添加自己的Item啦,想取什么名字你自己看着办吧。反正我添加了下面两个: 
#define ZCD_NV_APP_TEST1                   0x0201 
#define ZCD_NV_APP_TEST2                   0x0204   

欧了,我有自己的两个 item 了。接下来试试看好用不好用;怎么试?先写进去再读出来呗。这个程序怎么写不用多说了吧。什么?还不知道?好吧,我好人做到底。打开 Zmain.c文件,什么?这个文件在哪里?这位同学,你这手比我更加新了,现在不适合看我这个文档,去看点儿别的回头再说吧。  Zmain文件里面有一个函数:static ZSEG void zmain_ext_addr( void ),找到函数,这个函数开始定义一些变量之后,就调用了 osal_nv_item_init()和osal_nv_read()函数。好,我就把实验程序放在这个函数里面好了,在这个函数的变量定义之后添加(具体函数参数看一下OSAL那个 pdf文档吧): 

uint8 nv_data; 
  uint8 nv_origin_data=0x55 ; 
 
  osal_nv_item_init(ZCD_NV_APP_TEST1,1,NULL); 
  osal_nv_write(ZCD_NV_APP_TEST1,0,1,&nv_origin_data); 
  osal_nv_read(ZCD_NV_APP_TEST1,0,1,&nv_data); 
我这个就是定义了两个变量,调用了三个函数,按照 pdf 文档说,每次操作(不管读还是写)NV,都要先item init一下,之后我写一个字节 0x55,然后读出来。好了,把程序编译后 down 到板子上,在osal_nv_item_init(ZCD_NV_APP_TEST1,1,NULL)处设置一个断点,全速运行到断点后,单步一下,打开 watch窗口,添加要watch的变量,看看是不是确实写进去了哦?嘿嘿,偷笑,要是你还不会用IAR进行程序调试,我可管不了了。 干完这些事儿,可以自己定义 NV 的 item 了,也可以操作了,其实对于一般应用来说,知道这些就够了,剩下的事情就是在程序里面自由发挥什么时候要 write和 read 的(至于那三个函数具体又干了什么,目前看关系不大,不过要想刨根问底刨到祖坟上去,就花点儿时间再跟踪一下函数具体工作吧) ,不过还是要注意 pdf文档警告我们①操作 NV的过程不要被中断打断;②频繁写操作很费电,也磨损 flash;③升级协议栈也要为 NV 做点儿工作。 

第二个问题:自己的定义的 NV条目到底在哪里?

做单片机的人吧,有个毛病,总想知道数据去哪里了,不是精确到变量,而
是精确到物理地址。我本人虽然号称做光纤传感方向,可是那是后来转行的,所
以单片机人的毛病我也有啊。 

上面我定义的 item 的地址是多少?  疑问 卖糕的,0x0201,0x0204,不会吧?再看看别的,#define ZCD_NV_EXTADDR   0x0001,继续卖糕。这些定义的常数肯定不是地址!疑问疑问疑问 ??前面就说了,这个定义其实是定义一个编号,现在具体地址还指不定在啥地方呢,每个编号还可能有好几个字节呢。ZCD_NV_EXTADDR 就有8个字节,存IEEE地址的需要 8 个。 
那我定义的 #define ZCD_NV_APP_TEST1    0x0201,到底在 CC2430 的什么
地方啊? 
这个问题纠结了我好几天,到现在也还是有点儿纠结,下面我说说我的看法啊,不一定对哦,同学们按照我这么理解要是被老板开除了我可不管发工资,这就是一个愿打一个愿挨的事儿 。 
看 item 定义所在的 ZcomDef.h 文件,没啥有用信息啊………,继续找吧。

挖地三尺,终于发现了一点儿线索,看 Tool 文件夹下的 F8w2430.xcl,这是IAR 用来链接程序的一个指导性文件,里面有大量的段(Segment)声明啊,分配之类的说明。主要是-D,-P,-Z 几个链接选项。其中-D 是用来定义常量的,-Z和-P 是用来说明如何分配段的.包括代码段啊,数据段啊,常量啊一堆东西。 到了这里,不能不提 CC2430 的 bank 问题。在CC2430 中,因为标准 51 处理
器寻址空间最大为64K byte,CC2430-F128 有 128K byte(目前开发板我发现基本上都用的 128 版本,64 和 32 版本的处理器可能另有说法),按照传统 51 的寻址能力,是无法对 128K byte 存储器进行寻址的?那么在IAR+CC2430系统中,是如何实现超出 64K byte 存储空间的寻址呢?看看 2430 的 user guide,是用 bank的概念来解决这个问题。下面图大致说明了128K byte 的 bank 情况


从 F8w2430.xcl 文件中大体可以看到,在 zstack 1.4.3 中把 128Kbyte flash分成以下几个部分: 
(1) ROOT 部分 
-D_CODE_START=0x0000            // Code size = 128k for CC2430-F128 
-D_CODE_END=0x28FF             // Last address for ROOT bank 

  这一部分是第一段 CODE,地址从0x0000~0x28FF,我认为这个对应上面图中的 ROOT那一部分。不过不知道为什么只是划分了0x28FF这么多,为了工整,我把这个地方的 0x28FF改成了 0x7FFF: 
//-D_CODE_END=0x28FF             // Last address for ROOT bank 
-D_CODE_END=0x7fff 
编译后 down 到板子上,原来的例子程序照常运行,至于会不会出别的问题我就不得而知了,有深入研究过的大侠可以出来说说哦。

(2) banked部分 
紧接上面的 root 部分定义是: 
-D_BANK1A=(10000+_CODE_END+1)  // First address for BANK1 
 
几乎是文件的最后部分有以下定义: 
-D_BANK1_START=_BANK1A         // 1st overlayed code bank 
-D_BANK1_END=0x1FFFF 
// 
-D_BANK2_START=0x28000         // 2nd overlayed code bank 
-D_BANK2_END=0x2FFFF 
// 
-D_BANK3_START=0x38000         // 3rd overlayed code bank 
-D_BANK3_END=0x3DFFF 
// 
-D_BANK3b_START=(_ZIGNV_END+1)  // 3rd overlayed code bank after the 
//pages dedicated to NV. 
-D_BANK3b_END=0x3FFF7            // Last 8 bytes of last Flash page 

//reserved for IEEE address. 
-D_IEEE_ADDR_START=0x3FFF8       // Last 8 bytes of flash 
-D_IEEE_ADDR_END=0x3FFFF 

看看 0x3FFF8~0x3FFFF 这个地址范围?熟悉不?什么地方好像提到过吧?嗯,存储空间最后8 字节用来干什么?存储IEEE地址呗,看来确实如此).

从这里看到, xcl 文件把 Root 之外的存储空间划分成0x18000~0x1FFFF,0x28000~0x2FFFF,0x38000~0x3FFFF.这么几大块逻辑地址范围,(注意啊,是逻辑地址范围,都是相对的,实际存储器哪有 0x3FFFF 这么大啊,这里的 1,2,3 更像是这个 bank 的编号)当然了里面还有一些细分,我相信大家能看懂

为什么这么分呢?还是看看CC2430的说明书吧,说明书中有一个MEMCTR寄存器,是用来解决无法寻址 64Kbyte 之外地址空间问题的一个寄存器,下面是这个寄存器的简单说明。看完说明搞清楚了,这个寄存器中的两个位决定是把哪一个 32K byte 的一个大页映射到0x8000~0xFFFF这段可寻址的空间里面去。这是通过设置 MEMCTR中的 FMAP.MAP[1:0]这两位的值来实现的。 

(CC2430 user guide 41page) 

搞清楚了这些事情就不难想象了,将来可以把0x8000~0xFFFF,0x10000~0x17FFF,0x18000~0x1FFFF 这几块实际的物理地址映射到 CC2430 可以寻址的 0x8000~0xFFFF 地址空间去!.bank1(逻辑地址范围0x18000~0x1FFFF) 就是实际的 0x8000~0xFFFF , bank2 (逻辑地址范围0x28000~0x2FFFF)就是实际的 0x10000~0x17FFF,bank3(逻辑地址范围0x38000~0x3FFFF)就是实际的 0x18000~0x1FFFF。(这地方说的有点晕,自己理解理解吧). 
好了,有这些认识后,再看f8w2430.xcl 里面的一个定义: 

-D_ZIGNV_START=0x3E000         // The two pages before the last two 
//pages of the 3rd overlayed bank. 
-D_ZIGNV_SIZE=0x1000           // Size of ZigBee NV (2 pages) 
-D_ZIGNV_END=(_ZIGNV_START+_ZIGNV_SIZE-1) 

算一下,ZIGNV_END = 3EFFF. 

没错,从名字上看,ZIGNV_XXX,这个应该是 zigbee NV 的地址吧,那么如此说来,NV区域的起始地址按照 bank 来说,就应该是 0x3E000 开始,一直到 0x3EFFF。这样,按照之前关于bank映射关系的讨论, NV区实际的物理地址应该是从0x1E000~0x1EFFF这块空间。之后是 bank3b,再后就是前面提到用来存储 IEEE地址的那 8个字节,就是存储空间的最后了。 
  关于这个 NV具体在哪里的事情,上面这些应该是大致确定了其所在范围,但是具体精细到字节地址我还没搞清楚。 两个问题了,再凑一个问题?下一个问题讨论一下更细节的 NV数据结构和读写问题吧。今天先把这个传上来,万一能起到抛砖引玉功能,有人写个续之类的,我就省心了。 


PS:在此感谢原创者,帮助我们更好的理解Zstack。
 

  • 0
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值