S3C2440-Nandflash
三星公司是最主要的nandflash供應(yīng)商,因此在它所開發(fā)的各類處理器中,實現(xiàn)對nandflash的支持就不足為奇了。s3c2440不僅具有nandflash的接口,而且還可以利用某些機制實現(xiàn)直接從nandflash啟動并運行程序。本文只介紹如何對nandflash實現(xiàn)讀、寫、擦除等基本操作,不涉及nandflash啟動程序的問題。
在這里,我們使用的nandflash為K9F2G08U0A,它是8位的nandflash。不同型號的nandflash的操作會有所不同,但硬件引腳基本相同,這給產(chǎn)品的開發(fā)帶來了便利。因為不同型號的PCB板是一樣的,只要更新一下軟件就可以使用不同容量大小的nandflash。
K9F2G08U0A的一頁為(2K+64)字節(jié)(加號前面的2K表示的是main區(qū)容量,加號后面的64表示的是spare區(qū)容量),它的一塊為64頁,而整個設(shè)備包括了2048個塊。這樣算下來一共有2112M位容量,如果只算main區(qū)容量則有256M字節(jié)(即256M×8位)。要實現(xiàn)用8個IO口來要訪問這么大的容量,K9F2G08U0A規(guī)定了用5個周期來實現(xiàn)。第一個周期訪問的地址為A0"A7;第二個周期訪問的地址為A8"A11,它作用在IO0"IO3上,而此時IO4"IO7必須為低電平;第三個周期訪問的地址為A12"A19;第四個周期訪問的地址為A20"A27;第五個周期訪問的地址為A28,它作用在IO0上,而此時IO1"IO7必須為低電平。前兩個周期傳輸?shù)氖橇械刂?,后三個周期傳輸?shù)氖切械刂?。通過分析可知,列地址是用于尋址頁內(nèi)空間,行地址用于尋址頁,如果要直接訪問塊,則需要從地址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(); //復(fù)位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區(qū),然后在main區(qū)讀寫,產(chǎn)生main區(qū)ECC校驗,然后鎖定ECC,這樣ECC就被硬件寫入rNFMECC0/1,我們將它讀到spare
//區(qū)應(yīng)該存放校驗的位置2048"2051。在讀寫spare區(qū)的時候,即產(chǎn)生spare區(qū)的ECC,硬件把它自動寫入rNFSECC中,會產(chǎn)生spare區(qū)
//的校驗,兩個字節(jié),寫到2052"2053,在讀取的時候,我們將main區(qū)的ECC和spare區(qū)的ECC讀出來,放入rNFMECCD0/1和rNFSECC中,
//硬件完成rNFMECC0/1,rNFSECC和rNFMECCD0/1,rNFSECCD的校驗。
NF_MECC_ULOCK(); //解鎖main區(qū)的ECC
for(i = 0; i < 2048; i++){
NF_WRDATA8((char)(i+1)); //這個過程中產(chǎn)生ECC
}
NF_MECC_LOCK(); //鎖定main區(qū)ECC
mecc = rNFMECC0; //讀取main區(qū)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區(qū)的ECC
for(i = 0; i < 4; i++){
NF_WRDATA8(Ecc[ i]); //將maina區(qū)的ECC寫入spare前4個字節(jié),這個過程產(chǎn)生spare區(qū)的ECC
}
NF_SECC_LOCK(); //鎖定spare區(qū)的ECC
secc = rNFSECC; //讀取spare區(qū)的ECC
Ecc[4] = (secc)&0xff;
Ecc[5] = (secc>>8)&0xff;
for(i = 4; i < 6; i++){
NF_WRDATA8(Ecc[ i]); //將spare區(qū)的ECC寫入spare
}
NF_CMMD(CMD_WRITE2);
NF_DETECT(); //等待R/nB信號變高,即不忙
NF_CMMD(CMD_READSTATE); //發(fā)讀狀態(tài)命令, 0x70
do{
state = NF_RDDATA8(); //檢查狀態(tài) 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比較,看是否發(fā)生錯誤
rNFMECCD1 = ((mecc&0xff000000)>>8) | ((mecc&0xff0000)>>16); //校驗是因為nandflash很容易發(fā)生位反轉(zhuǎn),壞塊
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;
}
關(guān)鍵詞:
S3C2440Nandflash數(shù)據(jù)存
評論