weiqi7777

cortex-a8裸机系列:第十五章 NANDFLASH

0
阅读(1685)

一、            NAND接口

         九鼎开发板的NAND接口,虽然目前开发板没有NAND,但是硬件设计有留着接口,需要使用NAND,只需要焊上去就行了。

clip_image002

NAND的命名:如K9F2G08

         K9F:三星的NANDFLASH

         2G NAND的大小,2Gbit,除以8,也就是568MB

         08 表示NAND的数据位宽是8

NAND命名,可以看出: 厂家,大小,数据位宽

 

NAND的数据线

l  数据是并行接口

l  数据上也会传递命令

二、            NANDFLASH的功能框图

clip_image004

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

2.         Nand中有多个存储单元,每个单元都有自己的地址(地址是精确到字节的,但是不能按照字节访问)。因此Nand是地址编排精确到自己,但是实际读写却只能精确到页(所以Nand的很多操作要求地址页对齐,如2K4K等这样的地址)。

3.         Nand的读写时序传递是通过IO先发送的,因为地址有30位而IO只有8位,所以需要多个cycle才能发送完毕。一般的Nand都是4cycle或者5cycle发送地址(所以这里把Nand分为了4cycle5cycle)。

三、            NANDFLASH的组织结构

clip_image006

 

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

2.         NAND中可以被单次访问最小单元(对NAND进行一次读写,至少要读写这么多,或者是这么多的整数倍)叫做page。如K9F2G08page的大小是2KB+64B。也就是对这么芯片进行读写,至少要读写2KB或者2KB*n,即使只需要读一个字节。这就是典型的块设备。

3.         页往上还有Block(块),1个块有若干个页。如K9F2G08,一个块等于64个页。

4.         块上面就是整个芯片了,也就是Device,一个Device有若干个块。如K9F2G08,一个Device2048个块。所以该芯片大小为2048*64*2KB = 256MB

5.         块设备分pageblock。由于物理限制,对于块设备不能完全按字节访问而必须块访问。在NAND中,page是读写Nand的最小单位,Block是擦除Nand的最小单位。

 

总结:

Nand芯片内部有存储空间,并且有电路来管理这些存储空间,向外部提供统一的Nand接口的访问规则,然后外部的Soc可以使用Nand接口时序来读写这个Nand存储芯片。Nand接口是一种公用标准,是一种标准。

         理论上外部soc可以直接模拟Nand接口来读写Nand芯片,但是实际上因为Nand接口对时序要求比较严格,而且时序很复杂,所以一般的Soc都是通过专门的硬件的Nand控制器来操作Nand芯片。

 

 

NandFlash的结构

1.         Nand的单元组织:blockpage(大页Nand和小页Nand

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

         一个块是多少页也是不定的。不同的Nand也不同。一个Nand芯片有多少个block也是不定的。不同的Nand芯片也不同。

         因此Nand的组织结构不统一,接口时序也不同。造成不同厂家的Nand芯片,或者是同一个厂家的不同系列型号容量的Nand接口也不一样。所以Nand的很大问题是一旦升级容量或者换芯片系列,硬件需要更改,软件需要重新移植。

 

2.         页的带内数据和带外数据

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

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

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

 

3.         Nand的地址时序

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

Nand的地址在编写程序时,要按照Nand的时序和顺序去依次写入。

 

4.         Nand的命令码

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

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

clip_image008

         以上是Nand的命令码。不同的命令发送不同的内容。

5.   NandFlash的常见操作及流程分析

1.    坏块检查

Flash使用之前要先统一擦除(擦除的单位就是块)。擦除后,数据为0XFF(8)0XFFFF16位),也就是擦除后,数据全为1

检查坏块思路:先把块擦除,然后将块中的所有数据读出来,一次检测各字节是否为0xff,如果是则表明不是坏块,如果不是则表明是坏块。

clip_image010

 

2.    页写(program)操作

写之前确保这个页是被擦除过的。如果未被擦除,写进去的值不正确。

写操作在flash的操作中就是编程(program)。

SOCFlash时通过命令线、IO线依次发送写命令、写页地址、写数据。

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

因为Nand的读写有不靠谱情况,因此会为了安全会做ECC校验。ECC校验有硬件式校验和软件式检验两种。软件式检验可以采用的策略有很多,其中之一:将刚才写入的1页数据读出来,和写入的数据进行逐一对比。如果读出的和写入的完全一样,说明写入成功。

硬件式ECCsocNand控制器可以提供硬件式ECC(目前普遍的情况)

通过会在数据写入后,再进行校验。将之前写的数据再读出来,判断是否成功。硬件式ECC就是在Nand的控制器中有个硬件模块专门做ECC操作。当操作Nand芯片时,只要按照Soc的要求打开ECC生成开关,则当写入Nand芯片时socNand控制器的ECC模块会自动生成ECC数据,放在相应的寄存器。对于编程只需要将生成的ECC数据写入Nand芯片的带外数据区。在将来读取数据时,同样打开硬件ECC开关,然后开始读取数据,读的过程当中,硬件ECC会自动计算读进来的一页数据的ECC值并将之放到相应的寄存器中。然后再读取带外数据区中原来写入时存入的ECC值,和刚才得到的ECC值进行校验。检验通过则说明读写正确。校验不通过则说明不正确(放弃数据或者尝试修复)。

clip_image012

左边部分是将数据写入到Nand中,右边的部分是在效验,将刚刚写进去的数据读出来,和之前写的数据进行比较,然后写的数据是否成功,不成功的话,说明可能有坏块,就需要更换一个块进行重新写入数据。

如果使用ECC的话,就不需要这样检验了。

3.    擦除(erase)操作

擦除是以块为单位。即擦除时必须给块对齐的地址。如果给了不对齐的地址,结果不可知(有些Nand会自动将其对齐,而有些Nand会返回错误) 

clip_image013

4.    页读(read)操作

 

 

clip_image014

四、            s5pv210Nand代码解读

clip_image016

定义了一些寄存器。

1.         NFCONF

Nand控制器的参数(时序,页大小,地址周期)设置。

clip_image018

2.         NFCONT:

Nand控制器的控制寄存器。控制Nand的操作。如使能/禁止片选,ECC校验,中断使能/禁止等。

clip_image020

clip_image022

 

3.         NFCMMD:

Nand命令寄存器,需要发送的命令写入到这个寄存器,Nand控制器会自动按照时序发送该命令。

clip_image024

4.         NFADDR

Nand地址寄存器,需要发送的地址写入到这个寄存器,Nand控制器会自动按照时序发送该地址

clip_image026

5.         NFDATANFDATA8

这里两个寄存器的地址都是一样的,只是类型不一样。需要读取数据,直接读取该寄存器,对于NFDATA,一次性读取8位,对于NFDATA8,一次性读取32位。需要写入数据时,将数据写入到该寄存器中,对于NFDATA,一次性写8位,对于NFDATA8,一次性写32位。置于读取和写入数据的时序,Nand控制器会自动产生。

clip_image028

 

6.         NFSTAT:

Nand状态寄存器。里面有对Nand状态进行记录。主要是使用第4RnB_TransDetect ,能判断Nand操作是否结束。

clip_image030

 

7.         MP0_1CONMP0_2CONMP0_3CON

Nand有关的管脚的功能设置寄存器。在GPIO说明中,有说与NF有关的GPIOMP0_1MP0_2MP0_3。所以当要使用Nand控制器,需要将这些管脚设置为Nand的功能。

clip_image032

 

 

定义Nand的一些信息。最大块为8192,页大小是2KB,块大小64页。

clip_image034

Nand控制器需要的三个时序参数的值。这三个时序参数是很重要的,要根据具体使用的NAND的芯片进行设置。

clip_image036

Nand操作过程中的命令。

clip_image038

 

定义操作Nand的基本函数。

/*   Nand 初始化

参数:无

返回值:无

功能: Nand控制器进行初始化

*/

void nand_init(void);

 

/*   Nand 读取ID

参数:无

返回值:无

功能:对Nand芯片的ID号读取,保存到全局ID结构体nand_id_info变量中。

*/

void nand_read_id(void);

 

/* Nand 块擦除

参数:待擦除块的块数,有效范围 0 - MAX_NAND_BLOCK

返回值:0 成功

       1 失败

功能:对Nand的指定块进行擦除

*/

int nand_block_erase(unsigned long block_num);

 

/* Nand 页数据读取

参数1 页地址

参数2 内存地址

参数3 读取nand数据的长度

返回值:0  成功

       -1 失败

功能:对Nand的指定页进行读取

*/

int nand_page_read(unsigned int pgaddr, unsigned char *buf, unsigned int length);

 

/* Nand 页数据编程

参数1 页地址

参数2 内存地址

参数3 读取nand数据的长度

返回值:0  成功

       -1 失败

功能:对Nand的指定页进行写入

*/

int nand_page_write(unsigned int pgaddr, const unsigned char *buf, unsigned int length);

 

/* 拷贝Nand数据到DRAM

参数1 内存地址

参数2 nand的地址

参数3 读取nand数据的长度

返回值:0  成功

       -1 失败

功能:从Nand的指定地址(字节地址)读取length长度数据,并保存在起始地址为sdram_addr的内存中

*/

具体函数就不用再说明了,移植的时候,只需要修改Nand_init函数即可。其他基本上不用修改。

而这个nand_init函数,修改,只需要设置CONF寄存器,以及端口配置,即可。

clip_image040