《电子技术应用》
您所在的位置:首页 > 可编程逻辑 > 业界动态 > NAND型Flash在大容量存储回放系统中的应用

NAND型Flash在大容量存储回放系统中的应用

2008-06-18
作者:谢 民, 高梅国, 王 超

  摘 要: 在某些存储回放系统" title="回放系统">回放系统中,要求在存储容量大、数据可靠性高的同时,具有较宽的数据带宽,为此,可采用NAND型Flash实现容量要求和数据的非易失性;采用FPGA进行多片存储体并行读取,从而克服了NANDFlash固有的读取速度慢的缺点,并扩展了存储深度;同时引入双主设备的设计,利用FPGA与PC104实现存储和读取的功能分离,是存储方式灵活,控制方便的解决方案。本文介绍的方案降低了此类系统的实现难度,缩短了产品研发周期,已应用于实际系统中并得到好评。
  关键词: NAND Flash FPGA PC104


  闪存(Flash Memory)由于其具有非易失性、电可擦除性、可重复编程以及高密度、低功耗等特点,而被广泛地应用于U盘、MP3和数码相机等的数据存储" title="数据存储">数据存储设备中。NAND 和NOR Flash是目前市场上两种主要的非易失闪存芯片。与NOR型Flash相比,NAND型Flash在容量、功耗、使用寿命等方面的优势使得它成为高数据存储密度的理想解决方案。本文以Samsung公司生产的K9F1G08UOM为例,介绍NAND型Flash在板载大容量" title="大容量">大容量数据存储回放系统中的应用。
1 器件简介
1.1功能特性
  NAND型Flash芯片是Samsung 公司推出的新一代大容量数据存储器件,电源电压范围为1.7~3.6V,功耗低,TSSOP封装体积小,目前最大" title="最大">最大单片容量可达8Gb,按页读写,按块擦除。本次应用开发的是容量为1Gb的K9F1G08UOM,其功能框图[1]如图1所示。由图1可以看出,该器件按功能可以划分为如下几个部分:存储阵列、输入输出缓冲、命令寄存器、地址译码寄存器和控制逻辑产生。其中,命令寄存器用来确定外部设备对存储器进行操作的类型,地址译码寄存器保存被访问的地址并产生相应的译码选通信号。主设备通过8位的I/O" title="I/O">I/O端口分时复用访问器件命令、地址和数据寄存器,完成对芯片内存储体的访问。


1.2 存储体的组织结构
  K9F1G08UOM的组织结构框图[1]如图2所示。从图2可知,该K9F1G08UOM存储体由1024个块(Block)组成,每个Block含有64个页(Page),每个Page内有2K+64个字节,其中2KB为主存储区,用来保存用户数据;剩余的64个字节为辅助存储区,用来保存一些状态信息,如:坏块标志位、ECC码等。由图2中所列的表可知,由于I/O端口的宽度为8位,访问时需要在前两个地址访问周期内给出12位列地址(没有使用到的地址管脚必须拉至低电平),以及寻址到页内字节,然后在接下来的两个地址访问周期内给出16位的行地址以确定页号和块号;对于同等容量16位器件,由于二者的区别仅在于单页字节容量不同,所以访问时页内地址只需要给出11位,并且地址仍按8位经由I/O0~I/O7给出,其余未使用的地址管脚拉至低电平。

 


1.3 选择器件的参考因素
  选择NAND器件时,除了根据实际应用选择合适的容量以外,还需要考虑对NAND型Flash各种操作的速度是否能满足系统需求。表1给出了1Gb容量两种位宽类型的器件在读、写、擦除三种主要操作的近似速度,具体计算方法和参数可见参考文献[2][3]。需要强调的是:
  (1)位宽加倍对编程速度没有太大影响,这主要是因为在将一页数据写入Flash片内的寄存器后,器件自身将该页数据写入存储单元的时间基数较大。
  (2)位宽加倍使得读取速度接近翻番。
  (3)由于器件按块擦除,所以位宽对擦除速度基本没有影响。
2 应用实例
  以一板载大容量数据回放系统为例,其系统结构如图3所示,主要包括CPU模块、FPGA、NAND Flash和数模转换模块四部分。其中,CPU模块为一个与IBM-PC/AT兼容的PC/104 CPU模块,并作为整个系统的主控设备,完成数据接收、存储、回放参数设置等功能。CPU模块直接通过标准PC/104接插件固定在母板上;FPGA采用Xilinx公司Spartan3系列XC3S1000[2],主要完成数据的回放功能;数模转换模块完成数据从数字域到模拟域的转换,转换速率为100MBps;NAND Flash采用8位位宽、单片1Gb容量的K9F1G08UOM,用来存储回放数据,考虑单片Flash的数据输出率有限,系统中采用8片并行处理,所以存储容量是8Gb。


  FPGA模块是本系统的关键,其片内系统结构如图4所示。设计要点如下:


2.1 功能划分
  系统中允许两个主设备即FPGA和CPU模块访问Flash;在此将FPGA在逻辑上划分为Master和Slave两种模式。Master表示FPGA作为Flash的主设备,占用Flash 的总线,此时CPU模块只能访问FPGA内的控制寄存器;Slave则表示FPGA和Flash均作为CPU模块的从设备接受访问,Flash和FPGA均映射到CPU模块的某段I/O地址空间。此时对Flash来讲,FPGA只是提供CPU至Flash的数据和控制通路。FPGA片内系统结构如图4所示。图中:CPU通过PC/104总线访问控制寄存器的相应位来控制FPGA的状态切换,粗黑线只代表数据链路(控制链路都为单向信号,较数据链路简单,但连接方式与数据通路类似,为简化框图已省略)。
  虽然CPU模块与FPGA均能访问Flash,但是在具体实现时,如图4所示,FPGA内只实现对Flash的读控制,而其他诸如写操作、擦除以及检测坏块(invalid block)等操作则由CPU模块完成。这样设计的原因是:
  (1)系统带宽要求。前面提到了系统要求的输出数据速率为100MBps,而单片Flash的峰值数据输出速率仅为16MBps;PC/104总线的时钟频率为8MHz,且一个指令周期至少需要6个时钟,这样即使多片Flash并片操作也难满足系统要求。而FPGA实现时,则可以完全根据Flash的访问时序要求设计状态机,时间裕量可以很精确地调整,从而尽可能地接近对Flash访问的最大带宽。因此用FPGA实现其控制,性能要优于CPU实现的方案。
  (2)简化系统的设计和调试难度。虽然FPGA实现对Flash的访问可以达到最大带宽,但是它的设计以及调试却远较CPU实现复杂和困难。在FPGA设计中,设计者必须很精确地以数据流形式描述整个设计,必须很清楚地了解每个时刻信号的变化,而且设计当中的信号很不易观测,出现错误后对问题的定位比较困难。相比之下,CPU模块通过高级语言,以算法级的方式实现,再辅助以良好的开发调试环境,实现Flash控制要容易得多。本应用中将对Flash的写、擦除、记录坏块表等对时间要求不高的操作转移至CPU模块,这样可以大大降低整个系统的设计和调试难度。
2.2 FPGA与NAND Flash的接口设计
  NAND Flash和通常使用的存储器最大差别是接口的不同,通常使用的非易失性存储器如NOR Flash,由于它有一套完整的地址映射即访问接口,指定的地址总线和数据总线,从而可以很容易地访问其内部的每一个字节。而NAND Flash没有专门的地址线;它的接口是一种间接类I/O接口[3],通过8位的总线分别发送命令和地址到命令、地址寄存器来控制。以典型的“读”命令为例:写“读”命令到命令寄存器,写入4字节的地址到地址寄存器,等待设备将要求的数据放到输出寄存器,从数据寄存器读取一页的数据。NAND Flash这种接口的缺点是一般情况下无法用来引导系统,除非外接专门的状态机或控制器。其优点是:由于地址寄存器在芯片内部,芯片的管脚随着芯片容量的增加基本上不变,而且FPGA实现Flash访问,其接口设计无任何特殊要求,接口信号按通用I/O管脚设计即可(这里说的接口设计是指在Slave模式下,CPU模块与Flash接口设计)。本设计中采用的接口如图5所示。


  由图5可知,设计中通过L_A0、L_A1(在Slave模式下直接映射到PC/104总线对应的低地位地址线;在Master模式下则连接至读控制的对应输出端口)直接产生命令寄存器和地址寄存器选通信号,而芯片的Ready/Busy信号直接通过L_GPIO口传递给FPGA,然后给CPU模块。这种设计结构简单,访问速度快,唯一的缺点就是要求所使用的NAND型Flash必须具备CEDC(Chip Enable Don′t Care)特性,即不需要/CE(芯片使能信号)在整个操作的周期都一直拉低。


2.3 FPGA实现NAND型Flash读状态机的设计
  K9F1G08UOM的读时序如图6[2]所示。设计中的关键是保证命令、地址、数据以及控制信号在时序上的要求。由图可知,对Flash的读、写操作的最小时钟周期分别为tWC(45ns)和tRC(50ns)。为了方便设计,状态机的时钟选取40MHz(25ns)。当然,在资源足够的情况下也可以采用更高频率的时钟以减小时间裕量,从而提高访问速度。本设计程序实例如下:
  //cle_o-命令寄存器使能; ce_o-片选使能; we_o-写使能; ale_o-地址寄存器使能
  //re_o-读使能; rb_i-等待/忙信号 //start_i-读启动信号
  always @ (posedge clk_i )
  if ( rst_i) begin
  MooreState<=S0; //复位状态
  cle_o<=1′b0;ce_o<=1′b1;we_o<=1′b1;re_o<=1′b1;ale_o<=1′b0;io_o<=8′hxx;
  count_en<=1′b0; end
  else
  case (MooreState)
  S0:begin MooreState<=start_i?S1:S0;re_o<=1′b1;end
  S1: begin MooreState <= S2; //写命令寄存器
    cle_o<=1′b1;ce_o<=1′b0;we_o<=1′b0;io_o<=8′h00; end
  S2: begin MooreState<=S3;we_o<=1′b1;end
  S3: begin MooreState <=S4; //写地址寄存器1
    cle_o<=1′b0; we_o<=1′b0;ale_o<=1′b1;io_o<=
    coladr_l; end
  S4: begin MooreState<=S5;we_o<=1′b1;end
  S5: begin MooreState<=S6; //写地址寄存器2
    we_o<=1′b0;io_o<=coladr_h; end
  S6: begin MooreState<=S7;we_o<=1′b1;end
  S7: begin MooreState<=S8; //写地址寄存器3
    we_o<=1′b0;io_o<=radr_l; end
  S8: begin MooreState<=S9;we_o<=1′b1;end
  S9: begin MooreState<=S10; //写地址寄存器4
    we_o<=1′b0;io_o<=radr_h; end
  S10: begin MooreState<=S11;we_o<=1′b1;end
  S11: begin MooreState <= S12; //写命令寄存器
    cle_o<=1′b1;we_o<=1′b0;ale_o<=1′b0;io_o<=
    8′h30; end
  S12: begin MooreState<=S13;we_o<=1′b1;end
  S13: begin MooreState<= rb_i? //忙等待
  S14: S13;
    cle_o<=1′b0;io_o<=8′hxx; end
  S14: begin MooreState <= S15; //循环读一页数据
    re_o<=1′b0;count_en<=1′b1;end
  S15: begin MooreState<= (count_n==4095)?S16:S14;
    re_o<=1′b1; end
  S16: begin MooreState <=S0;   //结束
    ce_o<=1′b1;count_en<=1′b0; end
    endcase
    always @ (posedge clk_i )
  begin if (rst_i) count_n<=1;
  else if (count_en) count_n<=count_n+1;
  else count_n<=1;
  end
  上述程序中,在读操作时使用了Moore型状态机,其最大特点就是输出仅依赖于状态机的状态,与它的输入无关;而描述Moore状态机的最佳方式之一就是在always语句中使用case语句实现不同状态间的转换,且每种状态的输出逻辑都在相应的分支中描述。
  状态进程:本例中将读操作分成17个状态,其中状态S0用来初始化各输出信号,状态S1~S2和S12~S13完成对命令寄存器的写操作,状态S3~S11完成4次对地址寄存器的写操作,状态S14、S15则完成一页数据的连续读取。
  组合进程:组合进程是根据当前状态(现态)给输出信号赋值,并决定下一状态(次态)。在本例中,状态机根据不同的状态对ce、ale、cle、we、re、io等Flash信号进行赋值,以实现对Flash 的控制功能。
  另外,增加一个always语句实现同步计数,用于对读取的数据个数计数。
  上述程序只是读操作部分,具体读控制还包括地址产生、坏块表检测以及其他一些控制部分,由于篇幅有限,此处不赘述。
2.4 坏块表的建立
  由于NAND型Flash存储容量较大,难免在使用过程中出现存储单元的损坏,因此有必要记录每片Flash坏块的位置。设计中首先由CPU模块通过PC104总线访问Flash,检测器件中的坏块并建立坏块表(invalid block table),然后存储在FPGA内的双口RAM中。数据回放时,读状态机在跨块时需要将当前块的块号和坏块表中的块号按遍历方式进行比较,当确认该块为坏块时,将跳至下一可用块;否则读取该块数据。检测坏块的程序流程如图7所示,实现坏块检测的C代码如下:
  RAdr_H=0; RAdr_L=0;
  for(k=0; k<256; k++)
  //遍历1024个block,检测坏block
  {
  for(j=0; j<4; j++)
  { //读取第1页第2 048个字节
  outportb(ComReg,0x00);
  outportb (AddReg,0x00);
  outportb (AddReg,0x08);
  outportb (AddReg, RAdr_L);
  outportb (AddReg, RAdr_H);
  outportb (ComReg,0x30);
  while( inportb(RB_Adr )!=0x01) { };
  FP2048=inportb (DataReg);
  outportb(ComReg,0x00);
  //读取第2页第2 048个字节
  outportb (AddReg,0x00);
  outportb (AddReg,0x08);
  outportb (AddReg,RAdr_L+1);
  outportb (AddReg,RAdr_H);
  outportb (ComReg,0x30);
  while( inportb (RB_Adr)==0x01 ) {};  
  SP2048= inportb (DataReg);
  if((FP2048!=0xff)or(SP2048)!=0xff) )
  //判断第1、2页的第2048字节是否为0xff
  {Inv_Add=RAdr_H*256+RAdr_L&0xC0;
  outport(Inv_Add,Inv_Tab_Add);
  Inv_Tab_Add=Inv_Tab_Add+1;}
  RAdr_L=RAdr_L+0x40;
  } /* end of for(..j..) */
  RAdr_H=RAdr_H+1;
  } /* end of for(..k..) */
  上述代码中,ComReg为命令寄存器地址,AddReg为地址寄存器地址,DataReg为数据端口地址,Inv_Tab_Add为坏块表地址,RB_Adr则为芯片R/B信号反馈至GPIO口的端口地址。
2.5 数据缓冲问题
  如前所述,FPGA内部8个并行运行的读状态机独立完成每片Flash的读取操作,并片后,必然会导致各片Flash在读取数据时存在时间上的错位,特别是当其中一片Flash出现坏块,读状态机需要跨块读取时,这个问题会更加严重。为了解决这个问题,FPGA的设计中增加了用来缓冲数据的FIFO,以隔离FIFO前后速度非一致的数据流。FIFO的深度由读状态机跨块所需要的时间间隔和FIFO的输出时钟100MHz共同决定,以保证FIFO输出数据流不间断。
  本文介绍的系统利用FPGA和PC104模块分别完成对NAND型Flash的读写操作,不仅满足了系统存储深度8Gb的要求,而且利用FPGA内多个独立并行状态机实现了多片Flash的并行读取操作,满足了数据回放的带宽要求,并实际应用于某干扰系统中,效果理想。
参考文献
1 XILINX. Spartan-3 platform FPGA handbook[EB/OL],http://www.xilinx.com, 2003
2 Samsung. K9F1G08UOM K9F1G16UOM flash memory data-sheet rev.13[EB/OL],http://www.sumsung.com,2003
3 Samsung. NAND flash spare assignment recommendation [EB/OL],http://www.sumsung.com, 2003
4 TOSHIBA,What is NAND flash memory? [EB/OL],http://www.toshiba.com, 2003

本站内容除特别声明的原创文章之外,转载内容只为传递更多信息,并不代表本网站赞同其观点。转载的所有的文章、图片、音/视频文件等资料的版权归版权所有权人所有。本站采用的非本站原创文章及图片等内容无法一一联系确认版权者。如涉及作品内容、版权和其它问题,请及时通过电子邮件或电话通知我们,以便迅速采取适当措施,避免给双方造成不必要的经济损失。联系电话:010-82306118;邮箱:aet@chinaaet.com。