CC2530學習筆記2——Flash讀寫程式設計
在做CC2530 Flash讀寫時,對該晶片的Flash儲存器典型操作進行了一些學習,總結在這裡。理解不當甚至錯誤之處,請高手賜教,謝謝。
CC2530的Flash按頁組織,每頁2048位元組。與其它Flash儲存器一樣,被擦除為1,被寫為 0。另外,在後面與邏輯空間對映時,還有個BANK的概念,是32KB。
對Flash儲存器有3種操作,簡介如下:
擦除:最小單元是頁,即2048位元組;
寫入:最小單元是32位字,即4位元組,這也是後面的程式碼中寫入地址必須為4的倍數的原因;
讀取:資料手冊中說,當被CPU訪問讀取程式碼或資料時,是位元組可定址。當被Flash控制器訪問時,是字可定址,其中一個字由32位組成。我們要做的從Flash讀取資料是前一種情況,可位元組定址,也就是可以逐位元組讀取。後一種情況我還沒用過。(⊙o⊙)…
三種操作的程式碼如下。
一、 擦除
擦除沒啥好說的,這是寫入之前必須進行的操作。在資料手冊中描述的比較詳細,也有程式碼,直接用即可。
/************************************************************************************************** * @fn FLASH_PageErase * * @brief This function erases flash page of the 'pageNum'th page. * * input parameters * * @param pageNum - Valid flash page num. * * output parameters * * None. * * @return None. ************************************************************************************************** */ void FLASH_PageErase(uint8_t pageNum) { EA=0; while(FCTL & 0x80);//等待快閃記憶體控制器整備好 FADDRH = pageNum << 1;//選擇擦除頁面的序號,共128頁 FCTL |= 0x01;//啟動頁面擦除 while(FCTL & 0x80);//等待擦除完成 EA=1; }
二、 寫入
資料手冊對寫入描述的也比較詳細。其中有一點比較重要,手冊中說Flash寫操作正在進行的時候,CPU不能訪問快閃記憶體,即讀取程式程式碼。也就是說如果直接寫Flash,程式就沒法執行了。所以,提供了兩種寫入方式:使用DMA傳輸(首選方法),或者使用CPU執行來自SRAM的程式碼。我選擇推薦的DMA方法。所以,在真正寫入之前要初始化DMA控制器,詳見程式碼。
/************************************************************************************************** * @fn FLASH_Write * * @brief This function writes 'num_bytes' bytes to the uint16_ternal flash. * * input parameters * * @param addr - Valid flash write address: actual addr / 4 and quad-aligned. * @param data - Valid buffer space at least as big as 'cnt' X 4. * @param num_bytes - Number of bytes to write, MUST be Divisible by 4. * * output parameters * * None. * * @return None. ************************************************************************************************** */ void FLASH_Write(uint16_t addr,uint8_t *data, uint16_t num_bytes) { //配置DMA通道每次傳送一個位元組 DMADesc_t dmaConfig0;//定義DMA通道 dmaConfig0.SRCADDRH = ((uint16_t)data >> 8) & 0x00FF; //XData - To Be Written to Flash - Gets Incremented;儲存data的高8位; dmaConfig0.SRCADDRL = (uint16_t)data & 0x00FF;//儲存data地址的低8位; dmaConfig0.DESTADDRH = (((uint16_t)&FWDATA) >> 8) & 0x00FF; //Flash Controller Data Address - Flash Controller Writes Data//儲存寫暫存器的地址的高8位 dmaConfig0.DESTADDRL = ((uint16_t)&FWDATA) & 0x00FF;//儲存寫暫存器的低8位; dmaConfig0.VLEN = 0; //Variable num_bytes Transfer - 0=Fixed LEN Transfer//採用LEN作為傳送長度 dmaConfig0.LENH = (num_bytes>>8) & 0x00FF; //Number of WORDSZIE in Transfer - Must be Divisible by 4 - NET_ADDR_SIZE=4//儲存傳送長度高5位 dmaConfig0.LENL = num_bytes & 0x00FF;//儲存長度低8位; dmaConfig0.WORDSIZE = 0; //Size of Each Transfer - 0=8 Bit;每個DMA傳送採用8位傳送 dmaConfig0.TMODE = 0; //Transfer Mode - 1=Block, 0=Single,傳送模式為單一模式 dmaConfig0.TRIG = 18; //DMA Trigger - 0=Manual Via DMAREQ, 18=Flash;flash觸發 dmaConfig0.SRCINC = 1; //Source Address Increment - 1=1 Byte//源地址增量模式為1位元組/字 dmaConfig0.DESTINC = 0; //Destination Address Increment - 0=0 Bytes (Always Write to FWDATA, No Need to Increment)目標地址增量模式0位元組/字 dmaConfig0.IRQMASK = 0; //uint16_terrupt Mask - 0=Disable uint16_terrupts//禁止通道完成中斷產生 dmaConfig0.M8 = 0; //8th Bit Mode - 0=Use All 8 Bits使用全部8位作為傳送長度 dmaConfig0.PRIORITY = 2; //Priority - 10(2)=High Priority優先順序為DMA優先 //DMA模式寫 while (FCTL & 0x80); //Wait Until DMA Controller is Available - Busy Bit 7//等待寫或擦除狀態被啟用 /********* 儲存寫入flash頁地址 ***********************************************/ FADDRH =(addr >> 10) & 0x00FF; // page size: 2048; select the flash page via FADDRH[7:1] bits//由於寫入flash時是字(4位元組)定址的,所以儲存高位需要右移2位; FADDRL =(addr >> 2) & 0x00FF; //4位元組定址,儲存要寫入flash地址的低位元組需要右移2位 //通道0配置地址 DMA0CFGH = (((uint16_t)&dmaConfig0) >> 8) & 0x00FF; //Pass DmaConfig0 DMA0CFGL = ((uint16_t)&dmaConfig0) & 0x00FF; DMAARM |= 0x01; //Arm the DMA Channel//通道0進去工作狀態 FCTL |= 0x02; //Start Write //while (!(DMAIRQ & 0x01)); //Wait Until Write Complete //DMAIRQ &= 0xFE; //Clear Any DMA IRQ on Channel 0 - Bit 0 while (FCTL & (0x80)); //Wait Until Flash Controller is Not Busy - Busy Bit 7//等待或者擦除狀態啟用 return; }
三、 讀取
這個比較關鍵,資料手冊裡寫的不是很詳細,我在這裡也費了些功夫。需要結合第2章和第6章一起理解。
首先,在CC2530中有CODE、DATA、XDATA、SFR等邏輯儲存空間,參考這個部落格,不同儲存空間的特性總結如下:
1. CODE :程式儲存器, 用處存放程式程式碼和一些常量
有16根地址匯流排,所以CODE的定址範圍是 0000H~FFFFH 共64KB
2. DATA 資料儲存器,用於存放程式執行過程中的資料
有8根地址匯流排,所以DATA的定址空間為 00H~FFH 共256 byte.低128位可以直接定址,高128位只能間接定址。
3. XDATA 外部資料儲存器(只能間接定址,訪問速度比較慢) DMA是在XDATA上定址的,這一點很重要
有16根地址匯流排,所以 XDATA 的定址空間為 0000H ~ FFFFH 共64K
4. SFR 特殊功能暫存器 就是那些T1CTL, EA, P0 等配置暫存器儲存的地方 共128K。因為CC2530的配置暫存器比較多,所以一些多餘的暫存器就放到了XREG 裡面。XREG的大小為1K XREG的訪問速度比 SFR慢。
這些儲存空間實際是儲存在3個物理儲存器(Flash程式儲存器、SRAM和儲存對映儲存器)中的。這裡很明顯有個問題,CODE定址範圍只有64KB,但CC2530的Flash最大卻有256KB。那怎麼保證Flash的空間都能被定址呢?
所以,晶片搞了個對映機制,CODE空間的對映如下:
也就是說,CODE空間中前32KB是固定的,而後32KB是可設定的(從Flash的BANK0~BANK7),具體配置為哪個Flash,可通過暫存器FMAP設定。
類似地,XDATA的儲存空間如下:
由於XDATA是可以讀/寫的資料儲存空間,而它的XBANK區域(0x8000~0xFFFF範圍)可由暫存器MEMCTR設定為Flash的任一BANK。因此,可以通過設定MEMCTR選擇需要讀取的BANK,然後從XDATA資料儲存器中讀取出來。讀取部分程式碼如下。若想檢視讀取時儲存器中的值,可以在MEMCTR = old_map;語句處打斷點,按照XDATA的儲存空間對映,計算得出儲存器在XDATA空間中的實際地址(即offset的值),檢視即可。
/**************************************************************************************************
* @fn FLASH_Read
*
* @brief This function reads 'num_bytes' bytes from flash address addr to array data.
*
* input parameters
*
* @param addr - Valid flash read address: .
* @param data - Valid buffer space to store the data.
* @param num_bytes - Number of bytes to read.
*
* output parameters
*
* None.
*
* @return None.
**************************************************************************************************
*/
void FLASH_Read(uint16_t addr,uint8_t* data,uint8_t num_bytes)
{
uint8_t old_map;
uint8_t bank_num;
uint16_t offset;
uint8_t old_ea;
old_ea = EA;
EA = 0; // close global interrupt
bank_num = (addr>>FLASH_BANK_SHIFT)&FLASH_BANK_MAP_MASK;
offset = (addr & (FLASH_BANK_SIZE-1))+FLASH_BASE_ADDR;
old_map = MEMCTR;
MEMCTR = (old_map&~0X7)|bank_num; //map the correct flash bank to XBANK
memcpy(data,(uint8_t*)offset,num_bytes);
MEMCTR = old_map;
EA = old_ea;
return;
}
完整的IAR工程可以在如下連結下載:https://download.csdn.net/download/hnxyxiaomeng/10643545