您的位置 首页 观点

S3C2440-Nandflash

Nandflash在对大容量的数据存储中发挥着重要的作用。相对于norflash,它具有一些优势,但它的一个劣势是很容易产生坏块,因此在使用nandfla

Nandflash在对大容量的数据存储中发挥着重要的效果。相对于norflash,它具有一些优势,但它的一个下风是很简单产生坏块,因此在运用nandflash时,往往要运用校验算法发现坏块并标示出来,以便今后不再运用该坏块。nandflash没有地址或数据总线,假如是8位nandflash,那么它只需8个IO口,这8个IO口用于传输指令、地址和数据。nandflash主要以page(页)为单位进行读写,以block(块)为单位进行擦除。每一页中又分为main区和spare区,main区用于正常数据的存储,spare区用于存储一些附加信息,如块好坏的符号、块的逻辑地址、页内数据的ECC校验和等。

三星公司是最主要的nandflash供货商,因此在它所开发的各类处理器中,完结对nandflash的支撑就家常便饭了。s3c2440不只具有nandflash的接口,并且还可以运用某些机制完结直接从nandflash发动并运转程序。本文只介绍怎么对nandflash完结读、写、擦除等根本操作,不触及nandflash发动程序的问题。
在这里,咱们运用的nandflash为K9F2G08U0A,它是8位的nandflash。不同类型的nandflash的操作会有所不同,但硬件引脚根本相同,这给产品的开发带来了便当。由于不同类型的PCB板是相同的,只需更新一下软件就可以运用不同容量巨细的nandflash。
K9F2G08U0A的一页为(2K+64)字节(加号前面的2K表明的是main区容量,加号后边的64表明的是spare区容量),它的一块为64页,而整个设备包含了2048个块。这样算下来一共有2112M位容量,假如只算main区容量则有256M字节(即256M×8位)。要完结用8个IO口来要拜访这么大的容量,K9F2G08U0A规则了用5个周期来完结。第一个周期拜访的地址为A0″A7;第二个周期拜访的地址为A8″A11,它效果在IO0″IO3上,而此刻IO4″IO7有必要为低电平;第三个周期拜访的地址为A12″A19;第四个周期拜访的地址为A20″A27;第五个周期拜访的地址为A28,它效果在IO0上,而此刻IO1″IO7有必要为低电平。前两个周期传输的是列地址,后三个周期传输的是行地址。经过剖析可知,列地址是用于寻址页内空间,行地址用于寻址页,假如要直接拜访块,则需要从地址A18开端。
#include “2440addr.h”
#define CMD_READ1 0x00
#define CMD_READ2 0x30
#define CMD_READID 0x90
#define CMD_RESET 0xFF
#define CMD_WRITE1 0x80
#define CMD_WRITE2 0x10
#define CMD_BLOCKERASE1 0x60
#define CMD_BLOCKERASE2 0xD0
#define CMD_RANDOMWRITE 0x85
#define CMD_RANDOMREAD1 0x05
#define CMD_RANDOMREAD2 0xE0
#define CMD_READSTATE 0x70
#define NF_CMMD(cmd) rNFCMD = cmd
#define NF_ADDR(addr) rNFADDR = addr
#define NF_WRDATA(data) rNFDATA = data
#define NF_WRDATA8(data) rNFDATA8 = data
#define NF_RDDATA() rNFDATA
#define NF_RDDATA8() rNFDATA8
#define NF_CE_L() rNFCONT &= “(0x1<<1)
#define NF_CE_H() rNFCONT |= 0x1<<1
#define NF_MECC_LOCK() rNFCONT |= 0x1<<5
#define NF_MECC_ULOCK() rNFCONT &= “(0x1<<5)
#define NF_SECC_LOCK() rNFCONT |= 0x1<<6
#define NF_SECC_ULOCK() rNFCONT &= “(0x1<<6)
#define NF_RESETECC() rNFCONT |= 0x1<<4
#define NF_WAITRB() while(!(rNFSTAT&0x1))
#define NF_CLEARRB() rNFSTAT |= 0x1<<2
#define NF_DETECT() while(!(rNFSTAT&0x1<<2))
#define TACLS 1
#define TWRPH0 1
#define TWRPH1 1
#define U32 unsigned int
#define U8 unsigned char
U8 buffer[2048], Ecc[6];
U8 cmd, data, command;
U32 block, add, pagenumber, count;
U8 NF_BlockErase(U32 block){ //擦除以块为单位
U8 state;
NF_CE_L(); //翻开nandflash片选
NF_CLEARRB(); //等候R/nB信号安排妥当
NF_CMMD(CMD_BLOCKERASE1);
NF_ADDR((block<<6)&0xff);
NF_ADDR((block>>2)&0xff);
NF_ADDR((block>>10)&0xff);
NF_CMMD(CMD_BLOCKERASE2);
NF_WAITRB();
NF_CMMD(CMD_READSTATE);
do{
state = NF_RDDATA8();
}while(!(state&0x40));
if(state&0x1){
while(!(rUTRSTAT0&0x4));
rUTXH0 = 0x40;
return 0x40; //0x40块擦除失利
}
else{
while(!(rUTRSTAT0&0x4));
rUTXH0 = 0x60;
return 0x60; //0x60块擦除成功
}
}
U8 NF_PageWrite(U32 pagenumber){
U32 i, mecc, secc;
U8 state;
NF_CE_L();
NF_RESETECC(); //复位ECC
NF_CLEARRB();
NF_CMMD(CMD_WRITE1);
NF_ADDR(0x00);
NF_ADDR(0x00);
NF_ADDR(pagenumber&0xff);
NF_ADDR((pagenumber>>8)&0xff);
NF_ADDR((pagenumber>>16)&0xff);
//先解锁main区,然后在main区读写,产生main区ECC校验,然后确定ECC,这样ECC就被硬件写入rNFMECC0/1,咱们将它读到spare
//区应该寄存校验的方位2048″2051。在读写spare区的时分,即产生spare区的ECC,硬件把它主动写入rNFSECC中,会产生spare区
//的校验,两个字节,写到2052″2053,在读取的时分,咱们将main区的ECC和spare区的ECC读出来,放入rNFMECCD0/1和rNFSECC中,
//硬件完结rNFMECC0/1,rNFSECC和rNFMECCD0/1,rNFSECCD的校验。
NF_MECC_ULOCK(); //解锁main区的ECC
for(i = 0; i < 2048; i++){
NF_WRDATA8((char)(i+1)); //这个进程中产生ECC
}
NF_MECC_LOCK(); //确定main区ECC
mecc = rNFMECC0; //读取main区ECC
Ecc[0] = (U8)(mecc&0xff);
Ecc[1] = (U8)((mecc>>8)&0xff);
Ecc[2] = (U8)((mecc>>16)&0xff);
Ecc[3] = (U8)((mecc>>24)&0xff);
NF_SECC_ULOCK(); //解锁main区的ECC
for(i = 0; i < 4; i++){
NF_WRDATA8(Ecc[ i]); //将maina区的ECC写入spare前4个字节,这个进程产生spare区的ECC
}
NF_SECC_LOCK(); //确定spare区的ECC
secc = rNFSECC; //读取spare区的ECC
Ecc[4] = (secc)&0xff;
Ecc[5] = (secc>>8)&0xff;
for(i = 4; i < 6; i++){
NF_WRDATA8(Ecc[ i]); //将spare区的ECC写入spare
}
NF_CMMD(CMD_WRITE2);
NF_DETECT(); //等候R/nB信号变高,即不忙
NF_CMMD(CMD_READSTATE); //发读状况指令, 0x70
do{
state = NF_RDDATA8(); //查看状况 I/O 位0为0 是写成功 1 是失利, I/O 位6为0表明忙 为1是安排妥当
}while(!(state&0x40));
if(state&0x1){
while(!(rUTRSTAT0&0x4));
rUTXH0 = 0x43;
return 0x43; //0x43随机写失利
}
else{
while(!(rUTRSTAT0&0x4));
rUTXH0 = 0x63;
return 0x63; //0x63随机写成功
}
}
U8 NF_PageRead(U32 pagenumber){
U32 i, mecc, secc;
NF_CE_L();
NF_RESETECC();
NF_CLEARRB();
NF_CMMD(CMD_READ1);
NF_ADDR(0x00);
NF_ADDR(0x00);
NF_ADDR(pagenumber&0xff);
NF_ADDR((pagenumber>>8)&0xff);
NF_ADDR((pagenumber>>16)&0xff);
NF_CMMD(CMD_READ2);
NF_WAITRB();
NF_MECC_ULOCK();
for(i = 0; i < 2048; i++){
buffer[ i] = NF_RDDATA8();
}
NF_MECC_LOCK();
NF_SECC_ULOCK();
mecc = NF_RDDATA();
NF_SECC_LOCK();
rNFMECCD0 = ((mecc&0xff00)<<8) | (mecc&0xff); //读取方才的ECC 让rNFMECCD0/1,rNFSECCD与rNFMECC0/1,RNFSECC比较,看是否产生过错
rNFMECCD1 = ((mecc&0xff000000)>>8) | ((mecc&0xff0000)>>16); //校验是由于nandflash很简单产生位回转,坏块
secc = NF_RDDATA();
rNFSECCD = ((secc&0xff00)<<8)|(secc&0xff);
NF_CE_H();
if((rNFESTAT0 & 0x0f) == 0x0){ //假如低4位都是0,阐明没有过错
while(!(rUTRSTAT0&0x4));
rUTXH0 = 0x66;
for(i = 0; i < 8; i++){
while(!(rUTRSTAT0&0x4));
rUTXH0 = buffer[ i];
}
return 0x66;
}
else{
while(!(rUTRSTAT0&0x4));
rUTXH0 = 0x44;
return 0x44;
}
}

声明:本文内容来自网络转载或用户投稿,文章版权归原作者和原出处所有。文中观点,不代表本站立场。若有侵权请联系本站删除(kf@86ic.com)https://www.86ic.net/news/guandian/254738.html

为您推荐

联系我们

联系我们

在线咨询: QQ交谈

邮箱: kf@86ic.com

关注微信
微信扫一扫关注我们

微信扫一扫关注我们

返回顶部