K9F2G08U0A nand flash 的容量為256M byte,其內部有2048塊,每塊有64頁,每頁有2K+64字節,其中每頁會分為main區(主域)和spare區(備用域),main區一般用來存入主要數據,spare一般用來存放ECC校驗碼。本文引用地址:http://www.104case.com/article/201611/319263.htm下面幾點是編程時需要注意的:
1.NAND FLASH芯片手冊里說的column是指頁內地址,row是指頁地址,page也是指頁;
2.刪除時是以塊為單位的,但是刪除塊時寫的是row地址,自動會刪除row所在的塊;
3.讀寫方式有頁讀寫,或隨機讀寫,所謂的隨機讀寫就是可以在頁內的任一地方讀寫一個字節;
4.ECC校驗碼分為main區的ECC和spare區的ECC,它們一般都會存放在64字節的spare區內,下面是翻譯2440手冊的關于ECC編程的內容:
ECC 編程向導
1) 在軟件模式, ECC 模塊會為全部讀 / 寫數據產生 ECC 檢驗碼。所以你需要在讀或者寫數據前給 InitECC(NFCONT[4]) 位寫 1 和給 MainECCLock(NFCONT[5]) 位寫 0(Unlock) 來復位 ECC 值。
MainECCLock(NFCONT[5]) 和 SpareECCLock(NFCONT[6] 控制 ECC 校驗碼是否產生。
2) 任何時候讀或者寫數據時, ECC 模塊在 NFMECC0/1 上產生 ECC 校驗碼。
3) 在你完成讀或者寫一個頁后(不包含備用數據域),給 MainECCLock 位置 1(lock) 。 ECC 校驗碼被鎖上, ECC 狀態寄存器的值將不會被改變。
4) 清 0(Unlock) SpareECCLock(NFCONT[6]) 位來產生備用域的 ECC 校驗碼。
5) 任何時候讀或者寫數據時,備用域 ECC 模塊在寄存器 NFSECC 上產生 ECC 校驗碼。
6) 在完成讀或者寫備用域后,給 SpareECCLock 位置 1(lock) 。 ECC 校驗碼被鎖上, ECC 狀態寄存器的值將不會被改變。
7) 一旦完成你就可以使用這些值來記錄到備用域或者檢測位錯誤。
接下來是代碼:
NAND-FLASH.H內容:
#ifndef __NAND_FLASH_H__ //為了防止重復包含
#define __NAND_FLASH_H__
#include "lhg_def.h" //U8,U32相關的宏,也即變量類型
#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 //這樣的結構體變量保存芯片的ID信息
{
U8 IDm; //marker code
U8 IDd; //device code
U8 ID3rd;
U8 ID4th;
U8 ID5th;
} nand_id_info;
typedef struct bad_block_info //登記壞塊用的,只記錄數量,沒有記錄壞塊地址
{
U8 area[MAX_NAND_BLOCK];//0表示非壞塊,1表示壞塊
U32 sum;//壞塊的總數
} bad_block_info;
//
//NAND 操作指令,??從哪里來的,我看你怎么用
#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) //設置cle ale的持續時間,NFCONF[14:12]
#define S3C2440_NFCONF_TWRPH0_init (4<<8) //TWRPH0持續時間設置,NFCONF[10:8]
#define S3C2440_NFCONF_TWRPH1_init (0<<4) //TWRPH1持續時間設置,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 )片選信號設置不說了啊
#define controller_enable() ( rNFCONT |= 1 )
#define controller_disable() ( rNFCONT &= ~1 )nandflash控制器使能與否也不說了
//
extern void nand_flash_init(void);//初始化,extern意思是提供給外部上層函數要調用的入口
extern int nand_block_erase(U32 num);//num要刪除的塊號,一共2048個塊,這么大變量浪費了!
extern int nand_page_write(U32 addr,U8 *buffer,U32 size);//addr要寫的起始頁地址,buffer要寫的緩存,size要寫的字節大小最大為4G,這里是針對u32說的
extern int nand_page_read(U32 addr,U8 *buffer,U32 size);//addr開始頁地址,從每頁00地址開始讀
extern int nand_random_read(U32 paddr,U32 offset,U8 *data); //隨機讀數據 paddr頁地址,offset頁內偏移地址,每次一個字節
extern int nand_random_write(U32 paddr,U32 offset,U8 data);//隨機寫,paddr頁地址,offset頁內偏移地址
extern void nand_test_bad_block(void);//測試壞塊函數,并標記在nand_bbi變量里和spare區最后一個地址(如果非0xff則為壞塊??原因是什么)
#endif
NAND-FLASH.c內容:
#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;//定義來登記壞用的全局變量
void init_nand_bbi(void)//初始化變量
{
U32 i;
nand_bbi.sum=0;
for (i=0;i nand_bbi.area[i]=0;//這里放的是塊數,針對k9f1208是2048塊
}
void nand_mask_bad_block(U32 n)//標志壞塊,n是壞塊的塊號
{
#ifdef NAND_DEBUG//宏定義的一種,尼瑪也可以寫在這里
Uart_Printf("NAND found and mask a bad block=%d .",n);
#endif
if (nand_bbi.area[n]!=1)//注意這里是對入口參數n操作的
{
nand_bbi.area[n]=1;
nand_bbi.sum++;
nand_random_write(n*64,2048+64-1,0);//每塊的第一個spare的最后一個字節,標志本塊是否為壞塊,非0xff為壞塊,頁地址計算中要看具體芯片一塊中有多少頁,例如k9f1208是32頁
}
}
int detect_nand_busy(void)//檢測是否忙
{
U32 a;
a=0;
while(!(rNFSTAT&(1<<2)))//也即RnB狀態,0表示忙
{
a++;
if (a==5000000)//等待超時
{
Uart_Printf("/r/n Error: Detect Nand Busy time out!!! /r/n");
rNFSTAT |= (1<<2);//清忙標志,1表示不忙
return -1;//錯誤返回-1,這個-1表示的是你他媽的nandflash一直忙,這里是有問題的
}
}
rNFSTAT |= (1<<2);//清忙標志,沒有超時,我給你正常設為清閑,返回值也沒問題
return 1;
}
void nand_reset(void)//復位
{
rNFCMD = NAND_CMD_RES;//?從哪里查到的NFCMD命令集合?和韋教材一樣,0xff為復位命令
detect_nand_busy();//檢測忙,?為什么復位后檢測nandflash忙不忙呢?如果忙說明程序出錯在讀寫
}
void control_start(void){ //開啟
select_nand();
controller_enable();//也即最后兩位啟用nandflash和選中nandflash
rNFSTAT |= (1<<2);//清忙標志
nand_reset();
}
void control_end(void) //關閉
{
dis_select_nand();//取消片選,關閉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可以產生ecc
}
ecc_main_end(void)//結束main ECC
{
rNFCONT |= 1<<5;//unlock,main area不可以再產生ecc 了
}
void ecc_spare_start(void)//開始spare ECC
{
// rNFCONT |= 1<<4; //initEcc
rNFCONT &= ~(1<<6); //unlock,NFCONT[6]控制spare area的ecc產生
}
void ecc_spare_end(void)//結束spare ECC,同樣道理關閉ecc的產生
{
rNFCONT |= 1<<6; //unlock
}
void __irq nandINT(void) //中斷函數
{
//此處寫處理代碼
#ifdef NAND_DEBUG
Uart_Printf("/r/n Nand Error... In interrupt now!!!");//只有錯誤才會進入中斷
#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,不是發出4個地址序列嗎????
//讀ID
nand_id.IDm=(U8)rNFDATA8;//強制轉換為8位的,制造商
nand_id.IDd=(U8)rNFDATA8; //設備代碼
nand_id.ID3rd=(U8)rNFDATA8;//保留字節
nand_id.ID4th=(U8)rNFDATA8;//多層操作代碼
nand_id.ID5th=(U8)rNFDATA8;//??不知道是什么,反正一共5個信息數據
#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();//關控制,取消片選和關閉nandflash控制器
}
int nand_block_erase(U32 num)//num要擦除的塊號
{
num=num*64;//表示要擦除的塊地址,這種nandflash每一個塊有64頁,其他的就不一定了哈哈
control_start();//開控制
nand_reset();//復位
rNFCMD = NAND_CMD_BLOCK_ERASE_1st;//0x60命令
rNFADDR = num&0xff;//需要發3個地址序列,這里有3個,非常好!!!
rNFADDR = (num>>8)&0xff;
rNFADDR = (num>>16)&0xff;
rNFCMD = NAND_CMD_BLOCK_ERASE_2st;//0xd0命令
detect_nand_busy();//看看nandflash忙不忙
rNFCMD =NAND_CMD_READ_STATUS; //讀擦出的結果狀態,命令是0x70
if (rNFDATA8&1)//如果最高位是1,下面報錯,就是說擦除這個塊沒有成功,這個得記住!
{
#ifdef NAND_DEBUG
Uart_Printf("/r/n Error:nand erase error... block=0x%x",num/64);
#endif
control_end();//關控制
nand_mask_bad_block(num/64);//登記為壞塊
return -1;//刪除錯誤返回0
}
control_end();//關控制
#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要寫的起始頁地址,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();//測試并登記壞塊
}
評論