這篇文章不是介紹 nand flash的物理結(jié)構(gòu)和關(guān)于nand flash的一些基本知識(shí)的。你需要至少了解 你手上的 nand flash的物理結(jié)構(gòu)和一些諸如讀寫命令
操作的大概印象,你至少也需要看過 s3c2440中關(guān)于nand flash控制寄存器的說明。
由于本人也沒有專門學(xué)過這方面的知識(shí),下面的介紹也是經(jīng)驗(yàn)之談。
這里 我用的 K9F2G08-SCB0 這款nand flash 來介紹時(shí)序圖的閱讀。不同的芯片操作時(shí)序可能不同,讀的命令也會(huì)有一些差別。
當(dāng)然其實(shí)有時(shí)候像nand flash這種 s3c2440內(nèi)部集成了他的控制器的外設(shè)。具體到讀寫操作的細(xì)節(jié)時(shí)序(比如 CLE/ALE的建立時(shí)間,寫脈沖的寬度。數(shù)據(jù)的建立和保持時(shí)間等),不明白前期也沒有多大的問題。
因?yàn)閟3c2440內(nèi)部的nand flash控制器 做了大部分的工作,你需要做的基本就是設(shè)置 幾個(gè)時(shí)間參數(shù)而已。然后nand flash會(huì)自動(dòng)進(jìn)行這些細(xì)節(jié)操作。
當(dāng)然如果處理器上沒有集成 nand flash的控制器 那么久必須要自己來寫時(shí)序操作了。所以了解最底層的時(shí)序操作總是好的
但是上層一點(diǎn)的,比如讀寫操作的步驟時(shí)序(比如讀操作,你要片選使能,然后發(fā)命令,然后發(fā)地址,需要的話還需發(fā)一個(gè)命令,然后需要等待操作完成,然后再讀書數(shù)據(jù))。
是必須要明白的。這都不明白的話,怎么進(jìn)行器件的操作呢
也就是說 s3c2440 可以說在你設(shè)置很少的幾個(gè)時(shí)間參數(shù)后,將每一個(gè)步驟中 細(xì)微的操作都替你做好了。(比如寫命令,你只要寫個(gè)命令到相應(yīng)寄存器中,cpu內(nèi)部就會(huì)協(xié)各個(gè)引腳發(fā)出
適應(yīng)的信號(hào)來實(shí)現(xiàn)寫命令的操作)。
而我們所需要做的 就是 把這些寫命令,寫地址,等待操作完成。等步驟組合起來 。從而完成一個(gè) 讀操作
就像上面說的,雖然我們不會(huì)需要去編寫每個(gè) 步驟中的最細(xì)微的時(shí)序。 但是了解下。會(huì)讓你對(duì)每個(gè)操作步驟的底層細(xì)節(jié)更加明了
先來看一個(gè)命令鎖存的時(shí)序。也就是上面說的 讀 nand flash操作中不是有一個(gè) 寫命令步驟嗎。那么這個(gè)步驟具體是怎么實(shí)現(xiàn)的。
首先 我們肯定是要片選 nand flash。只有選中芯片才能讓他工作啊
nand flash是通過 ALE/CLE (高電平有效)來區(qū)分?jǐn)?shù)據(jù)線上的數(shù)據(jù)時(shí)命令(CLE有效),地址(ALE有效)還是數(shù)據(jù)(CLE/ALE都無效)。
那么這里既然是寫命令 那么就一定是 CLE有效(高電平) ALE無效(低電平)。
同樣命令既然是寫給nand flash的那么 肯定有一個(gè)寫周期。我們需要注意的是,寫是在上升沿有效還是下降沿有效。
時(shí)序圖如下:
1 這里是命令鎖存是時(shí)序,那么我們要注意的其實(shí)就只有 CLE 為高電平期間這段時(shí)序。(寫命令啊,CLE有效時(shí)(高電平)指示現(xiàn)在的數(shù)據(jù)其實(shí)命令)ALE此時(shí)一定為低電平我們可以不關(guān)心他
2 所以,CLE為 低電平的時(shí)期,其他大部分引腳上都是 灰色的陰影,這代表我們不需要關(guān)心這段時(shí)期這些引腳的電平
3 那么 這個(gè)數(shù)據(jù)是什么時(shí)候被nand flash讀取到的呢, 注意到 nWE信號(hào) 在上升沿有一個(gè)貫穿所有其他引腳時(shí)序的豎線(這好像是叫生命線?我也不清楚)
這就是說明,寫入的數(shù)據(jù)(命令也是數(shù)據(jù)啊,只是可以通過CLE有效來區(qū)分)是在 WE的上升沿有效。
也就是說,雖然 WE是在低電平有效,但并不是說 WE一變成低電平,命令就被鎖存了(即真正獲得命令)而是在 WE 的上升沿,命令才真正被鎖存。
知道了上面這三點(diǎn),也就知道了一個(gè)大概,那么剩下的圖中也只剩那些 txx 的標(biāo)號(hào)。明顯它指的是時(shí)間,但是具體指什么時(shí)間呢。
指的就是箭頭兩邊所指的兩條 豎線之間的時(shí)間。(在每個(gè)信號(hào)的跳變沿,都有小豎線)
剩下的就是這些時(shí)間到底是代表什么了。這里沒什么難的,剛接觸的覺得看不懂。是因?yàn)橹皬膩頉]接觸過。(就像單片機(jī)剛學(xué)的時(shí)候不也是各種不懂,原因就是我們從沒接觸過)。
這些時(shí)間標(biāo)號(hào),在數(shù)據(jù)手冊(cè)的前面都有 說明
比如 tCLS tCLH 從數(shù)據(jù)手冊(cè)中我們可以看到 分表代表的 CLE建立時(shí)間,和CLE信號(hào)保持時(shí)間。
簡(jiǎn)單點(diǎn)你可以理解為,我讓 CLE引腳 變成高電平,總得給人間一點(diǎn)時(shí)間去變成高電平吧。總不能瞬間就變成高電平
不過從 時(shí)序圖中我們能看到更多的端倪,之前不是說過 WE 的上升沿上不是有一個(gè)最長(zhǎng)貫穿其他信號(hào)線的 豎線嗎。我們說他指示了,數(shù)據(jù)(命令也是數(shù)據(jù))
是在上升沿被鎖存的,在 WE 的上升沿,我寫到數(shù)據(jù)線上的命令數(shù)據(jù)才真正被鎖存(接收),但是 我們注意到 CLE 信號(hào)在WE上升沿之前有就有效了。
所以我們說, 在命令數(shù)據(jù)真正被鎖存之前,CLE 有效的那段 tCLS 時(shí)間叫做 CLE信號(hào)建立時(shí)間。
WE上升沿后。命令已經(jīng)被接受了,但這時(shí)候 CLE 其實(shí)可以變?yōu)闊o效了,因?yàn)橐呀?jīng)獲取到命令了
但是他并沒有立刻結(jié)束,而是 Tclh時(shí)間之后才結(jié)束。那么我們 稱這段 時(shí)間 tCLH 為 CLE 保持時(shí)間。
那么再根據(jù)手冊(cè)中的說明 tCS 表示 片選信號(hào)建立時(shí)間,tCH表示片選信號(hào)保持時(shí)間
tDS表示數(shù)據(jù)建立時(shí)間,tDH表示數(shù)據(jù)保持時(shí)間
這里我們看到一個(gè)小規(guī)律,在數(shù)據(jù)手冊(cè)中 以 S 結(jié)尾的時(shí)間通常指的是建立時(shí)間, 以 H 結(jié)尾的時(shí)間指的是保持時(shí)間
這里命令鎖存的時(shí)序就分析完了。我們?cè)賮砜纯?nbsp; 地址鎖存時(shí)序圖,這個(gè)圖有點(diǎn)復(fù)雜,
因?yàn)閚and flash的 特性是 地址周期通常需要好幾個(gè),就是一個(gè)地址是分幾次發(fā)送的
再給出數(shù)據(jù)手冊(cè)中對(duì)應(yīng)時(shí)間標(biāo)號(hào)的說明
同樣我們按照上面分析的步驟
1 這里是地址鎖存是時(shí)序,那么我們要注意的其實(shí)就只有 ALE 為高電平期間這段時(shí)序。(寫命令啊,ALE有效時(shí)(高電平)指示現(xiàn)在的數(shù)據(jù)其實(shí)是地址)CLE此時(shí)一定為低電平,可以不用管
2 所以,ALE 為低電平的時(shí)期,其他大部分引腳上都是 灰色的陰影,這代表我們不需要關(guān)心這段時(shí)期這些引腳的電平
3 同樣 WE 的上升沿有一個(gè)貫穿其他信號(hào)線的長(zhǎng)豎線,這也是代表數(shù)據(jù)(這里其實(shí)是地址)在上升沿被鎖存
那么剩下的也好理解
tCLS 這個(gè)我們不需要關(guān)心,因?yàn)?CLE 壓根就是無效的。
tCS 就像之前分析的,它是指 CE片選信號(hào)在 WE上升沿也就是鎖存地址之前的有效時(shí)間,也就是 CE 建立時(shí)間
tWC 呢? 不知道? 不知道 看手冊(cè)啊,前面也說過這些時(shí)間標(biāo)號(hào)在手冊(cè)中都會(huì)給出。
從上面手冊(cè)的解釋我們看到,它指的是一個(gè)寫周期的時(shí)間
tWP 寫脈沖寬度(也就是 WE是低電平有限,twp指低電平持續(xù)時(shí)間,就是有效時(shí)間)
tWH 好理解了,就是高電平時(shí)間
ALS 這不就是 地址信號(hào) ALE 建立時(shí)間嘛
ALH ALE信號(hào)有效保持時(shí)間啊
TDS TDH 數(shù)據(jù)建立和保持時(shí)間
就像上面對(duì) 命令時(shí)序的分析,這里 信號(hào)的 建立 和 保持時(shí)間都是以 數(shù)據(jù)被 鎖存分界點(diǎn)(WE上升沿)
看到這里相信仔細(xì)看的人,應(yīng)該大致該如何看一個(gè)時(shí)序圖了,但是這里 我們牽涉到的 無非都是一些 上面 建立/保持時(shí)間。
復(fù)雜點(diǎn)的呢。
下面就來看一個(gè)復(fù)雜點(diǎn)的時(shí)序圖,其實(shí)也不復(fù)雜,主要是說明如何在不看手冊(cè)就能知道 txx指的是什么時(shí)間
這個(gè)時(shí)序其實(shí)并不復(fù)雜,只是他不是像上面分析的那樣都是一些 建立時(shí)間和保持時(shí)間。這里牽涉到跟多的時(shí)間標(biāo)號(hào)
不過就像前面說的. 看手冊(cè)! 手冊(cè)里對(duì)每個(gè)時(shí)間參數(shù)都有說明。不過初學(xué)者通常即使看手冊(cè),對(duì)這些時(shí)間參數(shù)也是不知道是什么意思。
這里我們看手冊(cè)前,先來自己分析下。方法會(huì)了,手冊(cè)就成了驗(yàn)證你對(duì)不對(duì)的東西了,而不是你尋找答案的東西。
TRC 這個(gè)參數(shù)有點(diǎn)簡(jiǎn)單。看他的范圍 是 一個(gè) RE周期 的時(shí)間,那么就跟前面的 tWC 應(yīng)該是一樣的。那它應(yīng)該代表的就是 RE信號(hào)的一個(gè)周期時(shí)間(讀信號(hào)的一個(gè)周期)
TREA 呢? 看標(biāo)號(hào)看不出所以然,那么我們就看他的起始和結(jié)束時(shí)間 從時(shí)序圖能看到,這個(gè)指的是從 RE有效(變低) 到數(shù)據(jù)出現(xiàn)之間的時(shí)間。
那么tREA 可想而知就應(yīng)該是 讀信號(hào)有效到數(shù)據(jù)被讀之間的時(shí)間
后面的都是這個(gè)同樣的分析方法
比如最后的那個(gè) tRHZ 是從 RE 無效(高電平)到數(shù)據(jù)線變成高阻態(tài) 之間的時(shí)間(數(shù)據(jù)線畫在中間表示的是高阻態(tài))
看下手冊(cè)中的解釋 也基本就是這個(gè)意思
到這里 對(duì)于時(shí)序圖怎么看,相信大家都應(yīng)該能理解了。甚至可能連手冊(cè)都不用看,就知道他是什么意思了。因?yàn)槲覀兡軓?時(shí)間的起始地址來推測(cè)時(shí)間標(biāo)號(hào)的意思
上面這些分析,都是很底層的操作,如果我們使用 s3c2440 這種高級(jí)的處理器 這些時(shí)序操作我們根本不需要去實(shí)現(xiàn),頂多也就往幾個(gè)寄存器中
設(shè)置一下上面說的一些時(shí)間 然后,CPU 中的 nand flash控制器會(huì)自動(dòng)完成上面所的所有操作。但是還需要了解的原因是,如果你碰到一個(gè)沒有
nand flash 控制器的處理器 怎么辦,那你只能親自實(shí)現(xiàn)這些 具體的 寫命令,寫地址。等等 單元操作。
然后才能將這些單元操作組合成 讀數(shù)據(jù),寫數(shù)據(jù)等操作(上面說過 比如讀操作 他并不是一個(gè)簡(jiǎn)單的命令而是一系列操作,你要片選使能,然后發(fā)命令(讀命令),
然后發(fā)地址(要讀的數(shù)據(jù)的地址),需要的話還需發(fā)一個(gè)命令,然后需要等待操作完成,然后讀書數(shù)據(jù))
說完了 這些具體的單元操作,那么我們?cè)賮砜纯匆粋(gè) 讀操作 具體需要哪些步驟。也就是我們需要真正必須掌握的時(shí)序操作
對(duì)于我這款 nand flash 讀操作時(shí)序如下
我們要注意的主要是 最下面一行 即 I/Ox 信號(hào)線的狀態(tài),他指示了 讀操作需要哪些,單元步驟。
1 首先 我們看到 有一個(gè) 0x00 是什么?數(shù)據(jù)?地址?命令? 看 ALE/CLE線啊,這兩根線不是決定了現(xiàn)在的數(shù)據(jù)的類型嘛
順著往上看,我們知道0x00是在 CLE有效期間的數(shù)據(jù)那么它就是一個(gè)命令
2 然后是 address(5Cycle) 即五個(gè)地址序列(這款nand flash 指定讀數(shù)據(jù)的地址時(shí)要發(fā)送五個(gè)地址序列),往上看,是在ALE有效期間的數(shù)據(jù),那么應(yīng)該就是地址了
(對(duì)于這五個(gè)地址,前面兩個(gè)是列地址,后面三個(gè)是行地址。在nand flash的物理結(jié)構(gòu)中 行地址對(duì)應(yīng)的某一頁,列地址就對(duì)應(yīng)這一頁中的某一列)
3 接著又是 0x30,此時(shí) CLE有效,那么就是命令了(也就是說這款nand flash的讀操作需要兩個(gè)命令)。
但是之后數(shù)據(jù)并未立刻出來,我們看到在到 DATA Output即數(shù)據(jù)輸出之前還有一段時(shí)間,為什么有這段時(shí)間?
往上看 R/nB 這個(gè)數(shù)據(jù)線上說明了原因,這段時(shí)間內(nèi)它是低電平 即指示現(xiàn)在 處于 忙碌狀態(tài),還未準(zhǔn)備好數(shù)據(jù)輸出。為什么會(huì)這樣?
因?yàn)槟?寫了 一個(gè)命令,寫了要讀數(shù)據(jù)的地址,又寫了一個(gè)命令。 你總要給 cpu一些時(shí)間去處理這些命令吧,
R/nB為低電平這段時(shí)間就是 在處理這些命令(實(shí)際上是根據(jù)命令將你定位的那一頁數(shù)據(jù)讀到內(nèi)部寄存器中),
等 R/nB變成高電平了,就指示命令處理完畢,現(xiàn)在數(shù)據(jù)也就可以讀出來了。
綜上我們從手冊(cè)中我們就知道了讀操作的具體步驟,
1 首先nand flash 也是一個(gè)外設(shè),要訪問他就需要片選它,所以在執(zhí)行時(shí)序圖上的步驟之前需要片選nand flash.
2 看后面就是安裝時(shí)序圖來了,看時(shí)序圖! 第一步先是發(fā)送一個(gè)命令 0x00.
3 看時(shí)序圖! 然后發(fā)送五個(gè)地址序列(先發(fā)送兩個(gè)列地址,在發(fā)送三個(gè)行地址(即頁地址))
4 看時(shí)序圖! 接著再是一個(gè)命令 0x30.
5 看時(shí)序圖! R/nB 引腳為低表示現(xiàn)在正忙,正在處理這些命令,那就要等待 R/nB 引腳變?yōu)楦唠娖?/font>
6 看時(shí)序圖! 這個(gè)時(shí)候就可以讀數(shù)據(jù)了
7 一次讀操作結(jié)束了 nand flash 暫時(shí)是不需要使用了,那么別忘了應(yīng)該 取消片選信號(hào)。
至于這每一個(gè)步驟中具體的時(shí)序,cpu中的nand flash控制器會(huì)幫我們完成。我們要做就是設(shè)置幾個(gè)時(shí)間參數(shù)
這里我們反復(fù)強(qiáng)調(diào)了要看時(shí)序圖。其實(shí)學(xué)嵌入式前期對(duì)數(shù)據(jù)手冊(cè)一定要多看,看多了你就回知道,什么東西的你重點(diǎn)要看的,什么是和你的編程操作無關(guān)的你不需要關(guān)心。這樣后面你才能,拿到一個(gè)外設(shè) 就能寫出他的操作。而不用跟著書背步驟。只要手冊(cè)在就行了。
上面的步驟,是一個(gè)具體的讀操作的步驟,不過在使用一個(gè)器件之前我們需要初始化一下它。至于初始化也就是設(shè)置我們上面多次提到的
我們說過 s3c2440已經(jīng)幫我做了很多底層的單元操作,我們只需設(shè)置幾個(gè)時(shí)間參數(shù) 片內(nèi)的 nand flash就會(huì)自動(dòng)發(fā)出相應(yīng)操作的時(shí)序操作
那么到底設(shè)置那幾個(gè)時(shí)間呢。
s3c2440 手冊(cè)上給出了 需要我們?cè)O(shè)置的幾個(gè)參數(shù)。
從中我們可以看出 第一幅時(shí)序圖是 命令和地址鎖存的時(shí)序,第二幅是 數(shù)據(jù)讀取和寫入的時(shí)序。
可以看出,他們要設(shè)置的時(shí)間都是一樣的。前面分析了那么多,這里應(yīng)該不難 看出
1 TACLS 很明表示的是 CLE/ALE 的建立時(shí)間(這里并不準(zhǔn)確,其實(shí)是 CLE/ALE有效到 WE 變成低電平之間的時(shí)間,但 WE 卻是在上升沿才鎖存命令/地址)
2 TWRPH0 代表的是 WE 的脈沖寬度,即有效時(shí)間
3 TWRPH1 代表的是 CLE/ALE 的保持時(shí)間
那到底設(shè)置成什么數(shù)字呢。既然 上圖中讀/寫/命令/地址 操作需要的時(shí)間參數(shù)都是一樣的
那么我們從 nand flash中隨便找一個(gè) 命令時(shí)序來對(duì)照不就行了
就拿上面我們說過的 命令鎖存時(shí)序來對(duì)比
那么我們就能得到下面的關(guān)系
TWRPH0 = tWP
TWRPH1 = tCLH
TACLS = tCLS - tWP
然后設(shè)置成多少呢? 看手冊(cè)啊,手冊(cè)中對(duì) tWP tCLH tCLS 都會(huì)至少給出 需要的最小時(shí)間
這款芯片nand flash手冊(cè)中這三個(gè)參數(shù)要求是
所以 TWRPH0 = tWP >=12ns
TWRPH1 = tCLH >=5ns
TACLS = tCLS - tWP >=0;
而這三個(gè)參數(shù)在s3c2440的數(shù)據(jù)手冊(cè)中說明為
當(dāng)然這里的時(shí)間都是以 HCLK 為單位的,這幾個(gè)參數(shù) 是在 nand flash控制寄存器中的 NFCONF中設(shè)置的
這里我沒用使用MPLL 所以HCLK是 12MHZ
所以 TWRPH0 = 0 TWRPH1 =0 TACLS =0; (如果你的時(shí)鐘頻率比較高,那就要設(shè)別的數(shù)了。當(dāng)然有是有你真不知道,設(shè)置大點(diǎn)總沒錯(cuò),只不過速度可能會(huì)慢點(diǎn)。)
所以 NFCONF =0;(NOFCONF其他位數(shù)據(jù)手冊(cè)中有說明,這里只是簡(jiǎn)單讀操作,其他位可以不設(shè)置)
然后是初始化一下 ECC 使能nand flash控制器(我們只是設(shè)置了幾個(gè)時(shí)間參數(shù),時(shí)序的具體操作就是靠他來完成的,所以要使能他)
然后先 取消片選nand flash 因?yàn)槲覀儸F(xiàn)在還沒有操作它啊,只是初始化一下。所以還是應(yīng)該先取消片選,等真正讀的時(shí)候再使能片選信號(hào)
NFCONT = (1<<4) | (1<<1) (1<<0);
(數(shù)據(jù)手冊(cè)中有對(duì)應(yīng)位的說明)
最后,第一次使用nand flash 我們需要復(fù)位操作一下。
綜上,nand flash 的初始化代碼如下
void nand_init(void){
NFCONF =0;
NFCONT = (1<<4) | (1<<1) | (1<<0);
nand_reset(); //nand reset代碼在后面
}
下面代碼一些地址的寫法是與 nand flash 型號(hào)有關(guān)的。具體需要參考芯片手冊(cè)
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
五個(gè)地址周期 (2個(gè)列地址 和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中讀出的數(shù)據(jù)放到哪
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){ //每讀一頁需要發(fā)一次命令
write_command(0x00);
write_address(start);
write_command(0x30);
wait_ready();
while((col<2048) && (start<end)){ 在一頁中讀,我用的型號(hào)一頁大小為2k[="" font][="" color][="" p][p="26," null,="" left]="" *des="read_one_data();
[p=26," des++;[="" col++;[="" start++;[="" }[="" col="0;



| 歡迎光臨 (http://www.denmoz.com/bbs/) | Powered by Discuz! X3.1 |