本文主要是關(guān)于Nor Flash的相關(guān)介紹,并著重對(duì)Nor Flash測(cè)試方法及其程序進(jìn)行了詳盡的闡述。
Nor Flash
Nor Flash 是現(xiàn)在市場(chǎng)上兩種主要的非易失閃存技術(shù)之一。Intel于1988年首先開(kāi)發(fā)出NOR Flash 技術(shù),徹底改變了原先由EPROM(Erasable Programmable Read-Only-Memory電可編程序只讀存儲(chǔ)器)和EEPROM(電可擦只讀存儲(chǔ)器Electrically Erasable Programmable Read - Only Memory)一統(tǒng)天下的局面。緊接著,1989年,東芝公司發(fā)表了NAND Flash 結(jié)構(gòu),強(qiáng)調(diào)降低每比特的成本,有更高的性能,并且像磁盤一樣可以通過(guò)接口輕松升級(jí)。NOR Flash 的特點(diǎn)是芯片內(nèi)執(zhí)行(XIP ,eXecute In Place),這樣應(yīng)用程序可以直接在Flash閃存內(nèi)運(yùn)行,不必再把代碼讀到系統(tǒng)RAM中。NOR 的傳輸效率很高,在1~4MB的小容量時(shí)具有很高的成本效益,但是很低的寫入和擦除速度大大影響到它的性能。NAND的結(jié)構(gòu)能提供極高的單元密度,可以達(dá)到高存儲(chǔ)密度,并且寫入和擦除的速度也很快。應(yīng)用NAND的困難在于Flash的管理需要特殊的系統(tǒng)接口。通常讀取NOR的速度比NAND稍快一些,而NAND的寫入速度比NOR快很多,在設(shè)計(jì)中應(yīng)該考慮這些情況?!?a target="_blank">ARM嵌入式Linux系統(tǒng)開(kāi)發(fā)從入門到精通》 李亞峰 歐文盛 等編著 清華大學(xué)出版社 P52 注釋 API Key
性能比較
flash閃存是非易失存儲(chǔ)器,可以對(duì)稱為塊的存儲(chǔ)器單元塊進(jìn)行擦寫和再編程。任何flash器件的寫入操作只能在空或已擦除的單元內(nèi)進(jìn)行,所以大多數(shù)情況下,在進(jìn)行寫入操作之前必須先執(zhí)行擦除。NAND器件執(zhí)行擦除操作是十分簡(jiǎn)單的,而NOR則要求在進(jìn)行擦除前先要將目標(biāo)塊內(nèi)所有的位都寫為0。
由于擦除NOR器件時(shí)是以64~128KB的塊進(jìn)行的,執(zhí)行一個(gè)寫入/擦除操作的時(shí)間為5s,與此相反,擦除NAND器件是以8~32KB的塊進(jìn)行的,執(zhí)行相同的操作最多只需要4ms。
執(zhí)行擦除時(shí)塊尺寸的不同進(jìn)一步拉大了NOR和NAND之間的性能差距,統(tǒng)計(jì)表明,對(duì)于給定的一套寫入操作(尤其是更新小文件時(shí)),更多的擦除操作必須在基于NOR的單元中進(jìn)行。這樣,當(dāng)選擇存儲(chǔ)解決方案時(shí),設(shè)計(jì)師必須權(quán)衡以下的各項(xiàng)因素。
l 、NOR的讀速度比NAND稍快一些。
2、 NAND的寫入速度比NOR快很多。
3 、NAND的4ms擦除速度遠(yuǎn)比NOR的5s快。
4 、大多數(shù)寫入操作需要先進(jìn)行擦除操作。
5 、NAND的擦除單元更小,相應(yīng)的擦除電路更少。
此外,NAND的實(shí)際應(yīng)用方式要比NOR復(fù)雜的多。NOR可以直接使用,并可在上面直接運(yùn)行代碼;而NAND需要I/O接口,因此使用時(shí)需要驅(qū)動(dòng)程序。不過(guò)當(dāng)今流行的操作系統(tǒng)對(duì)NAND結(jié)構(gòu)的Flash都有支持。此外,Linux內(nèi)核也提供了對(duì)NAND結(jié)構(gòu)的Flash的支持。
詳解
NOR和NAND是現(xiàn)在市場(chǎng)上兩種主要的非易失閃存技術(shù)。Intel于1988年首先開(kāi)發(fā)出NOR flash技術(shù),徹底改變了原先由EPROM和EEPROM一統(tǒng)天下的局面。緊接著,1989年,東芝公司發(fā)表了NAND flash結(jié)構(gòu),強(qiáng)調(diào)降低每比特的成本,更高的性能,并且象磁盤一樣可以通過(guò)接口輕松升級(jí)。但是經(jīng)過(guò)了十多年之后,仍然有相當(dāng)多的硬件工程師分不清NOR和NAND閃存。
像“flash存儲(chǔ)器”經(jīng)常可以與相“NOR存儲(chǔ)器”互換使用。許多業(yè)內(nèi)人士也搞不清楚NAND閃存技術(shù)相對(duì)于NOR技術(shù)的優(yōu)越之處,因?yàn)榇蠖鄶?shù)情況下閃存只是用來(lái)存儲(chǔ)少量的代碼,這時(shí)NOR閃存更適合一些。而NAND則是高數(shù)據(jù)存儲(chǔ)密度的理想解決方案。
NOR的特點(diǎn)是芯片內(nèi)執(zhí)行(XIP, eXecute In Place),這樣應(yīng)用程序可以直接在flash閃存內(nèi)運(yùn)行,不必再把代碼讀到系統(tǒng)RAM中。NOR的傳輸效率很高,在1~4MB的小容量時(shí)具有很高的成本效益,但是很低的寫入和擦除速度大大影響了它的性能。
NAND結(jié)構(gòu)能提供極高的單元密度,可以達(dá)到高存儲(chǔ)密度,并且寫入和擦除的速度也很快。應(yīng)用NAND的困難在于flash的管理需要特殊的系統(tǒng)接口。
接口差別
NOR flash帶有SRAM接口,有足夠的地址引腳來(lái)尋址,可以很容易地存取其內(nèi)部的每一個(gè)字節(jié)。
NAND器件使用復(fù)雜的I/O口來(lái)串行地存取數(shù)據(jù),各個(gè)產(chǎn)品或廠商的方法可能各不相同。8個(gè)引腳用來(lái)傳送控制、地址和數(shù)據(jù)信息。
NAND讀和寫操作采用512字節(jié)的塊,這一點(diǎn)有點(diǎn)像硬盤管理此類操作,很自然地,基于NAND的存儲(chǔ)器就可以取代硬盤或其他塊設(shè)備。
容量成本
NAND flash的單元尺寸幾乎是NOR器件的一半,由于生產(chǎn)過(guò)程更為簡(jiǎn)單,NAND結(jié)構(gòu)可以在給定的模具尺寸內(nèi)提供更高的容量,也就相應(yīng)地降低了價(jià)格。
NOR flash占據(jù)了容量為1~16MB閃存市場(chǎng)的大部分,而NAND flash只是用在8~128MB的產(chǎn)品當(dāng)中,這也說(shuō)明NOR主要應(yīng)用在代碼存儲(chǔ)介質(zhì)中,NAND適合于數(shù)據(jù)存儲(chǔ),NAND在CompactFlash、Secure Digital、PC Cards和MMC(多媒體存儲(chǔ)卡Multi Media Card)存儲(chǔ)卡市場(chǎng)上所占份額最大。
Nor Flash測(cè)試方法有哪些
NorFlash簡(jiǎn)單來(lái)說(shuō)與sdram與Nand的中間品,它能像sdram一樣直接讀,但是又得像nand一樣編程擦寫。因此程序可以直接在nor里跑,速度要比sdram慢一些,往nor里寫數(shù)據(jù)必須先擦除,因?yàn)閚or的每一位只能由1變?yōu)?。Nor可讀不可直接寫的特性可以被用來(lái)判斷是Nor啟動(dòng)還是nand啟動(dòng),因?yàn)閚and啟動(dòng)的話前4K是可寫的,我們寫入數(shù)據(jù)再讀取出來(lái)應(yīng)該是沒(méi)有問(wèn)題的,而nor啟動(dòng)的話,讀出的數(shù)據(jù)必然是錯(cuò)誤的。
NorFlash的硬件接線:
首先,如果做過(guò)sdram實(shí)驗(yàn)的朋友應(yīng)該知道,NorFlash與sdram很相似,只不過(guò)sdram位寬為32,NOR為16。在硬件連接上,Nor的地址線與cpu的地址線錯(cuò)開(kāi)1位,sdram錯(cuò)開(kāi)2位。簡(jiǎn)單分析一下:
32位的CPU地址線為32位,每一個(gè)地址對(duì)應(yīng)1個(gè)byte,地址的步長(zhǎng)為1byte
0x0000 0000 對(duì)應(yīng)第1個(gè)地址空間 大小為1bytes
0x0000 0001 對(duì)應(yīng) 2 大小為1bytes
依次類推。..
可以理解為cpu的地址類型 為 u8 * addraddr+1 移動(dòng)1個(gè)字節(jié)
32位的sdram,每一個(gè)地址對(duì)應(yīng)于4個(gè)byte,地址步長(zhǎng)為4byte
0x0000 0000 對(duì)應(yīng)第1個(gè)地址空間 大小為4bytes
0x0000 0001 對(duì)應(yīng) 2 大小為4bytes
依次類推。..
可以理解為sdram的地址類型 為 u32 * addraddr+1 移動(dòng)4個(gè)字節(jié)
16位的nor,每一個(gè)地址對(duì)應(yīng)于2個(gè)byte,地址步長(zhǎng)為2byte
0x0000 0000 對(duì)應(yīng)第1個(gè)地址空間 大小為2bytes
0x0000 0001 對(duì)應(yīng) 2 大小為2bytes
依次類推。..
可以理解為nor的地址類型 為 u16 * addraddr+1 移動(dòng)2個(gè)字節(jié)
因此,CPU的地址與它們的地址是錯(cuò)位的。
CPU的4個(gè)連續(xù)地址 如 0 1 2 3 均對(duì)應(yīng)于sdram的 0地址
CPU的2個(gè)連續(xù)地址 如 0 1 均對(duì)應(yīng)于nor 的 0地址
假如我想取sdram 0地址的 第二個(gè)byte 地址如何寫?對(duì)于sdram和nor具體的每一個(gè)byte是無(wú)法尋址的呀,但是arm有一個(gè)叫存儲(chǔ)管理器的東西,它大概會(huì)幫我們實(shí)現(xiàn)單字節(jié)的讀寫,至于sdram和nor支不支持單字節(jié)讀寫,我們后邊在分析。
NorFlash的軟件設(shè)置:
需要像初始化sdram一樣,設(shè)置Bank寄存器,主要是一些時(shí)序圖的時(shí)間大小。
位寬在BWSCON寄存器中設(shè)置,不過(guò)它是由硬件決定的,bank0的位寬,我們撥動(dòng)開(kāi)關(guān)選擇nor啟動(dòng)還是nand啟動(dòng)的時(shí)候,它就已經(jīng)確定了。
NorFlash信息:
我這款Nor大小為2M,32個(gè)Block,每個(gè)block分為16個(gè)sector,一個(gè)sector為4K,具體信息如下圖。
NorFlash寫、擦除、讀芯片ID:
Nor可以像sdram一樣直接讀取,對(duì)于其它的操作,例如寫、擦除、讀信息等需要寫特定的Date到特定的Addr。
這里尤其需要注意的是,Addr指的是nor地址線上看到的地址,相對(duì)于cpu也就是我們寫程序的時(shí)候,需要將addr《《1,這樣cpu錯(cuò)位的地址線發(fā)出的地址正好對(duì)上nor需求的地址。
對(duì)于擦除操作,nor支持按block、sector或者整片的擦除,整個(gè)擦除需要6個(gè)周期,以按sector擦除為例,前五個(gè)周期為往XXX里寫XXX,最后一個(gè)周期將0X30寫入要擦除的sector對(duì)應(yīng)的首地址即可。
對(duì)于寫操作,需要4個(gè)周期,前3個(gè)周期往XXX里寫XXX,最后一個(gè)周期將Data寫入addr,這里需要注意的是addr必須是半字對(duì)齊,data也要求為16bit。
對(duì)于讀取信息的操作,主要是讀ID的操作,前3個(gè)周期往XXX里寫XXX,第四個(gè)周期去讀特定的地址,對(duì)于DeviceID來(lái)說(shuō),A1-A19=0,A0=1,對(duì)于CPU來(lái)說(shuō)就是0x1《《1.
NorFlash的等待:
NorFlash有三種方式,1中讀硬件引腳,另外兩種讀地址線,主要用讀地址線的兩種方式。
1、Toggle
連續(xù)讀兩次相同地址的數(shù)據(jù),看DQ6是否相等,相等則擦除或?qū)懲瓿?/p>
2、polling
讀數(shù)據(jù),看DQ7是否正確,正確則擦除完成。如果擦除的話DQ7應(yīng)該等于1,寫操作的話,對(duì)比數(shù)據(jù)的第7位。
還有,很重要的一點(diǎn):
經(jīng)過(guò)我的測(cè)試,sdram的單字節(jié)讀取沒(méi)有問(wèn)題,但是Nor單字節(jié)讀取的時(shí)候,讀出的數(shù)據(jù)并不正確。比如我在0x00地址處寫入了0xff11,單字節(jié)讀取0x0理論上應(yīng)該得到0x11,而我在實(shí)際實(shí)驗(yàn)的時(shí)候得到的卻是0xff。也就是說(shuō)nor在存儲(chǔ)半字?jǐn)?shù)據(jù)的時(shí)候高8位于低8位互換了。
[cpp] view plain copy
#include “uart.h”
#define MAIN_SECT_SIZE (4*1024) /* 4 KB */
#define CMD_UNLOCK1 0x000000AA
#define CMD_UNLOCK2 0x00000055
#define CMD_ERASE_SETUP 0x00000080
#define CMD_ERASE_CONFIRM 0x00000030
#define CMD_PROGRAM 0x000000A0
#define MEM_FLASH_ADDR1 (*(volatile U16 *)(0x000005555 《《 1))
#define MEM_FLASH_ADDR2 (*(volatile U16 *)(0x000002AAA 《《 1))
#define U16 unsigned short
#define U32 unsigned long
#define U8 unsigned char
int write_hword (U32 dest, U16 data);
typedef struct {
U32 size; /* total bank size in bytes */
U16 sector_count; /* number of erase units */
U32 flash_id; /* combined device & manufacturer code */
U32 start[512]; /* physical sector start addresses */
} flash_info_t;
/*-----------------------------------------------------------------------*/
void flash_id(){
MEM_FLASH_ADDR1 = CMD_UNLOCK1;
MEM_FLASH_ADDR2 = CMD_UNLOCK2;
MEM_FLASH_ADDR1 = 0x00000090;
print(“Manufacturer ID :%x\r\n”,*((U16 *)0x00));
MEM_FLASH_ADDR1 = CMD_UNLOCK1;
MEM_FLASH_ADDR2 = CMD_UNLOCK2;
MEM_FLASH_ADDR1 = 0x00000090;
print(“Device ID :%x\r\n”,*((U16 *)(0x01《《1)));
}
void flash_init () //計(jì)算總大小,每個(gè)sector的起始地址
{
flash_id();
//print(“flash init OK\r\n”);
print(“*((U32 *)0x32000000) = 0x00001100\r\n”);
*((U32 *)0x32000000) = 0x00001100;
print(“U8 0x32000001 == %x\r\n”,*((U8 *)0x32000001));
*((U8 *)0x32000003) = 0xff;
print(“*((U8 *)0x32000003) = 0xff\r\n”);
print(“now the U32 0x32000000 should be 0xff001100\r\n”);
print(“U32 0x32000000 = %x\r\n”,*((U32 *)0x32000000));
print(“U8 0x32000000 = %x\r\n”,*((U8 *)0x32000000));
print(“U8 0x32000001 = %x\r\n”,*((U8 *)0x32000001));
print(“U8 0x32000002 = %x\r\n”,*((U8 *)0x32000002));
print(“U8 0x32000003 = %x\r\n”,*((U8 *)0x32000003));
if(flash_erase(0,1) == 0)
print(“erase OK\r\n”);
U32 a = 0x00001c15;
U16 b = 0x11ff;
write_hword(a,b);
print(“*(U32 *0x00001c15) == 0x11ff\r\n”);
print(“U8 0x1c15 = %x\r\n”,*((U8 *)0x1c15));
print(“U8 0x1c16 = %x\r\n”,*((U8 *)0x1c16));
print(“U16 0x1c15 = %x\r\n”,*((U16 *)0x1c15));
if(write_buff((1024*20),0,(7*1024)) == 0)
print(“write OK\r\n”);
}
int flash_erase (int s_first, int s_last)
{
int i,j;
U32 size = 0;
flash_info_t flash_info;
for (i = 0; i 《 1; i++) {
U32 flashbase = 0;
flash_info.size = 2*1024*1024;
flash_info.sector_count = 512;
flashbase = 0;
for (j = 0; j 《 flash_info.sector_count; j++) {
flash_info.start[j] =
flashbase + (j) * MAIN_SECT_SIZE;
//print(“%d \t:%d\r\n”,j,flash_info.start[j]);
}
}
int sect;
unsigned short temp;
/* Start erase on unprotected sectors */
for (sect = s_first; sect 《= s_last; sect++) {
print (“Erasing sector %d 。。。 \r\n”, sect+1);
volatile U16 * addr = (volatile U16 *)(flash_info.start[sect]);
MEM_FLASH_ADDR1 = CMD_UNLOCK1;
MEM_FLASH_ADDR2 = CMD_UNLOCK2;
MEM_FLASH_ADDR1 = CMD_ERASE_SETUP;
MEM_FLASH_ADDR1 = CMD_UNLOCK1;
MEM_FLASH_ADDR2 = CMD_UNLOCK2;
*addr = CMD_ERASE_CONFIRM;
print(“wait\r\n”);
while(1){
temp = (*addr) & 0x40; // 0100 0000 DQ6
if(temp != (*addr) & 0x40) //DQ6
continue;
if(*addr & 0x80) //dq7 ==1
break;
}
}
return 0;
}
//寫16位數(shù)據(jù),地址應(yīng)該是16位對(duì)齊的。
int write_hword (U32 dest, U16 data)
{
//print(“now to write %d\r\n”,dest);
int rc;
volatile U16 *addr = (volatile U16 *)dest;
U16 result;
//Check if Flash is (sufficiently) erased
result = *addr;
if ((result & data) != data)
return 1;
MEM_FLASH_ADDR1 = CMD_UNLOCK1;
MEM_FLASH_ADDR2 = CMD_UNLOCK2;
MEM_FLASH_ADDR1 = CMD_PROGRAM;
*addr = data;
while(1){
unsigned short i = *addr & 0x40;
if(i != (*addr & 0x40)) //D6 == D6
continue;
if((*addr & 0x80) == (data & 0x80)){
rc = 0;
break; //D7 == D7
}
}
//print(“write %d OK\r\n”,dest);
return rc;
}
int write_buff (U32 src, U32 addr, U32 len)
{
int rc;
U16 data; //16Bit?
if(addr % 2){
print(“addr is not for 16bit align\n”);
return 1;
}
while (len 》= 2) {
data = *((volatile U16 *) src);
if ((rc = write_hword (addr, data)) != 0) {
return (rc);
}
src += 2;
addr += 2;
len -= 2;
}
return 0;
}
Nor Flash測(cè)試程序
寫Flash需要用到以下的命令:
1.Read Array
2.Read Status Register
3.Clear Status Register
4.Write to Buffer
5.Block Erase
6.Clear Block Lock-Bits
具體如何操作 請(qǐng)看代碼分析或者手冊(cè)
寫Flash “Byte/Word Program Flowchart”為2個(gè)總線周期
流程如下:
Start-》 Write 40H, Address-》 Read Status Register-》 SR.7 =?-》 Full Status Check if Desired-》 Byte/Word Program Complete
其中Write 40H, Address的指令如下:
Word/Byte Program SCS/BCS 2 (周期1Write X 0x40 or 0x10)( 周期2Write PA PD) 1,12,13
PA = Address of memory location to be programmed.
PD = Data to be programmed at location PA. Data is latched on the rising edge of WE#.
下面是代碼解釋:
#define U32 unsigned int
#define U16 unsigned short
#define S32 int
#define S16 short int
#define U8 unsigned char
#define S8 char
//My Addr
#define MY_FLASHADDR 0x08040000//寫入的目標(biāo)地址
#define RAM_STARTADDR 0x30180000//數(shù)據(jù)在Ram中的開(kāi)始得志
#define RAM_READOUT_STARTADDR 0x31000000//驗(yàn)證的地址
#define TIME_WAIT_FLASH 100//Flash命令執(zhí)行后,等待的時(shí)間
//////////////////////////////////////////////////////////////////
void IntelFlashWrite(void);
void delay(int);// /Flash命令執(zhí)行后,等待
void panic(int i);
void clearstatusreg(void);//出錯(cuò)后要清除狀態(tài)寄存器
//////////////////////////////////////////////////////////////////
int main()
{
IntelFlashWrite();
return 0;
}
void IntelFlashWrite()
{
U16 temp; //16位數(shù)據(jù)線,所以用U16
U16 readfromflash,readfromram;
int i = 0;
int count = 0;
*(U16*)MY_FLASHADDR = 0x60;// 清除 Block Lock-Bits
delay(TIME_WAIT_FLASH);//等一下
*(U16*)MY_FLASHADDR = 0xD0;// 清除 Block Lock-Bits,周期2操作
delay(TIME_WAIT_FLASH);
*(U16*)MY_FLASHADDR = 0x20; //塊擦除,雖然手冊(cè)里沒(méi)說(shuō)要塊擦除。但是我們的片子如果不擦除的話,有時(shí)候會(huì)寫不進(jìn)去。
delay(TIME_WAIT_FLASH);
*(U16*)MY_FLASHADDR = 0xD0; //塊擦除,周期2操作
delay(TIME_WAIT_FLASH);
for(i = 0;i《=0x20000;i+=2,count = 0)//128k為一個(gè)block
{
readfromram = *(U16*)(RAM_STARTADDR+i);//從ram中把數(shù)據(jù)讀出來(lái)
*(U16*)(MY_FLASHADDR+i) = 0x40;//寫操作,周期1
delay(TIME_WAIT_FLASH);//等等
*(U16*)(MY_FLASHADDR+i) = readfromram;// 寫操作,周期2
temp = *(U16*)(MY_FLASHADDR+i);//After the program sequence is written, the device automatically outputs SRD when read
while(((temp&0x80) == 0)&&(count《1000))
{
temp = *(U16*)(MY_FLASHADDR+i);
count++;
}//讀1000次狀態(tài)寄存器,超過(guò)1000次,就終止。
if(count》=1000)//over time
{
count = 0;
while(1);
}
else//讀出狀態(tài)寄存器
{
*(U16*)(MY_FLASHADDR+i) = 0xFF;//發(fā)出readarray命令
delay(10);
readfromflash = *(U16*)(RAM_STARTADDR+i);//從Flash讀出剛才寫入的數(shù)據(jù)
if(readfromflash!=readfromram)//相等就好了
{
count = 0;
temp = 0;
readfromram = 0;
readfromflash = 0;
while(1);
}
}
if((temp&0x8) == 0x8)//Programming to Voltage Error Detect
{
while(1);
}
if((temp&0x2) == 0x2)//Device Protect Detect
{
while(1);
}
if((temp&0x10) == 0x10)//Programming Error
{
while(1);
}
count = 0;
temp = 0;
readfromram = 0;
readfromflash = 0;
}
while(1);//寫完了
}
void delay(int i)
{
volatile int j = 0;
volatile int q;
for(;j《=i;j++)
q = j*j;
}
void clearstatusreg()
{
*(U16*)MY_FLASHADDR = 0x50;
}
結(jié)語(yǔ)
關(guān)于Nor Flash測(cè)試的相關(guān)介紹就到這了,如有不足之處歡迎指正。
評(píng)論