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

奔跑的路發表於2015-10-24

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

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


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

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

當然其實有時候像nandflash這種 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無效(低電平)

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

時序圖如下:

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 控制器的處理器 怎麼辦,那你只能親自實現這些 具體的 寫命令,寫地址。等等 單元操作。

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

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

 

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

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

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

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

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

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

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

 

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 的保持時間


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

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

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


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

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 = 0TWRPH1 =0 TACLS =0; (如果你的時脈頻率比較高,那就要設別的數了。當然有是有你真不知道,設定大點總沒錯,只不過速度可能會慢點。)

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

 

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

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

 

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

(資料手冊中有對應位的說明)

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

綜上,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,unsignedint 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在一頁中讀,我用的型號一頁大小為2K

                        *des = read_one_data();

                       des++;

                        col++;

                        start++;

                }

                col =0;

       }

       deselect_chip();

}

相關文章