NorFlash

2019-04-14 15:49发布

一、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、引脚 2、NorFlash块图 3、扇区结构 Size: 2 MB in 35 Sectors Sector Start Addresses: 00000000 00004000 00006000 00008000 00010000 00020000 00030000 00040000 00050000 00060000 00070000 00080000 00090000 000A0000 000B0000 000C0000 000D0000 000E0000 000F0000 00100000 00110000 00120000 00130000 00140000 00150000 00160000 00170000 00180000 00190000 001A0000 001B0000 001C0000 001D0000 001E0000 001F0000   EN29LV160AB大小为2M,总共35个扇区,上图列出了每个扇区的起始地址。 三、NorFlash与ARM接线图   左图为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特有命令集操作。 2、NorFlash命令表   不利用CFI方式也可以操作,EN29LV160AB有自己的命令集,利用这个命令集可以完成需要的操作。 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 ",ManuID); printf("Device ID: %x ",DevID); } 2、读内容并显示 /******************************************************************* 函数功能:从NorFlash给定的地址处显示256B的内容 输入参数:addr 输出参数:无 *********************************************************************/ void NOR_2K_Content(unsigned char *addr) { unsigned int i; printf("Show 256 Bytes content of NorFlash: "); for(i=0; i<256; i++) { if((i%16)==0) printf(" %4x: ", i); printf("%02x ", *addr++); } printf(" "); } 3、擦除 /******************************************************************* 函数功能:擦除整个芯片 输入参数:无 输出参数:无 ********************************************************************/ void NOR_EraseChip(void) { printf("chip erasing is started! "); 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...... "); if(NOR_Wait()) { printf("Erasing done! "); } else { printf("Erasing error! "); } } /******************************************************************* 函数功能:擦除给定的扇区 输入参数:sect 扇区号 输出参数:无 *********************************************************************/ void NOR_EraseSector(unsigned char sect) { unsigned int sectaddr; if(sect > 34) { printf("sect number error! "); return ; } switch(sect) { case 0: sectaddr = 0x0; break; case 1: sectaddr = 0x2000; break; case 2: sectaddr = 0x3000; break; case 3: sectaddr = 0x4000; break; default: sectaddr = 0x8000*(sect - 3); } printf("Sector %d erasing is started! ",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...... "); if(NOR_Wait()) { printf("Erasing done! "); } else { printf("Erasing error! "); } } 4、编程 /******************************************************************* 函数功能:写一个字(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! "); for(i = 0;i < size;i += 2){ if( NOR_Program(desaddr,*srcaddr) != 1){ printf(" Write NorFlash error! "); return 0; } desaddr += 2; srcaddr++; } printf(" Write done. "); return 1; } 5、等待擦除或者编程结束   判断当前状态,从而决定是否等待以及判断是否出错是根据状态标志位来操作的。“等待擦除或者编程结束”有不同的方法实现,这里使用的是DQ6轮转判断。 /******************************************************************* 函数功能:等待擦除或者编程结束 输入参数:无 输出参数: 1 成功 0 失败 *********************************************************************/ static unsigned int NOR_Wait(void) { unsigned short oldstatus,newstatus; while(1) { oldstatus = NOR_RD(0x0); newstatus = NOR_RD(0x0); if( (oldstatus&0x40) == (newstatus&0x40) ) return 1; if( newstatus&0x20 ) { oldstatus = NOR_RD(0x0); newstatus = NOR_RD(0x0); if( (oldstatus&0x40) == (newstatus&0x40) ) return 1; else return 0; } } }   参考资料:CFI接口       Nor/Nand FLASH的读写      Nor Flash 在实际应用中的读取方式   测试代码及文档资料:      NorFlash.zip