1. 程式人生 > >關於Flash的學習(第二步,操作Flash時,為了延長Flash壽命的操作方法)

關於Flash的學習(第二步,操作Flash時,為了延長Flash壽命的操作方法)

承蒙專案和同事的要求,因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);