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

📄 nflash_1.c

📁 ARM
💻 C
📖 第 1 页 / 共 2 页
字号:

#include "k9f1208uom.h"

#include "SysConfig.h"

#ifdef _DEBUG_
#include "Uart1.h"
#endif

/*************************全局变量定义************************************************/

	
	union _K9fUnion DEV[2]; //支持0/1两个设备
/*************************底层读写和延时定义************************************************/	
#define NFLASH_DELAY(count)   { volatile int i; for(i=0;i<count;i++);}

#define NFLASH_CMD_LATCH_WAIT   NFLASH_DELAY(10)
#define NFLASH_ADDR_LATCH_WAIT   NFLASH_DELAY(10)
#define NFLASH_READ_ID_WAIT      NFLASH_DELAY(10)
#define NFLASH_READ_STATUS_WAIT      NFLASH_DELAY(100)
#define NFLASH_INPUT_DATA_WAIT      NFLASH_DELAY(350)
#define NFLASH_RB_WAIT             NFLASH_DELAY(500)  //  NFLASH_DELAY(100)


void __inline K9F_WriteCommand(unsigned char dev,unsigned char comm)
{
	if(dev==0)
  		DEV0_K9F_COMMAND=comm; 	//发送命令
  	else
  		DEV1_K9F_COMMAND=comm; 
}
void __inline K9F_WriteData(unsigned char dev,unsigned char d) 
{
	if(dev==0)
  		DEV0_K9F_DATA=d; 	//发送数据
  	else
  		DEV1_K9F_DATA=d; 	
}
unsigned char __inline K9F_ReadData(unsigned char dev)
{
	if(dev==0)
  		return	DEV0_K9F_DATA; 	//接收数据
  	else
  		return	DEV1_K9F_DATA; 	 
}
void __inline  K9F_Enable(unsigned char dev)
{
	if(dev==0)
	{
		DEV0_K9F_ENABLE;
	}
	else
	{
		DEV1_K9F_ENABLE;
	}
}

void __inline  K9F_Disable(unsigned char dev)
{
	if(dev==0)
	{
		DEV0_K9F_DISABLE;
	}
	else
	{
		DEV1_K9F_DISABLE;
	}
}
/*******************************中间层读写操作函数××××××××××××××××××××××********************/

void K9F_WriteAddr(unsigned char dev,unsigned int block,unsigned int page) //发送地址block-4096,page-32
{
	unsigned int addr[4];
	addr[3]=(block>>11)&0x0001;
	addr[2]=(block&0x07f8)>>3;
	addr[1]=((block&0x0007)<<5)|page;
	addr[0]=0x00;  	//从第0地址开始
	if(dev==0)
	{
		DEV0_K9F_ADDR=addr[0];
		DEV0_K9F_ADDR=addr[1];
		DEV0_K9F_ADDR=addr[2];
		DEV0_K9F_ADDR=addr[3];//从低到高发送地址
	}
	else
	{
		DEV1_K9F_ADDR=addr[0];
		DEV1_K9F_ADDR=addr[1];
		DEV1_K9F_ADDR=addr[2];
		DEV1_K9F_ADDR=addr[3];
	}
}
void K9F_WriteCheckAddr(unsigned char dev,unsigned int block,unsigned int page) //发送地址block-4096,page-32
{
	unsigned int addr[4];
	addr[3]=(block>>11)&0x0001;
	addr[2]=(block&0x07f8)>>3;
	addr[1]=((block&0x0007)<<5)|page;
	addr[0]=0x05;  	//从第517地址开始C区
	
	if(dev==0)
	{
		DEV0_K9F_ADDR=addr[0];
		DEV0_K9F_ADDR=addr[1];
		DEV0_K9F_ADDR=addr[2];
		DEV0_K9F_ADDR=addr[3];//从低到高发送地址
	}
	else
	{
		DEV1_K9F_ADDR=addr[0];
		DEV1_K9F_ADDR=addr[1];
		DEV1_K9F_ADDR=addr[2];
		DEV1_K9F_ADDR=addr[3];
	}
	
}

void K9F_WriteBlockAddr(unsigned char dev,unsigned int block)	//檫除使用
{
	unsigned int addr[3];
	addr[2]=(block>>11)&0x0001;
	addr[1]=(block&0x07f8)>>3;
	addr[0]=((block&0x0007)<<5)&0x00e0;
	
	if(dev==0)
	{
		DEV0_K9F_ADDR=addr[0];
		DEV0_K9F_ADDR=addr[1];
		DEV0_K9F_ADDR=addr[2];//从低到高发送地址
	}
	else
	{
		DEV1_K9F_ADDR=addr[0];
		DEV1_K9F_ADDR=addr[1];
		DEV1_K9F_ADDR=addr[2];
	}
}
//复位*********************************************
//可以不用
  void K9F_Reset(unsigned char dev)//flash reset
 {
 	K9F_WriteCommand(dev,K9F_RESET);
 }
//读ID**********************************************
unsigned int K9F_Read_Flash_Id(unsigned char dev)
{
	unsigned int i,j,k,l;
	K9F_Enable(dev);
	K9F_WriteCommand(dev,READ_K9F_ID);
	if(dev==0)
		DEV0_K9F_ADDR=0x00;
	else
		DEV1_K9F_ADDR=0x00;
	NFLASH_READ_ID_WAIT;
	i=K9F_ReadData(dev);//返回ID
	j=K9F_ReadData(dev);//返回ID
	k=K9F_ReadData(dev);//返回ID
	l=K9F_ReadData(dev);//返回ID
	K9F_Disable(dev);
	return (i<<24)|(j<<16)|(k<<8)|l;
}
//等待与成功失败*********************************************
unsigned char K9F_Read_Status(unsigned char dev) //io6为1表示准备好io0为0表示成功
{
	unsigned char j=0x00;
	K9F_Enable(dev);
	K9F_WriteCommand(dev,READ_STATUS);
	j=K9F_ReadData(dev);//K9F_ReadData();
	while((j&0x40)==0) //如果I/O6为0就一直等待
	{
		NFLASH_READ_STATUS_WAIT;
		j=K9F_ReadData(dev);
	}
	K9F_Disable(dev);
	return j;  //准备好
	
}

//***************************************************************************************//
//FLASH上层操作函数
//***************************************************************************************//
//dev=0,板上FLASH,dev=1,卡上FLASH
void K9F_Init(unsigned char dev)
{
	
	 SMC_SMCBCR3         =  0x0000ffef  ; 
	 SET_K9F_ENABLE; //卡上nand_FLASH的E引脚设置为输出
	 
	 if(K9F_ReadInfo(dev)==1)
	 {
		#ifdef _DEBUG_
			PutStr("  Have Creat info."); 
			PutNextLine();    
		#endif
	 	//已经建立信息
	 }
	 else
	 {
	 	#ifdef _DEBUG_
			PutStr("  Start to creat the info.");    
			PutNextLine();   
		#endif
	  	K9F_CreatInfo(dev);
	 }

}

//檫除块*********************************************
unsigned char K9F_Erase_Block(unsigned char dev,unsigned int block)
{
		unsigned int j;
			
			block=K9F_GetBlock(dev,block);
			
			K9F_Enable(dev);
			K9F_WriteCommand(dev,ERASE_START);
			K9F_WriteBlockAddr(dev,block);  //写地址
			K9F_WriteCommand(dev,ERASE_END);
			
			K9F_Disable(dev);
			
			NFLASH_RB_WAIT;
//			while(*PEDATDIR&0x0004==0);
			
			j=K9F_Read_Status(dev);
			if(j&0x01)
			{
			// 	AddBadBlock(block);
			 	return 0; //失败
			}
			else 
			 return 1;//成功
	  
}
//读一页*********************************************
void K9F_ReadPage(unsigned char dev,unsigned int block,unsigned int page,unsigned char *pData)
{
	
	unsigned int i=0, k=512;//每个扇区有528个字节读528字节  
	unsigned char *p=pData;
	        
	block=K9F_GetBlock(dev,block);
	        
	K9F_Read_Status(dev); 	
	K9F_Enable(dev);
	K9F_WriteCommand(dev,0);//从A-ARRAY开始
	K9F_WriteAddr(dev,block,page);  //写地址
		
	NFLASH_INPUT_DATA_WAIT;   
	
	do {       
		*p=K9F_ReadData(dev);     //读数据 
		i++;
		p++;
	}while(i<k);

	K9F_Disable(dev);
	
	NFLASH_DELAY(100000); //等待读完成,后来添加。
}
//写一页*********************************************
unsigned char K9F_WritePage(unsigned char dev,unsigned int block,unsigned int page,unsigned char *pData)
{
	
	unsigned int i,j,k=512;
	unsigned char *p=pData;
       
//	Read_Status();    	
	block=K9F_GetBlock(dev,block);
	
	K9F_Enable(dev);
	K9F_WriteCommand(dev,0x00);
	K9F_WriteCommand(dev,0x80);   //写开始
	K9F_WriteAddr(dev,block,page);  //写地址
	
	NFLASH_RB_WAIT;   
	
	for(i=0;i<k;i++) //当k不为0时,就继读;否则就停止读                                     
	{                                          
	 	K9F_WriteData(dev,*p);     //写数据 
		p++;
		NFLASH_DELAY(10); //等待写完成,后来添加。
	}
	K9F_WriteCommand(dev,0x10);//写结束	
	
	NFLASH_DELAY(1000); //等待写完成,后来添加。
	K9F_Disable(dev);
	
	NFLASH_DELAY(10000); //等待写完成,后来添加。
//	while(*PEDATDIR&0x0004==0); //硬件判忙
	j=K9F_Read_Status(dev);
	if(j&0x01)
	{
//		AddBadBlock(block);
		return 0; //失败表示为坏块了
	}
	else 
		return 1;//成功
}

//*********************文件管理函数***************************//???稍后做处理

//读取NAND-FLASH信息存到DEV0_K9fInfo结构中*********************************************
//return 1:已经处理的NAND
//return 0:没有处理的NAND
unsigned char K9F_ReadInfo(unsigned char dev)
{
	 
	K9F_ReadPage(dev,0,0,DEV[dev].Dbuf);
	if((DEV[dev].Dbuf[0]==0x0aa)&&(DEV[dev].Dbuf[1]==0x55))
	{ //表示已经建立坏块表
		return 1;
	}
	else
		return 0;

}

//把NAND-FLASH信息存到DEV0_K9fInfo结构中*********************************************
//return 1:
//return 0:
unsigned char K9F_WriteInfo(unsigned char dev)
{
 	unsigned int i,j;
 	unsigned char pDataCheck[512];
	//先擦除再写入
	K9F_Erase_Block(dev,0);
	NFLASH_DELAY(1000);
	K9F_WritePage(dev,0,0,DEV[dev].Dbuf);
	//check
	K9F_ReadPage(dev,0,0,pDataCheck);
	for(i=0;i<512;i++)
	{
		if(pDataCheck[i]!=DEV[dev].Dbuf[i])
		{
			#ifdef _DEBUG_
				 PutStr("Write Info Error!");
		 	     PutNextLine();
			#endif
			return 0;	
		/**/
		}
	}
	return 1;
}
//获得当前块的映射块地址***********************/
unsigned int K9F_GetBlock(unsigned char dev,unsigned int block)// 与记录坏块的表相对照的子程序
{
		unsigned int i;
		for(i=0;i<DEV[dev].K9fInfo.BlockTableNum;i++)
		{
			if(block==DEV[dev].K9fInfo.BlockTable[2*i])
				return DEV[dev].K9fInfo.BlockTable[2*i+1];//返回映射块
			 //每项占用两个单元
		}		
		return block;	//没有查找到,就是当前块。
}

//建立NAND信息表*********************************************
//包括容量大小,坏块映射表等等
void K9F_CreatInfo(unsigned char dev)
{
	unsigned int block,page;
	volatile unsigned int i,j,k;
	unsigned int bStop;
	unsigned int bad1,bad2;
	unsigned int blockAmount;
	unsigned int DevCode;
	 
	//建立容量大小等信息 
	 DevCode=K9F_Read_Flash_Id(dev);
      switch(DevCode)
      {
      	case K9F1208_ID :
      		DEV[dev].K9fInfo.BlockAmount=4096;
      		DEV[dev].K9fInfo.BlockUsed=4016;
      		break;
      	case K9F5608_ID :
      		DEV[dev].K9fInfo.BlockAmount=2048;
      		DEV[dev].K9fInfo.BlockUsed=2008;	
      		break;
      	default:
      		break;
      }      
      
	//初始化坏块结构
		DEV[dev].K9fInfo.BadBlockAmount=0; //初始坏块总数为0
		DEV[dev].K9fInfo.BlockTableNum=0; //初始坏块映射表项目为0
		DEV[dev].K9fInfo.BlockNextMux=DEV[dev].K9fInfo.BlockUsed;
		blockAmount=DEV[dev].K9fInfo.BlockAmount;

	//开始读取坏块
	for(block=0;block<blockAmount;block++)
	{
	
		for(page=0;page<2;page++)
		{
			K9F_Read_Status(dev); 
			K9F_Enable(dev);
			K9F_WriteCommand(dev,0x50);//从SPARE-ARRAY开始
			K9F_WriteCheckAddr(dev,block,page);  //写地址
	
			NFLASH_INPUT_DATA_WAIT;   			  
	 		j=K9F_ReadData(dev);     //读数据 
	 		NFLASH_READ_STATUS_WAIT;
			K9F_Disable(dev);
			
			if((j!=0xff)&&(page==0))
				bad1=1;
			if((j!=0xff)&&(page==1))
				bad2=1;
		}
		if((bad1==1)||(bad2==1))//坏的块,添加
		{
				bad1=0;bad2=0;
				DEV[dev].K9fInfo.BadBlockNum[DEV[dev].K9fInfo.BadBlockAmount]=block;
				DEV[dev].K9fInfo.BadBlockAmount++;
				if(DEV[dev].K9fInfo.BadBlockAmount>=80)
				{
					#ifdef _DEBUG_
    					 PutStr("Bad block exceed 80.program halted!");
    			 	     PutNextLine();
  					#endif
				}
		}	
	}
	
	//建立坏块映射表
	for(i=0;i<DEV[dev].K9fInfo.BlockUsed;i++)
	{
		for(j=0;j<DEV[dev].K9fInfo.BadBlockAmount;j++)
		{
			if(i==DEV[dev].K9fInfo.BadBlockNum[j])
			{
				
			   while(bStop==0) //找到一个不是坏块为止,DEV0_K9fInfo.BlockNextMux
			  	{
			  		bStop=1; //先假设是好的
			  		for(k=0;k<DEV[dev].K9fInfo.BadBlockAmount;k++)
					{
						if(DEV[dev].K9fInfo.BlockNextMux==DEV[dev].K9fInfo.BadBlockNum[k])
						{
							//如果替换块也是坏的,继续往下找
							DEV[dev].K9fInfo.BlockNextMux++;
							bStop=0;
							break; //一发现是坏的就不再继续判断
						}	
					}
				}		
				DEV[dev].K9fInfo.BlockTable[2*DEV[dev].K9fInfo.BlockTableNum]=i; //前一项为坏块
				DEV[dev].K9fInfo.BlockTable[2*DEV[dev].K9fInfo.BlockTableNum+1]=DEV[dev].K9fInfo.BlockNextMux;//后一项为替换好块
				DEV[dev].K9fInfo.BlockTableNum++;   //坏块替换表项数
				DEV[dev].K9fInfo.BlockNextMux++;
			}	
		}
	}
	//设置已经建立标志
	DEV[dev].K9fInfo.AppLen =255;
	DEV[dev].K9fInfo.IsCreat=0x55aa;
	//把NANDFLASH信息和坏块映射表写入BLOCK0-PAGE4
	K9F_WriteInfo(dev);
	
}
//添加坏块到信息表中*********************************************
void AddToBadBlock(unsigned char dev,unsigned int block)
{
	unsigned int k;
	unsigned int bStop=0;
	DEV[dev].K9fInfo.BadBlockNum[DEV[dev].K9fInfo.BadBlockAmount]=block;
	DEV[dev].K9fInfo.BadBlockAmount++;
	
	while(bStop==0) //找到一个不是坏块为止,DEV0_K9fInfo.BlockNextMux
  	{
  		bStop=1; //先假设是好的
  		for(k=0;k<DEV[dev].K9fInfo.BadBlockAmount;k++)
		{
			if(DEV[dev].K9fInfo.BlockNextMux==DEV[dev].K9fInfo.BadBlockNum[k])
			{
				//如果替换块也是坏的,继续往下找
				DEV[dev].K9fInfo.BlockNextMux++;
				bStop=0;
				break; //一发现是坏的就不再继续判断
			}	
		}
	}		
	DEV[dev].K9fInfo.BlockTable[2*DEV[dev].K9fInfo.BlockTableNum]=block; //前一项为坏块
	DEV[dev].K9fInfo.BlockTable[2*DEV[dev].K9fInfo.BlockTableNum+1]=DEV[dev].K9fInfo.BlockNextMux;//后一项为替换好块
	DEV[dev].K9fInfo.BlockTableNum++;   //坏块替换表项数
	DEV[dev].K9fInfo.BlockNextMux++;	
}
//测试模块*********************************************
void TestNandFlash(unsigned char dev)
{
	unsigned int i;
	unsigned char WriterBuf[512];
	unsigned char  ReadBuf[512];
	
	K9F_Init(dev);
	#ifdef _DEBUG_
      PutStr("  The nand flash is:");

⌨️ 快捷键说明

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