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

📄 rsvdflash.c

📁 通过建立逻辑映射表读写NAND_FLASH,可以延长NAND_FLASH的使用寿命,排除坏块的干扰!其中包括NAND_FLASH读写驱动以及逻辑映射表的建立!根据自己的要求修改读写驱动即可使用
💻 C
📖 第 1 页 / 共 2 页
字号:
			{	fail = NAND_FAIL;	}
			
			Return_value = Process_RsvedSpare(LogicSectorNumber,buffer);						//生成并写入ECC码和逻辑块号信息
			if(Return_value != NAND_PASS)
			{	fail = NAND_FAIL;	}
			
			
			tempSectorSpare[3] = 0x00;
			Return_value = NAND_SpareProgram(phaddress + 3, &tempSectorSpare[3], 1);			//在FLASH中将该新扇区的数据结束标记写入
			if(Return_value != NAND_PASS)
			{	fail = NAND_FAIL;	}
			
			//开始拷贝块内0扇区的数据
			if(pageoffsetnum != 0)
			{
				NAND_PageRead(oldphblocknum<<14, tempsectorbuffer, BytesPerSector);
				NAND_SpareRead(oldphblocknum<<14, tempSectorSpare, 16);
			
				Return_value = NAND_PageProgram(newphblocknum<<14, tempsectorbuffer, BytesPerSector);
				if(Return_value != NAND_PASS)
				{	fail = NAND_FAIL;	}
				
				
				Return_value = NAND_SpareProgram((newphblocknum<<14)|6, &tempSectorSpare[6], 10);//在FLASH中将该新块的0扇区的其他信息写入
				if(Return_value != NAND_PASS)
				{	fail = NAND_FAIL;	}
				
				tempSectorSpare[3] = 0x00;
				Return_value = NAND_SpareProgram((newphblocknum<<14)|3, &tempSectorSpare[3], 1);//在FLASH中将该新块0扇区的数据结束标记写入
				if(Return_value != NAND_PASS)
				{	fail = NAND_FAIL;	}
			}	
			
			if(fail == NAND_FAIL)
			{	NAND_BlockErase(newphblocknum);	}
			else
			{	break;	}
		}
	
		if(fail == NAND_FAIL)													//连续三次写入失败,表明该新块是坏块
		{	
			tempSectorSpare[5] = 0;
			NAND_SpareProgram((newphblocknum<<14)|5, &tempSectorSpare[5], 1);	//在FLASH中将该块的坏块标记信息写入
		}
	}while(fail == NAND_FAIL);

	//以上拷贝成功完成,返回新找到的物理块号
	
	NAND_BlockErase(oldphblocknum);												//在FLASH中将旧块擦除
				
	return newphblocknum;
}



/****************** 函数 WORD WriteLgSector(DWORD RsvedLgSector,BYTE* buffer) ***********************/
/* 功能:将Buffer中的数据写入由逻辑扇区号确定的页中,该页的实际物理地址在该函数内自动计算;			*/
/*       在写入时如果发现某一扇区损坏该函数将自动寻找一个空块写入,同时将原块中的数据拷贝到新块中。 */
/*		 并将旧块擦除;找到新块后逻辑映射表将被更改。无论是否改变物理块,该块中该扇区的C区中都将写入*/
/*		 逻辑块号																					*/
/* 注意:调用此函数前Buffer中要事先存放要写入的数据													*/
/* 入口参数:DWORD RsvedLgSector----逻辑扇区号,FLASH的保留区域单独编号编号,逻辑扇区与逻辑块对应	*/
/*			 BYTE* buffer----准备写到逻辑扇区的数据缓冲区,512字节长								*/
/* 返回值:写入的物理块号; 0xffff表示找不到空块,盘已满; 											*/
/* 说明:  用户使用函数																				*/
/****************************************************************************************************/
WORD WriteRsvedLgSector(DWORD RsvedLgSector,BYTE* buffer)//OK
{
	WORD oldphblocknum,newphblocknum;
	WORD LogicBlocknum;
	DWORD phaddress;
	BYTE tempSectorSpare[16];
	BYTE pageoffsetnum;
	NAND_Ret Return_value;
	
	if(RsvedLgSector >= (RSVED_SIZEOFWORD<<5))
	{	return  NULL;	}
	
	
	LogicBlocknum = SectorNumToClusterNum(RsvedLgSector);
	pageoffsetnum = RsvedLgSector % SectorsPerCluster;
	
	oldphblocknum = rsvedlgToph[LogicBlocknum];
	if(oldphblocknum == 0xffff)													
	{	
		oldphblocknum = Find_RsvedBlankPhBlock(FAT_SIZEOFWORD);
		if(oldphblocknum == 0xffff)
		{	return  NULL;	}
		
		rsvedlgToph[LogicBlocknum] = oldphblocknum;	
	}
	
	phaddress = (oldphblocknum<<14) | (pageoffsetnum<<9);						//求新块中对应于旧块原偏移扇区的位置
	
	//首先判断该页是否为空
	NAND_SpareRead(phaddress+2, &tempSectorSpare[2], 1);
	
	if(tempSectorSpare[2] != 0xff)												//该页非空
	{
		newphblocknum = Process_RsvedPageErrorOrFull(RsvedLgSector,buffer);	
		return newphblocknum;
	}
	else																		//该页空
	{
		tempSectorSpare[2] = 0x0f;
		NAND_SpareProgram(phaddress + 2, &tempSectorSpare[2], 1);				//在FLASH中将该新扇区的数据起始标记写入
		Return_value = NAND_PageProgram(phaddress, buffer, BytesPerSector);
				
		if( Return_value == NAND_FAIL)
		{	
			newphblocknum = Process_RsvedPageErrorOrFull(RsvedLgSector,buffer);	
			if(newphblocknum == 0xffff)
			{	return 0xffff;	}
			else
			{	return newphblocknum;	}
		}
		else
		{
			Process_RsvedSpare(RsvedLgSector,buffer);								//写入逻辑号和ECC码
			tempSectorSpare[3] = 0x00;
			Return_value = NAND_SpareProgram(phaddress + 3, &tempSectorSpare[3], 1);//在FLASH中将该新扇区的数据结束标记写入
			
			return oldphblocknum;
		}
	}
}




/********************************* 函数 int Gen_rsvedlgToph(void) ***********************************/
/* 功能:	依次读取FLASH保留区域的每个块,建立逻辑地址到物理地址的映射表rsvedlgToph[],该表中如果数*/
/*			据为0xFFFF说明未对应物理地址,即该逻辑地址未使用										*/
/* 入口参数:无																						*/
/* 出口参数:返回-1,则说明逻辑地址有误;否则返回已经编号的块的总数									*/
/* 说明:	用户使用函数																			*/
/****************************************************************************************************/
int Gen_rsvedlgToph(void)//OK
{
	DWORD blocknumber;
	DWORD logic_number,logic_no;
	BYTE  tempSectorSpare[16];
	
	logic_number = 0;
	
	for(logic_no=0; logic_no<RSVED_SIZEOFWORD; logic_no++)							//初始化逻辑映射表为0xFFFF
	{
		rsvedlgToph[logic_no] = 0xffff;
	}
	
	for(blocknumber=FAT_SIZEOFWORD; blocknumber<(FAT_SIZEOFWORD+RSVED_SIZEOFWORD); blocknumber++)
	{
		NAND_SpareRead(blocknumber<<14, tempSectorSpare, 16);
		
		if((tempSectorSpare[5] == 0xff) && (tempSectorSpare[4] == 0xff) &&(tempSectorSpare[3] == 0x00))	//该块非坏块并且没有被废弃,也不是脏数据
		{
			if(tempSectorSpare[7]!= 0xff)											//逻辑地址非空,说明该块已经使用
			{																		
				if((tempSectorSpare[6]!= tempSectorSpare[11]) || (tempSectorSpare[7]!= tempSectorSpare[12]))
				{	return -1;	}													//两个逻辑地址不同,返回出错信息
				else																//两个逻辑地址相同,建立映射表
				{
					logic_no = ((tempSectorSpare[7] & 0x0f) <<8) | tempSectorSpare[6];//计算逻辑地址
					rsvedlgToph[logic_no] = blocknumber;
					logic_number++;													//计算已经编号的块的总数
				}
			}
		}
	}
	return logic_number;
}


// Format Reserved Nand Flash;			
void Format_ResvedNandFlash(void)
{
	u32 logic_no,blocknumber;
	u8 tempSectorSpare[16];
	u8 tempReservedBuff[512];
	
//	MyDebugOut("format resv flash");

	//首先对所有块进行擦除
	for(blocknumber=FAT_SIZEOFWORD; blocknumber<(FAT_SIZEOFWORD+RSVED_SIZEOFWORD); blocknumber++)
    {
		//在擦除块之前先检查坏块标志,如果是坏块则不做擦除
		NAND_SpareRead((blocknumber<<14)|5, &tempSectorSpare[5], 1);
		if(tempSectorSpare[5] == 0xff)							//该块非坏块
		{
			if(NAND_BlockErase(blocknumber) == NAND_FAIL)
			{
				//Uart_Printf("\nErase Nand-flash failed!%d block,it can be omitted.",i);
				if((NAND_BlockErase(blocknumber) == NAND_FAIL))
				{
					tempSectorSpare[5] = 0;						//如果两次擦除均失败则做坏块标记
					NAND_SpareProgram((blocknumber<<14)|5, &tempSectorSpare[5], 1);
				}
			}
    	}
    }
 
	for(logic_no=0; logic_no<RSVED_SIZEOFWORD; logic_no++)							//初始化逻辑映射表为0xFFFF
	{
		rsvedlgToph[logic_no] = 0xffff;
	}
	
	memcpy(tempReservedBuff,VER_STRING,sizeof(VER_STRING) );
	WriteRsvedLgSector(0,tempReservedBuff);
}

////////////////////////////////////////////////////////////////////////////////////
// 判断当前的nand flash 是否格式化过;
// 格式化过的nand flash 中会写入当前软件版本号,以下程序判断里面的软件版本号是否真确;
////////////////////////////////////////////////////////////////////////////////////
u8 IsReservedFlashOk(void)
{
	u8 tempReservedBuff[512];

//	MyDebugOut("test flash");
		
	ReadRsvedLgSector(0,tempReservedBuff);
	
	if( memcmp(tempReservedBuff,VER_STRING,sizeof(VER_STRING)) == 0 ) return 1;
	else return 0;
}


/*************************************************************************************************/
/* 功能:根据输入的逻辑扇区号自动搜寻对应的物理扇区从NAND_FLASH中读出该扇区内offsetinsector地址*/
/*       开始的bytes个数据到Buffer中			                                                     */
/* 入口参数:DWORD StartLgSector----逻辑扇区号,整个保留区域单独编号								           */
/* 出口参数:BYTE* buffer----从逻辑扇区读出的数据存放缓冲区,bytes字节长								          */
/*			     如果读取发生错误,则返回NULL															                          */
/* 说明:	 用户使用函数																			                                    */
/****************************************************************************************************/
BYTE* ReadRsvedLgSectorBytes(DWORD RsvedLgSector,BYTE* buffer,WORD offsetinsector,WORD bytes)//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,bytes);
		return buffer;
	}
	else
	{
		if(offsetinsector+bytes>BytesPerSector)
			{
			 bytes=BytesPerSector-offsetinsector;	
			 if(bytes==0)
			 	{
			 	 return NULL;
			 	}	
			}
		
		phaddress = rsvedlgToph[lgBlocknum]<<14 | (RsvedLgSector%SectorsPerCluster)<<9| offsetinsector;
		temp = NAND_PageRead(phaddress, buffer, bytes);
		if(temp != NAND_PASS)
		{ 
			NAND_Operation_ReturnValue = NAND_FAIL;
			return NULL;
		}
		else
		{
			NAND_Operation_ReturnValue = NAND_PASS;
			return buffer;
		}
	}
	
}


⌨️ 快捷键说明

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