Nand Flash驅動(實現初始化以及讀操作)


 

 

本節來學習裸機下的Nand Flash驅動,本節學完后,再來學習Linux下如何使用Nand Flash驅動

 

 

 

Linux中的Nand Flash驅動,鏈接如下:

 

(分析MTD層以及制作Nand Flash驅動鏈接:http://www.cnblogs.com/lifexy/p/7701181.html)

 

 


 

本節簡單制作一個Nand Flash驅動(只需要初始化Flash以及讀Flash)

打開2440芯片手冊,K9F2G08U0M芯片手冊(因為2440中Nand Flash是用的256MB(2Gb)內存,8個數據引腳)

在芯片手冊中得到K9F2G08U0M=2048塊Block=128K頁Pages=256MB=2Gb            

1個設備=2048塊Block

1塊Block=64頁Pages

1頁=(2K+64)B            (因為每個地址里都存放了一個字節,所以用B表示)

其中64B是存放ECC的OOB地址,(ECC:存放判斷位反轉的校驗碼)

 

Nand Flash 缺點:

讀數據容易位反轉

可以通過ECC編碼器值來判斷讀數據是否位反轉,若位反轉則重新讀數據

寫過程:

  • 1)寫頁數據
  • 2)然后生成ECC
  • 3)將ECC寫入到OBB頁地址里(寫數據是不會出現位反轉)

讀過程:

  • 1)讀出頁數據,然后生成臨時ECC(此時ECC可能有錯)
  • 2)然后讀出OOB頁地址里的ECC
  • 3)比較兩個ECC,判斷是否出現位反轉

讀OOB方法:

讀整個Nand Flash時,是讀不出頁里面的OBB地址,比如讀2049這個地址數據時,是讀的第二頁上的第2個地址:

 

只有讀某一頁時,才能讀出這個頁里面的OOB地址, 比如讀第0頁的2049這個地址數據時,才是讀的第0頁OOB的第2個地址:

 

Nand Flash芯片硬件引腳圖:

 

  • RnB:就緒(ready)/忙(busy)輸出信號,需要采用上拉電阻(1:表示寫入數據成功,0:表示正在寫入)
  • CLE:命令(command)鎖存(latch)使能,(1:表示當前傳的是命令值)
  • ALE:地址鎖存使能,(1:表示當前傳的是地址值,當CLE=0和ALE=0,表示傳的是數據)
  • nCE:芯片使能(低電平使能)               (n:表示低電平有效)
  • nWE:寫使能 ,比如寫命令時,當CLE=1,ALE=0時,當nWE來個上升沿,則會將IO數據寫入flash中
  • nRE:讀使能,和we類似
  • nWP:寫保護(protect) (1:不保護,0:只能讀不能寫),默認接高電平.

1.編寫nand_init()函數

1.1設置通信時序 

 圖1(nandflash時序表):

 

圖2(nandflash時序圖):

 

 

通過圖2和圖1可以看出:

tCS是等待芯片使能CE的時間, tCS=20nS

tCLS和tALS是等待WE(寫信號)結束的時間, tCLS=tALS=15nS

tWP是WE(寫信號)維持時間,  tWP=15nS

 tALH是等待命令寫入成功的時間, tALH=5nS

 

tCLH是等待地址寫入成功的時間, tCLH=5nS

 

圖3(2440-nandflash時序圖):

 

首先查看2440芯片手冊里nandflash時序圖,如上圖,可以看出需要設置TACLS,TWRPH0TWRPH1,這三個參數

TACLS:屬於等待WE(寫信號)就緒的時間,對比圖2得出TACLS= tCLS- tWP=0nS

TWRPH0:屬於WE(寫信號)的時間, 對比圖2得出TWRPH0= tWP=15nS

TWRPH1:屬於等待命令寫入成功的時間,對比圖2得出TWRPH1=tALH=tCLH=5nS

最后,在NFCONF寄存器中設置這三個參數

TACLS[13:12] 

表示Duration(持續時間)=HCLK*TACLS,由於Duration=0nS,所以TACLS=0

TWRPH0 [10:8] 

表示Duration(持續時間)=HCLK*( TWRPH0+1),由於Duration=15nS,HCLK=10nS(100Mhz),所以TWRPH0 =1.

TWRPH1 [6:4] 

表示Duration(持續時間)= HCLK*( TWRPH1 +1),由於Duration=5nS,HCLK=10nS(100Mhz),所以TWRPH1 =0

1.2然后定義全局變量,並實現nand_init()初始化:


/* nand flash 時序 */
#define
TACLS 0 #define TWRPH0 1 #define TWRPH1 0 /* nand flash 寄存器 */ #define NFCONF *((unsigend int *)0X4E000000); //配置寄存器(用來設置時序) #define NFCONT *((unsigend int *)0X4E000000); //控制寄存器(用來使能nandflash控制器以及ECC編碼器,還有控制芯片使能CE腳) #define NFCMMD *((unsigend char *)0X4E000000);//發送命令寄存器(命令只有8位) #define NFADDR *((unsigend char *)0X4E000000);//發送地址寄存器(地址只有8位) #define NFDATA *((unsigend int *)0X4E000000);//讀/寫數據寄存器(數據只有8位) #define NFSTAT *((unsigend int *)0X4E000000);//運行狀態寄存器(用於判斷RnB腳) /*因為Nand Flash只有8位I/O腳,所以NFCMMD/ NFADDR/ NFDATA三個寄存器值都是unsigend char型 */

1.3 nand_init()函數初始化

void nand_init(void)
{

 /* 設置時序 */
NFCONF = (TACLS<<12)|(TWRPH0<<8)|(TWRPH1<<4);

/* bit4=1:初始化ECC,  bit1=1:禁止片選  bit0=1:啟動nandflash控制器*/    
NFCONT = (1<<4)|(1<<1)|(1<<0);

}

2編寫nand_read()函數

2.1編寫nand_read()函數需要以下幾個子函數:

2.1.1片選使能函數(在讀寫FLASH之前都要選中片選)

nand_select()               //使能片選
{
int i;
NFCONT&=~(1<<1);        // NFCONT控制器位1置0
for(i=0;i<10;i++);           //等待芯片使能成功
}

2.1.2取消片選函數(退出讀寫FLASH時需要取消片選)

nand_deselect()                 //取消片選
{
int i;
NFCONT&=~(1<<1);        // NFCONT控制器位1置0
for(i=0;i<10;i++);           //等待芯片使能成功
}

2.1.3讀命令函數

nand_cmd(unsigned char cmd)                 
{
int i;
NFCMMD= cmd;        // 向NFCMMD寄存器寫入命令
for(i=0;i<10;i++);        //等待寫入命令成功
}

2.1.4判斷RnB狀態函數(在寫入所有命令后都要判斷RnB腳是否為高電平就緒)

nand_waite_idle()                 
{
int i;
while(!(NFSTAT&0X01))       // 等待NFSTAT寄存器位0置1
for(i=0;i<10;i++);         
}

2.1.5讀數據函數

nand_read_data()                 
{
 unsigend char  p=NFDATA;    //讀取NFDATA寄存器
 return p;                   //返回
}

2.1.6 編寫寫入地址函數 (分5個周期)

首先Nand Flash引腳只有8位,然而地址共有2048(塊)*64(頁)*2KB,為了讀出多個地址,如下圖,所以需要分5個周期來實現發送地址

 

如上圖,其中  A10~A0對應頁大小(列),由於nandflash每頁2048B,所以只用到A10~A0

A28~A11對應頁目錄(行),表示共有2048塊*64(每塊有64頁)個目錄

例如,4097 地址就是:

  A10~A0=4097%2048= 1(A0=1,其余為0)

 A28~A11=4097/2048=2(A13=1,其余為0)

所以nand_write_nand()函數如下:

void nand_read_addr(unsigned int addr)
{

   unsigned int col  = addr % 2048;
   unsigned int page = addr / 2048;
volatile int i;

   NFADDR=(col>>0)&0xff;           //A7~A0,第1周期
for(i=0;i<10;i++);

   NFADDR=(col>>8)&0x0f;           //A10~A8,第2周期
   for(i=0;i<10;i++);

   NFADDR=(page>>0)&0xff;          //A18~A11,第3周期
   for(i=0;i<10;i++);

   NFADDR=(page>>8)&0xff;          //A26~A19,第4周期
   for(i=0;i<10;i++);

   NFADDR=(page>>16)&0xff;         //A27~A28,第5周期
   for(i=0;i<10;i++);  
}

2.2Nand Flash命令圖:

如上圖,例如:當要reset復位nand flash時


1)      使能片選nand_select();

2)      發送0XFF復位命令nand_cmd(0xFF);

3)      等待RnB狀態是否就緒 nand_wait_idle();

4)      取消片選 nand_deselect();


 

2.3Nand Flash讀數據時序圖:

 

從上圖可以看出nand flash 讀數據分為了以下幾個步驟:


(1)      使能片選CE,將CLE置1,等待發送命令

(2)      將WE置低,將IO置為0X00,然后拉高WE,觸發一次上升沿,則將把0x00寫入flash中

(3)      將CLE置0,表示發送地址(分為5個周期)

(4)      發送讀命令0X30

(5)     等待RnB信號為高電平

(6)     讀數據

(在同一頁里,數據可以連續讀,讀下一頁時,需要重新發送新的地址才行例如:讀1000地址到2050地址時,

1.發出1000地址,到達頁0的1000地址上,然后再連續讀(2048-1000)次,直到讀到頁0的2047處.

2.再發出2048地址,到達頁1的0地址上,然后連續讀(2051-2048)次,直到讀到2050為止)

(7)     取消片選nCE


 

 

2.4 所以nand_read()函數如下:

void nand_read(unsigned int  src,unsigned char  *dest,unsigned int  len)
/* src:源地址,為32位地址,所以用unsigend int表示
*dest:目的地址內容,由於這里是將數據讀出到目的地址內容中,所以需要用到*指針,因為每個地址里存的是一個字節,所以用unsigend char 型    */
{

int col=src%2048;      //第一次讀,可能不是讀的頁首地址,所以需要記錄當前頁的位置

int i=0;                //當前讀了0次

nand_select();           //1使能片選nCE     

while(i<len)

 { nand_cmd(0X00);        //2發送讀命令0X00  

   nand_write_addr(src);     // 3發送yuan地址(分為5個周期)

   nand_cmd(0X30);        //4發送讀命令0X30    

   nand_wait_idle();       //5等待RnB信號為高電平

   for(;(col<2048)&&(i<len);col++)      //連續讀頁內數據

   {dest[i]=nand_read_data();            //6.讀數據

    i++;            
src
++;} col=0;} nand_deselect(); // 取消片選nCE }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM