?? 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 + -