1. 程式人生 > >嵌入式bootloader開發之八----NAND Flash讀寫擦除操作實現(Tiny 6410)

嵌入式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);//拉高
}