NAND FLASH 驱动分析
一、NAND FLASH和NOR FLASH 的区别
1、 NAND比NOR便宜;NAND的容量比NOR大(指相同成本);NAND的擦写次数是NOR的十倍;NAND的擦除和写入速度比NOR快,读取速度比NOR稍慢;
2、 NAND和NOR的读都可以以字节为单位,但NAND的写以page为单位,而NOR可以随机写每一个字节。NAND和NOR的擦除都以block为单位,但一般NAND的block比NOR的block小。另外,不管是NAND还是NOR,在写入前,都必须先进行擦除操作,但是NOR在擦除前要先写0;
3、 NAND不能在片内运行程序,而NOR可以。但目前很多CPU都可以在上电时,以硬件的方式先将NAND的第一个block中的内容(一般是程序代码,且也许不足一个block,如2KB大小)自动copy到ram中,然后再运行,因此只要CPU支持,NAND也可以当成启动设备;
4、 NAND和NOR都可能发生比特位反转(但NAND反转的几率远大于NOR),因此这两者都必须进行ECC操作;NAND可能会有坏块(出厂时厂家会对坏块做标记),在使用过程中也还有可能会出现新的坏块,因此NAND驱动必须对坏块进行管理。
二、NAND FLASH简介
◆、NAND flash的物理组成
NAND Flash 的数据是以bit的方式保存在memory cell,一般来说,一个cell 中只能存储一个bit。这些cell 以8个或者16个为单位,连成bit line,形成所谓的byte(x8)/word(x16),这就是NAND Device的位宽。这些Line会再组成Page,(NAND Flash 有多种结构,我使用的NAND Flash 是K9F1208,下面内容针对三星的K9F1208U0M),每页528Bytes(512byte(Main Area)+16byte(Spare Area)),每32个page形成一个Block(32*528B)。具体一片flash上有多少个Block视需要所定。我所使用的三星k9f1208U0M具有4096个block,故总容量为4096*(32*528B)=66MB,但是其中的2MB是用来保存ECC校验码等额外数据的,故实际中可使用的为64MB。
NAND flash以页为单位读写数据,而以块为单位擦除数据。按照这样的组织方式可以形成所谓的三类地址:
Column Address:Starting Address of the Register. 翻成中文为列地址,地址的低8位
Page Address :页地址
Block Address :块地址
对于NAND Flash来讲,地址和命令只能在I/O[7:0]上传递,数据宽度是8位。
◆、NAND Flash地址的表示
512byte需要9bit来表示,对于528byte系列的NAND,这512byte被分成1st half Page Register和2nd half Page Register,各自的访问由地址指针命令来选择,A[7:0]就是所谓的column address(列地址),在进行擦除操作时不需要它,why?因为以块为单位擦除。32个page需要5bit来表示,占用A[13:9],即该page在块内的相对地址。A8这一位地址被用来设置512byte的1st half page还是2nd half page,0表示1st,1表示2nd。Block的地址是由A14以上的bit来表示。
例如64MB(512Mb)的NAND flash(实际中由于存在spare area,故都大于这个值),共4096block,因此,需要12个bit来表示,即A[25:14],如果是128MB(1Gbit) 的528byte/page的NAND Flash,则block address用A[26:14]表示。而page address就是blcok address|page address in block NAND Flash 的地址表示为: Block Address|Page Address in block|halfpage pointer|Column Address 地址传送顺序是Column Address,Page Address,Block Address。
由于地址只能在I/O[7:0]上传递,因此,必须采用移位的方式进行。 例如,对于512Mbit x8的NAND flash,地址范围是0~0x3FF_FFFF,只要是这个范围内的数值表示的地址都是有效的。 以NAND_ADDR 为例:
第1 步是传递column address,就是NAND_ADDR[7:0],不需移位即可传递到I/O[7:0]上,而halfpage pointer即A8 是由操作指令决定的,即指令决定在哪个halfpage 上进行读
写,而真正的A8 的值是不需程序员关心的。
第2 步就是将NAND_ADDR 右移9位,将NAND_ADDR[16:9]传到I/O[7:0]上;
第3 步将NAND_ADDR[24:17]放到I/O上;
第4步需要将NAND_ADDR[25]放到I/O上;
因此,整个地址传递过程需要4 步才能完成,即4-step addressing。 如果NAND Flash 的容量是32MB(256Mbit)以下,那么,block adress最高位只到bit24,因此寻址只需要3步。
下面,就x16 的NAND flash 器件稍微进行一下说明。由于一个page 的main area 的容量为256word,仍相当于512byte。但是,这个时候没有所谓的1st halfpage 和2nd halfpage 之分了,所以,bit8就变得没有意义了,也就是这个时候 A8 完全不用管,地址传递仍然和x8 器件相同。除了,这一点之外,x16 的NAND使用方法和 x8 的使用方法完全相同。
◆ NAND FLASH支持的命令
命令 命令值 描述
NAND_CMD_READ0 0 读操作
NAND_CMD_READ1 1 读操作
NAND_CMD_PAGEPROG 0x10 页编程操作
NAND_CMD_READOOB 0x50 读写OOB
NAND_CMD_ERASE1 0x60 读写操作
NAND_CMD_STATUS 0x70 读取状态
NAND_CMD_STATUS_MULTI 0x71 读取状态
NAND_CMD_SEQIN 0x80 写操作
NAND_CMD_READID 0x90 读Flash ID号
NAND_CMD_ERASE2 0xd0 擦写操作
NAND_CMD_RESET oxff 复位操作
三、S3C2440的Nand Flash控制器
s3c2440内部集成有内部SRAM(steppingstone),当选择从nand flash启动的时候,nand flash的前4k代码将会自动copy到内部SRAM中后运行。
◆、nand flash控制器的特性
1、支持读/写/编程NAND FLASH内存。
2、系统复位后nand flash的前4k代码自动copy到内部SRAM,copy完成后从SRAM启动,此时内部sram被映射为nGCS0。(当OM[1:0]=00时,使能NAND FLASH 启动模式)
3、支持硬件ECC校验。
4、系统启动后内部SRAM可以用做其他的用途。
◆、操作nand flash的方法
1、设置nand flash配置寄存器NFCONF;
2、向命令寄存器NFCMMD写入操作命令;
3、向地址寄存器NFADDR写入地址;
4、读/写数据前要读取状态寄存器NFSTAT来判断nand flash是否处于忙状态。
◆、ECC(错误纠错码)
nand flash控制器包括4个ECC模块,两个模块(一个用于data[7:0],一个用于data[15:8])可以被用于2048bytes为上限的ECC检验码的生成,另外两个模块(一个用于data[7:0],一个用于data[15:8])可以被用于16bytes为上限的ECC检验码的生成。
◆、NAND FLASH特殊功能寄存器的详细说明----见手册
NFCONF 0x4E000000 NAND flash configuration
NFCONT 0x4E000004 NAND flash control
NFCMD 0x4E000008 NAND flash command
NFADDR 0x4E00000C NAND flash address
NFDATA 0x4E000010 NAND flash data
NFMECC0 0x4E000014 NAND flash main area ECC0/1
NFMECC1 0x4E000018 NAND flash main area ECC2/3
NFSECC 0x4E00001C NAND flash spare area ECC
NFSTAT 0x4E000020 NAND flash operation status
NFESTAT0 0x4E000024 NAND flash ECC status for I/O[7:0]
NFESTAT1 0x4E000028 NAND flash ECC status for I/O[15:8]
NFMECC0 0x4E00002C NAND flash main area ECC0 status
NFMECC1 0x4E000030 NAND flash main area ECC1 status
NFSECC 0x4E000034 NAND flash spare area ECC status
NFSBLK 0x4E000038 NAND flash start block address
NFEBLK 0x4E00003C NAND flash end block address
◆、读nand flash一般步骤
1.设置NFCONF和NFCONT
NFCONF = 0x300 ;设置时序
NFCONT = (1<<4)|(1<<1)|(1<<0)
2.发出片选信号.
NFCONT&= ~(1<<11)
NFCMMD = 0xff; reset命令,第一次操作nand flash前,通常复位nand flash
3.发出读命令
NFCMMD = 0 (读命令)
4.发出地址信号
volatile unsigned char *p = (volatile unsigned char *)&s3c2440nand->NFADDR;
*p = addr & 0xff;//
*p = (addr>>9) & 0xff;
*p = (addr>>17) & 0xff;
*p = (addr>>25) & 0xff;
5.循环查询NFSTAT位0,直到它等于1。
6.连续读NFDATA寄存器512次,得到一页数据(512字节)
7.禁止nand flash的片选信号
NFCONT|= (1<<1)
例子:
void nand_read(unsigned char *buf, unsigned long start_addr, int size)
{
int i, j;
if ((start_addr & NAND_BLOCK_MASK) || (size & NAND_BLOCK_MASK)) {
return ; /* 地址或长度对齐判断 */
}
/* 选中芯片 */
nand_select_chip();
for(i=start_addr; i < (start_addr + size);) {
/* 发出READ0命令 */
write_cmd(0);
write_addr(i); /* Write Address */
wait_idle();
for(j=0; j < NAND_SECTOR_SIZE; j++, i++) {
*buf = read_data();
buf++;
}
}
nand_deselect_chip(); /* 取消片选信号 */
return ;
}
四、NAND FLASH的坏块表和坏块管理
NAND驱动在probe的时候会扫描整个nand flash,生成一张BBT(坏块表),此表其实就是一个字符数组,用2 bit来描述一个block,4种状态(好块,出厂时坏块,使用过程中生成的坏块,还有个保留状态),如果一个nand flash的大小为64M,4096个块的话,则字符数组的大小则为bbt[1024](4096/8*2=1024)。
BBT 有2种存储方式,如下:
1、直接存在内存中,在使用的过程中直接在内存中更新,断电重启则重新扫描生成BBT,此种方法的优点是不要考虑BBT 在FLASH中存储的备份问题,缺点是每次系统断电重启需要重新扫描生成新的BBT。
2、FLASH在启动的过程中先去FLASH中查找有没有BBT,一般是从FLASH的最后一个BLOCK中开始查找,并且有查找最多BLOCK的限制,如果没有找到则扫描整个FLASH,生成新的BBT,并且要写到FLASH中去,如果找到,则直接读出FLASH中的BBT到内存中。一般一个BBT会占用一个BLOCK的空间,并且会有个BBT的备份,防止在更新BBT到FLASH中去的时候,意外断电,有些还需要引入日志功能,所谓日志功能就是一个版本增加的功能,比方说第一次BBT的版本为V0,则后面从新拿一个BLOCK来存放新的BBT 版本为V1,一直累加到没有新的BLOCK来存放BBT的时候,则再进行垃圾收集,把旧的BBT擦除,很多文件系统也用到日志功能,但标准的MTD是没有日志功能的,貌似只有个双备份功能。第2种方法的优点是系统在掉电之后,BBT存在FLASH中,系统在上电时不要重新扫描整个FLASH,只要从FLASH中读出即可,可以节约一些扫描的时间,但缺点是要浪费几个BLOCK来存放BBT,并且需要机制来保证BBT的正确性。
综合以上2种方法的优缺点,可以选择使用,如果FLASH的大小不是很大的话,2种方法生成BBT的时间差不了多少,就64M的FLASH来说,2440选择的就是第1种方法。
坏块标志一般存放在BLOCK中第一个PAGE的第6个字节,如果是0XFF,则说明是好块,不是则是坏块。所以扫描4096块的话,应该是很快的。
由于NAND FLASH存在坏块,所以就必须对NAND FLASH的坏块进行管理,BBM(坏块管理)应运而生,标准的MTD貌似没有BBM,而是由文件系统来进行坏块管理,典型的YAFFS文件系统就是专门为NAND FLASH而作的,其中的BBM就放在YAFFS文件系统中进行。YAFFS文件系统还包括损耗平衡等功能。
BBM实际上就是维护了一张逻辑地址到物理地址的映射表,他也是一个数组,但它用2个字节来描述1个BLOCK,所以它是short int型,假如我们使用的是4096个BLOCK的FLASH,那么就是BBM[4096],4096即为2的12次方,所以2个字节中的12位用来记录此逻辑块对应的物理块号,逻辑块号当然就是数组的下标了。其他几位用来标记此BLOCK是否为空,是否已坏等其他信息,当然我们的数组元素也可以是4个字节或更大,这就看需要记录多少信息了。
如果要让NAND FLASH支持多种文件系统,如CRAMFS 等,这些文件系统不是专门为NAND FLASH做的,他们对NOR FLASH有很好的支持,但对NAND FLASH却不支持,原因是他们没有坏块管理(BBM),所以我们就必须修改MTD,通用的做法是在MTD原始设备层和NAND DRIVER之间加上一层BBM,这样对文件系统来是是透明的,就像操作NOR FLASH一样。
但这样貌似改动比较大,所以如果用NANDFLASH的话,还是建议用标准的MTD + YAFFS,这样又稳定,又缩短了开发周期。
标准的MTD + YAFFS还有个需要注意的地方就是ECC,由于YAFFS会对FLASH进行ECC校验,而MTD又对FLASH 进行ECC的话好像有点重复,所以MTD可以选择不进行ECC,但选择了也没有其他问题,我之前开发2440的时候就是2个都有选,也很稳定。因为他们2个对ECC的值存放的地址都不一样,虽然都放在FLASH 的OOB中。但YAFFS的ECC应该会覆盖MTD中生成的ECC。