📄 rsvdflash.c
字号:
#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 + -