Z-STACK之cc2530 flash驅動詳解上

       有一段時間沒有碰Z-STACK了,有點生疏,不過沒關係!我們繼續Z-STACK的驅動之旅!今天着重分析一下

z-stack的flash驅動。在分析flash驅動之前,需要熟讀cc2530的datasheet關於flash controller那一章節!

我們先從hal_flash.c文件中的HalFlashRead函數開始:

void HalFlashRead(uint8 pg, uint16 offset, uint8 *buf, uint16 cnt)
{
  // Calculate the offset into the containing flash bank as it gets mapped into XDATA.
  uint8 *ptr = (uint8 *)(offset + HAL_FLASH_PAGE_MAP) +
               ((pg % HAL_FLASH_PAGE_PER_BANK) * HAL_FLASH_PAGE_SIZE);
  uint8 memctr = MEMCTR;  // Save to restore.

#if !defined HAL_OAD_BOOT_CODE
  halIntState_t is;
#endif

  pg /= HAL_FLASH_PAGE_PER_BANK;  // Calculate the flash bank from the flash page.

#if !defined HAL_OAD_BOOT_CODE
  HAL_ENTER_CRITICAL_SECTION(is);
#endif

  // Calculate and map the containing flash bank into XDATA.
  MEMCTR = (MEMCTR & 0xF8) | pg;

  while (cnt--)
  {
    *buf++ = *ptr++;
  }

  MEMCTR = memctr;

#if !defined HAL_OAD_BOOT_CODE
  HAL_EXIT_CRITICAL_SECTION(is);
#endif
}

 在講解這個函數之前,先說一下z-stack中對flash的佈局。z-stack將256KBflash的最末八個字節作爲zigbee中的IEEE地址,當然在這八個字節之後還有16個字節lock bits,這些flash的lock所需要用的,每2kb(1page)的flash有1bit的lock位,那麼256kb的flash有128個2kb,當然也就有128(16X8)位的lock bits了。從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這個函數:

void HalFlashInit(void)
{
  // Load the code to run from RAM into its reserved area of RAM once at startup.
  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爲:

#pragma location="RAM_CODE_XDATA"
static __no_init uint8 ramCode[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字節呢?看到這個註釋,

Any code that will be run from RAM by setting XMAP of MEMCTL must have the same bank-relative
 address as the address in RAM to which the CODE will be copied to run.
 Thus, any part of the first 8k of any bank can be dedicated to code that will run from RAM as
long as the corresponding relative address range is reserved in RAM by RAM_CODE_XDATA.

 

這時候我們看到這幾句:

#pragma location="RAM_CODE_FLASH"
#if defined HAL_OAD_BOOT_CODE
static void HalFlashWriteTrigger(void);
#else
static __monitor void HalFlashWriteTrigger(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開始起的),那麼將其映射到code memory(64KB)中就是在32KB+3page+0x6DD處,記住code空間的第一個爲root bank,接着我們將

39EDD映射到code空間中,其bank爲7,其值爲115page+0x6DD(注意page也是從0開始的),16page爲1個bank,映射之後再code中的值爲32KB+3page+0x6DD,看到了嗎?

 

這兩個值在映射之後竟然爲同一地址,而且這一地址都是在switch bank的開始8kb末端23字節處!這說明什麼呢?

 

而且,從上面代碼看出,這23個字節存儲的就是HalFlashWriteTrigger這個函數的實現代碼,不信反彙編代碼去看看,這個函數代碼就是23個字節。

 

那麼在系統初始化flash的時候,0x39DEE映射到code空間,flash控制器將這23個字節的函數代碼複製到sram(8KB)的末端23字節的地址處,這樣當系統執行這個函數時,將這8KBsram映射到code空間的0x8000~

0x8000+sram_size-1,cpu就在sram中執行這個函數,很顯然,速度是超快的!那麼正好這個函數要求不能被中斷,那麼它最好是越快越好!當然就把它放在sram中執行啦~

 flash驅動先分析到這!下章介紹flash write函數!

 

 

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章