來源:韋東山嵌入式專欄_ARM裸機加強版維基教程
作者:韋東山
本文字數:2299,閱讀時長:3分鐘
在上節 我們實現了芯片ID的讀取,可是那個程序已經超過了4k,我們想把它燒到開發闆的話,必須把它燒寫到NOR FLASH上去,這節我們來講解NAND FLASH數據的讀取,并且實現超過4k的程序從NAND FLASH啟動。
下圖為NAND FLASH内部結構圖,從圖中可以可以知道,一個page含有2k 字節的頁數據,和64字節的oob區,後面會介紹頁數據和oob區有什麼關系。
下圖的表格,來說明NAND FLASH内部結構,前面2K(0~2047)表示頁數據,後邊64字節(2048~2111)表示oob。
問:CPU想讀取,第2048個數據,它是哪以一個?
答:是Page1的第0個字節。CPU使用某個地址訪問數據的時候,是在頁數據空間來尋址的,根本就看不到oob區。
我們知道NAND FLASH 和 NOR FLASH相比有個缺點,NAND FLASH讀或寫一頁數據的時候,可能會發生位反轉,裡面可能有一位是錯誤的,為了解決這個問題,引入oob區, 它寫頁數據的時候,把數據寫進頁數據的同時會生成一個校驗碼,把這個校驗碼寫進oob區裡面,當讀數據的時候,讀出1頁數據,讀取1數據裡面有可能有某一位發生錯誤,它繼續讀出原來的校驗碼,使用oob區裡面的校驗碼,來修正頁數據裡面的數據。從這裡我們可以得出一個結論,oob區的存在是為了解決NAND FLASH的缺陷而存在的。
CPU: 隻關心數據,不需要看到oob區的校驗碼(把數據讀出來,然後進行校驗再把正确的數據返回,就可以了)。CPU想使用某個addr來訪問數據的時候,addr是在頁數據區間來尋址的,addr根本不會在oob區裡面尋址。
為了形象在下面說一個幽默的對話來說明一下CPU和NAND FLASH的功能:
CPU大爺: 小nand啊,你的性能比不上小nor啊,聽說你有位反轉的毛病
Nand : 是的,大爺,位反轉是我天生的毛病,時有時無
CPU大爺: 靠,你說你價格便宜容量大,這不是害我嘛
Nand : 沒事,我有偏方,用OOB就可以解決這問題
CPU大爺: 得得得,你那偏方是什麼也别告訴我,我隻管能讀寫正确的數據
Nand : 是的,大爺,我這OOB偏方也就我自個私下使用。您就像使用nor一樣使喚我就可以了
下面我們開始寫程序,想去讀NAND FLASH應該怎樣操作,下面是nand flash的地址周期。
讀NAND FLASH步驟:(從程序的角度來說),我們需要先發出00命令再發出5個周期的地址,再發出30命令,然後就可以讀數據了。比如:我想訪問某個地址的數據,需要确定在哪一行page(row),在哪一列col(0~2047)。從NAND FLASH的地址周期中可以看出來,先發出2個col(列地址),再發出3個(Row)行地址。 下面是程序的編寫:
wait_ready函數等待NAND FLASHh空閑,從上圖可以看出當NFSTAT寄存器[0]的值為1時NAND FLASH是空閑的,我們可以通過該位來判斷NAND FLASH是否繁忙。代碼如下:
void wait_ready(void) { while (!(NFSTAT & 1)); }
nand_read函數為NAND FLASH的讀函數,代碼如下:
void nand_read(unsigned int addr, unsigned char *buf, unsigned int len) { int i = 0; int page = addr / 2048; int col = addr & (2048 - 1); nand_select(); while (i < len) { /* 發出00h命令 */ nand_cmd(00); /* 發出地址 */ /* col addr */ nand_addr_byte(col & 0xff); nand_addr_byte((col>>8) & 0xff); /* row/page addr */ nand_addr_byte(page & 0xff); nand_addr_byte((page>>8) & 0xff); nand_addr_byte((page>>16) & 0xff); /* 發出30h命令 */ nand_cmd(0x30); /* 等待就緒 */ wait_ready(); /* 讀數據 */ for (; (col < 2048) && (i < len); col ) { buf[i ] = nand_data(); } if (i == len) break; col = 0; page ; } nand_deselect(); }
在init.c文件中,加上如下代碼,用來判斷所使用的FLASH是NOR FLASH還是NAND FLASH。代碼如下:
int isBootFromNorFlash(void) { volatile unsigned int *p = (volatile unsigned int *)0; unsigned int val = *p; *p = 0x12345678; if (*p == 0x12345678) { /* 寫成功, 對應nand啟動 */ *p = val; return 0; } else { return 1; } }
在init.c文件中的copy2sdram函數裡面加上如下代碼,用來支持NAND FLASH啟動,當isBootFromNorFlash函數的返回值為1時,是從NOR FLASH啟動,當isBootFromNorFlash函數的返回值為0時,是從NAND FLASH啟動。
if (isBootFromNorFlash()) { while (dest < end) { *dest = *src ; } } else { nand_init(); nand_read(src, dest, len); } }
「新品首發」STM32MP157開發闆火爆預售!首批僅300套
,更多精彩资讯请关注tft每日頭條,我们将持续为您更新最新资讯!