NorFlash

时间:2022-01-07 05:09:47

一、NorFlash概述

1、NorFlash

  Intel于1988年首先开发出NOR Flash 技术,彻底改变了原先由EPROM(Erasable Programmable Read-Only-Memory电可编程序只读存储器)和EEPROM(电可擦只读存储器Electrically Erasable Programmable Read - Only Memory)一统天下的局面。

  NOR的优越之处是芯片内执行(XIP, eXecute In Place),这样应用程序可以直接在flash闪存内运行,不必再把代码读到系统RAM中。NOR的传输效率很高,在1~4MB的小容量时具有很高的成本效益,但是很低的写入和擦除速度大大影响了它的性能。

2、NandFlash和NorFlash对比

Nor/Nand Flash 的差别
  Nor  Nand
容量 1MB~32MB 16M~512MB
XIP Yes No
擦除 非常慢(5S) 快(3ms)
慢        快
可靠性 比较高,位反转的比例小于NandFlash的10% 比较低,位反转比较常见,必须有校验措施,比如TNR必须有坏块管理措施
可擦除次数 10000~100000               100000~1000000
生命周期     低于NandFlash的10%              是NorFlash的10倍以上    
接口       与RAM接口相同                    I/O接口
访问方法 随机访问 顺序访问
易用性 容易 复杂
主要用途 常用于保存代码和关键数据 用于保存数据
价格 便宜

3、CFI(Common Flash Interface)
   不同公司产的NOR Flash在 erase,program,lock,unlock等操作上有差别,即command set不一样。
   NorFlash要是支持CFI就好办多了,就不用改代码。通过CFI可以读出片子的manufacturer id,vendorid等等,在程序中就可以通过以上信息来选择正确的erase,program等操作方式。
   NorFlash的数据线和地址线都可能为32/16/8条.为了统一起见,通过CFI接口查询时, CFI接口描述的地址均为Flash芯片的地址,CFI接口查询到的数据,以低字节D7-D0上为准,高字节数据线无视就好了。

 CFI的作用是把NorFlash 的信息通过统一的方法读出来。

二、NorFlash物理结构

  以下内容皆以EN29LV160AB(word模式)为例进行说明。

1、引脚

NorFlash

2、NorFlash块图

NorFlash

3、扇区结构

  Size:  MB in  Sectors
Sector Start Addresses: 000A0000 000B0000
000C0000 000D0000 000E0000 000F0000 001A0000
001B0000 001C0000 001D0000 001E0000 001F0000

  EN29LV160AB大小为2M,总共35个扇区,上图列出了每个扇区的起始地址。

三、NorFlash与ARM接线图

NorFlashNorFlash

  左图为EN29LV160AB与ARM的接线图,右图是SRAM与ARM的接线图,可以看到两者没多大的差别。

、NorFlash相对于RAM使用的特殊性 

NorFlash相对于RAM使用的特殊性

RAM

NorFlash

读取/写入的叫法

读取/写入

读取/编程(Program)

读取/写入的最小单位

字节(Byte)

字(Word)

擦除(Erase)操作的最小单位

字节

Sector/扇区

擦除操作的含义

将数据删除/全部写入0

将整个块都擦除成全是1,也就是里面的数据都是0xFF

对于写操作

直接写即可

在写数据之前,要先擦除,然后再写

 五、NorFlash操作

1、CFI操作

  EN29LV160AB遵循CFI接口协议,所以可以进行CFI操作方式。下表仅仅是CFI查询信息的命令表,还有其他表格,这里不再列出。下边将要阐述的操作方式不是通用性的CFI操作,而是EN29LV160AB特有命令集操作。

NorFlash

2、NorFlash命令表

  不利用CFI方式也可以操作,EN29LV160AB有自己的命令集,利用这个命令集可以完成需要的操作。

NorFlash

3、状态标志位

DQ7

Data# Polling bit,在编程过程从正在编程的地址中读出的数据的 DQ7 为要写入数据位的补码。比如写入的数据为 0x0000 ,即输入的 DQ7 为  0 ,则在编程中读出的数据为  1  ;当编程完成时读出的数据又变回输入的数据  0  。在擦除过程中 DQ7 输出为   0 ;擦除完成后输出为 1 ;注意读取的地址必须是擦除范围内的地址。RY/BY#:高电平表示‘就绪’,低电平表示‘忙’。

DQ6

轮转位 1(Toggle Bit 1 ),在编程和擦除期间,读任意地址都会导致 DQ6 的轮转(0 ,1间相互变换)。当操作完成后,DQ6停止转换。

DQ2

轮转位 2 (Toggle Bit 2 ),当某个扇区被选中擦除时,读有效地址(地址都在擦除的扇区范围内)会导致 DQ2 的轮转。 注意: DQ2 只能判断一个特定的扇区是否被选中擦除,但不能区分这个扇区是否正在擦除中或者
正处于擦除暂停状态。相比之下,DQ6 可以区分 Nor Flash 是否处于擦除中或者擦除暂停状态,但不能区分哪个扇区被选中擦除,因此需要这 2 个位来确定扇区和模式状态信息。

DQ5

超时位(Exceeded Timing Limits) ,当编程或擦除操作超过了一个特定内部脉冲计数时 DQ5=1,表明操作失败。当编程时把 0 改为  1  就会导致 DQ5=1,因为只有擦除擦做才能把 0  改为 1 。当错误发生后需要执行复位命令才能返回到读数据状态。

DQ3

(扇区擦除计时位)Sector Erase Timer  ,只在扇区擦除指令时起作用。当擦除指令真正开始工作时 DQ3=1  ,此时输入的命令(除擦除暂停命令外)都被忽略,DQ3=0  时,可以添加附加的扇区用于多扇区擦除。

六、实现代码

1、读ID

/*******************************************************************
函数功能:显示NorFlash的“Manufacturer ID”和“Device ID”
输入参数:addr
输出参数:无
********************************************************************/
void NOR_Read_ID(void)
{
unsigned short ManuID,DevID; NOR_Rest();
NOR_WR(0x555,0xaa);
NOR_WR(0x2aa,0x55);
NOR_WR(0x555,0x90);
ManuID = NOR_RD(0x0);
DevID = NOR_RD(0x1);
printf("Manufacturer ID: %x\n",ManuID);
printf("Device ID: %x\n",DevID);
}

2、读内容并显示

/*******************************************************************
函数功能:从NorFlash给定的地址处显示256B的内容
输入参数:addr
输出参数:无
*********************************************************************/
void NOR_2K_Content(unsigned char *addr)
{ unsigned int i; printf("Show 256 Bytes content of NorFlash:\n");
for(i=; i<; i++) {
if((i%)==) printf("\n%4x: ", i);
printf("%02x ", *addr++);
}
printf("\n");
}

3、擦除

NorFlash

/*******************************************************************
函数功能:擦除整个芯片
输入参数:无
输出参数:无
********************************************************************/
void NOR_EraseChip(void)
{
printf("chip erasing is started!\n");
NOR_Rest();
NOR_WR(0x555,0xaa);
NOR_WR(0x2aa,0x55);
NOR_WR(0x555,0x80);
NOR_WR(0x555,0xaa);
NOR_WR(0x2aa,0x55);
NOR_WR(0x555,0x10);
printf("it may takes some seconds,plese wait......\n");
if(NOR_Wait())
{
printf("Erasing done!\n");
}
else
{
printf("Erasing error!\n");
}
} /*******************************************************************
函数功能:擦除给定的扇区
输入参数:sect 扇区号
输出参数:无
*********************************************************************/
void NOR_EraseSector(unsigned char sect)
{
unsigned int sectaddr; if(sect > )
{
printf("sect number error!\n");
return ;
} switch(sect)
{
case :
sectaddr = 0x0;
break;
case :
sectaddr = 0x2000;
break;
case :
sectaddr = 0x3000;
break;
case :
sectaddr = 0x4000;
break;
default:
sectaddr = 0x8000*(sect - );
}
printf("Sector %d erasing is started!\n",sect);
NOR_Rest();
NOR_WR(0x555,0xaa);
NOR_WR(0x2aa,0x55);
NOR_WR(0x555,0x80);
NOR_WR(0x555,0xaa);
NOR_WR(0x2aa,0x55);
NOR_WR(sectaddr,0x30);
printf("it may takes some seconds,plese wait......\n");
if(NOR_Wait())
{
printf("Erasing done!\n");
}
else
{
printf("Erasing error!\n");
}
}

4、编程

NorFlash

/*******************************************************************
函数功能:写一个字(2Byte)
输入参数:addr 要写入一个字的物理地址,注意第0位肯定是‘0’
data 要写入的数据
输出参数:1 成功
0 失败
********************************************************************/
static unsigned int NOR_Program(unsigned int addr,unsigned short data)
{
NOR_Rest();
NOR_WR(0x555,0xaa);
NOR_WR(0x2aa,0x55);
NOR_WR(0x555,0xa0);
NOR_WR_DAT(addr,data);
return NOR_Wait();
} /*******************************************************************
函数功能:写入多个字节
输入参数:srcaddr 源地址
desaddr 目的地址
size 大小(以Byte为单位)
输出参数:1 成功
0 失败
********************************************************************/
unsigned int NOR_Write(unsigned short *srcaddr,unsigned int desaddr,unsigned int size)
{
unsigned int i;
printf(" Write NorFlash start!\n");
for(i = ;i < size;i += ){
if( NOR_Program(desaddr,*srcaddr) != ){
printf(" Write NorFlash error!\n");
return ;
}
desaddr += ;
srcaddr++;
}
printf(" Write done.\n");
return ;
}

5、等待擦除或者编程结束

  判断当前状态,从而决定是否等待以及判断是否出错是根据状态标志位来操作的。“等待擦除或者编程结束”有不同的方法实现,这里使用的是DQ6轮转判断。

NorFlash

/*******************************************************************
函数功能:等待擦除或者编程结束
输入参数:无
输出参数: 1 成功
0 失败
*********************************************************************/
static unsigned int NOR_Wait(void)
{
unsigned short oldstatus,newstatus;
while()
{ oldstatus = NOR_RD(0x0);
newstatus = NOR_RD(0x0);
if( (oldstatus&0x40) == (newstatus&0x40) )
return ;
if( newstatus&0x20 )
{
oldstatus = NOR_RD(0x0);
newstatus = NOR_RD(0x0);
if( (oldstatus&0x40) == (newstatus&0x40) )
return ;
else
return ;
}
}
}

参考资料:CFI接口 

     Nor/Nand FLASH的读写

     Nor Flash 在实际应用中的读取方式

测试代码及文档资料:

     NorFlash.zip