NOR Flash

NOR Flash简介


    NOR FLASH是INTEL在1988年推出的一款商业性闪存芯片,它需要很长的时间进行抹写,大半生它能够提供完整的寻址与数据总线,并允许随机存取存储器上的任何区域,而且它可以忍受一万次到一百万次抹写循环,是早期的可移除式闪存储媒体的基础.

NOR Flash的原理


    从物理层面解释,NOR闸闪存的每个存储单元类似一个标准MOSFET,除了晶体管有两个而不是一个闸极.在顶部的是控制闸(CONTROL Gate,CG),它的徐阿奴阿布是土匪以氧化物层与周遭绝缘的浮闸(Floathing Gate,FG).由于这个FG在电气程度上是出于绝缘层独立的,所以湖边人员的毒啊班组会被困在里面,在一般的条件下,电荷经过很长时间都不会产生逃逸的情况.将FG放在CG与MOSFET通道之间.当FG抓到电荷时,它部分屏蔽掉来自CG的电场,并改变这个单元的阀电压(VT).在读出期间.利用向CG的电压,MOSFET通道会变的导电或保持绝缘.这视乎该单元的VT而定(而该单元的VT受到FG上的电荷控制).这股电流流过MOSFET通道,并以二进制码的方式读出、再现存储的数据.在每单元存储1位以上的数据的MLC设备中,为了能够更精确的测定FG中的电荷位准,则是以感应电流的量(而非单纯的有或无)达成的.

    逻辑上,单层NOR FLASH单元在默认状态代表二进制码中的"1"值,因为在以特定的电压值控制闸极时,电流会流经通道.经由以下流程,NOR FLASH 单元可以被设置为二进制码中的"0"值.

    1. 对CG施加高电压(通常大于5V).

    2. 现在通道是开的,所以电子可以从源极流入汲极(想像它是NMOS晶体管).

    3. 源-汲电流够高了,足以导致某些高能电子越过绝缘层,并进入绝缘层上的FG,这种过程称为热电子注入.

    由于汲极与CG间有一个大的、相反的极性电压,借由量子穿隧效应可以将电子拉出FG,所以能够地用这个特性抹除NORFLASH单元(将其重设为"1"状态).现代的NORFLASH芯片被分为若干抹除片段(常称为区扇(Blocks or sectors)),抹除操作只能以这些区块为基础进行;所有区块内的记忆单元都会被一起抹除.不过一般而言,写入NORFLASH单元的动作却可以单一字节的方式进行.

    虽然抹写都需要高电压才能进行,不过实际上现今所有闪存芯片是借由芯片内的电荷帮浦产生足够的电压,所以只需要一个单一的电压供应即可.

NOR Flash的访问方式


    在NOR FLASH的读取数据的方式来看,它与RAM的方式是相近的,只要能够提供数据的地址,数据总线就能够正确的挥出数据.考虑到以上的种种原因,多数微处理器将NORFLASH当做原地运行(Execute in place,XIP)存储器使用,这其实以为着存储在NORFLASH上的程序不需要复制到RAM就可以直接运行.由于NORFLASH没有本地坏区管理,所以一旦存储区块发生毁损,软件或驱动程序必须接手这个问题,否则可能会导致设备发生异常. 在解锁、抹除或写入NORFLASH区块时,特殊的指令会先写入已绘测的记忆区的第一页(Page).接着快闪记忆芯片会提供可用的指令清单给实体驱动程序,而这些指令是由一般性闪存接口(CommONFLASH memory Interface, CFI)所界定的. 与用于随机存取的ROM不同,NORFLASH也可以用在存储设备上;不过与NANDFLASH相比,NORFLASH的写入速度一般来说会慢很多.

NOR Flash 和 NAND Flash


    由1988年INTEL公司首先开发出NORFLASH技术,彻底颠覆了原先EPROM和EEPROM一统天下的局面;紧接1989年东芝公司发表了NANDFLASH结构,强调以成本为主,降低每bit的成本,具有更高的性能,并且能像硬盘一样可以通过接口轻松升级.NORFLASH和NANDFLASH是目前市面上两种主要的非易失闪存技术.NORFLASH 的特点是芯片内执行(XIP ,eXecute In Place),这样应用程序可以直接在FLASH闪存内运行,不必再把代码读到系统RAM中.NOR 的传输效率很高,在1~4MB的小容量时具有很高的成本效益,但是很低的写入和擦除速度大大影响到它的性能.NAND的结构能提供极高的单元密度,可以达到高存储密度,并且写入和擦除的速度也很快.应用NAND的困难在于FLASH的管理和需要特殊的系统接口.通常NOR的速度比NAND稍快一些,而NAND的写入速度比NOR快很多,在设计中应该考虑这些情况.

NOR Flash与NAND Flash的比较


    虽然NOR和NAND两种技术在现在的市场上都占有主流的地位,而且经过十几年的历史,但是现在仍然有相当多的硬件工程师分布清楚NOR和NAND闪存.相"FLASH存储器"经常可以与相"NOR存储器"互换使用.许多业内人士也搞不清楚NAND闪存技术相对于NOR技术的优越之处,因为大多数情况下闪存只是用来存储少量的代码,这时NOR闪存更适合一些.而NAND则是高数据存储密度的理想解决方案.

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

    NAND结构能提供极高的单元密度,可以达到高存储密度,并且写入和擦除的速度也很快.应用NAND的困难在于FLASH的管理和需要特殊的系统接口.

    性能比较

    FLASH闪存是非易失存储器,可以对称为块的存储器单元块进行擦写和再编程.任何FLASH器件的写入操作只能在空或已擦除的单元内进行,所以大多数情况下,在进行写入操作之前必须先执行擦除.NAND器件执行擦除操作是十分简单的,而NOR则要求在进行擦除前先要将目标块内所有的位都写为0.

    由于擦除NOR器件时是以64~128KB的块进行的,执行一个写入/擦除操作的时间为5s,与此相反,擦除NAND器件是以8~32KB的块进行的,执行相同的操作最多只需要4ms.

    执行擦除时块尺寸的不同进一步拉大了NOR和NADN之间的性能差距,统计表明,对于给定的一套写入操作(尤其是更新小文件时),更多的擦除操作必须在基于NOR的单元中进行.这样,当选择存储解决方案时,设计师必须权衡以下的各项因素.

    l NOR的读速度比NAND稍快一些.

    2 NAND的写入速度比NOR快很多.

    3 NAND的4ms擦除速度远比NOR的5s快.

    4 大多数写入操作需要先进行擦除操作.

    5 NAND的擦除单元更小,相应的擦除电路更少.

    接口差别

    NOR FLASH带有SRAM接口,有足够的地址引脚来寻址,可以很容易地存取其内部的每一个字节.

    NAND器件使用复杂的I/O口来串行地存取数据,各个产品或厂商的方法可能各不相同.8个引脚用来传送控制、地址和数据信息.

    NAND读和写操作采用512字节的块,这一点有点像硬盘管理此类操作,很自然地,基于NAND的存储器就可以取代硬盘或其他块设备.

    容量和成本

    NAND FLASH的单元尺寸几乎是NOR器件的一半,由于生产过程更为简单,NAND结构可以在给定的模具尺寸内提供更高的容量,也就相应地降低了价格.

    NOR FLASH占据了容量为1~16MB闪存市场的大部分,而NAND FLASH只是用在8~128MB的产品当中,这也说明NOR主要应用在代码存储介质中,NAND适合于数据存储,NAND在CompactFLASH、Secure Digital、PC Cards和MMC存储卡市场上所占份额最大.

    可靠性和耐用性

    采用flahs介质时一个需要重点考虑的问题是可靠性.对于需要扩展MTBF的系统来说,FLASH是非常合适的存储方案.可以从寿命(耐用性)、位交换和坏块处理三个方面来比较NOR和NAND的可靠性.

    寿命(耐用性)

    在NAND闪存中每个块的最大擦写次数是一百万次,而NOR的擦写次数是十万次.NAND存储器除了具有10比1的块擦除周期优势,典型的NAND块尺寸要比NOR器件小8倍,每个NAND存储器块在给定的时间内的删除次数要少一些.

NOR Flash的烧写方式


    相对于硬件工程师和嵌入式软件工程师一般在完成设计之后常常需要验证FLASH是否在工作.在应用当中,也有很多时候需要对FLASH进行写操作.该文章简单介绍了基于ARM芯片的NORFLASH烧写,并提供了2个具体的实例和源代码,希望对有需要的朋友有点帮助.在开始之前,先声明一下,这篇文章只是介绍了如何写 NORFLASH 的烧写驱动,和H-JTAG/H-FLASHER没有直接的联系.

    在后面的介绍里,如无特别说明,处理器指的是 ARM 处理器,FLASH 指的都是 NORFLASH.另外,BYTE 指的是8-BIT的数据单元,HALF-WORD代表的是16-BIT的数据单元,而WORD 则代表了32-BIT的数据单元.

    1. NOR FLASH 的简单介绍

    NOR FLASH 是很常见的一种存储芯片,数据掉电不会丢失.NOR FLASH支持Execute ON Chip,即程序可以直接在FLASH片内执行.这点和NANDFLASH不一样.因此,在嵌入是系统中,NORFLASH很适合作为启动程序的存储介质.

    NOR FLASH的读取和RAM很类似,但不可以直接进行写操作.对NOR FLASH的写操作需要遵循特定的命令序列,最终由芯片内部的控制单元完成写操作.从支持的最小访问单元来看,NORFLASH一般分为 8 位的和16位的(当然,也有很多NORFLASH芯片同时支持8位模式和是16 位模式,具体的工作模式通过特定的管脚进行选择) . 对8位的 NORFLASH芯片,或是工作在8-BIT模式的芯片来说,一个地址对应一个BYTE(8-BIT)的数据.例如一块8-BIT的NORFLASH,假设容量为4个 BYTE.那芯片应该有8个数据信号D7-D0 和2个地址信号,A1-A0.地址0x0对应第0个 BYTE,地址0x1对应于第1BYTE,地址0x2对应于第2个 BYTE,而地址0x3则对应于第3 个BYTE对16位的 NORFLASH芯片,或是工作在16-BIT模式的芯片来说,一个地址对应于一个HALF-WORD(16-BIT)的数据.例如,一块16-BIT的 NORFLASH,假设其容量为4个BYTE.那芯片应该有16 个数据信号线D15-D0 和1个地址信号A0.地址 0x0对应于芯片内部的第0个 HALF-WORD,地址0x1对应于芯片内部的第1个 HALF-WORD.FLASH一般都分为很多个SECTOR,每个SECTOR包括一定数量的存储单元.对有些大容量的FLASH,还分为不同的BANK,每个BANK包括一定数目的SECTOR.FLASH的擦除操作一般都是以SECTOR,BANK或是整片FLASH为单位的.

    在对FLASH进行写操作的时候,每个BIT可以通过编程由1变为0,但不可以有0修改为1.为了保证写操作的正确性,在执行写操作前,都要执行擦除操作.擦除操作会把FLASH的一个SECTOR,一个BANK或是整片FLASH 的值全修改为0xFF.这样,写操作就可以正确完成了.

    2. ARM 处理器的寻址

    ARM 可以说是目前最流行的32位嵌入式处理器.在这里只提一下 ARM 处理器的寻址,为后面做个铺垫.从处理器的角度来看,系统中每个地址对应的是一个BYTE的数据单元.这和很多别的处理器都是一样的.

    3.  处理器和 NOR FLASH 的硬件连接

    从前面的介绍,我们知道从处理器的角度来看,每个地址对应的是一个 BYTE 的数据单元.而,NORFLASH 的每个地址有可能对应的是一个BYTE的数据单元,也有可能对应的是一个HALF-WORD的数据单元.所以在硬件设计中,连接ARM处理器和 NORFLASH时,必须根据实际情况对地址信号做特别的处理.

    如果ARM处理器外部扩展的是8-BIT的NOR FLASH, 数据线和地址线的连接应该如图1所示. 从图中我们可以看到,处理器的数据信号D0-D7和 FLASH的数据信号D0-D7是一一对应连接的,处理器的地址信号A0-An和NOR FLASH的地址信号A0-An 也是一一对应连接的.

    如果ARM处理器外部扩展的是16-BIT的NOR FLASH, 数据线必须要错位连接. 图2给了一个ARM处理器和16-BITNOR  FLASH 的连接示意图.如图2所示,ARM处理器的数据信号D0-D15和FLASH 的数据信号D0-D15是一一对应的.而ARM处理器的地址信号和NORFLASH 的地址信号是错位连接的,ARM的 A0悬空,ARM 的A1 连接FLASH 的A0,ARM 的A2连接FLASH 的A1,依次类推.需要错位连接的原因是:ARM处理器的每个地址对应的是一个BYTE 的数据单元,而 16-BIT 的 FLASH 的每个地址对应的是一个 HALF-WORD(16-BIT)的数据单元.为了保持匹配,所以必须错位连接.这样,从ARM处理器发送出来的地址信号的最低位A0对16-BITFLASH来说就被屏蔽掉了.

    补充说明:

    1.  一般来说,ARM处理器内部要设置相应的寄存器,告诉处理器外部扩展的FLASH的位宽(8-BIT/16-BIT/32-BIT) .这样,处理器才知道在访问的时候如何从FLASH正确的读取数据.

    2.  有些ARM处理器内部可以设置地址的错位.对于支持软件选择地址错位的处理器,在连接16-BITFLASH的时候,硬件上可以不需要把地址线错位.读者设计的时候,请参考MCU的数据手册,以手册为准,以免造成不必要的麻烦.

    3.  如果处理器支持内部设置地址错位,在实际访问的时候,送出的地址实际上是在MCU内部做了错位处理,其作用是等效于硬件连接上的错位的.

    上面的描述可能比较抽象,下面让我们来看2个 ARM处理器访问16-BIT FLASH的例子:

    例子 1:ARM处理器需要从地址 0x0 读取一个 BYTE

    1 - ARM处理器在地址线An-A0上送出信号0x0;

    2 – 16-BIT FLASH在自己的地址信号An-A0上看到的地址是0x0,然后将地址0x0对应的16-BIT数据单元输出到D15-D0上;

    3 – ARM处理器知道访问的是16-BIT的FLASH,从D7-D0上读取所需要的一个BYTE的数据;

    例子 2:ARM处理器需要从地址 0x1 读取一个 BYTE

    1 - ARM处理器在地址线An-A0上送出信号0x1;

    2 – 16-BIT FLASH在自己的地址信号An-A0上看到的地址依然是0x0, 然后将地址0x0对应的16-BIT数据单元输出到D15-D0上;

    3 –ARM处理器知道访问的是16-BIT的FLASH,从D15-D8 上读取所需要的一个BYTE 的数据;

    4.  从软件角度来看 ARM 处理器和 NOR FLASH 的连接

    在上一个小节里,我们简单了解了 ARM 处理器和 FLASH 的硬件连接.在这个小节里面,我们从软件的角度来理解ARM处理器和 FLASH的连接.对于8-BIT的FLASH的连接,很好理解,因为ARM处理器和8-BITFLASH的每个地址对应的都是一个 BYTE 的数据单元.所以地址连接毫无疑问是一一对应的.如果 ARM 处理器连接的是 16-BIT 的处理器,因为 ARM 处理器的每个地址对应的是一个 BYTE 的数据单元,而 16-BITFLASH 的每个地址对应的是一个 HALF-WORD 的16-BIT的数据单元.所以,也毫无疑问,ARM处理器访问16-BIT处理器的时候,地址肯定是要错开一位的.在写FLASH驱动的时候,我们不需要知道地址错位是由硬件实现的,还是是通过设置ARM处理器内部的寄存器来实现的,只需要记住2点:

    1 – ARM处理器访问8-BIT FLASH的时候,地址是一一对应的;

    2 – ARM处理器访问16-BIT FLASH的时候,地址肯定是错位的.这一点对理解后面的例子会很有帮助.

    5. 8-BIT FLASH 烧写驱动实例 - HY29F040

    HY29F040是现代公司的一款8-BIT的NOR FLASH.在这个小节里,我们以这个芯片为例子,介绍如何对8-BIT NOR FLASH进行操作.

    HY29F040的容量为512K-BYTE,总共包括8 个SECTOR,每个SECTOR 的容量是64K-BYTE.该芯片支持SECTOR擦除,整片擦除和以BYTE 为基本单位的写操作.HY29F040的命令定义如表-1所示.

    下面,我们来看看如何实现基本的擦除和编程操作.在本节后面的描述中,我们使用了下面的2 个定义:

    U32 sysbase;              //该变量用来表示 FLASH 的起始地址

    #define SysADDR8(sysbase, offset)    ((volatile U8*)(sysbase)+(offset))   //用来方便对指定的 FALSH 地址进行操作

    先解释一下 SysAddr8 的定义.这个宏定义了一个 BYTE(8-BIT)指针,其地址为(sysbase + offset).假设FLASH 的起始地址为0x10000000,如果要将0xAB写到FLASH的第一个BYTE中去,可以用下面的代码:

    *SysAddr8(0x10000000, 0x1) = 0xAB;

    注意:

    在本节后面的描述中,SYSBASE代表的是 FLASH的起始地址,而SysAddr8中的OFFSET则代表了相对于FLASH起始地址的BYTE偏移量.OFFSET也是8-BITFLASH在自己的地址信号An-A0上看到的地址.

    整片擦除操作

    整片擦除操作共需要6个周期的总线写操作

    1 – 将 0xAA写到 FLASH 地址 0x5555

    2 – 将 0x55 写到 FLASH 地址 0x2AAA

    3 – 将 0x80 写到 FLASH 地址 0x5555

    4 – 将 0xAA写到 FLASH 地址 0x5555

    5 – 将 0x55 写到 FLASH 地址 0x2AAA

    6 – 将 0x10 写到 FLASH 地址 0x5555

    对应的代码:

    *SysAddr8(sysbase, 0x5555) = 0xAA;    //将值 0xAA写到FLASH 地址 0x5555

    *SysAddr8(sysbase, 0x2AAA) = 0x55;    //将值 0x55 写到FLASH 地址 0x2AAA

    *SysAddr8(sysbase, 0x5555) = 0x80;    //将值 0x80 写到FLASH 地址 0x5555

    *SysAddr8(sysbase, 0x5555) = 0xAA;    //将值 0xAA写到FLASH 地址 0x5555

    *SysAddr8(sysbase, 0x2AAA) = 0x55;    //将值 0x55 写到FLASH 地址 0x2AAA

    *SysAddr8(sysbase, 0x5555) = 0x10;    //将值 0x10 写到FLASH 地址 0x5555

    SECTOR 擦除操作

    SECTOR的擦除操作共需要6个周期的总线写操作

    1 – 将 0xAA写到 FLASH 地址 0x5555

    2 – 将 0x55 写到 FLASH 地址 0x2AAA

    3 – 将 0x80 写到 FLASH 地址 0x5555

    4 – 将 0xAA写到 FLASH 地址 0x5555

    5 – 将 0x55 写到 FLASH 地址 0x2AAA

    6 – 将 0x30 写到要擦除的 SECTOR 对应的地址

    对应的代码:

    *SysAddr8(sysbase, 0x5555) = 0xAA;    //将值 0xAA写到FLASH 地址 0x5555

    *SysAddr8(sysbase, 0x2AAA) = 0x55;    //将值 0x55 写到FLASH 地址 0x2AAA

    *SysAddr8(sysbase, 0x5555) = 0x80;    //将值 0x80 写到FLASH 地址 0x5555

    *SysAddr8(sysbase, 0x5555) = 0xAA;    //将值 0xAA写到FLASH 地址 0x5555

    *SysAddr8(sysbase, 0x2AAA) = 0x55;    //将值 0x55 写到FLASH 地址 0x2AAA

    *SysAddr8(sysbase, addr) = 0x30;     //将值 0x30 写到要擦除的 SECTOR 对应的地址

    BYTE 编程操作

    写一个BYTE 的数据到FLASH中去,需要 4个周期的总线写操作

    1 – 将 0xAA写到 FLASH 地址 0x5555

    2 – 将 0x55 写到 FLASH 地址 0x2AAA

    3 – 将 0xA0 写到 FLASH 地址 0x5555

    4 – 将编程数据(BYTE)写到对应的编程地址上去

    对应的代码:

    *SysAddr8(sysbase, 0x5555) = 0xAA;    //将值 0xAA写到FLASH 地址 0x5555

    *SysAddr8(sysbase, 0x2AAA) = 0x55;    //将值 0x55 写到FLASH 地址 0x2AAA

    *SysAddr8(sysbase, 0x5555) = 0xA0;    //将值 0xA0 写到FLASH 地址 0x5555

    *SysAddr8(sysbase, addr) = data;      //将一个 BYTE的数据写到期望的地址

    6. 16-BIT FLASH 烧写驱动实例 - SST39VF160

    SST39VF160是SST公司的一款16-BIT的NORFLASH. 在这个小节里, 我们以SST39VF160为例子, 介绍如何对16-BIT NORFLASH进行操作.对8-BITFLASH的操作很好理解,但对16-BITFLASH的操作理解起来要晦涩很多.我尽力描述得清楚些.

    SST39VF160的容量为2M-BYTE , 总共包括512个SECTOR, 每个SECTOR 的容量是4K-BYTE. 该芯片支持SECTOR擦除,整片擦除和以 HALF-WORD 为基本单位的写操作.SST39VF160 的命令定义如表-2 所示.在表 2 中,因为所有命令都是从FLASH的角度来定义的. 所以,   所有的地址都是HALF-WORD地址, 指的是16-BIT FLASH在自己的地址信号An-A0上看到的地址.

    在本节后面的描述中,我们使用了下面的2个定义:

    U32 sysbase;              //该变量用来表示 FLASH 的起始地址

    #define SysAddr16(sysbase, offset)  ((volatile U16*)(sysbase)+(offset))  //用来方便对指定的 FALSH 地址进行操作

    SysAddr16(sysbase,  offset)首先定义了一个16-BIT  HALF-WORD的指针,指针的地址为sysbase,然后根据offset做个偏移操作. 因为HALF-WORD指针的地址是2个BYTE对齐的, 所以每个偏移操作会使得地址加2.  最终, SysAddr16 (sysbase, offset)相当于定义了一个HALF-WORD的指针,其最终地址为(sysbase  +  2offset) .在使用SysAddr16 的时候,将sysbase设置成 FLASH 的起始地址,offset 则可以理解为相对于 FLASH 起始地址的 HALF-WORD 偏移量或是偏移地址.假设 FLASH 的起始地址为 0x10000000,SysAddr16(0x10000000, 0)指向 16-BIT FLASH 的第 0 个 HALF-WORD, SysAddr16(0x10000000, 1指向16-BIT FLASH的第1 个HALF-WORD.依次类推.如果要将0xABCD分别写到FLASH 的第0个和第 1个HALF-WORD 中去,可以用下面的代码:

    *SysAddr16(0x10000000, 0x0) = 0xABCD;

    *SysAddr16(0x10000000, 0x1) = 0xABCD;

    接下来,我们分别从ARM处理器的角度和FLASH的角度来具体分析一下.

    从 ARM 的角度来看:

    假设 FLASH 的起始地址为 0x10000000,因为 ARM 处理器知道 FLASH 的地址空间为 0x10000000 ~ (0x10000000 +FLASH容量 –  1),所以在对这个地址空间进行访问的时候,会设置好FLASH的片选信号,并将低位的地址输出到 地址信号上.以*SysAddr16(0x10000000, 0x1) = 0xABCD 为例.从ARM 处理器的角度来看,该操作是把0xABCD写到地址0x10000002上去.所以ARM处理器最终会在它的地址信号An-A0输出地址0x2,同时会在D15-D0 上输出0xABCD.

    从 FLASH 的角度来看:

    还是以  *SysAddr16(0x10000000, 0x1) = 0xABCD 为例,FLASH看到的地址是多少呢?接着分析.ARM 处理器在执行操作的时候,会设置好相应的FLASH片选使能信号,并在ARM的地址信号An-A0上输出 0x2.因为 ARM和 16-BIT FLASH的地址信号的连接是错开一位的, 所以, FLASH最终在自己的地址An-A0上看到的信号是0x1, 相当于将ARM

    处理器输出的地址往右做了一个移位操作,刚好对应的是FLASH的第1 个HALF-WORD.同时,FLASH会在自己的D15-D0上看到数据0xABCD.

    通过上面的分析,我们知道 SysAddr16 中指定的 offset 的值就是 16-BITFLASH 在自己的地址 An-A0 上看到的值.所以,我们可以很方便的通过 SysAddr16(sysbase, offset) 对FLASH 进行操作,其中 sysbase 代表FLASH 起始地址,offset 则代表了FLASH 的第几个HALF-WORD(HALF-WORD偏移量或偏移地址) .

    注意:

    1. 在本节后面的描述中,SysAddr16中的 SYSBASE代表的是FLASH的起始地址,而SysAddr16中的 OFFSET则代表了相对于FLASH起始地址的 HALF-WORD 偏移量或偏移地址.OFFSET 的值也是16-BIT FLASH在自己的地址信号An-A0上看到的值.

    2.在SST39VF160的命令定义中,所有的地址都是针对FLASH的HALF-WORD地址,指的是在FLASH自己的地址信号An-A0上看到的地址.

    整片擦除操作

    整片擦除操作共需要6个周期的总线写操作

    1 – 将 0x00AA写到 FLASH HALF-WORD 地址 0x5555

    2 – 将 0x0055 写到 FLASH HALF-WORD地址 0x2AAA

    3 – 将 0x0080 写到 FLASH HALF-WORD地址 0x5555

    4 – 将 0x00AA写到 FLASH HALF-WORD 地址 0x5555

    5 – 将 0x0055 写到 FLASH HALF-WORD地址 0x2AAA

    6 – 将 0x0010 写到 FLASH HALF-WORD地址 0x5555

    对应的代码:

    *SysAddr16(sysbase, 0x5555) = 0x00AA;    //将值 0x00AA 写到FLASH HALF-WORD地址 0x5555

    *SysAddr16(sysbase, 0x2AAA) = 0x0055;    //将值 0x0055 写到FLASH HALF-WORD地址 0x2AAA

    *SysAddr16(sysbase, 0x5555) = 0x0080;    //将值 0x0080 写到FLASH HALF-WORD地址 0x5555

    *SysAddr16(sysbase, 0x5555) = 0x00AA;    //将值 0x00AA 写到FLASH HALF-WORD地址 0x5555

    *SysAddr16(sysbase, 0x2AAA) = 0x0055;    //将值 0x0055 写到FLASH HALF-WORD地址 0x2AAA

    *SysAddr16(sysbase, 0x5555) = 0x0010;    //将值 0x0010 写到FLASH HALF-WORD地址 0x5555

    SECTOR 擦除操作

    SECTOR的擦除操作共需要6个周期的总线写操作

    1 – 将 0x00AA写到 FLASH HALF-WORD 地址 0x5555

    2 – 将 0x0055 写到 FLASH HALF-WORD地址 0x2AAA

    3 – 将 0x0080 写到 FLASH HALF-WORD地址 0x5555

    4 – 将 0x00AA写到 FLASH HALF-WORD 地址 0x5555

    5 – 将 0x0055 写到 FLASH HALF-WORD地址 0x2AAA

    6 – 将 0x0030 写到要擦除的 SECTOR 对应的 HALF-WORD地址

    对应的代码:

    *SysAddr16(sysbase, 0x5555) = 0x00AA;    //将值 0x00AA 写到FLASH HALF-WORD地址 0x5555

    *SysAddr16(sysbase, 0x2AAA) = 0x0055;    //将值 0x0055 写到FLASH HALF-WORD地址 0x2AAA

    *SysAddr16(sysbase, 0x5555) = 0x0080;    //将值 0x0080 写到FLASH HALF-WORD地址 0x5555

    *SysAddr16(sysbase, 0x5555) = 0x00AA;    //将值 0x00AA 写到FLASH HALF-WORD地址 0x5555

    *SysAddr16(sysbase, 0x2AAA) = 0x0055;    //将值 0x0055 写到FLASH HALF-WORD地址 0x2AAA

    *SysAddr16(sysbase, addr >> 1) = 0x0030;    //将值 0x0030 写到要擦除的 SECTOR 对应的

    HALF-WORD地址

    注意:

    上面的代码中第6个操作周期中的ADDR 是从ARM处理器的角度来看的BYTE地址,因为在擦除的时候,用户希望指定的是从 ARM 的角度看到的地址,这样更方便和更直观.而在 SysAddr16 的宏定义中,OFFSET 表示的是相对于FLASH起始地址的 HALF-WORD 偏移量,或是FLASH在自己的地址信号An-A0上看到的地址.所以需要执行一个右移操作,把ADDR转换成 HALF-WORD 地址.

    举例说明,SST39VF160 每个 SECTOR 的大小是 4K-BYTE.从 ARM 处器的角度和用户的角度来看,SECTOR-0 相对于FLASH起始地址的BYTE地址是0x0;从FLASH来看SECTOR-0 的HALF-WORD地址是0x0.从ARM处理器的角度和用户的角度来看, FLASH SECTOR-1相对于FLASH起始地址的BYTE地址0x1000; 从FLASH来看, SECTOR-1的HALF-WORD地址应该是(0x1000 >> 1) = 0x800.

    如果要擦除SECTOR-0,上面代码的第6条指令应该是:

    *SysAddr16(sysbase, 0x0 >> 1) = 0x0030;

    如果要擦除SECTOR-1,上面代码的第6条指令应该是:

    *SysAddr16(sysbase, 0x1000 >> 1) = 0x0030;

    HALF-WORD 编程操作

    写一个HALF-WORD的数据到FLASH中去,需要4个周期的总线写操作

    1 – 将 0x00AA写到 FLASH HALF-WORD 地址 0x5555

    2 – 将 0x0055 写到 FLASH HALF-WORD地址 0x2AAA

    3 – 将 0x00A0 写到 FLASH HALF-WORD 地址 0x5555

    4 – 将编程数据(HALF-WORD)写到对应的 HALF-WORD地址

    对应的代码:

    *SysAddr16(sysbase, 0x5555) = 0x00AA;      //将值 0x00AA 写到FLASH 地址 0x5555

    *SysAddr16(sysbase, 0x2AAA) = 0x0055;      //将值 0x0055 写到FLASH 地址 0x2AAA

    *SysAddr16(sysbase, 0x5555) = 0x00A0;      //将值 0x00A0 写到FLASH 地址 0x5555

    *SysAddr16(sysbase, addr >> 1) = data;      //将数据写到对应的 HALF-WORD 地址

    注意:

    上面的代码中第4个操作周期中的ADDR是从ARM处理器的角度来看的BYTE地址, 因为在执行写操作的时候,用户希望指定的是从 ARM 的角度看到的地址,这样会更方便和更直观.而在 SysAddr16 的宏定义中,OFFSET表示的是相对于FLASH起始地址的HALF-WORD偏移量. 所以需要执行一个右移操作, 把它转换成HALF-WORD

    地址.

    举例说明,如果要数据 0x0123 写到地址 0x0 去,对应的是 FLASH 的第 0 个 HAFL-WORD,对应的 HALF-WORD 地址应该是0x0,上面代码的第4条指令应该是:

    *SysAddr16(sysbase, 0x0 >> 1) = 0x0123;

    如果要数据0x4567写到地址0x2去, 对应的是FLASH的第1个 HALF-WORD, 对应的HALF-WORD地址应该是0x1, 上面代码的第4条指令应该是:

    *SysAddr16(sysbase, 0x2 >> 1) = 0x4567;

    如果要数据0x89AB写到地址0x4去, 对应的是FLASH的第2个HALF-WORD, 对应的HALF-WORD地址应该是0x2,上面代码的第4条指令应该是:

    *SysAddr16(sysbase, 0x4 >> 1) = 0x89AB;

    如果要数据 0xCDEF 写到地址 0x6 去,对应的是 FLASH 的第 3 个 HALF-WORD,对应的 HALF-WORD 地址应该是0x3,上面代码的第4条指令应该是:

    *SysAddr16(sysbase, 0x6 >> 1) = 0xCDEF;

    7. ADS 版源代码下载

    如果用户有需要,可以去下载在前面讨论的 2 个实例的 ADS 版的完整源代码和 FLASH 数据手册.提供给用户的程序都是在实际使用过程中经过测试的.源代码只供用户参考,并不一定能直接使用在用户的开发板上.用户需要根据自己实际使用的芯片进行相应的修改.

    源代码下载链接:Http://www.hjtag.com/forum/forumdisplay.php?fid=3

    8. 结束语

    这篇文章简单介绍了如何对NOR FLASH进行操作, 但没有包括状态查询, 保护等其他操作. 对于更复杂的多片FLASH并联的情况也没有讨论.有需要的朋友可以自己去研究.

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

    本实验是基于TQ2440的实验平台,采用S3C2440(ARM9)的CPU,以ADS/MDK的开发环境,使用的是AM29LV160DB的NORFLASH,进行开发学习的一个NORFLASH的编写和读取.

    (1)   Nor FLASH 工作模式

    Nor FLASH上电后处于数据读取状态(Reading Array Data).此状态可以进行正常的读.这和读取SDRAM/SRAM/ROM一样.(要是不一样的话,芯片上电后如何从NorFLASH中读取启动代码.~)

    一般再对FLASH进行操作前都要读取芯片信息比如设备ID号.这样做的主要目的是为了判断自己写的程序是否支持该设备.    NorFLASH支持2种方式获取ID号.一种是编程器所用的方法需要高电压(11.5V-12.5V).另一种方法就是所谓的in-sySTem方法,就是在系统中通过NorFLASH的命令寄存器来完成.本文中只对in-system方法进行说明.此时需要切换到自动选择(Autoselect Command),这要通过发送命令来完成.命令类型见下图.注意:

    进入自动选择(Autoselect Command)模式后需要发送复位命令才能回到数据读取状态(Reading Array Data).

    在完成信息获取后一般就要擦除数据. NorFLASH支持扇区擦(Sector Erase)除和整片擦除(Chip Erase).这2种模式都有对应的命令序列.在完成擦除命令后会自动返回到数据读取(Reading Array Data)状态.在返回前可查询编程的状态.

    完成擦除后就需要对芯片进行写入操作也就是编程.这就需要进入编程(Program)状态.在完成编程命令后会自动返回到数据读取(Reading Array Data)状态.在返回前可查询编程的状态.注意:编程前一定要先擦除.因为编程只能将'1'改写为'0',通过擦写可以将数据全部擦写为'1'.

    以上是主要的操作其他操作还有写保护等,请参考芯片数据手册.

    图1-1 命令与模式

    (2) Nor FLASH 硬件连接

    图2-1 Nor FLASH 引脚

    图2-2 TQ2440中实际连接

    上图中要注意的几个地方:

    1.引脚47 为BYTE# :当其为高电平时数据输出为16bit模式(此时地址线为A19:A0).低电平为8bit模式. (此时地址线为A19:A1)上图中Pin47加VCC选用的是16bit模式有效地址线为A19:A0.

    2.对于16bit模式要16bit对齐因此S3C2440A的LADDR1要与A0连接.此时要注意的是NorFLASH片内地址0x555对应S3C2440A的地址为baseaddr+0x555*2;其中baseaddr与NorFLASH映射的地址有关.一般NorFLASH放在Bank0.所以baseaddr=0,但是开启mmu后baseaddr=地址0映射到的新地址.0x555*2的原因是LADDR1与A0连接.也就是0x555表示片内第0x555个word(16bit).

    3.引脚15为RYBY#输出引脚.用于输出Ready与Busy信号.实际用时可以不接.可用命令查询NorFLASH状态代替.

    (3) Nor FLASH 模式编程

    1. 读ID

    上图中表明 读id共有4个指令周期,钱3个为写周期,最后一个为读周期;

    #define FLASH_base      0x00000000  //FLASH接到bank0上

    #define    CMD_ADDR0            *((volATIle U16 *)(0x555*2+FLASH_base))

    #define    CMD_ADDR1            *((volaTIle U16 *)(0x2aa*2+FLASH_base))

    #define    CMD_ADDR2            *((volatile U16 *)(0xaaa*2+FLASH_base))

    /*** 读取 Am29LV800D 的ID ***/

    U32  Get_Am29LV800D_ID(void)

    {

    U32 i="0";

    CMD_ADDR0 = 0xaa;   CMD_ADDR1 = 0x55;  CMD_ADDR0 = 0x90;

    i  = (*(U16 *)(0*2+FLASH_base))<<16;//Manufacturer ID = 01

    CMD_ADDR0 = 0xaa;   CMD_ADDR1 = 0x55;  CMD_ADDR0 = 0x90;

    i  |=  *(U16 *)(1*2+FLASH_base);//device ID = 2249

    return i;

    }

    2. 扇区擦除(Sector Erase)

    扇区擦除命令序列的每个周期均为写周期.

    void  Am29LV800D_SectorErase(U32 SA)

    {

    CMD_ADDR0 = 0xAA; CMD_ADDR1 = 0x55;  CMD_ADDR0 = 0x80;

    CMD_ADDR0 = 0xAA; CMD_ADDR1 = 0x55;//Word 模式命令序列

    *((volatile U16 *)(SA)) = 0x30;

    Waitfor_endofprg();//状态查询

    }

    3. 编程(Program)

    编程 命令序列的每个周期均为写周期.

    int  Am29LV800D_WordProg (U32 PA,U16 PD)

    {

    CMD_ADDR0 = 0xAA;  CMD_ADDR1 = 0x55;  CMD_ADDR0 = 0xA0;

    *((volatile U16 *)(PA)) = PD;// word模式,以上为4个命令周期

    return(Waitfor_endofprg());//状态查询

    }

    4.写操作状态(WRITE OPERATION STATUS)

    NorFLASH 提供几个数据位来确定一个写操作的状态,它们分别是: DQ2, DQ3, DQ5, DQ6,DQ7, and RY/BY#. 如上图所示.其中DQ7, RY/BY#引脚, 和 DQ6 中的每一个都提供了一种方法来判断一个编程或者擦除操作是否已经完成或正在进行中.实际编程中只需要使用其中的一种.

    DQ7:Data# Polling bit,DQ7在编程时的状态变化.

    在编程过程中从正在编程的地址中读出的数据的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可以区分NorFLASH是否处于擦除中或者擦除状态,但不能区分哪个快被选中擦除.因此需要这2个位来确定扇区和模式状态信息.

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

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

    以上讲了这些状态为,实际只需要使用几个就行,比较简单的就是选择DQ5,DQ6/DQ2.如下例.

    /****** Am29LV800D 的检测 ******/

    int Waitfor_endofprg(void)

    {

    volatile U16 FLASHStatus,old;

    old=*((volatile U16 *)0x0);//先读一次状态

    while(1)

    {

    FLASHStatus=*((volatile U16 *)0x0);//再读一次状态

    if( (old&0x40) == (FLASHStatus&0x40) ) break;//比较DQ6.相同说明设备已经就绪

    if( FLASHStatus&0x20 )  //判断DQ5,为'1'则超时

    {

    old=*((volatile U16 *)0x0);

    FLASHStatus=*((volatile U16 *)0x0);//在读取比较一次.因为可能在超时前刚好玩

    //成操作.

    if( (old&0x40) == (FLASHStatus&0x40) )

    return 1;

    else return 0;

    }

    old=FLASHStatus;

    }

    return 1;

    }

8位单片机与NOR Flash的借口设计

    引 言

    20世纪80年代诞生了FLASH存储器,简称闪速存储器,诞生之后迅速发展,它是一种新型的半导体不会发存储器,同时它有着RAM和ROM两者的优点,既可以在线擦除、改写,又能够在掉线之后保持数据的完成性.NORFLASH是FLASH存储器中最早出现的一个品种,和其他种类的FLASH存储器相比之下有很多优势:随机读取速度快,可以单字节或者单字编程,允许CPU直接从芯片中读取代码执行、可靠性高等.因此NORFLASH存储器在嵌入式系统应用开发中占有非常重要的地位.本文以SST公司的NORFLASH芯片SST39SF040和MCS-51单片机为例,针对大容量NORFLASH在8位低档单片机中应用的特殊性,详细介绍了其接口硬件和接口软件的设计方法.

    1 SST39SF040芯片介绍

    SST39SF040是SST公司最近推出的一种基于SuperFLASH技术的NORFLASH存储器,属于SST公司并行闪速存储器系列;适用于需要程序在线写入或大容量、非易失性数据重复存储的场合.

    1.1 芯片内部功能结构和外部引脚

    图1是SST39SF040的内部功能结构框图,由Super-FLASH存储单元、行译码器、列译码器、地址缓冲与锁存器、输入/输出缓冲和数据锁存器以及控制逻辑电路等部分组成.图2是其外部引脚分布图,其中A18~A0为地址线,CE为芯片选通信号,OE可作为读信号,WE为写信号,DQ7~DQ0为数据线.

    1.2 芯片的主要特性

    ① 容量为512 KB,按512K×8位结构组织.

    ② 采用单一的5 V电源供电,编程电源VPP在芯片内部产生.

    ③ 芯片可反复擦写100 000次,数据保存时间为100年.

    ④ 工作电流典型值为10 mA,待机电流典型值为30μA.

    ⑤ 扇区结构:扇区大小统一为4 KB.

    ⑥ 读取、擦除和字节编程时间的典型值:数据读取时间为45~70 ns;扇区擦除时间为18 ms,整片擦除时间为70 ms;字节编程时间为14μs.

    ⑦ 有记录内部擦除操作和编程写入操作完成与否的状态标志位.

    ⑧ 具有硬、软件数据保护功能.

    ⑨ 具有地址和数据锁存功能.

    1.3 芯片的操作

    1.3.1 芯片的软件操作命令序列

    SST39SF040的软件操作可以分成两类:普通读操作和命令操作.

    普通读操作非常简单,与RAM的读操作类似,当OE和CE信号同时为低电平时,即可从芯片读出数据.

    芯片的命令操作包括芯片的识别、字节编程、扇区擦除以及整片擦除等.这些操作分别由各自的软件操作命令序列来完成,如表1所列.其中,BA为待编程字节的地址,Data为字节编程数据,SAX为待擦除扇区的地址.命令中的地址只有低15位有效,高4位可任意设置为"0"或"1".

    SST39SF040的软件操作命令序列实际上是由一个或多个总线写操作组成的.以SST39SF040的扇区擦除为例,其操作过程包括3个步骤:第1步,开启擦除方式,用表1中给出的第1至第5周期的总线写操作来实现;第2步,装载扇区擦除命令(30H)和待擦除扇区的地址,用其对应的第6周期的总线写操作来实现;第3步,进行内部擦除.内部擦除时间最长为25 ms.

    总线写操作时,OE必须保持为高电平,CE和WE应为低电平.地址和数据的锁存由CE和WE两个信号的边沿进行控制.它们当中后出现的下降沿将锁存地址,先出现的上升沿将锁存数据.

    1.3.2 字节编程和擦除操作的状态检测

    芯片在进行内部字节编程或擦除操作时都需要花费一定的时间,虽然可以采用固定的延时来等待这些操作的完成,但为了优化系统的字节编程和擦除操作时间,以及时判断内部操作的完成与否,SST39SF040提供了两个用于检测的状态位,即跳变位DQ6和数据查询位DQ7.在芯片进行内部操作时,只要根据图3的流程对DQ6或者DQ7进行查询就能及时作出判断.

    2 SST39SF040与MCS-51的接口设计

    2.1 硬件设计

    硬件设计就是搭建合适的接口电路,将SST39SF040连接到MCS-51的系统总线上.根据SST39SF040和MCS-51系列单片机的结构特性,我们发现SST39SF040的数据线和读、写信号线可以很容易地连接到MCS-51的系统总线上,所以要考虑的主要问题是SST39SF040地址线的连接.由于其容量已经超出了MCS-51的寻址范围,19根地址线无法全部连接到MCS-51的地址总线上,因此必须在该系统中进行进一步的存储器扩展.存储器扩展通常可利用单片机空闲的I/O口线作为页面地址输出引脚来实现.但是许多应用系统当中,单片机的I/O口线都是非常紧张的,在没有多余的I/O口线时,页面地址就必须提前从数据总线输出并存放在锁存器中备用.具体做法是:将锁存器直接挂在数据总线上,为其安排一个I/O地址,从而构成页面寄存器,在访问存储器时,提前将页面地址作为数据写入页面寄存器即可.

    根据以上分析可设计出SST39SF040与MCS-51之间的接口电路,如图4所示.本系统中,将512 KB的存储器分为32页面,每页大小为16 KB.由此可得,页面地址需要5位,页内偏移量需要14位.页面地址的给出是在进行存储器访问之前完成的,具体的方法是:用一条"MOVX"'命令将页面地址输出到锁存器74LS374中,再由74LS374将页面地址保持在存储器的地址引脚A14~A18上.页内偏移量则直接在存储器的读写命令中给出,执行命令时,低8位地址A0~A7从P0口输出到74LS373中保持;地址A8~A13则由单片机的P2.0~P2.5直接提供.以上分时输出的地址信号A0~A18将在读/写控制信号开始作用后,同时有效,以实现对SST39SF040的512KB全地址空间的访问.P2.6和P2.7分别用作SKT39SF040和锁存器74LS374的片选信号,SST39SF040的片选信号地址范围是8000H~BFFFH,74LS374的片选信号地址范围是4000H~7FFFH.

    2.2 软件设计

    软件设计就是编写对SST39SF040的操作程序,包括字节读出、扇区或整片擦除以及字节编程等.下面给出第1个扇区的擦除程序,其中DELAY25为25 ms延时子程序,其他操作程序可参照编写.

    程序编写过程中的难点是,如何将SST39SF040中待访问的单元地址进行分解并对应到读写命令中去.以扇区擦除操作的第1个命令为例,该命令的功能是将数据AAH写入地址5555H中.对于地址5555H,其最高5位A18~A14是01H,低14位A13~A0为1555H.最高5位地址决定的页面号必须先作为数据写入锁存器74LS374中,再将数据AAH写入该页中由低14位地址决定的单元.写入页面号时,指令中的地址可在4000H~7FFFH范围内任选一个,即选中锁存器74LS374;写人数据AAH时,指令中的地址可由低14位地址1555H加上8000H得到,其值为9555H.

    第1扇区擦除程序代码如下:

    结 语

    本文从硬件和软件两个方面对大容量NOR FLASH存储器与8位单片机的接口技术进行了分析、探讨,给出了具体的设计方案.其思想和方法对嵌入式系统的应用设计具有较高的参考价值,笔者已将它应用到一款考勤机产品的设计开发当中.

原:http://www.weeqoo.com/zhuanti/NOR-Flash/


你可能感兴趣的:(FLASH)