學習uboot前奏之hardware-nand flash[s3c2440]
好久沒有更新博文了,最近確實懶惰了,哎,不說了。開始今天的學習吧,今天讓我們來學習下嵌入式開發中不可缺少的模組-NAND FLASH。
FLASH主要分為兩類: NAND FLASH 和NOR FLASH
兩者的主要區別和適用場合如下
引數 | NAND | NOR |
---|---|---|
容量 | 1-32MB | NAND:16-512MB 甚至更大 |
XIP | 不可以 | 可以直接在其上執行程式碼 |
介面 | IO介面 | RAM介面 |
訪問方法 | 順序訪問 | 隨機訪問 |
可靠性 | 比較低,位反轉比較常見 | 比較高 |
可擦寫次數 | 10000-100000 | 100000-1000000 |
主要用途 | 儲存資料和程式碼 | 儲存程式碼 |
總結下的話就是NOR FLASH可以支援XIP,可靠性高,但是讀寫速度相對於NAND FLASH來說慢一些
NAND 不支援XIP,但是它的價效比比較高,但是也有一個比較嚴重的問題就是發生位翻轉的概率比較大,因此NAND FLASH 在使用的時候都配備軟體的ECC或者硬體的ECC。
在本人接觸的有限的產品中,NAND FLASH用的比較多,功能類似PC的硬體,本文以三星公司生產的K9F1208U0M為例進行介紹NAND FLASH
K9F1208U0M的主要引腳如下:
對於NAND FLASH訪問的命令、地址、資料都是通過I/O輸入/輸出,這種形式減少了
晶片的引腳個數,並使得系統很容易升級到更大的容量。
寫入命令、地址或者資料時,都需要將WE#、CE#、訊號同時拉低。資料在WE#訊號的
上升沿被NAND FLASH鎖存;命令鎖存訊號CLE、地址鎖存訊號ALE用來分辨、鎖存命令命令或者地址
地址序列
K9F1208U0M一頁大小為528位元組,而列地址A0~A7可以定址的範圍是256位元組,所以必須輔以其他手段才能完全定址這528位元組。將一頁分為A、B、C、三個區;A區為0~255位元組,B區為256~511位元組,C區為512~527位元組。訪問某頁,需要選定特定的區,這成為“使地址指標指向特定的區”。通過三個命令實現:命令00h讓地址指標指向A區、命令01h讓地址指標指向B區、命令50h讓地址指標指向C區。命令00h和50h會使得訪問FLASH的地址指標一直從A區或C區開始,除非發出了其他的修改地址的命令。命令01h的效果只能維持一次,當前的讀、寫、擦除、復位或者上電操作完成後,地址指標重新指向A區。寫A區或C區的資料時,必須在發出命令80h之前發出00h或者50h;寫B區的資料,發出命令01h後必須緊接就發出命令80h
下面講下NAND FLASH的讀寫操作次序:
- 設定NFCONF(對於S3C2440還要設定NFCONT)暫存器,配置NAND Flash
- 向NFCMD暫存器寫入命令,命令字參考具體的FLASH手冊
- 向NFADDR暫存器寫入地址
- 讀/寫資料:通過暫存器NFSTAT檢測NAND Flash的狀態,在啟動某個操作後,應該檢測R/nB訊號以確定該操作是否完成、成功
舉個讀操作的例子:
- 設定NFCONF,NFCONT
NFCONF=0x300(TACLS=0,TWRPH0=3,TWRPH1=0)
設定NFCONT暫存器如下,表示使能NAND FlASH控制器、禁止控制引腳訊號nFCE、初始化ECC
NFCONT = (1<<4)|(1<<1)|(1<<0)
2.在第一次操作NAND Flash前,通常復位一下NAND flash
NFCONT &= ~(1<<1) (發出片選訊號)
NFCMD = 0xff (reset訊號)
然後迴圈查詢NFSTAT位0,直到它等於1。
最後禁止片選訊號,在實際使用NAND Flash時再使能
NFCONT |= 0X2
3.發出讀命令
先使能NAND Flash,然後發出讀命令
NFCONT &= ~(1<<1)(發出片選訊號)
NFCMD = 0 (讀命令)
4 發出地址訊號
在上面的表中列舉出了地址的操作步驟和對應的以及對應的地址線,地址線A8不需要直接設定由A8設定,當讀命令為0時,A8=0;當讀命令為1時,A8=0,具體地址設定如下。
NFADDR = addr & 0xff
NFADDR = (addr>>9)&0xff
NFADDR = (addr>>17)&0xff
NFADDR = (addr>>25)&0xff
5 迴圈查詢NFSTAT位0,直到它等於1,這時就能讀取資料了
6 連續讀NFDATA既存器512次,得到一頁資料
7 最後,禁止 NAND Flash的片選訊號
下面以實際程式碼講解NAND Flash操作。nand實驗的原始檔為head.s、init.c和main.c。程式的功能是將點燈的程式放在NAND flash地址4096後,當程式啟動後通過NAND flash控制器將它們讀出來執行。
連線指令碼nand.lds把所有的源程式分為兩部分,nand.lds程式碼如下:
SECTIONS
{
firtst 0x00000000 : { head.o init.o nand.o}
second 0x30000000 : AT(4096) { main.o }
}
其中連結指令碼的第二行表示head.o、init.o、nand、這3個檔案的執行地址為0,它們在生成的映像檔案中的偏移地址也為0(從0開始存放)
第3行表示main.o,它在生成的映像檔案中的偏移地址為4096
下面開始分析原始碼head.s
.text
.global _start
_start:
@函數disable_watch_dog, memsetup, init_nand, nand_read_ll在init.c中定義
ldr sp, =4096 @設置堆疊
bl disable_watch_dog @關WATCH DOG
bl memsetup @初始化SDRAM
bl nand_init @初始化NAND Flash
@將NAND Flash中地址4096開始的1024位元組程式碼(main.c編譯得到)複製到SDRAM中
@nand_read_ll函式需要3個引數:
ldr r0, =0x30000000 @1. 目標地址=0x30000000,這是SDRAM的起始地址
mov r1, #4096 @2. 源地址=4096,連線的時候,main.c中的程式碼在NAND Flash地址4096處
mov r2, #2048 @3. 複製長度= 2048(bytes)
bl nand_read @調用C函式nand_read
ldr sp, =0x34000000 @設置棧
ldr lr, =halt_loop @設置返回地址
ldr pc, =main @b指令和bl指令只能前後跳轉32M的範圍,所以這裡使用向pc賦值的方法進行跳轉
halt_loop:
b halt_loop
head.S中呼叫init.c中的函式來管WATCH DOG、初始化SDRAM;呼叫nand.c中函式來初始化NAND Flash,然後將main.c中的程式碼從NAND Flash地址4096開始處複製到SDRAM中,最後跳到main.c中的main函式繼續執行。
下面再仔細分析nand_read函式
/* 讀函式 */
void nand_read(unsigned char *buf, unsigned long start_addr, int size)
{
int i, j;
if ((start_addr & NAND_BLOCK_MASK) || (size & NAND_BLOCK_MASK)) {
return ; /* 地址或長度不對齊 */
}
/* 選中晶片 */
nand_select_chip();
for(i=start_addr; i < (start_addr + size);)
{
/* 發出READ0命令 */
write_cmd(0);
/* Write Address */
write_addr(i);
wait_idle();
for(j=0; j < NAND_SECTOR_SIZE; j++, i++)
{
*buf = read_data();
buf++;
}
}
/* 取消片選訊號 */
nand_deselect_chip();
return ;
}
函式功能為從NAND flash中將起始地址為start_addr開始的size大小的資料拷貝到buf對應的地址處。從上面的程式可以看出讀Flash資料的過程如下:
- 選擇晶片
- 發出讀命令
- 發出地址
- 等待資料就緒
- 讀取資料
- 結束後,取消片選訊號
好的,本節到此為止了