S5PV210系列 (裸机十四)之 NandFlash

来源:互联网 发布:软件框架设计的艺术 编辑:程序博客网 时间:2024/06/05 19:45

NandFlash的接口

Nand的型号与命名

(1) Nand 的型号命名都有含义,就拿 K9F2G08 来示例分析一下:K9F 表示是三星公司的 NandFlash 系列。2G 表示 Nand 的大小是 2Gbit(256MB)。08 表示Nand 是 8 位的( 8 位就是数据线有 8 根)

(2) Nand 命名中可以看出:厂家、系列型号、容量大小、数据位数。

Nand的数据位

(1) Nand 有 8 位数据位的,有 16 位数据位的。做电路时 / 写软件时应该根据自己实际采购的 Nand 的位数来设计电路/写软件。

(2)说明 Nand 是并行接口的( 8 / 16 位)

(3) Nand 的数据线上传递的不一定全部是有效数据,也可能有命令、地址等。

Nand 的功能框图

这里写图片描述

(1) Nand 的结构可以看成是一个矩阵式存储器,其中被分成一个一个的小块,每一小块可以存储一个 bit 位,然后彼此以一定单位组合成整个 Nand。

(2) Nand 中可以被单次访问的最小单元(就是说对Nand进行一次读写至少要读写这么多,或者是这么多的整数倍)叫做 Page(页),在 K9F2G08 芯片中,Page的大小是 2KB + 64B。也就是说我们要读写 K9F2G08,每次至少要读写 2KB 或者 n*2KB,即使我们只是想要其中的一个字节。这就是我们说的典型的块设备(现在有些块设备为了方便,提供了一种 random read 模式,可以只读取 1 个字节)。

(3)页往上还有个 Block(块)的概念,1 个块等于若干个页(譬如在 K9F2G08 中1 个块等于 64 页)。

(4)页往上就是整个 Nand 芯片了,叫做 Device。一个 Device 是若干个 Block,譬如 K9F2F08 一个 Device 有 2028 个 block。所以整个 Device 大小为:2048×64×2K = 256MB

(5)块设备分 page、block 有什么意义?首先要明白,块设备不能完全按字节访问而必须块访问是物理上的限制,而不是人为设置的障碍。其次,Page 和 Block 各有各的意义,譬如 Nand 中:Page 是读写 Nand 的最小单位;Block 是擦除 Nand的最小单位。(这些规则都是 Nand 的物理原理和限制要求的,不是谁想要这样的,所以对于我们做软件的来说,只能去想办法适应硬件,不是想着超越硬件)。

(6)Nand 芯片中主要包含2部分:Nand 存储颗粒+ Nand 接口电路。存储颗粒就是纯粹的 Nand 原理的存储单元,类似于仓库;Nand 接口电路是用来管理存储颗粒,并且给外界提供一个统一的 Nand 接口规格的访问接口的。

(7)Nand 中有多个存储单元,每个单元都有自己的地址(地址是精确到字节的)。所以 Nand 是地址编排精确到字节,但是实际读写却只能精确到页(所以Nand 的很多操作都要求给的地址是页对齐的,譬如 2K、4K、512K 等这样的地址,不能给 3000B 这样的地址)。Nand 读写时地址传递是通过 IO 线发送的,因为地址有 30 位而 IO 只有 8 位,所以需要多个 cycle 才能发送完毕。一般的 Nand都是 4cycle 或者 5cycle 发送地址(从这里把 Nand 分为了 4cycle Nand 和 5cycle Nand)。

总结:Nand 芯片内部有存储空间,并且有电路来管理这些存储空间,向外部提供统一的 Nand 接口的访问规则,然后外部的 SoC 可以使用 Nand 接口时序来读写这个 Nand 存储芯片。Nand 接口是一种公用接口,是一种标准,理论上来说外部 SoC 可以直接模拟 Nand 接口来读写 Nand 芯片,但是实际上因为 nand 接口对时序要求非常严格,而且时序很复杂,所以一般的 SoC 都是通过专用的硬件的Nand 控制器(这些控制器一般是作为 SoC 的内部外设来存在的)来操控 Nand 芯片的。

NandFlash的结构

Nand 的单元组织:block 与 page( 大页 Nand 与小页 Nand )

(1) Nand 的页和以前讲过的块设备(尤其是硬盘)的扇区是类似的。扇区最早在磁盘中是 512 字节,后来也有些高级硬盘扇区不是 512 字节而是 1024 字节/ 2048 字节/4096字节等。Nand也是一样,不同的Nand的页的大小是不同的,也有512字节/1024字节/2048字节/4096字节等。

(2)一个block等于多少page也是不定的,不同的Nand也不同。一个Nand芯片有多少block也是不定的,不同的Nand芯片也不同。
总结:Nand的组织架构挺乱的,接口时序也不同,造成结构就是不同厂家的Nand芯片,或者是同一个厂家的不同系列型号存储容量的nand接口也不一样。所以nand有一个很大的问题就是一旦升级容量或者换芯片系列则硬件要重新做、软件要重新移植。

带内数据和带外数据(ECC与坏块标记)

(1)Nand的每个页由2部分组成,这2部分各自都有一定的存储空间。譬如K9F2G08中为2K+64字节。其中的2K字节属于带内数据,是我们真正的存储空间,将来存储在Nand中的有效数据就是存在这2K范围内的(我们平时计算nand的容量时也是只考虑这2KB);64字节的带外数据不能用来存储有效数据,是作为别的附加用途的(譬如用来存储ECC数据、用来存储坏块标志等····)

(2)什么是ECC:(error correction code,错误校验码)。因为nand存储本身出错(位反转)概率高(Nand较Nor最大的缺点就是稳定性),所以当我们将有效信息存储到Nand中时都会同时按照一定算法计算一个ECC信息(譬如CRC16等校验算法),将ECC信息同时存储到Nand这个页的带外数据区。然后等将来读取数据时,对数据用同样的算法再计算一次ECC,并且和从带外数据区读出的ECC进行校验。如果校验通过则证明Nand的有效数据可信,如果校验不通过则证明这个数据已经被损坏(只能丢弃或者尝试修复)。

(3)坏块标志:Nand芯片用一段时间后,可能某些块会坏掉(这些块无法擦除了,或者无法读写了),nand的坏块非常类似于硬盘的坏道。坏块是不可避免的,而且随着Nand的使用坏块会越来越多。当坏块还不算太多时这个Nand都是可以用的,除非坏块太多了不划算使用了才会换新的。所以我们为了管理Nand发明了一种坏块标志机制。Nand的每个页的64字节的带外数据中,我们(一般是文件系统)定义一个固定位置(譬如定位第24字节)来标记这个块是好的还是坏的。文件系统在发现这个块已经坏了没法用了时会将这个块标记为坏块,以后访问nand时直接跳过这个块即可。

Nand 的地址时序

(1) nand 的地址有多位,分 4/5 周期通过 IO 引脚发送给 Nand 芯片来对 Nand 进行寻址。寻址的最小单位是字节,但是读写的最小单位是页。

(2) nand 的地址在写代码时要按照 Nand 要求的时序和顺序去依次写入。

Nand 的命令码

这里写图片描述

(1)外部 SoC 要想通过 Nand 控制器来访问 Nand(实质就是通过 Nand 接口),就必须按照 Nand 接口给 nand 发送命令、地址、数据等信息来读写 Nand。

(2) Nand 芯片内部的管理电路本身可以接收外部发送的命令,然后根据这些命令来读写 Nand 内容与外部 SoC 交互。所以我们对 nand 进行的所有操作(擦除、读、写···)都要有命令、地址、数据的参与才能完成,而且必须按照 Nand 芯片规定的流程来做。

NandFlash 的常见操作及流程分析

坏块检查

(1) Flash 使用之前要先统一擦除(擦除的单位是块)。Flash 类设备擦除后里面全是 1,所以擦干净之后读出来的值是 0xff。

(2)检查坏块的思路就是:先块擦除,然后将整块读出来,依次检测各自节是否为0xff,如果是则表明不是坏块,如果不是则表明是坏块。

页写(program)操作

这里写图片描述

(1)写之前确保这个页是被擦除干净的。如果不是擦除干净的(而是脏的、用过的)页,写进去的值就是错的,不是你想要的结果。

(2)写操作(write)在 flash 的操作中就叫编程( program )

(3) SoC 写 Flash 时通过命令线、IO 线依次发送写命令、写页地址、写数据等进入 NandFlash。

(4)写的过程:SOC 通过 Nand 控制器和 Nand 芯片完成顺序对接,然后按照时序要求将一页数据发给 Nand 芯片内部的接口电路。接口电路先接收收据到自己的缓冲区,然后再集中写入 Nand 芯片的存储区域中。Nand 接口电路将一页数据从缓冲区中写入 Nand 存储系统中需要一定的时间,这段时间 Nand 芯片不能再响应 SOC 发过来的其他命令,所以 SoC 要等待 Nnad 接口电路忙完。等待方法是SoC 不断读取状态寄存器(这个状态寄存器有2种情况:一种是SoC的Nand控制器自带的,另一种是SoC通过发命令得到命令响应得到的),然后通过检查这个状态寄存器的状态位就能知道Nand接口电路刚才写的那一页数据写完了没、写好了没。直到SoC收到正确的状态寄存器响应才能认为刚才要写的那一页数据已经ok。(如果SoC收到的状态一直不对,可以考虑重写或者认为这一页所在的块已经是坏块,或者整个 Nand 芯片已经挂掉了)。

(5)正常情况下到了第四步就已经完了。但是因为Nand的读写有不靠谱情况,因此我们为了安全会去做ECC校验。ECC校验有硬件式校验和软件式校验2种。软件式校验可以采用的策略有很多,其中之一(Nand芯片手册上推荐的方式是):将刚才写入的1页数据读出来,和写入的内容进行逐一对比。如果读出的和写入的完全一样,说明刚才的写入过程正确完成了;如果读出来的和写入的不完全一样那就说明刚才的写入有问题。

(6)硬件式ECC:SoC的Nand控制器可以提供硬件式ECC(这个也是比较普遍的情况)。硬件式ECC就是在Nand的控制器中有个硬件模块专门做ECC操作。当我们操作Nand芯片时,只要按照SoC的要求按时打开ECC生成开关,则当我们写入Nand芯片时SoC的Nand控制器的ECC模块会自动生成ECC数据放在相应的寄存器中,然后我们只需要将这生成的ECC数据写入Nand芯片的带外数据区即可;在将来读取这块Nand芯片时,同样要打开硬件ECC开关,然后开始读,在读的过程当中硬件ECC会自动计算读进来的一页数据的ECC值并将之放到相应的寄存器中。然后我们再读取带外数据区中原来写入时存入的ECC值,和我们刚才读的时候得到的ECC值进行校验。校验通过则说明读写正确,校验不通过则说明不正确(放弃数据或者尝试修复)。

擦除(erase)操作

这里写图片描述

(1)擦除时必须给块对齐的地址。如果给了不对齐的地址,结果是不可知的(有些Nand芯片没关系,它内部会自动将其对齐,而有些Nand会返回地址错误)。

(2)读写时给的地址也是一样,要求是页对齐地址。如果给了不对齐的,也是有可能对有可能错。

页读(read)操作

这里写图片描述

S5PV210的NandFlash控制器

SoC的Nand控制器的作用

(1)Nand 芯片本身通过 Nand 接口电路来存取数据,Nand 接口电路和 SOC 之间通过 Nand 接口时序来通信。Nand 接口时序相对复杂,如果要 SoC 完全用软件来实现 Nand 接口时序有一些不好(主要是:第一很难保证时序能满足、容易不稳定;第二代码很难写)。解决方案是:在 SoC 内部集成一个 Nand 控制器(实质就是一块硬件电路,这个硬件电路完全满足 Nand 接口时序的操作,然后将接口时序的操作寄存器化)。

(2) SOC 和 Nand 芯片之间通信,在 SoC 没有 Nand 控制器时需要 SoC 自己来处理接口时序,编程很麻烦,需要程序员看 Nand 芯片的接口时序图,严格按照接口时序图中编程(尤其要注意各个时间参数);在 SoC 有 Nand 控制器时 SoC 只需要编程操控 Nand 控制器的寄存器即可,Nand 控制器内部硬件会根据寄存器值来生成合适的 Nand 接口时序和 Nand 芯片通信。所以在有 Nand 控制器时编程要简单很多,我们读写 Nand 芯片时再也不用关注 Nand 接口时序了,只要关注 SoC 的 Nand 控制器的寄存器即可。

(3)扩展来讲,现在的技术趋势就是:几乎所有的外设在 SoC 内部都有对应的控制器来与其通信,那么 SoC 内部集成的各种控制器(也就是各种内部外设)越多,则 SoC 硬件能完成的功能越多,将来用这个 SoC 来完成相应任务时软件编程越简单。譬如说图形处理和图像处理领域,2D 图像编码( jpeg 编码)、视频编码( h.264 编码),现在大部分的 application 级别的 SoC 都有集成的内部编码器(像 S5PV210 就有、更复杂的譬如 4418、6818 就更不用说了,只会更多更先进),我们可以利用这些硬件编码器来进行快速编解码,这样软件工作量和难度降低了很多(这就是所谓的硬件加速)。

结构框图分析

(1)结构框图中关键点:SFR(我们后续编程的关键,编程时就是通过读写 SFR 来产生 Nand 接口时序以读写 Nand 芯片的) + Nand interface(硬件接口,将来和 Nand 芯片的相应引脚进行连接) + ECC 生成器

S5PV210 的 Nand 控制器的主要寄存器
NFCONF、NFCONT、NFCMMD、NFADDR、NFDATA、NFMECCD0&NFMECCD1、NFSECCD、NFSTAT

这里写图片描述

总结:

(1)像 NandFlash 这类芯片,通过专用的接口时序和 SoC 内部的控制器相连(这种连接方式是非常普遍的,像 LCD、DDR 等都是类似的连接)。这种接法和设计对我们编程来说,关键在于两点:SoC 的控制器的寄存器理解和 Nand 芯片本身的文档、流程图等信息。

(2)对于我们来说,学习 NandFlash,要注意的是:
第一,要结合 SoC 的数据手册、Nand 芯片的数据手册、示例代码三者来理解。
第二,初学时不要尝试完全不参考自己写出 Nand 操作的代码,初学时应该是先理解实例代码,知道这些代码是怎么写出来的,必要时对照文档来理解代码。代码理解之后去做实践,实践成功后以后再考虑自己不参考代码只参考文档来写出nand操作的代码。

原创粉丝点击