//addr要写的起始页地址,buffer要写的缓存,size要写的字节大小最大为4G
//这样的话addr是有格式要求的比如末尾几个零,结果这个函数里面没有加上所谓“对齐判断”失败啊!!
{
U32 i,n,p,temp,ecc;
U8 *bu;
bu=buffer;
temp=0;
//我自己加上的对齐判断,假如每页是2kbyte的话,也可以再加上串口打印信息
if(addr & 0xfff) {return -1;}
//
n=size/2048+(((size 48)==0)?0:1); //计算出要写的页数,小于一页的部分当作一页
for (i=0;i{
control_start();//开控制,选中nandflash和开启nandflash控制器
nand_reset();//复位
#ifdef USE_ECC
ecc_main_init();
ecc_main_start();//可以产生main区ECC
#endif
// detect_nand_busy();
//检测忙,这里有相当于是复位nandflash后检测nandflash,复位都不相信了,擦!
//检测了更好考虑问题更全面
rNFCMD = NAND_CMD_WRITE_PAGE_1st;//0x80命令,
rNFADDR = 0; //从每页的0地址开始
rNFADDR = 0; //从每页的0地址开始
rNFADDR = (addr)&0xff;//???不是发送四个地址序列吗?
rNFADDR = (addr>>8)&0xff;
rNFADDR = (addr>>16)&0xff;
for (p=0;p<2048;p++)//写入一页
{
temp=temp+1;
if (temp>size)//这个temp并没有在每一页中重新置零!!!
rNFDATA8 = 0xff;//多余的填写0xff,NFDATA是32位数据
else
rNFDATA8 = *(bu+p);
}
delay_lhg(100,100);//?草具体的延时函数在哪里
#ifdef USE_ECC//也即宏定义里面是否启用了ecc产生记录
ecc_main_end();//锁定main区ecc
ecc=rNFMECC0;//main ECC值写入备用区的头0~4个地址内,NFMECCO是main aera的ecc产生的临时地方
ecc_spare_start();//开始spare区ECC
rNFDATA8 = ecc&0xff;//这样来看ecc32位数据,
rNFDATA8 = (ecc>>8)&0xff;
rNFDATA8 = (ecc>>16)&0xff;
rNFDATA8 = (ecc>>24)&0xff;//自动完成写入
ecc_spare_end();
delay_lhg(100,100);//
ecc = rNFSECC;//spare ECC值写入备用区的5~6两个地址内,NFSECC是spare area生成ecc的临时地方
rNFDATA8 = ecc&0xff;
rNFDATA8 = (ecc>>8)&0xff;//我靠 spare area的ecc只有16位
#endif
bu=bu+2048;//页增量
addr++;//起始页地址为何是++?
rNFCMD = NAND_CMD_WRITE_PAGE_2st;//这个命令是ox10,意思是启动写操作
detect_nand_busy();//检测忙
rNFCMD =NAND_CMD_READ_STATUS; //读nandflash忙不忙的状态指令,这个命令是0x70
if (rNFDATA8&1)//???为什么出来最后一位是1则是有问题啊!!!!
{
#ifdef NAND_DEBUG
Uart_Printf("/r/n nand write page error: page addr=0x%d",addr-1);//写入失败
#endif
control_end();//关控制,取消选中nandflash然后关闭nandflash控制器
nand_mask_bad_block((addr-1)/64);//登记为坏块,我靠整个块都是坏的!!!
return -1;//写入错误返回-1
}
control_end();//关控制
}
return 1;//成功返回1
}
int nand_page_read(U32 addr,U8 *buffer,U32 size)//addr开始页地址,从每页00地址开始读
{
U32 i,n,p,temp,ecc;
U8 *bu,no;
bu=buffer;
temp=0;
n=size/2048+(((size 48)==0)?0:1); //计算出要读的页数,小于一页的部分当作一页
for (i=0;i++;i {
control_start();//开控制,选中nandflash并且打开nandflash控制器
nand_reset();//复位,擦 下边例行监测nandflash的busy与否
detect_nand_busy();
#ifdef USE_ECC
rNFESTAT0 = 0;//复位错误标志位
ecc_main_init();
ecc_main_start();//可以产生main区ECC
#endif
rNFCMD = NAND_CMD_READ_1st;
rNFADDR = 0;
rNFADDR = 0;
rNFADDR = addr&0xff;
rNFADDR = (addr>>8)&0xff;
rNFADDR = (addr>>16)&0xff;//尼玛地址序列发送的这么混乱!!!
rNFCMD = NAND_CMD_READ_2st;//这个命令应该是0x50,读取的是c区的数据
detect_nand_busy();
for (p=0;p<2048;p++)
{
temp=temp+1;
if (temp>size)
no=rNFDATA8;//多余的读出来扔掉,给了一个无用的临时变量
else
*(bu+p) = rNFDATA8;
}
#ifdef USE_ECC
rNFESTAT0=0;//这个表示io0-io7的ecc状态
ecc_main_end();//锁定main区ECC
delay_lhg(100,100);//
ecc_spare_start();//解锁spare区ecc
ecc=rNFDATA8;//从flash读出main区ECC
no=rNFDATA8;
ecc |= ((U32)no)<8;
no=rNFDATA8;
ecc |= ((U32)no)<16;
no=rNFDATA8;
ecc |= ((U32)no)<24;
//这个是什么意思啊?就是用中间变量no让ecc存储了32位的main area的ecc
rNFMECCD0 = ((ecc&0xff00)<8)|(ecc&0xff);//硬件检验main ECC,一次检验16位
rNFMECCD1 = ((ecc&0xff000000)>>8)|((ecc&0xff0000)>>16);
ecc_spare_end();//锁定spare区ecc
delay_lhg(100,100);//
ecc=rNFDATA8;//从flash读出spare区ECC的值
no=rNFDATA8;
ecc |= ((U32)no)<8;
rNFSECCD = ((ecc&0xff00)<8)|(ecc&0xff);//硬件检验spare ECC
delay_lhg(100,100);//延时一会
ecc=rNFESTAT0&0xffffff;//ecc只是临时用一下错误状态,并非ecc内容
if (ecc!=0)//有错误
{
//以后再优化
#ifdef NAND_DEBUG
Uart_Printf("/r/n Nand ecc check error... page addr=0x%x,NFESTAT0=0x%x ",addr,ecc);
#endif
nand_mask_bad_block((addr+i)/64);//登记为坏块
return -1;//
}
#endif
bu=bu+2048;
addr++;
control_end();//关控制
}
return 1;
}
int nand_random_read(U32 paddr,U32 offset,U8 *data) //随机读数据 paddr页地址,offset页内偏移地址
{
control_start();//开控制
nand_reset();//复位
rNFCMD = NAND_CMD_READ_1st;
rNFADDR = 0;
rNFADDR = 0;
rNFADDR = paddr&0xff;
rNFADDR = (paddr>>8)&0xff;
rNFADDR = (paddr>>16)&0xff;
rNFCMD = NAND_CMD_READ_2st;
detect_nand_busy();
rNFCMD = NAND_CMD_RANDOM_READ_1st;
rNFADDR = offset&0xff; //写入页内偏移地址
rNFADDR = (offset>>8)&0xff;
rNFCMD = NAND_CMD_RANDOM_READ_2st;
*data = rNFDATA8;
control_end();
return 1;
}
int nand_random_write(U32 paddr,U32 offset,U8 data)//随机写,paddr页地址,offset页内偏移地址
{
control_start();//开控制
nand_reset();//复位
rNFCMD = NAND_CMD_WRITE_PAGE_1st;
rNFADDR = 0;
rNFADDR = 0;
rNFADDR = paddr&0xff;
rNFADDR = (paddr>>8)&0xff;
rNFADDR = (paddr>>16)&0xff;
rNFCMD = NAND_CMD_RANDOM_WRITE;
rNFADDR = offset&0xff; //写入页内偏移地址
rNFADDR = (offset>>8)&0xff;
rNFDATA8 = data;
rNFCMD = NAND_CMD_WRITE_PAGE_2st;
detect_nand_busy();//检测忙
rNFCMD =NAND_CMD_READ_STATUS; //读状态
if (rNFDATA8&1)
{
#ifdef NAND_DEBUG
Uart_Printf("/r/n Error:nand random write error... paddr=0x%x,offset=0x%x ",paddr,offset);
#endif
return -1;//删除错误返回0
}
control_end();
return 1;//成功返回1
}
void nand_test_bad_block(void)//测试坏块函数,并标记spare区最后一个地址,如果非0xff则为坏块
{
U8 dest[64*2048];//一个块的main区容量
U8 src [64*2048];
U32 i,k;
#ifdef NAND_DEBUG
Uart_Printf("/r/n test and mask bad block is begain. /r/n");
#endif
//
//main区检测
for (i=0;i<64*2048;i++)
{
dest[i]=0xff;//初始化缓冲区
src [i]=0;
}
//删除所有块
for (i=0;i
{
nand_block_erase(i);
}
for (i=0;i
{
nand_page_write(i*64,src,64*2048);
nand_page_read(i*64,dest,64*2048);//使用了ecc校验读出来即可登记坏块信息
}
for (i=0;i<64*2048;i++)
{
dest[i]=0;//初始化缓冲区
src [i]=0xff;
}
//删除所有块
for (i=0;i
{
nand_block_erase(i);
}
for (i=0;i
{
nand_page_write(i*64,src,64*2048);
nand_page_read(i*64,dest,64*2048);//使用了ecc校验读出来即可登记坏块信息
}
//
//spare区检测
for (i=0;i<64;i++)
{
dest[i]=0xff;//初始化缓冲区
src [i]=0;
}
//删除所有块
for (i=0;i
{
nand_block_erase(i);
}
for (i=0;i
{
if ( nand_bbi.area[i/64] ==1 )//如果是坏块则跳过
continue;
for (k=0;k<64;k++)
{
nand_random_write(i,2048+k,src[k]);
nand_random_read(i,2048+k,&dest[k]);
if (dest[k]!=src[k])//不相等则登记为坏块
{
nand_mask_bad_block(i/64);
break;
}
}
}
for (i=0;i<64;i++)
{
dest[i]=0x0;//初始化缓冲区
src [i]=0xff;
}
//删除所有块
for (i=0;i
{
nand_block_erase(i);
}
for (i=0;i
{
if ( nand_bbi.area[i/64] ==1 )//如果是坏块则跳过
continue;
for (k=0;k<64;k++)
{
nand_random_write(i,2048+k,src[k]);
nand_random_read(i,2048+k,&dest[k]);
if (dest[k]!=src[k])//不相等则登记为坏块
{
nand_mask_bad_block(i/64);
break;
}
}
}
#ifdef NAND_DEBUG
Uart_Printf("/r/n test and mask bad block is over. /r/n");
#endif
}
void nand_flash_init(void)//初始化
{
#ifdef NAND_DEBUG
Uart_Printf("/r/nNAND FLASH init");//
#endif
//中断入口地址
pISR_NFCON = (U32)nandINT;
//配置GPIO
rGPGUP |= 0x7<13; //GPG13~15关闭上位
rGPGCON &= ~((U32)0x3f<26);//GPG13~15为输入
//初始化各寄存器
S3C2440_NFCONF_init();
S3C2440_NFCONT_init();
S3C2440_NFSTAT_init();
S3C2440_NFESTAT0_init();
S3C2440_NFESTAT1_init();
//关于中断
rINTMSK &= ~(0x1 rINTMOD &= ~(0x1 rSRCPND |= 0x1 rINTPND |= 0x1
init_nand_bbi();//初始化全局变量
nand_read_id();//读ID
nand_test_bad_block();//测试并登记坏块
}