關於Flash的學習(第二步,操作Flash時,為了延長Flash壽命的操作方法)
阿新 • • 發佈:2018-12-21
承蒙專案和同事的要求,因Flash擦除、寫入太過於頻繁,所以需要更換Flash地址寫資料。
背景簡介:嵌入式開發,需要關機儲存資料,C語言寫。用512K Byte Flash。
程式碼簡介:用容量512k Byte的Flash,在0x20000 Byte起始的地址,在0x20000~0x3FFFF之間進行迴圈儲存資料。因Flash每次擦除最小單位為4K Byte的扇區,所以在0x20000~0x3FFFF之間一個週期總共能儲存32次。
儲存資料原理簡介:每個扇區的第一個32位資料,儲存資料有效標誌位(比如我寫入1),第二個32位,儲存我想要儲存的資料。迴圈讀取32個扇區的第一個32位,查詢時如果不是0xFFFFFFFF,則認為此段扇區已經寫入,則進行擦除此段,進而在下一段扇區寫入資料。
讀取資料原理簡介:迴圈讀取32個扇區的第一個32位,查詢時如果不是0xFFFFFFFF,則認為此段扇區中是有效資料,進行讀取。(當然讀取時防止出錯,加上出錯時返回預設值)
本人寫尚處於學習進步階段,寫此部落格記錄所學。且尚有很多不足,往多多指教。歡迎新增QQ進一步學習探討1742037504.
#define POWEROFF_SAVE_ADDR 0x10020000 #define POWEROFF_SAVE_LENGTH 0x20000 void flashOperation( UINT32 erushAddress , UINT32 erushNumber, UINT32 * writeData) { //儲存相關引數 UINT32 argv[5]; UINT32 saveData[2]; //儲存資料僅2個 saveData[0] = 1; //第一個資料位有效位標誌 saveData[1] = * writeData; //第二個資料位儲存的資料 argv[0] = 0; argv[1] = 0; argv[2] = erushAddress&0x0FFFFFFF; argv[3] = erushNumber*4; //Erasure POWEROFF_SAVE_NUMBER Bit32 data,so Mul 4. FTSPI020_xip_port_sel(0); //cmd port SpiFlashErase(4, argv); //如果擦除失敗,重新進行擦除 erushAddress += 4096;//擦除上一個扇區,給下一個扇區寫入。相隔一個扇區(4KByte) if( erushAddress >= (POWEROFF_SAVE_ADDR + POWEROFF_SAVE_LENGTH)) {//如果儲存資料地址已經到末尾,則迴圈至開頭。進行寫操作 erushAddress = POWEROFF_SAVE_ADDR; } argv[0] = 0; argv[1] = 0; argv[2] = erushAddress&0x0FFFFFFF; argv[3] = erushNumber*4; //Save POWEROFF_SAVE_NUMBER Bit32 data,so Mul 4. argv[4] = (UINT32)&saveData[0]; SpiFlashWrite(5, argv); FTSPI020_xip_port_sel(1); //cmd port } UINT8 SaveEffModeProcess(UINT32* address, UINT32* data, UINT32 saveDataNumber)//比如,0x10020000,32,data { UINT32 availFlag; UINT8 i; UINT8 saveCheckLoopNum = (POWEROFF_SAVE_LENGTH/4096); //長度除以4KByte UINT32 curDataNumber = (saveDataNumber + 1); //因還有第一個標誌資料,所以長度+1; for( i = 0; i < saveCheckLoopNum ; i++ ) {//迴圈檢檢視哪個地址有儲存過資料 availFlag = *address; if( availFlag != 0xFFFFFFFF ) {//找到已經寫過的地址,進行擦除當前資料,寫入儲存資料操作 flashOperation((UINT32)address , curDataNumber, data); return 1; } address += (4096>>2);//因此資料為32位,所以所加資料要除以4 } //在儲存範圍內未檢查到有儲存資料記錄,則進行對起始空間進行儲存操作 address = (UINT32*)POWEROFF_SAVE_ADDR; flashOperation((UINT32)address , curDataNumber, data); return 0; } UINT8 ReadEffModeProcess(UINT32* address ) { UINT32 availFlag; UINT8 readEffMode; UINT8 i; UINT8 saveCheckLoopNum = (POWEROFF_SAVE_LENGTH/4096); //長度除以4KByte for( i = 0; i < saveCheckLoopNum ; i++ ) {//迴圈檢檢視哪個地址有儲存過資料 availFlag = *address; if( availFlag != 0xFFFFFFFF ) {//找到已經寫過的地址,讀取資料 readEffMode = *(address+1);//因第一個是儲存資料標誌位,第二個資料是儲存的有效值 if( readEffMode > 2)//防止讀到的資料出錯,出錯時置為預設值 { readEffMode = 0;//這裡我預設值為0 } return readEffMode; } address += (4096>>2);//因此資料為32位,所以所加資料要除以4 } //在儲存範圍內未檢查到有儲存資料記錄,則返回預設值 readEffMode = 0; //這裡我預設值為0 return readEffMode; } //呼叫讀取函式入口 eqModeNum = ReadEffModeProcess((UINT32*)POWEROFF_SAVE_ADDR); //呼叫寫入入口 address = (UINT32*) POWEROFF_SAVE_ADDR; SaveData = (UINT32)eqModeNum; saveDataNumber = 1; SaveEffModeProcess(address, (UINT32*)&SaveData, saveDataNumber);