introduction
nand flash 是一种非易失性存储介质,被广泛用于嵌入式领域。
NOR Flash vs NAND Flash
而之前,嵌入式领域常用 nor flash 作为非易失性内存, 但是由于 nand flash 的低成本以及高颗粒密度, nand flash 已经逐渐成为市场主流 .
以下是 nand flash 和 nor flash 各自的优缺点 :
NAND Flash structure
由于 nand flash 并不支持随机访问任意位置的内容, 它的最小可访问单位称为 page , 大小一般为 2K , 而如果需要修该 page 中的内容之前,需要先擦除该 page , 而最小的擦除单位称为 block , 大小一般为 128K , 所以一个 block 一般包含 64 个 page , 也就是说一次擦除操作 最少会擦除 64 个 page 的内容 . 当然,每个 page 还会包含一个 spare 区域,该区域主要 用户存放 ecc 校验数据、坏块标记、以及剩下的用户可以自定义的部分, 该区域的大小根据不同的颗粒为 64 或者 128 字节, 下图是一个 2Gb nand flash 的整体结构图 :
由于 ecc 校验机制的最小操作单位一般为 512 字节, 所以,一个 page 的数据区通常又分为多个 sector , 每个 sector 的大小为 512 字节, 而 page 中 sector 和 spare 区域的分布,主要分为以下两种 :
该数据分布主要用于 nand flash , 每个 sector 之后都跟随一个 16 字节的 spare 区域, 主要用于存放 ecc.
该结构主要用于 spi flash , sector 和 spare 区是分开存放的.
Hardware signal
nand flash 颗粒一般和 flash controller 通过硬件管脚连接, 控制器负责通过这些管脚发送相关的命令 、交互数据内容, 数据线的位宽一般为 8bit 或 16bit , 除了数据线,nand flash 一般还包含以下 6 个控制信号线 :
(‘#’ 代表低电平有效)
在同一时刻,8bit/16bit 的数据在 WE# 的上升沿被写入到 flash 中, 同理,在同一时刻,数据在 RE# 的上升沿从 flash 中读出, 而所有对 flash 的操作,首先都是先发送一个命令操作码, 该操作码通过数据线在 CLE 高电平时被颗粒接收, 紧接着,如果是读写操作,还会跟随一个地址,用于标示该 操作的在颗粒中的位置,下图是一个典型的读一个 page 的时序图 :
Commands
flash 操作都是由不同的操作码来标示,对于不同的操作, 所需的 command、address 以及 data cycle 都是不同的, 下图是常见的 flash 操作所对应的 cycle :
而在每个 cycle 中,对于 address 和 command 无论数据线是 8bit 还是 16bit 都只能传递 8bit , 所以这里会看到用多个 cycle 来传递 address 或者 command 的情形 .
这里我们详细看下 address 是如何传递的,首先我们假设 : page 的大小为 2k , spare 的大小为 64 字节,一个 block 包含 64 个 page , 而整个 flash 包含 2048 个 block , 那么对于 page 内的寻址我们需要 11 个 bit , 而对于 block 内 page 的寻址我们需要 6 个 bit , 而对于 flash 中 block 的寻址我们需要 10 个 bit , 这样加起来是 27 个 bit , 对于一个 cycle 只能传递 8bit , 我们至少需要 4 个 cycle , 那为什么 read page 操作时 需要 5 个 cycle 呢,其实,真实的地址是这样传输的 :
这里 :
- CA: colomn address 表示一个 page 内的寻址
- PA: page address 表示一个 block 中对 page 的寻址
- BA: block address 表示 flash 中对 block 的寻址
reset command
reset 命令一般用于颗粒上电之后的复位,以及在操作过程中颗粒状态出现错误时的 补救措施,reset 命令会立刻终止之前还没完成的操作,并叫颗粒复位到初始状态 .
read id command
read id 命令用于读取 flash 颗粒的 id 信息,包含厂商、型号、颗粒结构等信息
read status command
read status 命令用于查询 flash 颗粒当前的状态,或者之前操作是否完成 .
erase command
对于 flash 颗粒的内容的修改,在最低层其实是将 1 变为 0 的过程,所以在 任何对内容的修改之前,都需要将对应的 bit 置 1 , 而这个操作就是 erase , 该操作按照 block 来进行的,所以根据之前的 address 传递方式,这里只需要 cycle 3、4、5 这三个 cycle .
program command
program 操作只能将对应的 page 中的 bit 置 0 , 操作的最小单位为一个 page .
read command
read 操作用于从 flash 中读取数据,每次读取一个 page 的数据 .
read page cache command
之前我们看到从 flash 读取数据时,颗粒内部都是先将数据搬到一个 data register 中, 之后 controller 再从该 register 将数据读出,但是这样在读连续的多个页数据时, 性能是很差的,因为每次我们都需要等待颗粒将数据搬到 data register 中 . 所以现在很多颗粒都提供 cache read mode , 当打开该模式时,颗粒内部会打开一个 cache register , 当其空闲时,data register 的数据会被快速的搬到其中, 之后自动 load 下一页的数据,而当 controller 将 cache register 中的数据读出之后, 在 data register 中的新的数据就可以快速的再次填充到 cache register 中了 .
program page cache command
和 read page 的 cache 思路一样,当 program page 时,采用 cache 模式同样可以提高 性能,具体的结构和时序如下 :
ECC
nand flash 由于硬件特性的原因,部分 bit 在读取时会发生跳变, 所以我们需要使用 ecc 机制来纠正这种情况,该机制可以由硬件实现, 也可以由软件实现,这里我们这讨论硬件 ecc .
当 program page 时,颗粒会以 sector 为单位计算 ecc , 并将计算的结果保存在 spare 区,当读取一个 page 时,颗粒同样会计算 ecc , 并和保存的 ecc 继续比较, 如果发现不同,则会根据使用的 ecc 算法进行 bit 矫正,当然如果发生跳变的 bit 数超过了 ecc 算法所能纠正的最大位数,则颗粒会 ecc 状态位标记,控制器可以 读取该状态,来判断读取的数据的有效性 .
常用的 ecc 校验算法主要有 :
- Hamming codes: 该算法最多只能纠正 1bit 的跳变
- Reed-Solomon codes: 该算法较 hamming code 可校验的 bit 位数更多
- BCH codes: 该算法同样可以校验多个 bit 跳变,而且性能也是最好的,现在大多数颗粒都是采用这种算法
对于不同校验 bit 数,不同的算法所需的 ecc codes 的位数也是不同的, 具体见下图 :
注意,这里的纠正位数是在一个 sector 中的 .
Bad block
每个颗粒在出厂时,厂商经过测试会明确标记一个 block 为 bad block , 所以我们在使用时,需要知道些信息,从而避免使用 bad block , 该信息称为坏块标记,一般保存在每个 block 的第一 page 的 spare 区, 而在 spare 区域的具体位置,对于 page size 为 512byte , 那么 spare 区域的 第六个字节不为 0xff 则认为是 bad block , 而对于 page size 为 2k , 那么如果 spare 区域的第一个字节不为 0xff 则认为是 bad block .
在烧录一个 flash 时,对 bad block 的处理也有以下几种选择 .
Skip bad block
到遇到一个 bad block 时,会跳过该 block 并将数据写入到和该坏块连续的下一个 good block 中 :
reserve block
该方法将整个 flash 颗粒分为 user block area (uba) 和 reserved block area (rba) 当 uba 中遇到某个 bad block 会使用 rba 中的一个 good block 进行替换, 同时 这些 bad block 和 good block 的映射关系会通过一个 table 的范式保存在 flash 中的固定位置,具体结构如下 :
write over bad block
该方法是忽略坏块标记,即不考虑坏块,该方法一般用于软件会判断数据的可靠性 .
FIN