http://www.crifan.com/files/doc/docbook/linux_nand_driver/release/html/linux_nand_driver.html
简单说就是,常见的Nand Flash,内部只有一个chip,每个chip只有一个plane。
而有些复杂的,容量更大的Nand Flash,内部有多个chip,每个chip有多个plane。这类的Nand Flash,往往也有更加高级的功能,比如下面要介绍的Multi Plane Program和Interleave Page Program等。
概念上,由大到小来说,就是:
Nand Flash ⇒ Chip ⇒ Plane ⇒ Block ⇒ Page ⇒ oob
比如,型号为K9K8G08U0A这块Nand Flash(有时候也被称为此块chip芯片),其内部有两个K9F4G08U0A的chip,chip#1和chip#2,每个K9F4G08U0A的chip包含了2个Plane,每个Plane是2Gbbit,所以K9F4G08U0A的大小是2Gb×2 = 4Gb = 512MB,因此,K9K8G08U0A内部有2个K9F4G08U0A,或者说4个Plane,总大小是×256MB=1GB。
公式 1.1. K9K8G08U0A的物理结构所组成的总容量 K9K8G08U0A(这块Nand Flash) = 2 × K9F4G08U0A(K9F4G08U0A是chip,1 K9F4G08U0A = 2 Plane) = 2 × 2个Plane = 4 Plane(1 Plane = 2048 Block) = 4 × 2048个Block(1 Block = 64 Page) = 4 × 2048 × 64Page(1 Page = 2KB) = 4 × 2048 × 64Page × 2KB = 4 × 2048 × 128KB(1 Block = 128KB) = 4 × 256MB(1 Plane = 2Gb = 256MB) = 2 × 512MB(1 K9F4G08U0A = 4Gb = 512MB) = 1GB(1 K9K8G08U0A = 1GB)而型号是K9WAG08U1A的Nand Flash,内部包含了2个K9K8G08U0A,所以,总容量是K9K8G08U0A的两倍=1GB×2=2GB,类似地K9NBG08U5A,内部包含了4个K9K8G08U0A,总大小就是4×1GB=4GB。
Nand Flash物理存储单元的阵列组织结构
1.2.5.1. Block块
一个Nand Flash(的chip,芯片)由很多个块(Block)组成,块的大小一般是128KB,256KB,512KB,此处是128KB。其他的小于128KB的,比如64KB,一般都是下面将要介绍到的small block的Nand Flash。
块Block,是Nand Flash的擦除操作的基本/最小单位。
每个块里面又包含了很多页(page)。每个页的大小,对于现在常见的Nand Flash多数是2KB,最新的Nand Flash的是4KB、8KB等,这类的页大小大于2KB的Nand Flash,被称作big block的Nand Flash,对应的发读写命令地址,一共5个周期(cycle),而老的Nand Flash,页大小是256B,512B,这类的Nand Flash被称作small block,地址周期只有4个。
页Page,是读写操作的基本单位。
不过,也有例外的是,有些Nand Flash支持subpage(1/2页或1/4页)子页的读写操作,不过一般很少见。
每一个页,对应还有一块区域,叫做空闲区域(spare area)/冗余区域(redundant area),而Linux系统中,一般叫做OOB(Out Of Band),这个区域,是最初基于Nand Flash的硬件特性:数据在读写时候相对容易错误,所以为了保证数据的正确性,必须要有对应的检测和纠错机制,此机制被叫做EDC(Error Detection Code)/ECC(Error Code Correction, 或者 Error Checking and Correcting),所以设计了多余的区域,用于放置数据的校验值。
Oob的读写操作,一般是随着页的操作一起完成的,即读写页的时候,对应地就读写了oob。
关于oob具体用途,总结起来有:
标记是否是坏快存储ECC数据存储一些和文件系统相关的数据。如jffs2就会用到这些空间存储一些特定信息,而yaffs2文件系统,会在oob中,存放很多和自己文件系统相关的信息。
Nand Flash的位反转,也叫做位翻转,对应的英文表达有:Bit Flip=Bit Flipping=Bit-Flip=Bit twiddling。
Nand Flash由于本身硬件的内在特性,会导致(极其)偶尔的出现位反转的现象。
所谓的位反转,bit flip,指的是原先Nand Flash中的某个位,变化了,即要么从1变成0了,要么从0变成1了。
Nand Flash的位反转现象,主要是由以下一些原因/效应所导致:
漂移效应(Drifting Effects)漂移效应指的是,Nand Flash中cell的电压值,慢慢地变了,变的和原始值不一样了。
编程干扰所产生的错误(Program-Disturb Errors)此现象有时候也叫做,过度编程效应(over-program effect)。
对于某个页面的编程操作,即写操作,引起非相关的其他的页面的某个位跳变了。
读操作干扰产生的错误(Read-Disturb Errors)此效应是,对一个页进行数据读取操作,却使得对应的某个位的数据,产生了永久性的变化,即Nand Flash上的该位的值变了。
位反转,说白了,就是读取数据的时候,数据出错了。
因此,如果你读取的数据正好是属于某个重要的文件中的数据,比如系统的配置文件等,那么此时错了一位,都会导致系统出现异常,问题相对会很严重。
而如果此数据属于音视频流中的数据,那么此时即使错了一位,对整个音视频的播放产生的影响也很小,所以问题也不大。
对应的位反转的类型,有两种:
一种是nand flash物理上的数据存储的单元上的数据,是正确的,只是在读取此数据出来的数据中的某位,发生变化,出现了位反转,即读取出来的数据中,某位错了,本来是0变成1,或者本来是1变成0了。此处可以成为软件上位反转。此数据位的错误,当然可以通过一定的校验算法检测并纠正。另外一种,就是nand flash中的物理存储单元中,对应的某个位,物理上发生了变化,原来是1的,变成了0,或原来是0的,变成了1,发生了物理上的位的数据变化。此处可以成为硬件上的位反转。此错误,由于是物理上发生的,虽然读取出来的数据的错误,可以通过软件或硬件去检测并纠正过来,但是物理上真正发生的位的变化,则没办法改变了。不过个人理解,好像也是可以通过擦除Erase整个数据块Block的方式去擦除此错误,不过在之后的Nand Flash的使用过程中,估计此位还是很可能继续发生同样的硬件的位反转的错误。以上两种类型的位反转,其实对于从Nand Flash读取出来的数据来说,解决其中的错误的位的方法,都是一样的,即通过一定的校验算法,常称为ECC,去检测出来,或检测并纠正错误。如果只是单独检测错误,那么如果发现数据有误,那么再重新读取一次即可。实际中更多的做法是,ECC校验发现有错误,会有对应的算法去找出哪位错误并且纠正过来。其中对错误的检测和纠正,具体的实现方式,有软件算法,也有硬件实现,即硬件Nand Flash的控制器controller本身包含对应的硬件模块以实现数据的校验和纠错的。
表 1.4. Nand Flash引脚功能的中文说明
引脚名称引脚功能I/O0 ~ I/O7用于输入地址/数据/命令,输出数据CLECommand Latch Enable,命令锁存使能,在输入命令之前,要先在模式寄存器中,设置CLE使能ALEAddress Latch Enable,地址锁存使能,在输入地址之前,要先在模式寄存器中,设置ALE使能CE#Chip Enable,芯片使能,在操作Nand Flash之前,要先选中此芯片,才能操作RE#Read Enable,读使能,在读取数据之前,要先使CE#有效。WE#Write Enable,写使能, 在写取数据之前,要先使WE#有效WP#Write Protect,写保护R/B#Ready/Busy Output,就绪/忙,主要用于在发送完编程/擦除命令后,检测这些操作是否完成,忙,表示编程/擦除操作仍在进行中,就绪表示操作完成VccPower,电源VssGround,接地N.CNon-Connection,未定义,未连接数据手册中的#表示低电平 在数据手册中,你常会看到,对于一个引脚定义,有些字母上面带一横杠的,那是说明此引脚/信号是低电平有效,比如你上面看到的RE头上有个横线,就是说明,此RE是低电平有效,此外,为了书写方便,在字母后面加“#”,也是表示低电平有效,比如我上面写的CE#;如果字母头上啥都没有,就是默认的高电平有效,比如上面的CLE,就是高电平有效。
以前老的Nand Flash,编程/擦除时间比较短,比如K9G8G08U0M,才5K次,而后来的多数也只有10K=1万次,而现在很多新的Nand Flash,技术提高了,比如,Micron的MT29F1GxxABB,Numonyx的 NAND04G-B2D/NAND08G-BxC,都可以达到100K,也就是10万次的编程/擦除,达到和接近于之前常见的Nor Flash,几乎是同样的使用寿命了。
在一个块内,对每一个页进行编程的话,必须是顺序的,而不能是随机的。比如,一个块中有128个页,那么你只能先对page0编程,再对page1编程,。。。。,而不能随机的,比如先对page3,再page1,page2,page0,page4,。。。
关于此处对于只能顺序给页编程的说法,只是翻译自datasheet,但是实际情况却发现是,程序中没有按照此逻辑处理,可以任意对某Block内的Page去做Program的动作,而不必是顺序的。但是datasheet为何如此解释,原因未知,有待知情者给解释一下。
图 1.6. Nand Flash K9K8G08U0A的命令集合
从上图可以看到,如果要实现读一个页的数据,就要发送Read的命令,而且是分两个周期(Cycle),即分两次发送对应的命令,第一次是0x00h,第二次是0x30h,而两次命令中间,需要发送对应的你所要读取的页的地址,关于此部分详细内容,留待后表。
对应地,其他常见的一些操作,比如写一个页的数据(Page Program),就是先发送0x80h,然后发生要写入的地址,再发送0x10h。
对于不同厂家的不同型号的Nand Flash 的基本操作,即读页数据Read Page,写页数据(对页进行编程)Page Program,擦除整个块的数据Erase Block等操作,所用的命令都是一样的,但是针对一些Nand Flash的高级的一些特性,比如交错页编程(Interleave Page Program),多片同时编程(Simultaneously Program Multi Plane)等,所用的命令,未必一样,不过对于同一厂家的Nand Flash的芯片,那一般来说,都是统一的。
Nand flash的写操作叫做编程Program,编程,一般情况下,是以页为单位的。
有的Nand Flash,比如K9K8G08U0A,支持部分页编程(Partial Page Program),但是有一些限制:在同一个页内的,连续的部分页的编程,不能超过4次。一般情况下,都是以页为单位进行编程操作的,很少使用到部分页编程。
关于这个部分页编程,本来是一个页的写操作,却用两个命令或更多的命令去实现,看起来是操作多余,效率不高,但是实际上,有其特殊考虑:
至少对于块擦除来说,开始的命令0x60是擦除设置命令(erase setup comman),然后传入要擦除的块地址,然后再传入擦除确认命令(erase confirm command)0xD0,以开始擦除的操作。
这种完成单个操作要分两步发送命令的设计,即先开始设置,再最后确认的命令方式,是为了避免由于外部由于无意的/未预料而产生的噪音,比如,由于某种噪音,而产生了0x60命令,此时,即使被Nand Flash误认为是擦除操作,但是没有之后的确认操作0xD0,Nand Flash就不会去擦除数据,这样使得数据更安全,不会由于噪音而误操作。
黄色竖线所处的时刻,是在发送读操作的第一个周期的命令0x00之前的那一刻。让我们看看,在那一刻,其所穿过好几行都对应什么值,以及进一步理解,为何要那个值。
黄色竖线穿过的第一行,是CLE。还记得前面介绍命令所存使能(CLE)那个引脚吧?CLE,将CLE置1,就说明你将要通过I/O复用端口发送进入Nand Flash的,是命令,而不是地址或者其他类型的数据。只有这样将CLE置1,使其有效,才能去通知了内部硬件逻辑,你接下来将收到的是命令,内部硬件逻辑,才会将受到的命令,放到命令寄存器中,才能实现后面正确的操作,否则,不去将CLE置1使其有效,硬件会无所适从,不知道你传入的到底是数据还是命令了。而第二行,是CE#,那一刻的值是0。这个道理很简单,你既然要向Nand Flash发命令,那么先要选中它,所以,要保证CE#为低电平,使其有效,也就是片选有效。第三行是WE#,意思是写使能。因为接下来是往Nand Flash里面写命令,所以,要使得WE#有效,所以设为低电平。第四行,是ALE是低电平,而ALE是高电平有效,此时意思就是使其无效。而对应地,前面介绍的,使CLE有效,因为将要数据的是命令(此时是发送图示所示的读命令第二周期的0x30),而不是地址。如果在其他某些场合,比如接下来的要输入地址的时候,就要使其有效,而使CLE无效了。第五行,RE#,此时是高电平,无效。可以看到,知道后面低6阶段,才变成低电平,才有效,因为那时候,要发生读取命令,去读取数据。第六行,就是我们重点要介绍的,复用的输入输出I/O端口了,此刻,还没有输入数据,接下来,在不同的阶段,会输入或输出不同的数据/地址。第七行,R/B#,高电平,表示R(Ready)/就绪,因为到了后面的第5阶段,硬件内部,在第四阶段,接受了外界的读取命令后,把该页的数据一点点送到页寄存器中,这段时间,属于系统在忙着干活,属于忙的阶段,所以,R/B#才变成低,表示Busy忙的状态的。介绍了时刻①的各个信号的值,以及为何是这个值之后,相信,后面的各个时刻,对应的不同信号的各个值,大家就会自己慢慢分析了,也就容易理解具体的操作顺序和原理了。
在介绍具体读取数据的详细流程之前,还要做一件事,那就是,先要搞懂我们要访问的地址,以及这些地址,如何分解后,一点点传入进去,使得硬件能识别才行。
此处还是以K9K8G08U0A为例,此Nand Flash,一共有8192个块,每个块内有64页,每个页是2K+64 Bytes。
物理地址 =块大小×块号 + 页大小×页号 + 页内地址
接下来,我们就看看,怎么才能把这个实际的物理地址,转化为Nand Flash所要求的格式。
在解释地址组成之前,先要来看看其datasheet中关于地址周期的介绍:
图 1.8. Nand Flash的地址周期组成
此Nand Flash地址周期共有5个,2个列(Column)周期,3个行(Row)周期。
对应地,列地址A0~A10,就是页内地址,地址范围是从 0 到 2047。细心的读者可能注意到了,为何此处多出来个A11呢?
这样从A0到A11,一共就是12位,可以表示的范围就是0~212,即从 0 到 4096。
实际上,由于我们访问页内地址,可能会访问到oob的位置,即2048-2111这64个字节的范围内,所以,此处实际上只用到了2048~2111,用于表示页内的oob区域,其大小是64字节。
对应地,A12~A17,称作页号,页的号码,可以定位到对应的块的哪一个页 ( 0 .. 63 )。A18~A30,表示对应的块号,即属于哪个块 ( 0..8191 )。准备工作终于完了,下面就可以开始解释说明,对于读操作的,上面图中标出来的,1-6个阶段,具体是什么含义。
操作准备阶段:此处是读(Read)操作,所以,先发一个图5中读命令的第一个阶段的0x00,表示,让硬件先准备一下,接下来的操作是读。
发送两个周期的列地址。也就是页内地址,表示,我要从一个页的什么位置开始读取数据。
接下来再传入三个行地址。对应的也就是页号。
然后再发一个读操作的第二个周期的命令0x30。接下来,就是硬件内部自己的事情了。
Nand Flash内部硬件逻辑,负责去按照你的要求,根据传入的地址,找到哪个块中的哪个页,然后把整个这一页的数据,都一点点搬运到页缓存中去。而在此期间,你所能做的事,也就只需要去读取状态寄存器,看看对应的位的值,也就是R/B#那一位,是1还是0,如果是0的话,就表示,系统是busy,仍在”忙“(着读取数据),如果是1,就说系统活干完了,忙清了,已经把整个页的数据都搬运到页缓存里去了,你可以接下来读取你要的数据了。
对于这里。估计有人会问了,这一个页一共2048+64字节,如果我传入的页内地址,就像上面给的1208一类的值,只是想读取1028到2011这部分数据,而不是页开始的0地址整个页的数据,那么内部硬件却读取整个页的数据出来,岂不是很浪费吗?答案是,的确很浪费,效率看起来不高,但是实际就是这么做的,而且本身读取整个页的数据,相对时间并不长,而且读出来之后,内部数据指针会定位到你刚才所制定的1208的那个位置。
转载于:https://www.cnblogs.com/shangdawei/archive/2013/05/14/3077018.html
相关资源:数据结构—成绩单生成器