z-stack的flash驱动。在分析flash驱动之前,需要熟读cc2530的datasheet关于flashcontroller那一章节!我们先从hal_flash.c文件中的HalFlashRead函数开始:voidHalFlashRead(uint8pg,uint16offset,uint8*buf,uint16cnt){//CalculatetheoffsetintothecontainingflashbankasitgetsmappedintoXDATA.uint8*ptr=(uint8*)(offset+HAL_FLASH_PAGE_MAP)+((pg%HAL_FLASH_PAGE_PER_BANK)*HAL_FLASH_PAGE_SIZE);uint8memctr=MEMCTR;//Savetorestore.#if!definedHAL_OAD_BOOT_CODEhalIntState_tis;#endifpg/=HAL_FLASH_PAGE_PER_BANK;//Calculatetheflashbankfromtheflashpage.#if!definedHAL_OAD_BOOT_CODEHAL_ENTER_CRITICAL_SECTION(is);#endif//CalculateandmapthecontainingflashbankintoXDATA.MEMCTR=(MEMCTR&0xF8)|pg;while(cnt--){*buf++=*ptr++;}MEMCTR=memctr;#if!definedHAL_OAD_BOOT_CODEHAL_EXIT_CRITICAL_SECTION(is);#endif}在讲解这个函数之前,先说一下z-stack中对flash的布局。z-stack将256KBflash的最末八个字节作为zigbee中的IEEE地址,当然在这八个字节之后还有16个字节lockbits,这些flash的lock所需要用的,每2kb(1page)的flash有1bit的lock位,那么256kb的flash有128个2kb,当然也就有128(16X8)位的lockbits了。从F8w2530.xcl文件中可以看出:-D_IEEE_ADDRESS_SPACE_START=(((_NR_OF_BANKS+1)*_FIRST_BANK_ADDR)-0x18)-D_IEEE_ADDRESS_SPACE_END=(_IEEE_ADDRESS_SPACE_START+7)-Z(CODE)IEEE_ADDRESS_SPACE=_IEEE_ADDRESS_SPACE_START-_IEEE_ADDRESS_SPACE_END注:0x18=24=16+8;_IEEE_ADDRESS_SPACE_START容易算出来,_NR_OF_BANKS值为0x07,_FIRST_BANK_ADDR值为0x8000,这些值是在options...里面设置的。所以_IEEE_ADDRESS_SPACE_START的值为0x40000-0x18=0x3FFE8,_IEEE_ADDRESS_SPACE_END值就为0x3FFE8+7=0x3FFEF。Z-STACK将flash的最末处的12KB(6page)用来作为Nv存储的,具体看:-D_ZIGNV_ADDRESS_SPACE_START=(((_NR_OF_BANKS+1)*_FIRST_BANK_ADDR)-0x3800)-D_ZIGNV_ADDRESS_SPACE_END=(_ZIGNV_ADDRESS_SPACE_START+0x2FFF)-Z(CODE)ZIGNV_ADDRESS_SPACE=_ZIGNV_ADDRESS_SPACE_START-_ZIGNV_ADDRESS_SPACE_END我们知道0x3800为7个page即14KB,0x2FFF为6个page,则Z-STACK将最末的7个page的前6个page用来作为Nv存储,最后一个page用来存储其他信息,如IEEE地址。好!我们接下来看这个函数。uint8*ptr=(uint8*)(offset+HAL_FLASH_PAGE_MAP)+((pg%HAL_FLASH_PAGE_PER_BANK)*HAL_FLASH_PAGE_SIZE);首先计算了这个地址映射到XDATA中之后的值,HAL_FLASH_PAGE_MAP为0X8000,HAL_FLASH_PAGE_PER_BANK值为16,HAL_FLASH_PAGE_SIZE值为2024即2KB,这个计算很显然了。z-stack中的page是从0开始的,一直到127,总共128page,假如我们要读某一page中的数据,那么我们必须先把这个page所在的bank映射到XDATA的0x8000~0xFFFF中,我们读取page值为100,偏移量为20的数据时,这个地址通过上面的表达式就很容易计算出来为20+0x8000+(100%16)*2024=0x9FB4,注意这个地址转换成了(uint8*),即为XDATA空间的地址。pg/=HAL_FLASH_PAGE_PER_BANK;计算page所在的bank,如果pg为100,则其所在bank值为100/16=6;MEMCTR=(MEMCTR&0xF8)|pg;这句是将刚才计算所得的bank映射到XDATA的0x8000~0xFFFF中去,MEMCTR的低三位为XDATA的bank选择位while(cnt--){*buf++=*ptr++;}很明显,将ptr指针指向的数据复制到buf指针所指向的地址去,这个buf和ptr变量是在运行时堆栈上的,只不过是将数据从XDATA的一个地放复制到sram中某个地方!那么这个函数的最用就很明显了:它是将flash内部的某个page,相对其偏移量为offet地址处的数据,读取cnt个字节到buf中去。接下来看看HalFlashInit这个函数:voidHalFlashInit(void){//LoadthecodetorunfromRAMintoitsreservedareaofRAMonceatstartup.HalFlashRead(PAGE_OF_RAM_CODE,OSET_OF_RAM_CODE,ramCode,SIZE_OF_RAM_CODE);}这个flash初始化函数直接调用了HalFlashRead函数,我们看看这几个实参数据,PAGE_OF_RAM_CODE值为51,OSET_OF_RAM_CODE值为0x6DD,SIZE_OF_RAM_CODE为0x23,ramCode为:#pragmalocation=RAM_CODE_XDATAstatic__no_inituint8ramCode[SIZE_OF_RAM_CODE];这个ramCode是不能初始化的静态数组这个ramCode是在RAM_CODE_XDATAsegment,打开F8w2530.xcl文件:-D_RAM_CODE_XDATA_START=0x01EDD-D_RAM_CODE_XDATA_END=(_RAM_CODE_XDATA_START+0x22)-Z(XDATA)RAM_CODE_XDATA=_RAM_CODE_XDATA_START-_RAM_CODE_XDATA_END很明显RAM_CODE_XDATA这段范围是8kb的sram中最末的23个字节,那么这个初始化函数的作用就是将flash中23个字节的代码加载到ram去运行。那么这个有什么用途呢?而且为什么是23字节呢?看到这个注释,AnycodethatwillberunfromRAMbysettingXMAPofMEMCTLmusthavethesamebank-relativeaddressastheaddressinRAMtowhichtheCODEwillbecopiedtorun.Thus,anypartofthefirst8kofanybankcanbededicatedtocodethatwillrunfromRAMaslongasthecorrespondingrelativeaddressrangeisreservedinRAMbyRAM_CODE_XDATA.这时候我们看到这几句:#pragmalocation=RAM_CODE_FLASH#ifdefinedHAL_OAD_BOOT_CODEstaticvoidHalFlashWriteTrigger(void);#elsestatic__monitorvoidHalFlashWriteTrigger(void);#endif__monitor表示此函数不能被中断!这个函数的位置就是在RAM_CODE_FLASH处,-Z(CODE)RAM_CODE_FLASH=_RAM_CODE_FLASH_START-_RAM_CODE_FLASH_END-D_RAM_CODE_FLASH_START=0x39EDD-D_RAM_CODE_FLASH_END=(_RAM_CODE_FLASH_START+0x22)这个表示的code段RAM_CODE_FLASH范围,为0x39EDD~0x39EFF,这个跟之前的那个51page,0x6DD是什么关系呢?我们先看这个地址值出在什么位置,51page出在第三个bank里(注意bank是从0开始起的),那么将其映射到codememory(64KB)中就是在32KB+3page+0x6DD处,记住code空间的第一个为rootbank,接着我们将39EDD映射到code空间中,其bank为7,其值为115page+0x6DD(注意page也是从0开始的),16page为1个bank,映射之后再code中的值为32KB+3page+0x6DD,看到了吗?这两个值在映射之后竟然为同一地址,而且这一地址都是在switchbank的开始8kb末端23字节处!这说明什么呢?而且,从上面代码看出,这23个字节存储的就是HalFlashWriteTrigger这个函数的实现代码,不信反汇编代码去看看,这个函数代码就是23个字节。那么在系统初始化flash的时候,0x39DEE映射到code空间,flash控制器将这23个字节的函数代码复制到sram(8KB)的末端23字节的地址处,这样当系统执行这个函数时,将这8KBsram映射到code空间的0x8000~0x8000+sram_size-1,cpu就在sram中执行这个函数,很显然,速度是超快的!那么正好这个函数要求不能被中断,那么它最好是越快越好!当然就把它放在sram中执行啦~flash驱动先分析到这!下章介绍flashwrite函数!今天来分析一下flash的write函数:voidHalFlashWrite(uint16addr,uint8*buf,uint16cnt){halDMADesc_t*ch=HAL_NV_DMA_GET_DESC();HAL_DMA_SET_SOURCE(ch,buf);HAL_DMA_SET_DEST(ch,&FWDATA);HAL_DMA_SET_VLEN(ch,HAL_DMA_VLEN_USE_LEN);HAL_DMA_SET_LEN(ch,(cnt*HAL_FLASH_WORD_SIZE));HAL_DMA_SET_WORD_SIZE(ch,HAL_DMA_WORDSIZE_BYTE);HAL_DMA_SET_TRIG_MODE(ch,HAL_DMA_TMODE_SINGLE);HAL_DMA_SET_TRIG_SRC(ch,HAL_DMA_TRIG_FLASH);HAL_DMA_SET_SRC_INC(ch,HAL_DMA_SRCINC_1);HAL_DMA_SET_DST_INC(ch,HAL_DMA_DSTINC_0);//TheDMAistobepolledandshallnotissueanIRQuponcom