歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux編程 >> Linux編程

怎麼看時序圖--nand flash的讀操作詳解

這篇文章不是介紹 nand flash的物理結構和關於nand flash的一些基本知識的。你需要至少了解 你手上的 nand flash的物理結構和一些諸如讀寫命令

操作的大概印象,你至少也需要看過 s3c2440中關於nand flash控制寄存器的說明。

由於本人也沒有專門學過這方面的知識,下面的介紹也是經驗之談。

這裡 我用的 K9F2G08-SCB0 這款nand flash 來介紹時序圖的閱讀。不同的芯片操作時序可能不同,讀的命令也會有一些差別

當然其實有時候像nand flash這種 s3c2440內部集成了他的控制器的外設。具體到讀寫操作的細節時序(比如 CLE/ALE的建立時間,寫脈沖的寬度。數據的建立和保持時間等),不明白前期也沒有多大的問題。

因為s3c2440內部的nand flash控制器 做了大部分的工作,你需要做的基本就是設置 幾個時間參數而已。然後nand flash會自動進行這些細節操作。

當然如果處理器上沒有集成 nand flash的控制器 那麼久必須要自己來寫時序操作了。所以了解最底層的時序操作總是好的

但是上層一點的,比如讀寫操作的步驟時序(比如讀操作,你要片選使能,然後發命令,然後發地址,需要的話還需發一個命令,然後需要等待操作完成,然後再讀書數據)。

是必須要明白的。這都不明白的話,怎麼進行器件的操作呢

也就是說 s3c2440 可以說在你設置很少的幾個時間參數後,將每一個步驟中 細微的操作都替你做好了。(比如寫命令,你只要寫個命令到相應寄存器中,cpu內部就會協各個引腳發出

適應的信號來實現寫命令的操作)。

而我們所需要做的 就是 把這些寫命令,寫地址,等待操作完成。等步驟組合起來 。從而完成一個 讀操作

就像上面說的,雖然我們不會需要去編寫每個 步驟中的最細微的時序。 但是了解下。會讓你對每個操作步驟的底層細節更加明了

先來看一個命令鎖存的時序。也就是上面說的 讀 nand flash操作中不是有一個 寫命令步驟嗎。那麼這個步驟具體是怎麼實現的。

首先 我們肯定是要片選 nand flash。只有選中芯片才能讓他工作啊

nand flash是通過 ALE/CLE (高電平有效)來區分數據線上的數據時命令(CLE有效),地址(ALE有效)還是數據(CLE/ALE都無效)。

那麼這裡既然是寫命令 那麼就一定是 CLE有效(高電平) ALE無效(低電平)

同樣命令既然是寫給nand flash的那麼 肯定有一個寫周期。我們需要注意的是,寫是在上升沿有效還是下降沿有效

時序圖如下:

1 這裡是命令鎖存是時序,那麼我們要注意的其實就只有 CLE 為高電平期間這段時序。(寫命令啊,CLE有效時(高電平)指示現在的數據其實命令)ALE此時一定為低電平我們可以不關心他

2 所以,CLE為 低電平的時期,其他大部分引腳上都是 灰色的陰影,這代表我們不需要關心這段時期這些引腳的電平

3 那麼 這個數據是什麼時候被nand flash讀取到的呢, 注意到 nWE信號 在上升沿有一個貫穿所有其他引腳時序的豎線(這好像是叫生命線?我也不清楚)

       這就是說明,寫入的數據(命令也是數據啊,只是可以通過CLE有效來區分)是在 WE的上升沿有效。

       也就是說,雖然 WE是在低電平有效,但並不是說 WE一變成低電平,命令就被鎖存了(即真正獲得命令)而是在 WE 的上升沿,命令才真正被鎖存

知道了上面這三點,也就知道了一個大概,那麼剩下的圖中也只剩那些 txx 的標號。明顯它指的是時間,但是具體指什麼時間呢。

指的就是箭頭兩邊所指的兩條 豎線之間的時間。(在每個信號的跳變沿,都有小豎線)

剩下的就是這些時間到底是代表什麼了。這裡沒什麼難的,剛接觸的覺得看不懂。是因為之前從來沒接觸過。(就像單片機剛學的時候不也是各種不懂,原因就是我們從沒接觸過)。
這些時間標號,在數據手冊的前面都有 說明

比如  tCLS  tCLH 從數據手冊中我們可以看到 分表代表的 CLE建立時間,和CLE信號保持時間。

簡單點你可以理解為,我讓 CLE引腳  變成高電平,總得給人間一點時間去變成高電平吧。總不能瞬間就變成高電平

不過從 時序圖中我們能看到更多的端倪,之前不是說過 WE 的上升沿上不是有一個最長貫穿其他信號線的 豎線嗎。我們說他指示了,數據(命令也是數據)

       是在上升沿被鎖存的,在 WE 的上升沿,我寫到數據線上的命令數據才真正被鎖存(接收),但是 我們注意到 CLE 信號在WE上升沿之前有就有效了。

       所以我們說, 在命令數據真正被鎖存之前,CLE 有效的那段 tCLS 時間叫做 CLE信號建立時間。

      WE上升沿後。命令已經被接受了,但這時候 CLE 其實可以變為無效了,因為已經獲取到命令了

       但是他並沒有立刻結束,而是 Tclh時間之後才結束。那麼我們 稱這段 時間 tCLH  CLE 保持時間


那麼再根據手冊中的說明  tCS 表示 片選信號建立時間,tCH表示片選信號保持時間

      tDS表示數據建立時間,tDH表示數據保持時間

這裡我們看到一個小規律,在數據手冊中 以 S 結尾的時間通常指的是建立時間, 以 H 結尾的時間指的是保持時間

     

     

這裡命令鎖存的時序就分析完了。我們再來看看  地址鎖存時序圖,這個圖有點復雜,

因為nand flash的 特性是 地址周期通常需要好幾個,就是一個地址是分幾次發送的

再給出數據手冊中對應時間標號的說明


同樣我們按照上面分析的步驟

1 這裡是地址鎖存是時序,那麼我們要注意的其實就只有 ALE 為高電平期間這段時序。(寫命令啊,ALE有效時(高電平)指示現在的數據其實是地址)CLE此時一定為低電平,可以不用管


2 所以,ALE 為低電平的時期,其他大部分引腳上都是 灰色的陰影,這代表我們不需要關心這段時期這些引腳的電平


3 同樣 WE 的上升沿有一個貫穿其他信號線的長豎線,這也是代表數據(這裡其實是地址)在上升沿被鎖存

那麼剩下的也好理解

tCLS 這個我們不需要關心,因為 CLE 壓根就是無效的。

tCS 就像之前分析的,它是指 CE片選信號在 WE上升沿也就是鎖存地址之前的有效時間,也就是 CE 建立時間

tWC 呢? 不知道? 不知道 看手冊啊,前面也說過這些時間標號在手冊中都會給出。

       從上面手冊的解釋我們看到,它指的是一個寫周期的時間

tWP 寫脈沖寬度(也就是 WE是低電平有限,twp指低電平持續時間,就是有效時間)

tWH 好理解了,就是高電平時間

ALS    這不就是 地址信號  ALE 建立時間嘛

ALH   ALE信號有效保持時間啊

TDS TDH 數據建立和保持時間

就像上面對 命令時序的分析,這裡 信號的 建立  保持時間都是以 數據被 鎖存分界點(WE上升沿)

看到這裡相信仔細看的人,應該大致該如何看一個時序圖了,但是這裡 我們牽涉到的 無非都是一些 上面 建立/保持時間。

復雜點的呢。

下面就來看一個復雜點的時序圖,其實也不復雜,主要是說明如何在不看手冊就能知道 txx指的是什麼時間 

 

 

 

這個時序其實並不復雜,只是他不是像上面分析的那樣都是一些 建立時間和保持時間。這裡牽涉到跟多的時間標號

不過就像前面說的. 看手冊! 手冊裡對每個時間參數都有說明。不過初學者通常即使看手冊,對這些時間參數也是不知道是什麼意思。

這裡我們看手冊前,先來自己分析下。方法會了,手冊就成了驗證你對不對的東西了,而不是你尋找答案的東西。

TRC 這個參數有點簡單。看他的范圍 是 一個 RE周期 的時間,那麼就跟前面的 tWC 應該是一樣的。那它應該代表的就是 RE信號的一個周期時間(讀信號的一個周期)

TREA 呢? 看標號看不出所以然,那麼我們就看他的起始和結束時間 從時序圖能看到,這個指的是從 RE有效(變低) 到數據出現之間的時間。

那麼tREA 可想而知就應該是 讀信號有效到數據被讀之間的時間

後面的都是這個同樣的分析方法

比如最後的那個 tRHZ 是從 RE 無效(高電平)到數據線變成高阻態 之間的時間(數據線畫在中間表示的是高阻態)

看下手冊中的解釋 也基本就是這個意思

到這裡 對於時序圖怎麼看,相信大家都應該能理解了。甚至可能連手冊都不用看,就知道他是什麼意思了。因為我們能從 時間的起始地址來推測時間標號的意思

上面這些分析,都是很底層的操作,如果我們使用 s3c2440 這種高級的處理器 這些時序操作我們根本不需要去實現,頂多也就往幾個寄存器中

設置一下上面說的一些時間 然後,CPU 中的 nand flash控制器會自動完成上面所的所有操作。但是還需要了解的原因是,如果你碰到一個沒有

nand flash 控制器的處理器 怎麼辦,那你只能親自實現這些 具體的 寫命令,寫地址。等等 單元操作。

然後才能將這些單元操作組合成 讀數據,寫數據等操作(上面說過 比如讀操作 他並不是一個簡單的命令而是一系列操作,你要片選使能,然後發命令(讀命令),

然後發地址(要讀的數據的地址),需要的話還需發一個命令,然後需要等待操作完成,然後讀書數據)

說完了 這些具體的單元操作,那麼我們再來看看一個 讀操作 具體需要哪些步驟。也就是我們需要真正必須掌握的時序操作

對於我這款 nand flash 讀操作時序如下

我們要注意的主要是 最下面一行 即 I/Ox 信號線的狀態,他指示了 讀操作需要哪些,單元步驟。

1 首先 我們看到 有一個 0x00 是什麼?數據?地址?命令?  ALE/CLE線啊,這兩根線不是決定了現在的數據的類型嘛

       順著往上看,我們知道0x00是在 CLE有效期間的數據那麼它就是一個命令

2 然後是 address(5Cycle) 即五個地址序列(這款nand flash 指定讀數據的地址時要發送五個地址序列),往上看,是在ALE有效期間的數據,那麼應該就是地址了

       (對於這五個地址,前面兩個是列地址,後面三個是行地址。在nand flash的物理結構中 行地址對應的某一頁,列地址就對應這一頁中的某一列)

3 接著又是 0x30,此時 CLE有效,那麼就是命令了(也就是說這款nand flash的讀操作需要兩個命令)。

       但是之後數據並未立刻出來,我們看到在到 DATA Output即數據輸出之前還有一段時間,為什麼有這段時間?

       往上看 R/nB 這個數據線上說明了原因,這段時間內它是低電平 即指示現在 處於 忙碌狀態,還未准備好數據輸出。為什麼會這樣?

       因為你 寫了 一個命令,寫了要讀數據的地址,又寫了一個命令。 你總要給 cpu一些時間去處理這些命令吧,

       R/nB為低電平這段時間就是 在處理這些命令(實際上是根據命令將你定位的那一頁數據讀到內部寄存器中),

        R/nB變成高電平了,就指示命令處理完畢,現在數據也就可以讀出來了

綜上我們從手冊中我們就知道了讀操作的具體步驟,

1 首先nand flash 也是一個外設,要訪問他就需要片選它,所以在執行時序圖上的步驟之前需要片選nand flash.

2 看後面就是安裝時序圖來了,看時序圖! 第一步先是發送一個命令 0x00.

3 看時序圖! 然後發送五個地址序列(先發送兩個列地址,在發送三個行地址(即頁地址))

4 看時序圖! 接著再是一個命令 0x30.

5 看時序圖!  R/nB 引腳為低表示現在正忙,正在處理這些命令,那就要等待 R/nB 引腳變為高電平

6 看時序圖! 這個時候就可以讀數據了

7 一次讀操作結束了 nand flash 暫時是不需要使用了,那麼別忘了應該 取消片選信號。

至於這每一個步驟中具體的時序,cpu中的nand flash控制器會幫我們完成。我們要做就是設置幾個時間參數

這裡我們反復強調了要看時序圖。其實學嵌入式前期對數據手冊一定要多看,看多了你就回知道,什麼東西的你重點要看的,什麼是和你的編程操作無關的你不需要關心。這樣後面你才能,拿到一個外設 就能寫出他的操作。而不用跟著書背步驟。只要手冊在就行了。

上面的步驟,是一個具體的讀操作的步驟,不過在使用一個器件之前我們需要初始化一下它。至於初始化也就是設置我們上面多次提到的

我們說過 s3c2440已經幫我做了很多底層的單元操作,我們只需設置幾個時間參數 片內的 nand flash就會自動發出相應操作的時序操作

那麼到底設置那幾個時間呢。 

s3c2440 手冊上給出了 需要我們設置的幾個參數。

 

 

 

從中我們可以看出 第一幅時序圖是 命令和地址鎖存的時序,第二幅是 數據讀取和寫入的時序。
可以看出,他們要設置的時間都是一樣的。前面分析了那麼多,這裡應該不難 看出


1 TACLS 很明表示的是 CLE/ALE 的建立時間(這裡並不准確,其實是 CLE/ALE有效到 WE 變成低電平之間的時間,但 WE 卻是在上升沿才鎖存命令/地址)

2 TWRPH0 代表的是 WE 的脈沖寬度,即有效時間

3 TWRPH1 代表的是 CLE/ALE 的保持時間


那到底設置成什麼數字呢。既然 上圖中讀/寫/命令/地址 操作需要的時間參數都是一樣的

那麼我們從 nand flash中隨便找一個 命令時序來對照不就行了

就拿上面我們說過的 命令鎖存時序來對比


那麼我們就能得到下面的關系

TWRPH0 = tWP 

TWRPH1 = tCLH

TACLS  = tCLS - tWP

 
然後設置成多少呢? 看手冊啊,手冊中對 tWP  tCLH  tCLS 都會至少給出 需要的最小時間


這款芯片nand flash手冊中這三個參數要求是

 

所以 TWRPH0 = tWP  >=12ns

       TWRPH1 = tCLH >=5ns

       TACLS  = tCLS - tWP >=0;

而這三個參數在s3c2440的數據手冊中說明為

 

當然這裡的時間都是以 HCLK 為單位的,這幾個參數 是在 nand flash控制寄存器中的 NFCONF中設置的

這裡我沒用使用MPLL 所以HCLK是 12MHZ

所以 TWRPH0 = 0 TWRPH1 =0 TACLS =0; (如果你的時鐘頻率比較高,那就要設別的數了。當然有是有你真不知道,設置大點總沒錯,只不過速度可能會慢點。)

       所以 NFCONF =0;(NOFCONF其他位數據手冊中有說明,這裡只是簡單讀操作,其他位可以不設置)

然後是初始化一下 ECC 使能nand flash控制器(我們只是設置了幾個時間參數,時序的具體操作就是靠他來完成的,所以要使能他)

然後先 取消片選nand flash 因為我們現在還沒有操作它啊,只是初始化一下。所以還是應該先取消片選,等真正讀的時候再使能片選信號

NFCONT = (1<<4) | (1<<1) (1<<0);

(數據手冊中有對應位的說明)

最後,第一次使用nand flash 我們需要復位操作一下。

綜上,nand flash 的初始化代碼如下

void nand_init(void){

        NFCONF =0;

        NFCONT = (1<<4) | (1<<1) | (1<<0);

        nand_reset();  //nand reset代碼在後面

}

下面代碼一些地址的寫法是與 nand flash 型號有關的。具體需要參考芯片手冊

     

void select_chip(void){

        NFCONT  &= (~(1<<1)) ;   

        int i;

        for(i=10;i>0;i--);

}

void deselect_chip(void){

        NFCONT |= (1<<1);

        int i;

        for(i=10;i>0;i--);

}

void write_command(unsigned char command){

        NFCMMD = command;

        int i;

        for(i=10;i>0;i--);

}

/*

       這款nand flash 的頁大小是 2K

       五個地址周期  (2個列地址 和3和行地址(頁地址))

*/

void write_address(unsigned int address){

        unsigned int page = address/2048;

        unsigned int col  = address&2048;

        int i;

        NFADDR = col & 0xff;

        for(i=5;i>0;i--);

        NFADDR = (col >>8) & 0x0f;

        for(i=5;i>0;i--);

        NFADDR = page & 0xff;

        for(i=5;i>0;i--);

        NFADDR = (page >>8)& 0xff;

        for(i=5;i>0;i--);

        NFADDR = (page >>16)&0x01;

        for(i=5;i>0;i--);

}

unsigned char read_one_data(void){

        return NFDATA;

        int i;

        for(i=10;i>0;i--);

}

void wait_ready(void){

        while(!(NFSTAT & 1));

        int i;

        for(i=10;i>0;i--);

}

static void nand_reset(void){

        select_chip();

        write_command(0xff);

        wait_ready();

        deselect_chip();

}

void nand_init(void){

        NFCONF =0;

        NFCONT = (1<<4) | (1<<1) | (1<<0);

        nand_reset();

}

/*

nand flash 的讀操作是以頁為單位的。

 des: nand flash中讀出的數據放到哪

 start_addr: 從哪裡開始讀

 size: 讀多大

*/

void nand_read(unsigned char *des,unsigned int start_addr,unsigned int size){

        unsigned int col  = start_addr & 2048;

        select_chip();

        unsigned int start = start_addr;

        unsigned int end  = start_addr + size;

        while(start < end){                            //每讀一頁需要發一次命令

               write_command(0x00);

                write_address(start);

                write_command(0x30);

                wait_ready();

                while((col<2048) && (start<end)){  //在一頁中讀,我用的型號一頁大小為2K

                        *des = read_one_data();

                        des++;

                        col++;

                        start++;

                }

                col =0;

        }

        deselect_chip();

}

Copyright © Linux教程網 All Rights Reserved