📄 fat12.c
字号:
/*******************************************************************************
* 修改时间: 2007/09/11 14:19 by shenwf
* 修改原因: 修改 AllocDir 中,申请新的一个组的数据后,没有清零剩余数据的问题.
*******************************************************************************/
#include "globe.h"
//unsigned char mybuf[512];
//请注意每个扇区实际为528个字节,最后还有16个字节
//BYTE SectorSpare[16]; //Nandflash的备用区,防止sectorbuffer与clusterbuffer冲突
WORD lgToph[FAT_SIZEOFWORD]; //逻辑地址到物理地址的映射表,含义是lgToph[逻辑地址] = 物理地址
_FILE files[16];
void fat_datetime(FatDateTime *fatdatetime);
WORD WriteLgSector(DWORD LogicSectorNumber,BYTE* buffer);
WORD Find_BlankPhBlock(WORD startPhblock);
BYTE* ECC_Generate(BYTE* buffer256);
WORD Process_PageErrorOrFull(DWORD LogicSectorNumber,BYTE* buffer);
NAND_Ret Process_Spare(DWORD LogicSectorNumber,BYTE* buffer);
WORD FirstDataSector;
WORD FATsectors;
WORD FirstFATSector;
DWORD RootDirSectors; // Numbers of sectors occupied by Root Directory.
DWORD RootDirCount;
WORD SectorsPerCluster;
WORD BytesPerSector;
WORD FirstDirSector; //第一个根目录扇区(应该是33)
const char VolLab[12]="GoodWill ";
//以下变量暂时赋值,这些变量需要由系统的实时时钟给出
/*
WORD RTCYear = 2006;
BYTE RTCMonth = 7;
WORD RTCDay = 18;
BYTE RTCDate = 2;
BYTE RTCHour = 19;
BYTE RTCMinute = 04;
BYTE RTCSecond = 0;*/
WORD GarbageSearchNumber = 0;
/*** 函数 int fat_format(unsigned char Media,unsigned char Sizeofdisk_M,unsigned char FilesysType) ***/
/* 功能:磁盘格式化 */
/* 入口参数:unsigned char Media----取NAND_FLASH_Drv,介质类型,可移动磁盘 */
/* unsigned char Sizeofdisk_M----取DISK_48M,即48 */
/* unsigned char FilesysType ----取PART_TYPE_FAT12 */
/* 返回参数:1----格式化成功;0xffff------格式化失败 */
/* 说明: 用户使用函数 */
/*****************************************************************************************************/
int fat_format(unsigned char Media,unsigned char Sizeofdisk_M,unsigned char FilesysType)//OK
{
DWORD i,fatsec;
BOOTSECTOR50 *bootsector;
BPB50 *bpb;
EXTBOOT *ext;
DIRENTRY *dir;
FatDateTime datatime;
BYTE tempbuffer[512];
BYTE tempSectorSpare[16];
const char OEMname[9]="MSDOS5.0";
const char *fat16_str="FAT12 ";
SectorsPerCluster = 32; //每cluster的sector数目32
BytesPerSector = 512; //每sector的字节数512
FirstFATSector = 1; //FAT区的起始地址1
FATsectors = (Sizeofdisk_M*3)/16; //每个FAT表的扇区数9,FAT12的每个表项占12位,9个扇区容量对应3072个簇
FirstDirSector = FirstFATSector + FATsectors*2;//第一个根目录扇区19
FirstDataSector = 64; //第一个数据扇区64
RootDirSectors = FirstDataSector - FirstDirSector; //根目录区所占用的扇区数 = 45
RootDirCount = (RootDirSectors * BytesPerSector)/sizeof(DIRENTRY);//根目录项总数720
//首先对所有块进行擦除
for(i=0;i<FAT_SIZEOFWORD;i++)
{
//在擦除块之前先检查坏块标志,如果是坏块则不做擦除
NAND_SpareRead((i<<14)|5, &tempSectorSpare[5], 1);
if(tempSectorSpare[5] == 0xff) //该块非坏块
{
if(NAND_BlockErase(i) == NAND_FAIL)
{
//Uart_Printf("\nErase Nand-flash failed!%d block,it can be omitted.",i);
if((NAND_BlockErase(i) == NAND_FAIL))
{
tempSectorSpare[5] = 0; //如果两次擦除均失败则做坏块标记
NAND_SpareProgram((i<<14)|5, &tempSectorSpare[5], 1);
}
}
}
}
for(i=0; i<FAT_SIZEOFWORD; i++)
{ lgToph[i] = 0xffff; } //在格式化时逻辑映射表全部为0xffff,表示不对应任何物理地址
for(i=0; i<BytesPerSector; i++)
{ tempbuffer[i] = 0x00;}
if(Media==NAND_FLASH_Drv) //对Nand-flash进行格式化
{
/******************************* 第0镞0扇区为DBR ********************************/
bootsector = (BOOTSECTOR50 *)tempbuffer;
bpb = (BPB50 *)(bootsector->Bs_BPB);
ext = (EXTBOOT *)(bootsector->Bs_Ext);
bootsector->Bs_jmpBoot[0] = 0xeb;
bootsector->Bs_jmpBoot[1] = 0x3c;
bootsector->Bs_jmpBoot[2] = 0x90;
for(i=0;i<8;i++)
{ bootsector->BO_OEMName[i] = OEMname[i]; }
bootsector->Bs_BootSectSig0 = BOOTSIG0;
bootsector->Bs_BootSectSig1 = BOOTSIG1;
bpb->BPB_BytesPerSec = BytesPerSector;
bpb->BPB_SecPerClust = SectorsPerCluster;
if((FilesysType==PART_TYPE_FAT12)||(FilesysType==PART_TYPE_DOSFAT16)
||(FilesysType==PART_TYPE_FAT16)||(FilesysType==PART_TYPE_FAT16LBA))
{ bpb->BPB_RsvdSecCnt = 1; }
else if((FilesysType==PART_TYPE_FAT32)||(FilesysType==PART_TYPE_FAT32LBA))
{ bpb->BPB_RsvdSecCnt = 32;}
bpb->BPB_NumFATs = 2;
bpb->BPB_RootEntCnt = RootDirCount;
bpb->BPB_TotSec16 = 0;
bpb->BPB_Media = 0xf8; //必须与FAT[0]一致。
fatsec = bpb->BPB_FATSz16 = FATsectors;
bpb->BPB_SecPerTrack = 0;
bpb->BPB_NumHeads = 0;
bpb->BPB_HiddSec = 0;
bpb->BPB_TotSec32 = Sizeofdisk_M << 11;
ext->BPB_DrvNum = 0x80;
ext->BS_Reserved1 = 0;
ext->BS_BootSig = EXBOOTSIG;
ext->BS_VoLID = 0x88331446;
for(i=0;i<11;i++)
{ ext->BS_VoLLab[i] = VolLab[i]; }
for(i=0;i<8;i++)
{ ext->BS_FilSysType[i] = *fat16_str++; }
if(WriteLgSector(0,tempbuffer) == 0xffff) //将引导扇区的数据写入逻辑块号0的0扇区
{ return 0xffff; }
/**************************** 以下写FAT表及根目录区 *******************************/
/* 第0镞1--31扇区是根目录区,占用15个扇区,每个根目录项占用sizeof(DIRENTRY)字节 */
/* 所以总共可以存放496个根目录项即整个硬盘可以存放496个文件 */
/* 第1镞0--15扇区是FAT表1,共占用16个扇区 */
/* 第1镞16--31扇区是FAT表2,共占用16个扇区 */
/************************************************************************************/
memset(tempbuffer,0,BytesPerSector); //tempbuffer全部清0
tempbuffer[0]=0xf8; //准备FAT表1的第0项(磁盘标识字)
tempbuffer[1]=0xff;
tempbuffer[2]=0xff; //准备FAT表1的第1项(第一镞被占用)
//tempbuffer[3]=0x0f;
if(WriteLgSector(FirstFATSector,tempbuffer) == 0xffff)//将FAT表1的数据写入逻辑块号0的第1扇区
{ return 0xffff; }
if(WriteLgSector((FirstFATSector + FATsectors),tempbuffer) == 0xffff)//将FAT表2的数据写入逻辑块号0的第17扇区
{ return 0xffff; }
memset(tempbuffer,0,BytesPerSector); //tempbuffer全部清0
for(i=(FirstFATSector+1); i<(FirstFATSector+FATsectors); i++)
{
if(WriteLgSector(i,tempbuffer) == 0xffff) //将FAT表1的其它数据0写入第2~16扇区
{ return 0xffff; }
}
for(i=(FirstFATSector+FATsectors+1); i<(FirstFATSector+FATsectors*2); i++)
{
if(WriteLgSector(i,tempbuffer) == 0xffff) //将FAT表2的其它数据0写入第18~32扇区
{ return 0xffff; }
}
memset(tempbuffer,0,BytesPerSector); //tempbuffer全部清0
/*********** 以下填充根目录中的属性时间等信息 *****************/
dir = (DIRENTRY *)tempbuffer;
memcpy((BYTE *)(dir->deName), VolLab, 11); //赋根目录名为卷标
dir->deAttributes = ATTR_VOLUME; //赋根目录的属性为卷标
fat_datetime(&datatime); //写系统的当前时间到datatime中
dir->WrtDate = datatime.Date; //更新目录中的日期
dir->WrtTime = datatime.Time+1; //更新目录中的时间
if(WriteLgSector(FirstDirSector,tempbuffer) == 0xffff) //将根目录区的目录项数据写入33扇区
{ return 0xffff; }
memset(tempbuffer,0,BytesPerSector); //tempbuffer全部清0
for(i=FirstDirSector+1; i<(FirstDirSector+RootDirSectors); i++)
{//根目录区其余部分全部清0
if(WriteLgSector(i,tempbuffer) == 0xffff) //将根目录区的数据0写入34~63扇区
{ return 0xffff; }
}
//Format Nand-flash Successfully!
return 1;
}
return 0xffff;
}
/************************** 函数 WORD SectorNumToClusterNum(DWORD SectorNum) ************************/
/* 功能:根据输入的扇区号求出它所在的镞号 */
/* 入口参数:扇区号(整个FLASH连续编号) */
/* 出口参数:镞号 */
/* 说明: 非用户使用函数 */
/****************************************************************************************************/
WORD SectorNumToClusterNum(DWORD SectorNum)//OK
{
return (WORD)(SectorNum / SectorsPerCluster);
}
/************************** 函数 DWORD ClusterNumToSectorNum(WORD ClusterNum) ***********************/
/* 功能:根据输入的镞号求出该簇的其始扇区号 */
/* 入口参数:(数据区所在镞计1)镞号 */
/* 出口参数:扇区号(整个FLASH连续编号) */
/* 说明: 非用户使用函数 */
/****************************************************************************************************/
DWORD ClusterNumToSectorNum(WORD ClusterNum)//OK
{
return (DWORD)(ClusterNum * SectorsPerCluster );
}
/************************ BYTE* ReadLgSector(DWORD StartLgSector,BYTE* buffer) **********************/
/* 功能:根据输入的逻辑扇区号自动搜寻对应的物理扇区从NAND_FLASH中读出该扇区的数据到Buffer中 */
/* 入口参数:DWORD StartLgSector----逻辑扇区号 */
/* 出口参数:BYTE* buffer----从逻辑扇区读出的数据存放缓冲区,512字节长 */
/* 返回Buffer中的值,同时更新NAND_operation_Returnvalue用来判断操作的结果是否正确 */
/* 如果读取发生错误,则返回NULL */
/* 说明:非用户使用函数 */
/****************************************************************************************************/
char NAND_Operation_ReturnValue;
BYTE* ReadLgSector(DWORD StartLgSector,BYTE* buffer)//OK
{
char temp;
WORD lgBlocknum;
DWORD phaddress;
if(StartLgSector >= (FAT_SIZEOFWORD<<5))
{ return NULL; }
lgBlocknum = SectorNumToClusterNum(StartLgSector);
if(lgToph[lgBlocknum] == 0xFFFF) //考虑到USB第一次读取空的FLASH时逻辑映射表全空,则返回全0
{
memset(buffer,0,BytesPerSector);
return buffer;
}
else
{
phaddress = lgToph[lgBlocknum]<<14 | (StartLgSector%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;
}
}
}
BYTE* ReadLgSectorFat(DWORD StartLgSector,BYTE* buffer,WORD offsetinsector)
{
char temp;
WORD lgBlocknum;
DWORD phaddress;
if(StartLgSector >= (FAT_SIZEOFWORD<<5))
{ return NULL; }
lgBlocknum = SectorNumToClusterNum(StartLgSector);
if(lgToph[lgBlocknum] == 0xFFFF) //考虑到USB第一次读取空的FLASH时逻辑映射表全空,则返回全0
{
/*memset(buffer,0,2);
return buffer;FAT*/
return NULL;
}
else
{
phaddress = lgToph[lgBlocknum]<<14 | (StartLgSector%SectorsPerCluster)<<9 | offsetinsector;
if(offsetinsector != (BytesPerSector - 1)) //逻辑簇号未跨扇区,直接读取
{
temp = NAND_PageRead(phaddress, buffer, 2);
}
else
{
temp = NAND_PageRead(phaddress, buffer, 1);
}
if(temp != NAND_PASS)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -