#include "def.h"
#include "2440addr.h"
#include "mynand.h"
//define command
#define CMD_READ1 0x00 //页读命令1
#define CMD_READ2 0x30 //页读命令2
#define CMD_READID 0x90 //读取ID
#define CMD_RESET 0xff //复位
#define CMD_WRITE1 0x80 //页写命令1
#define CMD_WRITE2 0x10 //页写命令2
#define CMD_ERASE1 0x60 //块擦除命令1
#define CMD_ERASE2 0xd0 //块擦除命令2
#define CMD_STATUS 0x70 //读取状态命令
#define CMD_RANDOMREAD1 0X05 //随机读取命令1
#define CMD_RANDOMREAD2 0xe0 //随机读取命令2
#define CMD_RANDOMWRITE 0x85 //随机写命令
#define NF_CE_L() {rNFCONT &=~(1<<1);} //使能片选
#define NF_CE_H() {rNFCONT |=(1<<1);} //关闭片选
#define NF_MECC_UnLock() {rNFCONT&=~(1<<5);} //解锁main去ECC
#define NF_MECC_Lock() {rNFCONT|=(1<<5);} //锁定main去ECC
#define NF_SECC_UnLock() {rNFCONT &= ~(1<<6); } //解锁spare区ECC
#define NF_SECC_Lock() {rNFCONT |= (1<<6); } //锁定spare区ECC
#define NF_RSTECC() {rNFCONT |= (1<<4); } //复位ECC
#define NF_WAITRB() {while(!(rNFSTAT &(1<<0))) ;} //等待nand flash 空闲
#define NF_CLEAR_RB() {rNFSTAT |= (1<<2); } //清除RnB信号
#define NF_DETECT_RB() {while(!(rNFSTAT&(1<<2)));}
#define NF_RDDATA8() ((*(volatile unsigned char*)0x4E000010) )
#define NF_CMD(cmd) {rNFCMD = (cmd);} //命令
#define NF_ADDR( addr) {rNFADDR = (addr);} //地址
#define NF_RDDATA() (rNFDATA) //读取32位数据
//#define NF_RDDATA8() (rNFDATA) //读取8位数据
#define NF_WRDATA(data) { rNFDATA = (data);} //写32位数据
#define NF_WRDATA8(data) { rNFDATA8 = (data);} //写8位数据
#define TACLS 1
#define TWRPH0 2
#define TWRPH1 0
externvoidDelay(inttime);
voidnand_init(void)
{
rGPACON = rGPACON & (~(0x3f<<17)) |(0x3f<<17) ;
rNFCONF = (TACLS<<12) |(TWRPH0<<8) |(TWRPH1<<4) |(0<<0) ;
//非锁定,屏蔽nandflash中断,初始化ECC及锁定main区和spare区ECC,使能nandflash片选及控制器
rNFCONT = (0<<13)|(0<<12)|(0<<10)|(0<<9)|(0<<8)|(1<<6)|(1<<5)|(1<<4)|(1<<1)|(1<<0);
}
//复位nand
voidnand_reset()
{
inti;
NF_CE_L();//cs
NF_CLEAR_RB();//清除RnB信号
for(i=0;i<10;i++) ;
NF_CMD(CMD_RESET);//写入复位命令
NF_DETECT_RB();//等待RnB信号变高,即不忙
NF_CE_H();//关闭nandflash片选
}
//读取nand的id号,首先需要写入读ID命令,然后再写入0x00地址,就可以读取到一共五个周期的芯片ID,第一个周期为厂商ID,第二个周期为设备ID,
//第三个周期至第五个周期包括了一些具体的该芯片信息
U8 read_id(void)
{
inti;
U8 first, second, third, forth, fifth;//分别读取1---5个周期的数据
NF_CE_L();//cs
//NF_CLEAR_RB(); //清除RnB信号
// for(i=0;i<10;i++) ;
NF_CMD(CMD_READID);//读ID命令
NF_ADDR(0x0);//写0x00地址
first = NF_RDDATA8() ;//厂商ID: 0Xec
second = NF_RDDATA8() ;//设备ID,一般从这个参数可以判断出nand的一些参数
third = NF_RDDATA8() ;//0x00
forth = NF_RDDATA8() ;//0x95
fifth = NF_RDDATA8() ;// 0x40
NF_CE_H();//关闭nandflash片选
returnsecond;
}
//带硬件ECC校验的读,page_numer为页号,每页2K
U8 nand_readpage_ecc(U32 page_number, U8 *buffer)
{
inti;
U32 mainecc0, spareecc;//用于存放ecc的临时值
NF_RSTECC();//复位ECC
NF_MECC_UnLock()//解锁主区ECC
NF_CE_L();//cs
NF_CLEAR_RB();//清除RnB信号
NF_CMD(CMD_READ1);//页读命令周期1
//写入地址,首先写入列地址(也即相对每一个页开始的地址),再写入行地址(也即页号)
NF_ADDR(0x00);//列地址A0~A7,这里直接从每页的开始读可以使用下面被注释的4行代码优化
NF_ADDR(0x00);//列地址A8~A11
// page = page_number/4;
// data_addr = 512 *(page_number%4);
// NF_ADDR(data_addr&0xff);
// NF_ADDR((data_addr>>8)&0xff);
NF_ADDR((page_number) & 0xff);//行地址A12~A19
NF_ADDR((page_number >> 8) & 0xff);//行地址A20~A27
NF_CMD(CMD_READ2);//页读命令周期2
NF_DETECT_RB();//等待RnB信号变高,即不忙
for(i=0;i<2048;i++)
buffer[i] = NF_RDDATA8() ;
NF_MECC_Lock();//锁定main区ECC值
NF_SECC_UnLock();//解锁spare区ECC
mainecc0=NF_RDDATA();//读spare区的前4个地址内容,即第2048~2051地址,这4个字节为main区的ECC
//把读取到的main区的ECC校验码放入NFMECCD0/1的相应位置内
rNFMECCD0=((mainecc0&0xff00)<<8)|(mainecc0&0xff);
rNFMECCD1=((mainecc0&0xff000000)>>8)|((mainecc0&0xff0000)>>16);
NF_SECC_Lock();//锁定spare区的ECC值
spareecc=NF_RDDATA();//继续读spare区的4个地址内容,即第2052~2055地址,其中前2个字节为spare区的ECC值
//把读取到的spare区的ECC校验码放入NFSECCD的相应位置内
rNFSECCD=((spareecc&0xff00)<<8)|(spareecc&0xff);
NF_CE_H();//关闭nandflash片选
//判断所读取到的数据是否正确
if((rNFESTAT0&0xf) == 0x0)
return0x66;//正确
else
return0x44;
}
U8 nand_writepage_ecc(U32 page_number, U8 *buffer)
{
inti,stat;
U32 mecc0, secc;//用于存放ecc的临时值
charECCBuf[10];
i = nand_is_badblock(page_number>>6) ;
if( i ==0x33)
return0x42 ;//坏块
NF_RSTECC();//复位ECC
NF_MECC_UnLock()//解锁主区ECC
NF_CE_L();//cs
NF_CLEAR_RB();//清除RnB信号
NF_CMD(CMD_WRITE1);//页读命令周期1
//写入地址,首先写入列地址(也即相对每一个页开始的地址),再写入行地址(也即页号)
NF_ADDR(0x00);//列地址A0~A7,这里直接从每页的开始读可以使用下面被注释的4行代码优化
NF_ADDR(0x00);//列地址A8~A11
// page = page_number/4;
// data_addr = 512 *(page_number%4);
// NF_ADDR(data_addr&0xff);
// NF_ADDR((data_addr>>8)&0xff);
NF_ADDR((page_number) & 0xff);//行地址A12~A19
NF_ADDR((page_number >> 8) & 0xff);//行地址A20~A27
for(i=0;i<2048;i++)
NF_WRDATA8(buffer[i]);
NF_MECC_Lock();//锁定main区ECC值
mecc0=rNFMECC0;//读取main区的ECC校验码
//把ECC校验码由字型转换为字节型,并保存到全局变量数组ECCBuf中
ECCBuf[0]=(U8)(mecc0&0xff);
ECCBuf[1]=(U8)((mecc0>>8) & 0xff);
ECCBuf[2]=(U8)((mecc0>>16) & 0xff);
ECCBuf[3]=(U8)((mecc0>>24) & 0xff);
NF_SECC_UnLock();//解锁spare区ECC
for(i=0;i<4;i++)
{
NF_WRDATA8(ECCBuf[i]);
}
NF_SECC_Lock();//锁定spare区的ECC值
secc=rNFSECC;//读取spare区的ECC校验码
//把ECC校验码保存到全局变量数组ECCBuf中
ECCBuf[4]=(U8)(secc&0xff);
ECCBuf[5]=(U8)((secc>>8) & 0xff);
//把spare区的ECC值继续写入到spare区的第2052~2053地址内
for(i=4;i<6;i++)
{
NF_WRDATA8(ECCBuf[i]);
}
NF_CMD(CMD_WRITE2);//页读命令周期2
Delay(100);
NF_CMD(CMD_STATUS);//读状态命令
//判断状态值的第6位是否为1,即是否在忙,该语句的作用与NF_DETECT_RB();相同
do{
stat = NF_RDDATA8();
}while(!(stat&0x40));
NF_CE_H();//关闭nandflash片选
//判断所读取到的数据是否正确
if(stat & 0x1)
{
i = rNF_MarkBadBlock(page_number>>6);//标注该页所在的块为坏块
if(i == 0x21)
return0x43 ;//标注坏块失败
else
return0x44;//写操作失败
}
else
return0x66;
}
U8 nand_random_readpage(U32 page_number, U32 add)
{
NF_CE_L();//cs
NF_CLEAR_RB();//清除RnB信号
NF_CMD(CMD_READ1);//页读命令周期1
//写入地址,首先写入列地址(也即相对每一个页开始的地址),再写入行地址(也即页号)
NF_ADDR(0x00);//列地址A0~A7,这里直接从每页的开始读可以使用下面被注释的4行代码优化
NF_ADDR(0x00);//列地址A8~A11
// page = page_number/4;
// data_addr = 512 *(page_number%4);
// NF_ADDR(data_addr&0xff);
// NF_ADDR((data_addr>>8)&0xff);
NF_ADDR((page_number) & 0xff);//行地址A12~A19
NF_ADDR((page_number >> 8) & 0xff);//行地址A20~A27
NF_CMD(CMD_READ2);//页读命令周期2
NF_DETECT_RB();//等待RnB信号变高,即不忙
NF_CMD(CMD_RANDOMREAD1);//随意读命令周期1
//页内地址
NF_ADDR((char)(add&0xff));//列地址A0~A7
NF_ADDR((char)((add>>8)&0x0f));//列地址A8~A11
NF_CMD(CMD_RANDOMREAD2);//随意读命令周期2
returnNF_RDDATA8();//读取数据
}
U8 nand_random_writepage(U32 page_number, U32 add, U8 data)
{
U8 stat;
NF_CE_L();//cs
NF_CLEAR_RB();//清除RnB信号
NF_CMD(CMD_WRITE1);//页读命令周期1
//写入地址,首先写入列地址(也即相对每一个页开始的地址),再写入行地址(也即页号)
NF_ADDR(0x00);//列地址A0~A7,这里直接从每页的开始读可以使用下面被注释的4行代码优化
NF_ADDR(0x00);//列地址A8~A11
// page = page_number/4;
// data_addr = 512 *(page_number%4);
// NF_ADDR(data_addr&0xff);
// NF_ADDR((data_addr>>8)&0xff);
NF_ADDR((page_number) & 0xff);//行地址A12~A19
NF_ADDR((page_number >> 8) & 0xff);//行地址A20~A27
NF_CMD(CMD_RANDOMWRITE);//页读命令周期2
//页内地址
NF_ADDR((char)(add&0xff));//列地址A0~A7
NF_ADDR((char)((add>>8)&0x0f));//列地址A8~A11
NF_WRDATA8(data);//写入数据
NF_CMD(CMD_WRITE2);//页写命令周期2
//判断状态值的第6位是否为1,即是否在忙,该语句的作用与NF_DETECT_RB();相同
do{
stat = NF_RDDATA8();
}while(!(stat&0x40));
NF_CE_H();//关闭nandflash片选
//判断所读取到的数据是否正确
if(stat & 0x1)
return0x44;
else
return0x66;
}
U8 nand_is_badblock(U32 block)
{
returnnand_random_readpage(block*64, 2054);
}
U8 rNF_MarkBadBlock(U32 block)
{
U8 result;
result = nand_random_writepage(block*64, 2054, 0x33);
if(result == 0x44)
return0x21;//写坏块标注失败
else
return0x60 ;
}