嵌入式bootloader開發之八----NAND Flash讀寫擦除操作實現(Tiny 6410)
概要:
本節主要記錄開發Tiny6410自帶的NAND FLASH的過程,實現了NAND FLASH的擦除,讀寫資料功能,但都只是簡單的實現而已,並沒有做精細而完整的實現,畢竟只是想學原理。
前言:
工欲善其事,必先利其器。在做開發之前,必須保證良好的環境和裝置,筆者所使用的tiny6410光碟中自帶的uboot版本比較老,而且其並不支援MLC2的讀寫操作,但是之前並不知道,寫了很多次,但是總是寫不到NAND FLASH中去,還以為是NAND FLASH裝置的壞塊太多,各種原因各種奇葩猜想,還好,最後時刻想起了友善之臂的官網,無意間看到了uboot的某一版的發行註釋中寫著實現了MLC2的讀寫,啊。。。。。有點怒了。。。。竟然是使用的uboot的問題,立即馬上下載,然後燒錄進去,重寫NAND FLASH,寫入成功!!!
為了方便,現將新版的uboot和System.map檔案共享出來,版權屬於友善之臂公司。
uboot-ram256M nand-flash版:uboot
詳細的有關NAND FLASH裝置的介紹以及一些常識請自行百度或者直接查閱S3C6410資料手冊和相應的NAND FLASH資料手冊,本文中以Tiny6410中使用的三星公司產的MLC的NAND FLASH晶片K9GAG08U0E(2GB MLC)為例。
具體NAND FLASH的介面電路如下:
LDATA0~LDATA7是I/O口,傳輸資料、命令或者地址
FWEn:NAND FLASH寫資料訊號,低有效
FREn:NAND FLASH讀資料訊號,低有效
FCLE:命令鎖存訊號
FALE:地址鎖存訊號
RnB:忙或準備好狀態標誌位
S3C6410本身整合有NAND FLASH控制器,若要使用只需進行相應的配置即可。
相關的暫存器如下:
//nand flash K9GAG08U0E #define Base 0x70200000 #define NFCONF (*(volatile unsigned long *)(Base + 0x00)) #define NFCONT (*(volatile unsigned long *)(Base + 0x04 )) #define NFCMMD (*(volatile unsigned char *)(Base + 0x08 )) #define NFADDR (*(volatile unsigned char *)(Base + 0x0c)) #define NFDATA (*(volatile unsigned char *)(Base + 0x10))
#define NFSTAT (*(volatile unsigned long *)(Base + 0x28))
NAND FLASH controller的初始化主要有:
1.初始化NFCONF,配置TACLS 、TWRPH0、TWRPH1 等。
2.初始化NFCONT,使能NAND FLASH控制器
具體程式碼如下:
void nand_init(){
reset();//無關緊要,要不要都可以
NFCONF &=~((0x7<<4)|(0x7<<8)|(0x7<<12)|(1<<30));
NFCONF |=((TACLS<<12)|(TWRPH0<<8)|(TWRPH1<<4));
NFCONT |= 1 ;// enable controller
}
讀操作的流程如下:
1.片選有效
2.傳送命令0x00H
3.傳送地址訊號
4.傳送命令0x30h
5.檢測ready/busy狀態標誌位,若不忙,讀取指定位元組的資料
6.拉高片選訊號,使無效
具體程式碼實現如下:
void nand_read(unsigned long addr,char *buf,int len)
{
NFCONT &= ~(1<<1);//片選有效
NFCMMD = 0x00; //read 1 circle
get_addr(addr);
NFCMMD = 0x30;//read 2 circle
volatile int i;
while(!(NFSTAT & 1)) //wait until ready
;
for(i=0;i<PAGE_SIZE;++i)//read a page
buf[i]=NFDATA;
NFCONF |= (1<<1);//拉高
}
寫操作的流程如下:
1.片選有效
2.傳送命令0x80
3.傳送地址訊號
4.傳送命令0x10
5.檢測ready/busy狀態標誌位,若不忙,讀取指定位元組的資料
6.拉高片選訊號,使無效
具體程式碼實現如下:
void nand_write(unsigned long addr,char *buf,int len)
{
volatile int i;
NFCONT &= ~(1<<1);//片選有效
NFCMMD = 0x80; //write 1 circle
get_addr(addr);
for(i=0;i<len;++i)//write a page
NFDATA=buf[i];
for(i=len;i<PAGE_SIZE;++i)
NFDATA = 0xff;
NFCMMD = 0x10;//write 2 circle
while(!(NFSTAT & 1)) //wait until ready
;
show("nand write ok!\n");
NFCONF |= (1<<1);//拉高
}
擦除操作的流程如下:
1.片選有效
2.傳送命令0x60
3.傳送地址訊號(注意這裡的地址是頁號)
4.傳送命令0xd0
5.檢測ready/busy狀態標誌位,若不忙,讀取指定位元組的資料
6.拉高片選訊號,使無效
void nand_erase(unsigned long addr)
{
volatile int i,row;
NFCONT &= ~(1<<1);//片選有效
NFCMMD = 0x60; //write 1 circle
row = addr / PAGE_SIZE;
NFADDR = row &0xff;
NFADDR =(row>>8) &0xff;
NFADDR = (row>>16) & 0xff;
NFCMMD = 0xd0;//write 2 circle
while(!(NFSTAT & 1)) //wait until ready
;
show("nand erase ok!\n");
NFCONF |= (1<<1);//拉高
}