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