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