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

📄 fat12.c

📁 FAT12 文件系统,囊括了文件系统的各个函数,另外还包括了地址映射,适合读写NAND_FLASH
💻 C
📖 第 1 页 / 共 5 页
字号:

/*******************************************************************************
* 修改时间: 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 + -