一、NandFlash 的接口
1、Nand 的型号与命名
(1) Nand 的型号命名都有含义,就拿 K9F2G08 来示例分析一下:K9F 表示是三星公司的 NandFlash 系列。2G 表示 Nand 的大小是 2Gbit(256MB)。08 表示 Nand 是 8 位的( 8 位就是数据线有 8 根)。
(2) Nand 命名中可以看出:厂家、系列型号、容量大小、数据位数。
2、Nand 的数据位
(1) Nand 有 8 位数据位的,有 16 位数据位的。做电路时/写软件时应该根据自己实际采购的 Nnad 的位数来设计电路/写软件。
(2) 说明 Nand 是并行接口的(8/16位)。
(3) Nand 的数据线上传递的不一定全部是有效数据,也可能有命令、地址等。
3、Nand 的功能框图
(1) Nand 的结构可以看成是一个矩阵式存储器,其中被分成一个一个的小块,每一小块可以存储一个 bit 位,然后彼此以一定单位组合成整个 Nand。
(2) Nand 中可以被单次访问的最小单元(就是说对 Nand 进行一次读写至少要读写这么多,或者是这么多的整数倍)叫做 Page(页)。在 K9F2G08 芯片中,Page 的大小是 2KB+64B。也就是说我们要读写 K9F2G08,每次至少要读写 2KB 或者 n*2KB,即使我们只是想要其中的一个字节。这就是我们说的典型的块设备(现在有些块设备为了方便,提供了一种 random read 模式,可以只读取 1 个字节)。
(3) 页往上还有个 Block(块)的概念,1个块 Block 等于若干个页 Page(譬如在 K9F2G08 中 1 个块 Block 等于 64 页 Page)。
(4) 块 Block 往上就是整个 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 是地址编排精确到字节,但是实际读写却只能精确到页 Page(所以 Nand 的很多操作,都要求给的地址是页 Page 对齐的,譬如 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 的结构
1、Nand 的单元组织:block与page(大页Nand与小页Nand)
(1) Nand 的页 page 和以前讲过的块设备(尤其是硬盘)的扇区 sector 是类似的。 扇区最早在磁盘中是 512 字节,后来也有些高级硬盘扇区不是 512 字节,而是 1024字节/2048字节/4096字节等。Nand 也是一样,不同的 Nand 的页的大小是不同的,也有 512字节/1024字节/2048字节/4096字节等。
(2) 一个 block 等于多少 page 也是不定的,不同的 Nand 也不同。一个 Nand 芯片有多少 block 也是不定的,不同的 Nand 芯片也不同。
总结:Nand 的组织架构挺乱的,接口时序也不同,造成结果就是不同厂家的 Nand 芯片,或者是同一个厂家的不同系列型号存储容量的 nand 接口也不一样。所以 nand 有一个很大的问题就是,一旦升级容量或者换芯片系列则硬件要重新做、软件要重新移植。
2、带内数据和带外数据(ECC与坏块标记)
(1) Nand 的每个页 page 由 2 部分组成,这 2 部分各自都有一定的存储空间。譬如 K9F2G08 中为 2K+64 字节。其中的 2K 字节属于带内数据,是我们真正的存储空间,将来存储在 Nand 中的有效数据就是存在这 2K 范围内的(我们平时计算 nand 的容量时也是只考虑这 2KB);64 字节的带外数据不能用来存储有效数据,是作为别的附加用途的(譬如用来存储 ECC 数据、用来存储坏块标志等····)。
(2) 什么是 ECC:(error correction code,错误校验码)。因为 nand 存储本身出错(位反转)概率高(NandFlash 较 NorFlash 最大的缺点就是稳定性),所以当我们将有效信息存储到 Nand 中时都会同时按照一定算法,计算一个 ECC 信息(譬如 CRC16 等校验算法),将 ECC 信息同时存储到 Nand 这个页的带外数据区。 然后等将来读取数据时,对数据用同样的算法再计算一次 ECC,并且和从带外数据区读出的 ECC 进行校验。 如果校验通过,则证明 Nand 的有效数据可信;如果校验不通过,则证明这个数据已经被损坏(只能丢弃或者尝试修复)。
(3) 坏块标志:Nand 芯片用一段时间后,可能某些块会坏掉(这些块无法擦除了,或者无法读写了),nand 的坏块非常类似于硬盘的坏道。坏块是不可避免的,而且随着 Nand 的使用,坏块会越来越多。当坏块还不算太多时,这个 Nand 都是可以用的,除非坏块太多了不划算使用了才会换新的。所以我们为了管理 Nand 发明了一种坏块标志机制。Nand 的每个页的 64 字节的带外数据中,我们(一般是文件系统)定义一个固定位置(譬如定位第24字节)来标记这个块是好的还是坏的。文件系统在发现这个块已经坏了没法用了时,会将这个块标记为坏块,以后访问 nand 时直接跳过这个块即可。
Invalid Block(s)
3、Nand 的地址时序
(1) nand 的地址有多位,分 4/5 周期通过 IO 引脚发送给 Nand 芯片来对 Nand 进行寻址。寻址的最小单位是字节,但是读写的最小单位是页 page。
(2) nand 的地址在写代码时,要按照 Nand 要求的时序和顺序去依次写入。
4、Nand 的命令码
(1) 外部 SoC 要想通过 Nand 控制器来访问 Nand(实质就是通过 Nand 接口),就必须按照Nand 接口给 nand 发送命令、地址、数据等信息来读写 Nand。
(2) Nand 芯片内部的管理电路本身可以接收外部发送的命令,然后根据这些命令来读写 Nand 内容与外部 SoC 交互。所以我们对 nand 进行的所有操作(擦除、读、写···)都要有命令、地址、数据的参与才能完成,而且必须按照 Nand 芯片规定的流程来做。
三、NandFlash的常见操作及流程分析
1、坏块检查
(1) Flash 使用之前要先统一擦除(擦除的单位是块)。Flash 类设备擦除后里面全 是1,所以擦干净之后读出来的值是 0xff。
(2) 检查坏块的思路就是:先块擦除,然后将整块读出来,依次检测各自节是否为 0xff,如果是则表明不是坏块,如果不是则表明是坏块。
2、页写(program)操作
(1) 写之前确保这个页是被擦除干净的。如果不是擦除干净的(而是脏的、用过的)页,写进去的值就是错的,不是你想要的结果。
(2) 写操作(write)在 flash 的操作中就叫编程(program)。
(3) SoC 写 Flash 时通过命令线、IO 线依次发送写命令、写页地址、写数据等进入 NandFlash。
(4) 写的过程:SoC 通过 Nand 控制器和 Nand 芯片完成顺序对接,然后按照时序要求,将一页 page 数据发给 Nand 芯片内部的接口电路。 接口电路先接收数据到自己的缓冲区,然后再集中写入 Nand 芯片的存储区域中。Nand 接口电路将一页 page 数据从缓冲区中写入 Nand 存储系统中需要一定的时间,这段时间 Nand 芯片不能再响应 SoC 发过来的其他命令,所以 SoC 要等待Nand 接口电路忙完。等待方法是, 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 值进行校验。 校验通过则说明读写正确,校验不通过则说明不正确(放弃数据或者尝试修复)。
3、擦除(erase)操作
(1) 擦除时必须给块对齐的地址。如果给了不对齐的地址,结果是不可知的(有些 Nand 芯片没关系,它内部会自动将其对齐,而有些 Nand 会返回地址错误)。
(2) 读写时给的地址也是一样,要求是页对齐地址。如果给了不对齐的,也是有可能对有可能错。
4、页读(read)操作
四、S5PV210 的 NandFlash 控制器
1、SoC 的 Nand 控制器的作用
由于 NOR flash 以及价格适中的 DRAM 和 NAND flash 的价格最近有所上涨,客户更喜欢在NAND flash 上执行引导代码 boot code,并在 DRAM 上执行主代码 main code 。
S5PV210 中的引导代码 boot code 可以在外部 NAND flash 上执行。它将 NAND flash 数据复制到 DRAM。为了验证 NAND 闪存数据,S5PV210 包括硬件纠错码(ECC)。NAND flash 内容复制到 DRAM 后,主程序 main program 将在 DRAM 上执行。
(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编码),现在大部分的a pplication 级别的 SoC 都有集成的内部编码器(像S5PV210就有、更复杂的譬如4418、6818就更不用说了,只会更多更先进),我们可以利用这些硬件编码器来进行快速编解码,这样软件工作量和难度降低了很多(这就是所谓的硬件加速)。
2、结构框图分析
结构框图中关键点:SFR(我们后续编程的关键,编程时就是通过读写 SFR 来产生 Nand 接口时序,以读写 Nand 芯片的) + Nand interface(硬件接口,将来和 Nand 芯片的相应引脚进行连接) + ECC 生成器。
3、S5PV210 的 Nand 控制器的主要寄存器
NFCONF、NFCONT、NFCMMD、NFADDR、NFDATA、NFMECCD0&NFMECCD1、NFSECCD、NFSTAT。
《x210cv3.pdf》
五、Nand 操作代码解析
1、擦除函数
2、页读取函数
3、页写入函数
总结:
(1) 像 NandFlash 这类芯片,通过专用的接口时序和 SoC 内部的控制器相连(这种连接方式是非常普遍的,像 LCD、DDR 等都是类似的连接)。这种接法和设计对我们编程来说,关键在于两点:SoC 的控制器的寄存器理解,和 Nand 芯片本身的文档、流程图等信息。
(2) 对于我们来说,学习 NandFlash,要注意的是:
第一,要结合 SoC 的数据手册、Nand 芯片的数据手册、示例代码三者来理解。
第二,初学时不要尝试完全不参考,自己写出 Nand 操作的代码,初学时应该是先理解实例代码,知道这些代码是怎么写出来的,必要时对照文档来理解代码。代码理解之后去做实践,实践成功后以后再考虑,自己不参考代码只参考文档来写出 nand 操作的代码。
源自朱有鹏老师.