⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 rsvdflash.c

📁 通过建立逻辑映射表读写NAND_FLASH,可以延长NAND_FLASH的使用寿命,排除坏块的干扰!其中包括NAND_FLASH读写驱动以及逻辑映射表的建立!根据自己的要求修改读写驱动即可使用
💻 C
📖 第 1 页 / 共 2 页
字号:
#include "globe.h"

#define RSVED_SIZEOFWORD   (TOTAL_MASS_MEMORY_SIZE - MASS_MEMORY_SIZE)/(16*1024)	//保留的块总数,用于建立保留区域的逻辑映射表
#define STARTRSVEDSECTOR   FAT_SIZEOFWORD*32

										
extern NAND_Ret NAND_BlockErase(udword Blocknumber);
extern NAND_Ret NAND_PageRead(udword udAddress, dataWidth *Buffer, udword udlength);
extern WORD SectorNumToClusterNum(DWORD SectorNum);

extern WORD  SectorsPerCluster; 
extern WORD  BytesPerSector;

WORD   rsvedlgToph[RSVED_SIZEOFWORD];			//保留区域的逻辑映射表


#define VER_STRING "VER 1.3 By wf.shen "

 

//一个测试程序 
/*void Rsved_Nandflash_test(void)
{
	int	 i;
	BYTE temp[512];
	BYTE buff[]="wangxinjiangqin123456abcdefghijk";
   
	
	for(i=0; i<16; i++)
	{
		memcpy(&temp[i*32],buff,32);
	}
	
	while(1)
	{
	WriteRsvedLgSector(0,temp);	
	ReadRsvedLgSector(1,temp);
	ReadRsvedLgSector(0,temp);
	}	
}*/


/****************************** 函数 WORD RsvedGarbageProcess(void) *********************************/
/* 功能:	垃圾块处理,读取FLASH的保留部分,并判断是否有脏数据并且非坏块。如果满足这些条件则擦除该	*/
/*			块,同时返回该块号																		*/
/* 入口参数:无																						*/
/* 出口参数:如果找到并擦除了一个垃圾块,则返回该块号,否则返回0xffff								*/
/* 说明:	非用户使用函数																			*/
/****************************************************************************************************/
WORD RsvedGarbageProcess(void)
{
	BYTE tempSectorSpare[16];
	WORD i;
	
	for(i=FAT_SIZEOFWORD; i<(FAT_SIZEOFWORD+RSVED_SIZEOFWORD); i++)
	{
		NAND_SpareRead(i<<14, tempSectorSpare, 16);
		
		if((tempSectorSpare[2] == 0x0f) &&(tempSectorSpare[3] != 0)) 	//该块是脏数据
		{
			if(tempSectorSpare[5] == 0xff)								//该块非坏块
			{
				NAND_BlockErase(i);
				return i;
			}
		}
	}	
	return 0xffff;	
}



/*********************** 函数 WORD Find_RsvedBlankPhBlock(WORD startPhblock) ************************/
/* 功能:	 从输入的物理块号开始,寻找一个空块,找到之后返回新的物理块号							*/
/* 寻找策略:先从输入的块号开始向后找,如果直到最后没有空镞,再从保留区域头开始寻找					*/
/* 入口参数:开始搜寻的起始块号																		*/
/* 返回值:	 找到的空物理块号. 0xffff表示找不到空块,盘已满											*/
/* 说明:	 非用户使用函数																			*/
/****************************************************************************************************/
WORD Find_RsvedBlankPhBlock(WORD startPhblock)//OK
{
	WORD newblocknum,i;
	BYTE tempSectorSpare[16];
	BYTE full = 0xff;

	if(startPhblock < (FAT_SIZEOFWORD+RSVED_SIZEOFWORD-1))					//如果startPhblock==4095,则直接从前找
	{
		for(i=startPhblock; i<(FAT_SIZEOFWORD+RSVED_SIZEOFWORD); i++)		//先向后找 
		{	
			NAND_SpareRead(i<<14 | 2, &tempSectorSpare[2], 6);
			if((tempSectorSpare[5] == 0xff) && (tempSectorSpare[7] == 0xff) && (tempSectorSpare[2] == 0xff))		
			{	//该块非坏块并且为空
				newblocknum = i;
				full = 0;
				break;														//找到好块,退出该循环
			}
		}
	}
	if((startPhblock >= (FAT_SIZEOFWORD+RSVED_SIZEOFWORD-1)) || (full == 0xff))	//不能向后或向后没有找到新块,再从前找
	{
		for(i=FAT_SIZEOFWORD; i<startPhblock; i++)
		{
			NAND_SpareRead(i<<14 | 2, &tempSectorSpare[2], 6);
			if((tempSectorSpare[5] == 0xff) && (tempSectorSpare[7] == 0xff) && (tempSectorSpare[2] == 0xff))		
			{	//该块非坏块并且为空
				newblocknum = i;
				full = 0;
				break;														//找到好块,退出该循环
			}
		}
	}
	
	if(full == 0xff)														//FLASH满,没有空的块
	{	
			newblocknum = RsvedGarbageProcess( );							//清理一个垃圾块
			if(newblocknum != 0xffff)
			{	return 	 newblocknum;	}									//找到一个,返回
	}
	
	return 	 newblocknum;
}



/************************ BYTE* ReadLgSector(DWORD StartLgSector,BYTE* buffer) **********************/
/* 功能:根据输入的逻辑扇区号自动搜寻对应的物理扇区从NAND_FLASH中读出该扇区的数据到Buffer中			*/
/* 入口参数:DWORD StartLgSector----逻辑扇区号,整个保留区域单独编号								*/
/* 出口参数:BYTE* buffer----从逻辑扇区读出的数据存放缓冲区,512字节长								*/
/*			 返回Buffer中的值,同时更新NAND_operation_Returnvalue用来判断操作的结果是否正确			*/
/*			 如果读取发生错误,则返回NULL															*/
/* 说明:	 用户使用函数																			*/
/****************************************************************************************************/
extern char NAND_Operation_ReturnValue;

BYTE* ReadRsvedLgSector(DWORD RsvedLgSector,BYTE* buffer)//OK
{
	char temp;
	WORD lgBlocknum;
	DWORD phaddress;
	
	if(RsvedLgSector >= (RSVED_SIZEOFWORD<<5))
	{	return  NULL;	}
	
	lgBlocknum = SectorNumToClusterNum(RsvedLgSector);
	if(rsvedlgToph[lgBlocknum] == 0xFFFF)				//读取空的FLASH时逻辑映射表全空,则返回全0
	{
		memset(buffer,0,BytesPerSector);
		return buffer;
	}
	else
	{
		phaddress = rsvedlgToph[lgBlocknum]<<14 | (RsvedLgSector%SectorsPerCluster)<<9;
		temp = NAND_PageRead(phaddress, buffer, BytesPerSector);
		if(temp != NAND_PASS)
		{ 
			NAND_Operation_ReturnValue = NAND_FAIL;
			return NULL;
		}
		else
		{
			NAND_Operation_ReturnValue = NAND_PASS;
			return buffer;
		}
	}
}



/*************** 函数 NAND_Ret Process_RsvedSpare(DWORD LogicSectorNumber,BYTE* buffer) *************/
/* 功能:	 写入逻辑块号信息																		*/
/* 入口参数:DWORD LogicSectorNumber----准备写入的逻辑扇区号										*/
/*			 BYTE* buffer----即将生成ECC码的源数据缓冲区,512字节长									*/
/* 返回值:  NAND_PASS----成功;NAND_FAIL----表示逻辑号操作错误										*/
/* 注意:    此函数仅被Process_RsvedPageErrorOrFull和WriteRsvedLgSector函数调用						*/
/* 说明:    非用户使用函数																			*/
/****************************************************************************************************/
NAND_Ret Process_RsvedSpare(DWORD LogicSectorNumber,BYTE* buffer)//OK
{
	WORD LogicBlocknum;
	BYTE pageoffsetnum;
	WORD phblocknum;
	DWORD phaddress ;
	BYTE tempSectorSpare[16];
	//BYTE *ptemp;
	
	LogicBlocknum = SectorNumToClusterNum(LogicSectorNumber);
	pageoffsetnum = LogicSectorNumber % SectorsPerCluster;
	phblocknum = rsvedlgToph[LogicBlocknum];
	phaddress = (phblocknum<<14) | (pageoffsetnum<<9);
	
	tempSectorSpare[6]  = LogicBlocknum & 0xff;					//写入该块的逻辑号
	tempSectorSpare[7]  = LogicBlocknum>>8; 
	tempSectorSpare[11] = tempSectorSpare[6];
	tempSectorSpare[12] = tempSectorSpare[7];
	NAND_SpareProgram(phaddress+6, &tempSectorSpare[6], 7);		//在FLASH中将该块冗余信息写入
	
	return NAND_PASS;
}



/*********** 函数 WORD Process_PageErrorOrFull(DWORD LogicSectorNumber,BYTE* buffer) ****************/
/* 功能:在写页时该页非空或出错时进行处理,具体过程是寻找一个空物理块,将对应新页以前的旧块中的扇	*/
/*		区内容拷贝到新块中,再将新的数据写到入口扇区中,同时将旧块擦除。另外更改逻辑映射表			*/
/* 入口参数:DWORD LogicSectorNumber-----准备写入的逻辑扇区号										*/
/*			 BYTE* buffer----准备写到逻辑扇区的数据缓冲区,512字节长								*/
/* 返回值:	找到的空物理块号. 0xffff表示找不到空块,盘已满											*/
/* 注意:	此函数仅被WriteLgSector函数调用															*/
/* 说明:	非用户使用函数																			*/
/****************************************************************************************************/
WORD Process_RsvedPageErrorOrFull(DWORD LogicSectorNumber,BYTE* buffer)//OK
{
	WORD newphblocknum,oldphblocknum,i,j;
	WORD LogicBlocknum;
	BYTE pageoffsetnum;
	DWORD phaddress;
	BYTE tempsectorbuffer[512];
	BYTE tempSectorSpare[16];

	
	NAND_Ret Return_value,fail;
	
	
	LogicBlocknum = SectorNumToClusterNum(LogicSectorNumber);
	pageoffsetnum = LogicSectorNumber % SectorsPerCluster;
	oldphblocknum = rsvedlgToph[LogicBlocknum];
	do
	{
		//寻找一个空块,逻辑地址对应的块号即为实际物理位置
		newphblocknum = Find_RsvedBlankPhBlock(oldphblocknum+1);
		
		if(newphblocknum != 0xffff)											//找到了空块,改变逻辑映射表
		{
			rsvedlgToph[LogicBlocknum] = newphblocknum;
			phaddress = (newphblocknum<<14) | (pageoffsetnum<<9);			//求新块中对应于旧块原偏移扇区的位置
		}
		else
		{	return 0xffff;	}												//FLASH满,无法找到空块写入扇区

		
		//此时更新了块,需要把旧块中其他扇区的内容复制到新块中对应的扇区中
		for(j=1; j<4; j++)													//连续写三次,不成功则表明该块确实坏
		{
			fail = NAND_PASS;
			
			tempSectorSpare[2] = 0x0f;
			Return_value = NAND_SpareProgram((newphblocknum<<14)|2, &tempSectorSpare[2], 1);//在FLASH中将该新块0扇区的数据起始标记写入
			if(Return_value != NAND_PASS)
			{	fail = NAND_FAIL;	}
			
			for(i=1; i<SectorsPerCluster; i++)
			{
				
				if(i!=pageoffsetnum)
				{
					//首先判断该页是否为空
					NAND_SpareRead((oldphblocknum<<14)|(i<<9), tempSectorSpare, 16);
					if(tempSectorSpare[2] != 0xff) 							//该页非空
					{
						NAND_PageRead((oldphblocknum<<14)|(i<<9), tempsectorbuffer, BytesPerSector);
						Return_value = NAND_PageProgram((newphblocknum<<14)|(i<<9), tempsectorbuffer, BytesPerSector);
						NAND_SpareProgram((newphblocknum<<14)|(i<<9), tempSectorSpare, 16);
							
						//Return_value = NAND_CopyBack((oldphblocknum<<14)|(i<<9), (newphblocknum<<14)|(i<<9));//该函数有问题
						if(Return_value != NAND_PASS)
						{	fail = NAND_FAIL;	}
					}
				}
			}
			
			//开始向准备写入的扇区写新的数据
			if(pageoffsetnum != 0)
			{
				tempSectorSpare[2] = 0x0f;
				NAND_SpareProgram(phaddress + 2, &tempSectorSpare[2], 1);						//在FLASH中将该新扇区的数据起始标记写入
				if(Return_value != NAND_PASS)
				{	fail = NAND_FAIL;	}
			}
			Return_value = NAND_PageProgram(phaddress, buffer, BytesPerSector);
			if(Return_value != NAND_PASS)

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -