K9F2G08U0A nand flash 的容量為256M byte,其內(nèi)部有2048塊,每塊有64頁(yè),每頁(yè)有2K+64字節(jié),其中每頁(yè)會(huì)分為main區(qū)(主域)和spare區(qū)(備用域),main區(qū)一般用來(lái)存入主要數(shù)據(jù),spare一般用來(lái)存放ECC校驗(yàn)碼。本文引用地址:http://m.butianyuan.cn/article/201611/319263.htm下面幾點(diǎn)是編程時(shí)需要注意的:
1.NAND FLASH芯片手冊(cè)里說(shuō)的column是指頁(yè)內(nèi)地址,row是指頁(yè)地址,page也是指頁(yè);
2.刪除時(shí)是以塊為單位的,但是刪除塊時(shí)寫的是row地址,自動(dòng)會(huì)刪除row所在的塊;
3.讀寫方式有頁(yè)讀寫,或隨機(jī)讀寫,所謂的隨機(jī)讀寫就是可以在頁(yè)內(nèi)的任一地方讀寫一個(gè)字節(jié);
4.ECC校驗(yàn)碼分為main區(qū)的ECC和spare區(qū)的ECC,它們一般都會(huì)存放在64字節(jié)的spare區(qū)內(nèi),下面是翻譯2440手冊(cè)的關(guān)于ECC編程的內(nèi)容:
ECC 編程向?qū)?/p>
1) 在軟件模式, ECC 模塊會(huì)為全部讀 / 寫數(shù)據(jù)產(chǎn)生 ECC 檢驗(yàn)碼。所以你需要在讀或者寫數(shù)據(jù)前給 InitECC(NFCONT[4]) 位寫 1 和給 MainECCLock(NFCONT[5]) 位寫 0(Unlock) 來(lái)復(fù)位 ECC 值。
MainECCLock(NFCONT[5]) 和 SpareECCLock(NFCONT[6] 控制 ECC 校驗(yàn)碼是否產(chǎn)生。
2) 任何時(shí)候讀或者寫數(shù)據(jù)時(shí), ECC 模塊在 NFMECC0/1 上產(chǎn)生 ECC 校驗(yàn)碼。
3) 在你完成讀或者寫一個(gè)頁(yè)后(不包含備用數(shù)據(jù)域),給 MainECCLock 位置 1(lock) 。 ECC 校驗(yàn)碼被鎖上, ECC 狀態(tài)寄存器的值將不會(huì)被改變。
4) 清 0(Unlock) SpareECCLock(NFCONT[6]) 位來(lái)產(chǎn)生備用域的 ECC 校驗(yàn)碼。
5) 任何時(shí)候讀或者寫數(shù)據(jù)時(shí),備用域 ECC 模塊在寄存器 NFSECC 上產(chǎn)生 ECC 校驗(yàn)碼。
6) 在完成讀或者寫備用域后,給 SpareECCLock 位置 1(lock) 。 ECC 校驗(yàn)碼被鎖上, ECC 狀態(tài)寄存器的值將不會(huì)被改變。
7) 一旦完成你就可以使用這些值來(lái)記錄到備用域或者檢測(cè)位錯(cuò)誤。
接下來(lái)是代碼:
NAND-FLASH.H內(nèi)容:
#ifndef __NAND_FLASH_H__ //為了防止重復(fù)包含
#define __NAND_FLASH_H__
#include "lhg_def.h" //U8,U32相關(guān)的宏,也即變量類型
#define MAX_NAND_BLOCK 2048
#define NAND_PAGE_SIZE 2048 //2048 blocks,1block has 64pages, each page has 2k+64 bytes
typedef struct nand_id_info //這樣的結(jié)構(gòu)體變量保存芯片的ID信息
{
U8 IDm; //marker code
U8 IDd; //device code
U8 ID3rd;
U8 ID4th;
U8 ID5th;
} nand_id_info;
typedef struct bad_block_info //登記壞塊用的,只記錄數(shù)量,沒有記錄壞塊地址
{
U8 area[MAX_NAND_BLOCK];//0表示非壞塊,1表示壞塊
U32 sum;//壞塊的總數(shù)
} bad_block_info;
//
//NAND 操作指令,??從哪里來(lái)的,我看你怎么用
#define NAND_CMD_READ_1st 0x00
#define NAND_CMD_READ_2st 0x30
#define NAND_CMD_RANDOM_WRITE 0x85
#define NAND_CMD_RANDOM_READ_1st 0x05
#define NAND_CMD_RANDOM_READ_2st 0xe0
#define NAND_CMD_READ_CB_1st 0x00
#define NAND_CMD_READ_CB_2st 0x35
#define NAND_CMD_READ_ID 0x90
#define NAND_CMD_RES 0xff
#define NAND_CMD_WRITE_PAGE_1st 0x80
#define NAND_CMD_WRITE_PAGE_2st 0x10
#define NAND_CMD_BLOCK_ERASE_1st 0x60
#define NAND_CMD_BLOCK_ERASE_2st 0xd0
#define NAND_CMD_READ_STATUS 0x70
//NAND 中斷向量,?這是什么意思
#define INT_NFCON (24)
//NFCONF HCLK=100MHZ,nandflash configuration register
#define S3C2440_NFCONF_TACLS_init (1<<12) //設(shè)置cle ale的持續(xù)時(shí)間,NFCONF[14:12]
#define S3C2440_NFCONF_TWRPH0_init (4<<8) //TWRPH0持續(xù)時(shí)間設(shè)置,NFCONF[10:8]
#define S3C2440_NFCONF_TWRPH1_init (0<<4) //TWRPH1持續(xù)時(shí)間設(shè)置,NFCONF[6:4]
#define S3C2440_NFCONF_BusWidth_init (0) //bus_width for autobooting or general access,0 for1B
#define S3C2440_NFCONF_init() ( rNFCONF = S3C2440_NFCONF_TACLS_init | /
S3C2440_NFCONF_TWRPH0_init | /
S3C2440_NFCONF_TWRPH1_init | /
S3C2440_NFCONF_BusWidth_init ) //牛逼啊這句話
//NFCONT,nandflash control register
#define S3C2440_NFCONT_LockTight_init (0<<13)//disable lock-tight
#define S3C2440_NFCONT_SoftLock_init (0<<12)//disable lock
#define S3C2440_NFCONT_EnbIllegalAccINT_init (1<<10)//illegal access interrupt enable
#define S3C2440_NFCONT_EnbRnBINT_init (0<<9)//RnB ready not busy
#define S3C2440_NFCONT_RnB_TransMode_init (0<<8)//detect RnB type is rising edge
#define S3C2440_NFCONT_SpareECCLock_init (1<<6)//1 is to lock sparearea ecc generation
#define S3C2440_NFCONT_MainECCLock_init (1<<5)//1 is to lock main area ecc generation
#define S3C2440_NFCONT_InitECC_init (1<<4)//1 is to initialize ecc decoder and encoder
#define S3C2440_NFCONT_Reg_nCE_init (1<<1)//force nFCE to high,namely disable chip-select
#define S3C2440_NFCONT_MODE_init (0)//disable nandflash controller
#define S3C2440_NFCONT_init() ( rNFCONT = S3C2440_NFCONT_LockTight_init | /
S3C2440_NFCONT_SoftLock_init | /
S3C2440_NFCONT_EnbIllegalAccINT_init | /
S3C2440_NFCONT_EnbRnBINT_init | /
S3C2440_NFCONT_RnB_TransMode_init | /
S3C2440_NFCONT_SpareECCLock_init | /
S3C2440_NFCONT_MainECCLock_init | /
S3C2440_NFCONT_InitECC_init | /
S3C2440_NFCONT_Reg_nCE_init | /
S3C2440_NFCONT_MODE_init )
//NFSTAT
#define S3C2440_NFSTAT_init() ( rNFSTAT &= 0x3 )//NFSTAT 8 bits, 0x3 means nCE output high,
//nandflash is ready to operate
//NFESTAT0
#define S3C2440_NFESTAT0_init() ( rNFESTAT0 = 0 )//ecc status for io0-io7,k9f1208 only io0-i07
//NFESTAT1
#define S3C2440_NFESTAT1_init() ( rNFESTAT1 = 0 )//ecc status for io8-io15
//
#define select_nand() ( rNFCONT &= ~(1<<1) )
#define dis_select_nand() ( rNFCONT |= 1<<1 )片選信號(hào)設(shè)置不說(shuō)了啊
#define controller_enable() ( rNFCONT |= 1 )
#define controller_disable() ( rNFCONT &= ~1 )nandflash控制器使能與否也不說(shuō)了
//
extern void nand_flash_init(void);//初始化,extern意思是提供給外部上層函數(shù)要調(diào)用的入口
extern int nand_block_erase(U32 num);//num要?jiǎng)h除的塊號(hào),一共2048個(gè)塊,這么大變量浪費(fèi)了!
extern int nand_page_write(U32 addr,U8 *buffer,U32 size);//addr要寫的起始頁(yè)地址,buffer要寫的緩存,size要寫的字節(jié)大小最大為4G,這里是針對(duì)u32說(shuō)的
extern int nand_page_read(U32 addr,U8 *buffer,U32 size);//addr開始頁(yè)地址,從每頁(yè)00地址開始讀
extern int nand_random_read(U32 paddr,U32 offset,U8 *data); //隨機(jī)讀數(shù)據(jù) paddr頁(yè)地址,offset頁(yè)內(nèi)偏移地址,每次一個(gè)字節(jié)
extern int nand_random_write(U32 paddr,U32 offset,U8 data);//隨機(jī)寫,paddr頁(yè)地址,offset頁(yè)內(nèi)偏移地址
extern void nand_test_bad_block(void);//測(cè)試壞塊函數(shù),并標(biāo)記在nand_bbi變量里和spare區(qū)最后一個(gè)地址(如果非0xff則為壞塊??原因是什么)
#endif
NAND-FLASH.c內(nèi)容:
#include "2440addr.h"
#include "NAND-FLASH.h"
#include "uart.h"
#include "lhg_def.h"
//#include "iic_lhg.h"
#define NAND_DEBUG 1
#define USE_ECC 1
nand_id_info nand_id;//定義登記芯片ID的全局變量
bad_block_info nand_bbi;//定義來(lái)登記壞用的全局變量
void init_nand_bbi(void)//初始化變量
{
U32 i;
nand_bbi.sum=0;
for (i=0;i nand_bbi.area[i]=0;//這里放的是塊數(shù),針對(duì)k9f1208是2048塊
}
void nand_mask_bad_block(U32 n)//標(biāo)志壞塊,n是壞塊的塊號(hào)
{
#ifdef NAND_DEBUG//宏定義的一種,尼瑪也可以寫在這里
Uart_Printf("NAND found and mask a bad block=%d .",n);
#endif
if (nand_bbi.area[n]!=1)//注意這里是對(duì)入口參數(shù)n操作的
{
nand_bbi.area[n]=1;
nand_bbi.sum++;
nand_random_write(n*64,2048+64-1,0);//每塊的第一個(gè)spare的最后一個(gè)字節(jié),標(biāo)志本塊是否為壞塊,非0xff為壞塊,頁(yè)地址計(jì)算中要看具體芯片一塊中有多少頁(yè),例如k9f1208是32頁(yè)
}
}
int detect_nand_busy(void)//檢測(cè)是否忙
{
U32 a;
a=0;
while(!(rNFSTAT&(1<<2)))//也即RnB狀態(tài),0表示忙
{
a++;
if (a==5000000)//等待超時(shí)
{
Uart_Printf("/r/n Error: Detect Nand Busy time out!!! /r/n");
rNFSTAT |= (1<<2);//清忙標(biāo)志,1表示不忙
return -1;//錯(cuò)誤返回-1,這個(gè)-1表示的是你他媽的nandflash一直忙,這里是有問題的
}
}
rNFSTAT |= (1<<2);//清忙標(biāo)志,沒有超時(shí),我給你正常設(shè)為清閑,返回值也沒問題
return 1;
}
void nand_reset(void)//復(fù)位
{
rNFCMD = NAND_CMD_RES;//?從哪里查到的NFCMD命令集合?和韋教材一樣,0xff為復(fù)位命令
detect_nand_busy();//檢測(cè)忙,?為什么復(fù)位后檢測(cè)nandflash忙不忙呢?如果忙說(shuō)明程序出錯(cuò)在讀寫
}
void control_start(void){ //開啟
select_nand();
controller_enable();//也即最后兩位啟用nandflash和選中nandflash
rNFSTAT |= (1<<2);//清忙標(biāo)志
nand_reset();
}
void control_end(void) //關(guān)閉
{
dis_select_nand();//取消片選,關(guān)閉nandflash控制器
controller_disable();
}
void ecc_main_init(void)//初始化ECC值
{
rNFCONT |= 1<<4;//NFCONT[4]初始化ecc編解碼器
void ecc_main_start(void)//開始main ECC
{
rNFCONT &= ~(1<<5);//unlock NFCONT[5],main area可以產(chǎn)生ecc
}
ecc_main_end(void)//結(jié)束main ECC
{
rNFCONT |= 1<<5;//unlock,main area不可以再產(chǎn)生ecc 了
}
void ecc_spare_start(void)//開始spare ECC
{
// rNFCONT |= 1<<4; //initEcc
rNFCONT &= ~(1<<6); //unlock,NFCONT[6]控制spare area的ecc產(chǎn)生
}
void ecc_spare_end(void)//結(jié)束spare ECC,同樣道理關(guān)閉ecc的產(chǎn)生
{
rNFCONT |= 1<<6; //unlock
}
void __irq nandINT(void) //中斷函數(shù)
{
//此處寫處理代碼
#ifdef NAND_DEBUG
Uart_Printf("/r/n Nand Error... In interrupt now!!!");//只有錯(cuò)誤才會(huì)進(jìn)入中斷
#endif
rSRCPND |= 0x1< rINTPND |= 0x1<}
void nand_read_id(void)//讀取芯片ID信息
{
control_start();//開控制選中nandflash和開啟nandflash控制器
rNFCMD = NAND_CMD_READ_ID;//讀id命令為0x90,韋教材上有
rNFADDR = 0;//nandflash address set register,不是發(fā)出4個(gè)地址序列嗎????
//讀ID
nand_id.IDm=(U8)rNFDATA8;//強(qiáng)制轉(zhuǎn)換為8位的,制造商
nand_id.IDd=(U8)rNFDATA8; //設(shè)備代碼
nand_id.ID3rd=(U8)rNFDATA8;//保留字節(jié)
nand_id.ID4th=(U8)rNFDATA8;//多層操作代碼
nand_id.ID5th=(U8)rNFDATA8;//??不知道是什么,反正一共5個(gè)信息數(shù)據(jù)
#ifdef NAND_DEBUG
Uart_Printf("/r/n Read NAND Flash ID:");
Uart_Printf("/r/n NAND Mark code: 0x%x ",nand_id.IDm);//打印ID信息
Uart_Printf("/r/n NAND Device code: 0x%x ",nand_id.IDd);
Uart_Printf("/r/n NAND 3rdID code: 0x%x ",nand_id.ID3rd);
Uart_Printf("/r/n NAND 4thID code: 0x%x ",nand_id.ID4th);
Uart_Printf("/r/n NAND 5thID code: 0x%x ",nand_id.ID5th);
#endif
control_end();//關(guān)控制,取消片選和關(guān)閉nandflash控制器
}
int nand_block_erase(U32 num)//num要擦除的塊號(hào)
{
num=num*64;//表示要擦除的塊地址,這種nandflash每一個(gè)塊有64頁(yè),其他的就不一定了哈哈
control_start();//開控制
nand_reset();//復(fù)位
rNFCMD = NAND_CMD_BLOCK_ERASE_1st;//0x60命令
rNFADDR = num&0xff;//需要發(fā)3個(gè)地址序列,這里有3個(gè),非常好?。?!
rNFADDR = (num>>8)&0xff;
rNFADDR = (num>>16)&0xff;
rNFCMD = NAND_CMD_BLOCK_ERASE_2st;//0xd0命令
detect_nand_busy();//看看nandflash忙不忙
rNFCMD =NAND_CMD_READ_STATUS; //讀擦出的結(jié)果狀態(tài),命令是0x70
if (rNFDATA8&1)//如果最高位是1,下面報(bào)錯(cuò),就是說(shuō)擦除這個(gè)塊沒有成功,這個(gè)得記住!
{
#ifdef NAND_DEBUG
Uart_Printf("/r/n Error:nand erase error... block=0x%x",num/64);
#endif
control_end();//關(guān)控制
nand_mask_bad_block(num/64);//登記為壞塊
return -1;//刪除錯(cuò)誤返回0
}
control_end();//關(guān)控制
#ifdef NAND_DEBUG
Uart_Printf("/r/n NAND block %d erase completed.",num/64);
#endif
return 1;
}
int nand_page_write(U32 addr,U8 *buffer,U32 size)
//addr要寫的起始頁(yè)地址,buffer要寫的緩存,size要寫的字節(jié)大小最大為4G
//這樣的話addr是有格式要求的比如末尾幾個(gè)零,結(jié)果這個(gè)函數(shù)里面沒有加上所謂“對(duì)齊判斷”失敗?。?!
{
U32 i,n,p,temp,ecc;
U8 *bu;
bu=buffer;
temp=0;
//我自己加上的對(duì)齊判斷,假如每頁(yè)是2kbyte的話,也可以再加上串口打印信息
if(addr & 0xfff) {return -1;}
//
n=size/2048+(((size 48)==0)?0:1); //計(jì)算出要寫的頁(yè)數(shù),小于一頁(yè)的部分當(dāng)作一頁(yè)
for (i=0;i{
control_start();//開控制,選中nandflash和開啟nandflash控制器
nand_reset();//復(fù)位
#ifdef USE_ECC
ecc_main_init();
ecc_main_start();//可以產(chǎn)生main區(qū)ECC
#endif
// detect_nand_busy();
//檢測(cè)忙,這里有相當(dāng)于是復(fù)位nandflash后檢測(cè)nandflash,復(fù)位都不相信了,擦!
//檢測(cè)了更好考慮問題更全面
rNFCMD = NAND_CMD_WRITE_PAGE_1st;//0x80命令,
rNFADDR = 0; //從每頁(yè)的0地址開始
rNFADDR = 0; //從每頁(yè)的0地址開始
rNFADDR = (addr)&0xff;//???不是發(fā)送四個(gè)地址序列嗎?
rNFADDR = (addr>>8)&0xff;
rNFADDR = (addr>>16)&0xff;
for (p=0;p<2048;p++)//寫入一頁(yè)
{
temp=temp+1;
if (temp>size)//這個(gè)temp并沒有在每一頁(yè)中重新置零?。?!
rNFDATA8 = 0xff;//多余的填寫0xff,NFDATA是32位數(shù)據(jù)
else
rNFDATA8 = *(bu+p);
}
delay_lhg(100,100);//?草具體的延時(shí)函數(shù)在哪里
#ifdef USE_ECC//也即宏定義里面是否啟用了ecc產(chǎn)生記錄
ecc_main_end();//鎖定main區(qū)ecc
ecc=rNFMECC0;//main ECC值寫入備用區(qū)的頭0~4個(gè)地址內(nèi),NFMECCO是main aera的ecc產(chǎn)生的臨時(shí)地方
ecc_spare_start();//開始spare區(qū)ECC
rNFDATA8 = ecc&0xff;//這樣來(lái)看ecc32位數(shù)據(jù),
rNFDATA8 = (ecc>>8)&0xff;
rNFDATA8 = (ecc>>16)&0xff;
rNFDATA8 = (ecc>>24)&0xff;//自動(dòng)完成寫入
ecc_spare_end();
delay_lhg(100,100);//
ecc = rNFSECC;//spare ECC值寫入備用區(qū)的5~6兩個(gè)地址內(nèi),NFSECC是spare area生成ecc的臨時(shí)地方
rNFDATA8 = ecc&0xff;
rNFDATA8 = (ecc>>8)&0xff;//我靠 spare area的ecc只有16位
#endif
bu=bu+2048;//頁(yè)增量
addr++;//起始頁(yè)地址為何是++?
rNFCMD = NAND_CMD_WRITE_PAGE_2st;//這個(gè)命令是ox10,意思是啟動(dòng)寫操作
detect_nand_busy();//檢測(cè)忙
rNFCMD =NAND_CMD_READ_STATUS; //讀nandflash忙不忙的狀態(tài)指令,這個(gè)命令是0x70
if (rNFDATA8&1)//???為什么出來(lái)最后一位是1則是有問題啊?。。?!
{
#ifdef NAND_DEBUG
Uart_Printf("/r/n nand write page error: page addr=0x%d",addr-1);//寫入失敗
#endif
control_end();//關(guān)控制,取消選中nandflash然后關(guān)閉nandflash控制器
nand_mask_bad_block((addr-1)/64);//登記為壞塊,我靠整個(gè)塊都是壞的?。。?br /> return -1;//寫入錯(cuò)誤返回-1
}
control_end();//關(guān)控制
}
return 1;//成功返回1
}
int nand_page_read(U32 addr,U8 *buffer,U32 size)//addr開始頁(yè)地址,從每頁(yè)00地址開始讀
{
U32 i,n,p,temp,ecc;
U8 *bu,no;
bu=buffer;
temp=0;
n=size/2048+(((size 48)==0)?0:1); //計(jì)算出要讀的頁(yè)數(shù),小于一頁(yè)的部分當(dāng)作一頁(yè)
for (i=0;i++;i {
control_start();//開控制,選中nandflash并且打開nandflash控制器
nand_reset();//復(fù)位,擦 下邊例行監(jiān)測(cè)nandflash的busy與否
detect_nand_busy();
#ifdef USE_ECC
rNFESTAT0 = 0;//復(fù)位錯(cuò)誤標(biāo)志位
ecc_main_init();
ecc_main_start();//可以產(chǎn)生main區(qū)ECC
#endif
rNFCMD = NAND_CMD_READ_1st;
rNFADDR = 0;
rNFADDR = 0;
rNFADDR = addr&0xff;
rNFADDR = (addr>>8)&0xff;
rNFADDR = (addr>>16)&0xff;//尼瑪?shù)刂沸蛄邪l(fā)送的這么混亂!?。?br /> rNFCMD = NAND_CMD_READ_2st;//這個(gè)命令應(yīng)該是0x50,讀取的是c區(qū)的數(shù)據(jù)
detect_nand_busy();
for (p=0;p<2048;p++)
{
temp=temp+1;
if (temp>size)
no=rNFDATA8;//多余的讀出來(lái)扔掉,給了一個(gè)無(wú)用的臨時(shí)變量
else
*(bu+p) = rNFDATA8;
}
#ifdef USE_ECC
rNFESTAT0=0;//這個(gè)表示io0-io7的ecc狀態(tài)
ecc_main_end();//鎖定main區(qū)ECC
delay_lhg(100,100);//
ecc_spare_start();//解鎖spare區(qū)ecc
ecc=rNFDATA8;//從flash讀出main區(qū)ECC
no=rNFDATA8;
ecc |= ((U32)no)<<8;
no=rNFDATA8;
ecc |= ((U32)no)<<16;
no=rNFDATA8;
ecc |= ((U32)no)<<24;
//這個(gè)是什么意思???就是用中間變量no讓ecc存儲(chǔ)了32位的main area的ecc
rNFMECCD0 = ((ecc&0xff00)<<8)|(ecc&0xff);//硬件檢驗(yàn)main ECC,一次檢驗(yàn)16位
rNFMECCD1 = ((ecc&0xff000000)>>8)|((ecc&0xff0000)>>16);
ecc_spare_end();//鎖定spare區(qū)ecc
delay_lhg(100,100);//
ecc=rNFDATA8;//從flash讀出spare區(qū)ECC的值
no=rNFDATA8;
ecc |= ((U32)no)<<8;
rNFSECCD = ((ecc&0xff00)<<8)|(ecc&0xff);//硬件檢驗(yàn)spare ECC
delay_lhg(100,100);//延時(shí)一會(huì)
ecc=rNFESTAT0&0xffffff;//ecc只是臨時(shí)用一下錯(cuò)誤狀態(tài),并非ecc內(nèi)容
if (ecc!=0)//有錯(cuò)誤
{
//以后再優(yōu)化
#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();//關(guān)控制
}
return 1;
}
int nand_random_read(U32 paddr,U32 offset,U8 *data) //隨機(jī)讀數(shù)據(jù) paddr頁(yè)地址,offset頁(yè)內(nèi)偏移地址
{
control_start();//開控制
nand_reset();//復(fù)位
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; //寫入頁(yè)內(nèi)偏移地址
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)//隨機(jī)寫,paddr頁(yè)地址,offset頁(yè)內(nèi)偏移地址
{
control_start();//開控制
nand_reset();//復(fù)位
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; //寫入頁(yè)內(nèi)偏移地址
rNFADDR = (offset>>8)&0xff;
rNFDATA8 = data;
rNFCMD = NAND_CMD_WRITE_PAGE_2st;
detect_nand_busy();//檢測(cè)忙
rNFCMD =NAND_CMD_READ_STATUS; //讀狀態(tài)
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;//刪除錯(cuò)誤返回0
}
control_end();
return 1;//成功返回1
}
void nand_test_bad_block(void)//測(cè)試壞塊函數(shù),并標(biāo)記spare區(qū)最后一個(gè)地址,如果非0xff則為壞塊
{
U8 dest[64*2048];//一個(gè)塊的main區(qū)容量
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區(qū)檢測(cè)
for (i=0;i<64*2048;i++)
{
dest[i]=0xff;//初始化緩沖區(qū)
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校驗(yàn)讀出來(lái)即可登記壞塊信息
}
for (i=0;i<64*2048;i++)
{
dest[i]=0;//初始化緩沖區(qū)
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校驗(yàn)讀出來(lái)即可登記壞塊信息
}
//
//spare區(qū)檢測(cè)
for (i=0;i<64;i++)
{
dest[i]=0xff;//初始化緩沖區(qū)
src [i]=0;
}
//刪除所有塊
for (i=0;i
{
nand_block_erase(i);
}
for (i=0;i
{
if ( nand_bbi.area[i/64] ==1 )//如果是壞塊則跳過(guò)
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;//初始化緩沖區(qū)
src [i]=0xff;
}
//刪除所有塊
for (i=0;i
{
nand_block_erase(i);
}
for (i=0;i
{
if ( nand_bbi.area[i/64] ==1 )//如果是壞塊則跳過(guò)
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關(guān)閉上位
rGPGCON &= ~((U32)0x3f<<26);//GPG13~15為輸入
//初始化各寄存器
S3C2440_NFCONF_init();
S3C2440_NFCONT_init();
S3C2440_NFSTAT_init();
S3C2440_NFESTAT0_init();
S3C2440_NFESTAT1_init();
//關(guān)于中斷
rINTMSK &= ~(0x1< rINTMOD &= ~(0x1< rSRCPND |= 0x1< rINTPND |= 0x1<
init_nand_bbi();//初始化全局變量
nand_read_id();//讀ID
nand_test_bad_block();//測(cè)試并登記壞塊
}
評(píng)論