现在的位置: 首页 > 综合 > 正文

nand flash 总结

2012年01月09日 ⁄ 综合 ⁄ 共 21845字 ⁄ 字号 评论关闭

NAND Flash产品可以分为三大架构,分别是Single Level Cell;SLC,包括三星电子、Hynix、Micron以及东芝都是此技术使用者,第二种则是Multi Level Cell;MLC,目前有东芝、Renesas使用,不过三星电子将在2005第四季推出相关产品,最后则是Infineon与Saifun Semiconductors合资利用NROM技术所共同开发的Multi Bit Cell;MBC。

MLC是Intel在1997年9月最先开发成功的,其作用是将两个位的信息存入一个Floating Gate(NADA Flash存储单元中存放电荷的部分),然后利用不同Level的电荷,透过内存储存格的电压控制精准读写,假设以4种电压控制、1个晶体管可存取2 bits 的数据,若是控制8种电压就可以存取3 bits 的数据,使Flash 的容量大幅提升,类似Rambus的QRSL技术,通过精确控制浮动栅上的电荷数量,使其呈现出4种不同的存储状态,每种状态代表两个二进制数值(从00到11)。

当然不光是NOR型NAND Flash在使用,东芝在2003年2月推出第一款MLC型的NAND Flash,并接续2004年4月推出采用MLC技术的4Gbit与8Gbit NAND Flash,显然这对于本来就以容量见长的NAND Flash更是如虎添翼。根据Semiconductor Insights研究,东芝利用90nm MLC技术所开发出来的4Gb,其die面积为144 mm2。

至于SLC技术与EEPROM相同,但在Floating gate与Source gate之中的氧化薄膜更薄,其数据的写入是透过对浮置闸极的电荷加电压,然后可以透过源极,即可将所储存的电荷消除,藉由这样的方式,便可储存1个个信息位,这种技术的单一位细胞方式能提供快速的程序编程与读取,不过此技术受限于Silicon efficiency的问题,必须要藉由较先进的流程强化技术Process enhancements,才能向上提升SLC制程技术。

将上述所言,做一个比较,SLC架构是0和1两个充电值,而MLC架构可以一次储存4个以上的充电值,因此MLC架构可以有比较好的储存密度,再加上可利用比较老旧的生产设备来提高产品的容量,而无须额外投资生产设备,可以享有成本与良率的优势。

不过MLC架构有着让使用者很难容忍的缺点,就是使用寿命较短,其次MLC架构只能承受约1万次的存取,远低于SLC架构的10万次。至于存取速度,SLC架构比MLC架构要快速三倍以上,加上MLC架构对于电力的消耗较多,因此使用者若是考虑长久使用、安全储存数据以及高速的存取速度等要求,恐怕会改采用SLC架构。

其实在NAND Flash市场中,若以理论数据比较,Renesas的AG-AND技术或是Infineon的MBC技术,其实并不逊于三星电子、东芝或是其它业者,甚至于有过之而无不及,不过这两家业者因为产能、技术开发等问题造成延迟扩大市场占有率时机,这也印证商场中的一句话,任何东西都必须要能够适时适地推出,否则只是将市场拱手让给对方。

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),每页528Byte,每32 个page 形成一个Block, Sizeof(block)=16kByte 。1 block=16kbyte,512Mbit=64Mbyte,Numberof(block)=1024 1block=32page, 1page=528byte=512byte(Main Area)+16byte(Spare Area)

Nand flash 以页为单位读写数据,而以块为单位擦除数据。按照这样的组织方式可以形成所谓的三类地址: --Block Address -- Page Address   --Column Address(即为页内偏移地址)

对于NAND Flash 来讲,地址和命令只能在I/O[7:0]上传递,数据宽度是8 位。

512byte需要9bit来表示,对于528byte系列的NAND,这512byte被分成1st half和2nd half,各自的访问由地址指针命令来选择,A[7:0]就是所谓的column address。32 个page 需要5bit 来表示,占用A[13:9],即该page 在块内的相对地址。Block的地址是由A14 以上的bit 来表示,例如512Mb 的NAND,共4096block,因此,需要12 个bit 来表示,即A[25:14],如果是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 即bit8 是由操作指令决定的,即指令决定在哪个halfpage 上进行读写。而真正的bit8 的值是don/'t care 的。 第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 的容量是256Mbit 以下,那么,block adress 最高位只到bit24,因此寻址 只需要3 步。

下面,就x16 的NAND flash 器件稍微进行一下说明。 由于一个page 的main area 的容量为256word,仍相当于512byte。但是,这个时候没有所谓 的1st halfpage 和2nd halfpage 之分了,所以,bit8就变得没有意义了,也就是这个时候 bit8 完全不用管,地址传递仍然和x8 器件相同。除了,这一点之外,x16 的NAND使用方法和 x8 的使用方法完全相同。

norflash和nandflash的区别

norflash中可以运行程序,nandflash不可以

Nor flash按sector可擦除,按bit可读写。Nand Flash按Block可擦除,按Page可读写。

最主要是寻址方式不同

*********************************************************************************************************************************

Nand Flash 寻址方式

NAND Flash的寻址方式和NAND Flash的memory组织方式紧密相关。NAND Flash的数据是以bit的方式保存在memory cell,一般来说,一个cell中只能存储一个bit。这些cell以8个或者16个为单位,连成bit line,形成所谓的byte(x8)/word(x16),这就是NAND Device的位宽。

     这些Line会再组成Page,通常是528Byte/page或者264Word/page。然后,每32个page形成一个Block,Sizeof(block)=16kByte.

     Block是NAND Flash中最大的操作单元,擦除就是按照block为单位完成的,而

编程/读取是按照page为单位完成的。

     所以,按照这样的组织方式可以形成所谓的三类地址:

     -Block   Address

     -Page    Address

     -Column Address

     首先,必须清楚一点,对于NAND Flash来讲,地址和命令只能在I/O[7:0]上传递,数据宽度可以是8位或者16位,但是,对于x16的NAND Device,I/O[15:8]只用于传递数据。

     清楚了这一点,我们就可以开始分析NAND Flash的寻址方式了。

     以528Byte/page 总容量512Mbit+512kbyte的NAND器件为例:

因为,

     1 block=16kbyte,

     512Mbit=64Mbyte,

     Numberof(block)=1024

     1block=32page,

     1page=528byte=512byte(Main Area)+16byte(Spare Area)

用户数据保存在main area中。

     512byte需要9bit来表示,对于528byte系列的NAND,这512byte被分成1st half和2nd half,各自的访问由所谓的pointer operation命令来选择,也就是选择了bit8的高低。因此A8就是halfpage pointer,A[7:0]就是所谓的column address。

     32个page需要5bit来表示,占用A[13:9],即该page在块内的相对地址。Block的地址是由A14以上的bit来表示,例如512Mb 的NAND,共4096block,因此,需要12个bit来表示,即A[25:14],如果是1Gbit的528byte/page的NAND Flash,共8192个block,则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即bit8是由操作指令决定的,即指令决定在哪个halfpage上进行读写,而真正的bit8的值是don't care的。

     第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的容量是256Mbit以下,那么,block adress最高位只到bit24,因此寻址只需要3步。

NAND Flash 的数据是以bit 的方式保存在memory cell,一般来说,一个cell 中只能存储一个bit。这些cell 以8 个或者16 个为单位,连成bit line,形成所谓的byte(x8)/word(x16),这就是NAND Device 的位宽。这些Line 会再组成Page.

(Nand Flash 有多种结构,下面内容针对三星的K9F1208U0M),每页528Byte,每32 个page 形成一个Block, Sizeof(block)=16kByte 。

1 block="16kbyte",

512Mbit=64Mbyte,

Numberof(block)=4096 1block=32page,

1page=528byte=512byte(Main Area)+16byte(Spare Area) ;

Nand flash 以页为单位读写数据,而以块为单位擦除数据。

按照这样的组织方式可以形成所谓的三类地址:

--Block Address

-- Page Address

--Column Address

对于NAND Flash 来讲,地址和命令只能在I/O[7:0]上传递,数据宽度是8 位。

512byte需要9bit来表示,对于528byte系列的NAND,这512byte被分成1st half和2nd half,各自的访问由地址指针命令来选择,A[7:0]就是所谓的column address。

32 个page 需要5bit 来表示,占用A[13:9],即该page 在块内的相对地址。Block的地址是由A14 以上的bit 来表示,例如512Mb 的NAND,共4096block,因此,需要12 个bit 来表示,即A[25:14],如果是1Gbit 的528byte/page的NAND Flash,则block address用A[26:24]表示。而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 即bit8 是由操作指令决定的,即指令决定在哪个halfpage 上进行读写。而真正的bit8 的值是don't care 的。

第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 的容量是256Mbit 以下,那么,block adress 最高位只到bit24,因此寻址 只需要3 步。 下面,就x16 的NAND flash 器件稍微进行一下说明。 由于一个page 的main area 的容量为256word,仍相当于512byte。但是,这个时候没有所谓 的1st halfpage 和2nd halfpage 之分了,所以,bit8就变得没有意义了,也就是这个时候 bit8 完全不用管,地址传递仍然和x8 器件相同。除了,这一点之外,x16 的NAND使用方法和 x8 的使用方法完全相同。

正如硬盘的盘片被分为磁道,每个磁道又分为若干扇区,一块nand flash也分为若干block,每个block分为如干page。一般而言,block、page之间的关系随着芯片的不同而不同,典型的分配是这样的:

1block = 32page

1page = 512bytes(datafield) + 16bytes(oob)

需要注意的是,对于flash的读写都是以一个page开始的,但是在读写之前必须进行flash的擦写,而擦写则是以一个block为单位的。同时必须提醒的是,512bytes理论上被分为1st half 和2sd half,每个half各占256个字节。

我们讨论的K9F1208U0B总共有4096 个Blocks,故我们可以知道这块flash的容量为4096 *(32 *528)= 69206016 Bytes = 66 MB 但事实上每个Page上的最后16Bytes是用于存贮检验码和其他信息用的,并不能存放实际的数据,所以实际上我们可以操作的芯片容量为4096 *(32 *512) = 67108864 Bytes = 64 MB由 上图所示,1个Page总共由528 Bytes组成,这528个字节按顺序由上而下以列为单位进行排列(1列代表一个Byte。第0行为第0 Byte ,第1行为第1 Byte,以此类推,每个行又由8个位组成,每个位表示1个Byte里面的1bit)。这528Bytes按功能分为两大部分,分别是Data Field和Spare Field,其中Spare Field占528Bytes里的16Bytes,这16Bytes是用于在读写操作的时候存放校验码用的,一般不用做普通数据的存储区,除去这 16Bytes,剩下的512Bytes便是我们用于存放数据用的Data Field,所以一个Page上虽然有528个Bytes,但我们只按512Bytes进行容量的计算。

读 命令有两个,分别是 Read1,Read2其中Read1用于读取Data Field的数据,而Read2则是用于读取Spare Field的数据。对于Nand Flash来说,读操作的最小操作单位为Page,也就是说当我们给定了读取的起始位置后,读操作将从该位置开始,连续读取到本Page的最后一个 Byte为止(可以包括Spare Field)

Nand Flash的寻址

    Nand Flash的地址寄存器把一个完整的Nand Flash地址分解成Column Address与Page Address.进行寻址。

Column Address: 列地址。Column Address其实就是指定Page上的某个Byte,指定这个Byte其实也就是指定此页的读写起始地址。

Paage Address:页地址。由于页地址总是以512Bytes对齐的,所以它的低9位总是0。确定读写操作是在Flash上的哪个页进行的。

Read1命令

当我们得到一个Nand Flash地址src_addr时我们可以这样分解出Column Address和Page Address

column_addr=src_addr%512;                      // column address

page_address=(src_addr>>9);                       // page address

也可以这么认为,一个Nand Flash地址的A0~A7是它的column_addr,A9~A25是它的Page Address。(注意地址位A8并没有出现,也就是A8被忽略,在下面你将了解到这是什么原因)

Read1 命令的操作分为4个Cycle,发送完读命令00h或01h(00h与01h的区别请见下文描述)之后将分4个Cycle发送参数,1st.Cycle是 发送Column Address。2nd.Cycle ,3rd.Cycle和4th.Cycle则是指定Page Address(每次向地址寄存器发送的数据只能是8位,所以17位的Page Address必须分成3次进行发送

Read1的 命令里面出现了两个命令选项,分别是00h和01h。这里出现了两个读命是否令你意识到什么呢?是的,00h是用于读写1st half的命令,而01h是用于读取2nd half的命令。现在我可以结合上图给你说明为什么K9F1208U0B的DataField被分为2个half了。

如上文我所提及的,Read1的1st.Cycle是发送Column Address,假设我现在指定的Column Address是0,那么读操作将从此页的第0号Byte开始一直读取到此页的最后一个Byte(包括Spare Field),如果我指定的Column Address是127,情况也与前面一样,但不知道你发现没有,用于传递Column Address的数据线有8条(I/O0~I/O7,对应A0~A7,这也是A8为什么不出现在我们传递的地址位中),也就是说我们能够指定的 Column Address范围为0~255,但不要忘了,1个Page的DataField是由512个Byte组成的,假设现在我要指定读命令从第256个字节处 开始读取此页,那将会发生什么情景?我必须把Column Address设置为256,但Column Address最大只能是255,这就造成数据溢出。。。正是因为这个原因我们才把Data Field分为两个半区,当要读取的起始地址(Column Address)在0~255内时我们用00h命令,当读取的起始地址是在256~511时,则使用01h命令.假设现在我要指定从第256个byte开 始读取此页,那么我将这样发送命令串

column_addr=256;

NF_CMD=0x01; ?                                     从2nd half开始读取

NF_ADDR=column_addr&0xff;                       1st Cycle

NF_ADDR=page_address&0xff;                   2nd.Cycle

NF_ADDR=(page_address>>8)&0xff;          3rd.Cycle

NF_ADDR=(page_address>>16)&0xff;           4th.Cycle

其中NF_CMD和NF_ADDR分别是NandFlash的命令寄存器和地址寄存器的地址解引用,我一般这样定义它们,

#define rNFCMD        (*(volatile unsigned char *)0x4e000004)        //NADD Flash command

#define rNFADDR        (*(volatile unsigned char *)0x4e000008)        //NAND Flash address

事实上,当NF_CMD=0x01时,地址寄存器中的第8位(A8)将被设置为1(如上文分析,A8位不在我们传递的地址中,这个位其实就是硬件电路根据 01h或是00h这两个命令来置高位或是置低位),这样我们传递column_addr的值256随然由于数据溢出变为1,但A8位已经由于NF_CMD =0x01的关系被置为1了,所以我们传到地址寄存器里的值变成了

A0   A1   A2   A3   A4   A5   A6   A7   A8

1     0    0    0 0     0 0 0    1

这8个位所表示的正好是256,这样读操作将从此页的第256号byte(2nd half的第0号byte)开始读取数据。 nand_flash.c中包含3个函数

void nf_reset(void);

void nf_init(void);

void nf_read(unsigned int src_addr,unsigned   char *desc_addr,int size);

nf_reset()将被nf_init()调用。nf_init()是nand_flash的初始化函数,在对nand flash进行任何操作之前,nf_init()必须被调用。

nf_read(unsigned int src_addr,unsigned   char *desc_addr,int size);为读函数,src_addr是nand flash上的地址,desc_addr是内存地址,size是读取文件的长度。

在nf_reset和nf_read函数中存在两个宏

NF_nFCE_L();

NF_nFCE_H();

你可以看到当每次对Nand Flash进行操作之前NF_nFCE_L()必定被调用,操作结束之时NF_nFCE_H()必定被调用。这两个宏用于启动和关闭Flash芯片的工作(片选/取消片选)。至于nf_reset()中的

rNFCONF=(1<<15)|(1<<14)|(1<<13)|(1<<12)|(1<<11)|(TACLS<<8)|(TWRPH0<<4)|(TWRPH1<<0);

这一行代码是对NandFlash的控制寄存器进行初始化配置,rNFCONF是Nand Flash的配置寄存器,各个位的具体功能请参阅s3c2410数据手册。

现在举一个例子,假设我要从Nand Flash中的第5000字节处开始读取1024个字节到内存的0x30000000处,我们这样调用read函数

nf_read(5000, 0x30000000,1024);

我们来分析5000这个src_addr.

根据

column_addr=src_addr%512;       

page_address=(src_addr>>9);   

我们可得出column_addr=5000%512=392

page_address=(5000>>9)=9

于是我们可以知道5000这个地址是在第9页的第392个字节处,于是我们的nf_read函数将这样发送命令和参数

column_addr=5000%512;

>page_address=(5000>>9);

NF_CMD=0x01;                                        从2nd half开始读取

NF_ADDR= column_addr &0xff;                   1st Cycle

NF_ADDR=page_address&0xff;                   2nd.Cycle

NF_ADDR=(page_address>>8)&0xff;          3rd.Cycle

NF_ADDR=(page_address>>16)&0xff;           4th.Cycle

向NandFlash的命令寄存器和地址寄存器发送完以上命令和参数之后,我们就可以从rNFDATA寄存器(NandFlash数据寄存器)读取数据了.

我用下面的代码进行数据的读取.

for(i=column_addr;i<512;i++)

{

       *buf++=NF_RDDATA();

}

每当读取完一个Page之后,数据指针会落在下一个Page的0号Column(0号Byte).

下面是源代码:

/*

    http://www.another-prj.com/    

    author: caiyuqing    

    本代码只属于交流学习,不得用于商业开发

*/

#include "s3c2410.h"

#include "nand_flash.h"

static unsigned char seBuf[16]={0xff};

//--------------------------------------------------------------------------------------

unsigned short nf_checkId(void)

{

    int i;

    unsigned short id;

    NF_nFCE_L();        //chip enable

   

    NF_CMD(0x90);        //Read ID

    NF_ADDR(0x0);

    for(i=0;i<10;i++);    //wait tWB(100ns)

   

    id="NF"_RDDATA()<<8;    // Maker code(K9S1208V:0xec)

    id|=NF_RDDATA();    // Devide code(K9S1208V:0x76)

   

    NF_nFCE_H();        //chip enable

    return id;

}

//--------------------------------------------------------------------------------------

static void nf_reset(void)

{

    int i;

    NF_nFCE_L();        //chip enable

    NF_CMD(0xFF);        //reset command

    for(i=0;i<10;i++);     //tWB = 100ns.

    NF_WAITRB();         //wait 200~500us;

    NF_nFCE_H();        //chip disable

}

//--------------------------------------------------------------------------------------

void nf_init(void)

{

    rNFCONF=(1<<15)|(1<<14)|(1<<13)|(1<<12)|(1<<11)|(TACLS<<8)|(TWRPH0<<4)|(TWRPH1<<0);   

    //         1     1        1         1       1      xxx     r xxx,      r xxx       

    //         En     r    r       ECCR    nFCE="H" tACLS   tWRPH0      tWRPH1

    nf_reset();

}

//--------------------------------------------------------------------------------------

void nf_read(unsigned int src_addr,unsigned char *desc_addr,int size)

{

    int i;

    unsigned int column_addr = src_addr % 512;            // column address

    unsigned int page_address = (src_addr >> 9);        // page addrress

    unsigned char *buf = desc_addr;

    while((unsigned int)buf < (unsigned int)(desc_addr) + size)

    {

        NF_nFCE_L();                    // enable chip

       

        /*NF_ADDR和NF_CMD为nand_flash的地址和命令寄存器的解引用*/

        if(column_addr > 255)                // 2end halft   

            NF_CMD(0x01);                // Read2 command.   cmd 0x01: Read command(start from 2end half page)       

        else

            NF_CMD(0x00);                // 1st halft?

       

        NF_ADDR(column_addr & 0xff);                // Column Address

        NF_ADDR(page_address & 0xff);            // Page Address

        NF_ADDR((page_address >> 8) & 0xff);        // ...

        NF_ADDR((page_address >> 16) & 0xff);        // ..

        for(i = 0; i < 10; i++);                // wait tWB(100ns)/////??????

            NF_WAITRB();                    // Wait tR(max 12us)

   

        // Read from main area

        for(i = column_addr; i < 512; i++)

        {

            *buf++= NF_RDDATA();

        }

        NF_nFCE_H();                    // disable chip

        column_addr = 0;

        page_address++;

    }

    return ;

}

今天在利用ARM7上的nandflash控制器驱动,ID已读取成功,擦写,读取等尚未完成,晚上就在网上查查相关的知识,觉得有一个不错,转贴如下:

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),每页528Byte,每32 个page 形成一个Block, Sizeof(block)=16kByte 。

1 block="16kbyte",512Mbit=64Mbyte,Numberof(block)=4096 1block=32page, 1page=528byte=512byte(Main Area)+16byte(Spare Area)

Nand flash 以页为单位读写数据,而以块为单位擦除数据。

按照这样的组织方式可以形成所谓的三类地址:

--Block Address -- Page Address --Column Address

对于NAND Flash 来讲,地址和命令只能在I/O[7:0]上传递,数据宽度是8 位。

512byte需要9bit来表示,对于528byte系列的NAND,这512byte被分成1st half和2nd half,各自的访问由地址指针命令来选择,A[7:0]就是所谓的column address。

32 个page 需要5bit 来表示,占用A[13:9],即该page 在块内的相对地址。Block的地址是由A14 以上的bit 来表示,例如512Mb 的NAND,共4096block,因此,需要12 个bit 来表示,即A[25:14],如果是1Gbit 的528byte/page的NAND Flash,则block address用A[26:24]表示。而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 即bit8 是由操作指令决定的,即指令决定在哪个halfpage 上进行读写。而真正的bit8 的值是don't care 的。 第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 的容量是256Mbit 以下,那么,block adress 最高位只到bit24,因此寻址 只需要3 步。 下面,就x16 的NAND flash 器件稍微进行一下说明。 由于一个page 的main area 的容量为256word,仍相当于512byte。但是,这个时候没有所谓 的1st halfpage 和2nd halfpage 之分了,所以,bit8就变得没有意义了,也就是这个时候 bit8 完全不用管,地址传递仍然和x8 器件相同。除了,这一点之外,x16 的NAND使用方法和 x8 的使用方法完全相同。

正如硬盘的盘片被分为磁道,每个磁道又分为若干扇区,一块nand flash也分为若干block,每个block分为如干page。一般而言,block、page之间的关系随着芯片的不同而不同,典型的分配是这样的:

1block = 32page

1page = 512bytes(datafield) + 16bytes(oob)

需要注意的是,对于flash的读写都是以一个page开始的,但是在读写之前必须进行flash的擦写,而擦写则是以一个block为单位的。同时必须提醒的是,512bytes理论上被分为1st half 和2sd half,每个half各占256个字节。

我们讨论的K9F1208U0B总共有4096 个Blocks,故我们可以知道这块flash的容量为4096 *(32 *528)= 69206016 Bytes = 66 MB 但事实上每个Page上的最后16Bytes是用于存贮检验码和其他信息用的,并不能存放实际的数据,所以实际上我们可以操作的芯片容量为4096 *(32 *512) = 67108864 Bytes = 64 MB由 上图所示,1个Page总共由528 Bytes组成,这528个字节按顺序由上而下以列为单位进行排列(1列代表一个Byte。第0行为第0 Byte ,第1行为第1 Byte,以此类推,每个行又由8个位组成,每个位表示1个Byte里面的1bit)。这528Bytes按功能分为两大部分,分别是Data Field和Spare Field,其中Spare Field占528Bytes里的16Bytes,这16Bytes是用于在读写操作的时候存放校验码用的,一般不用做普通数据的存储区,除去这 16Bytes,剩下的512Bytes便是我们用于存放数据用的Data Field,所以一个Page上虽然有528个Bytes,但我们只按512Bytes进行容量的计算。

读 命令有两个,分别是 Read1,Read2其中Read1用于读取Data Field的数据,而Read2则是用于读取Spare Field的数据。对于Nand Flash来说,读操作的最小操作单位为Page,也就是说当我们给定了读取的起始位置后,读操作将从该位置开始,连续读取到本Page的最后一个 Byte为止(可以包括Spare Field)

Nand Flash的寻址

    Nand Flash的地址寄存器把一个完整的Nand Flash地址分解成Column Address与Page Address.进行寻址。

Column Address: 列地址。Column Address其实就是指定Page上的某个Byte,指定这个Byte其实也就是指定此页的读写起始地址。

Paage Address:页地址。由于页地址总是以512Bytes对齐的,所以它的低9位总是0。确定读写操作是在Flash上的哪个页进行的。

Read1命令

当我们得到一个Nand Flash地址src_addr时我们可以这样分解出Column Address和Page Address

column_addr=src_addr%512;                      // column address

page_address=(src_addr>>9);                       // page address

也可以这么认为,一个Nand Flash地址的A0~A7是它的column_addr,A9~A25是它的Page Address。(注意地址位A8并没有出现,也就是A8被忽略,在下面你将了解到这是什么原因)

Read1 命令的操作分为4个Cycle,发送完读命令00h或01h(00h与01h的区别请见下文描述)之后将分4个Cycle发送参数,1st.Cycle是 发送Column Address。2nd.Cycle ,3rd.Cycle和4th.Cycle则是指定Page Address(每次向地址寄存器发送的数据只能是8位,所以17位的Page Address必须分成3次进行发送

Read1的 命令里面出现了两个命令选项,分别是00h和01h。这里出现了两个读命是否令你意识到什么呢?是的,00h是用于读写1st half的命令,而01h是用于读取2nd half的命令。现在我可以结合上图给你说明为什么K9F1208U0B的DataField被分为2个half了。

如上文我所提及的,Read1的1st.Cycle是发送Column Address,假设我现在指定的Column Address是0,那么读操作将从此页的第0号Byte开始一直读取到此页的最后一个Byte(包括Spare Field),如果我指定的Column Address是127,情况也与前面一样,但不知道你发现没有,用于传递Column Address的数据线有8条(I/O0~I/O7,对应A0~A7,这也是A8为什么不出现在我们传递的地址位中),也就是说我们能够指定的 Column Address范围为0~255,但不要忘了,1个Page的DataField是由512个Byte组成的,假设现在我要指定读命令从第256个字节处 开始读取此页,那将会发生什么情景?我必须把Column Address设置为256,但Column Address最大只能是255,这就造成数据溢出。。。正是因为这个原因我们才把Data Field分为两个半区,当要读取的起始地址(Column Address)在0~255内时我们用00h命令,当读取的起始地址是在256~511时,则使用01h命令.假设现在我要指定从第256个byte开 始读取此页,那么我将这样发送命令串

column_addr=256;

NF_CMD=0x01; ?                                     从2nd half开始读取

NF_ADDR=column_addr&0xff;                       1st Cycle

NF_ADDR=page_address&0xff;                   2nd.Cycle

NF_ADDR=(page_address>>8)&0xff;          3rd.Cycle

NF_ADDR=(page_address>>16)&0xff;           4th.Cycle

其中NF_CMD和NF_ADDR分别是NandFlash的命令寄存器和地址寄存器的地址解引用,我一般这样定义它们,

#define rNFCMD        (*(volatile unsigned char *)0x4e000004)        //NADD Flash command

#define rNFADDR        (*(volatile unsigned char *)0x4e000008)        //NAND Flash address

事实上,当NF_CMD=0x01时,地址寄存器中的第8位(A8)将被设置为1(如上文分析,A8位不在我们传递的地址中,这个位其实就是硬件电路根据 01h或是00h这两个命令来置高位或是置低位),这样我们传递column_addr的值256随然由于数据溢出变为1,但A8位已经由于NF_CMD =0x01的关系被置为1了,所以我们传到地址寄存器里的值变成了

A0   A1   A2   A3   A4   A5   A6   A7   A8

1     0    0    0 0     0 0 0    1

这8个位所表示的正好是256,这样读操作将从此页的第256号byte(2nd half的第0号byte)开始读取数据。 nand_flash.c中包含3个函数

void nf_reset(void);

void nf_init(void);

void nf_read(unsigned int src_addr,unsigned   char *desc_addr,int size);

nf_reset()将被nf_init()调用。nf_init()是nand_flash的初始化函数,在对nand flash进行任何操作之前,nf_init()必须被调用。

nf_read(unsigned int src_addr,unsigned   char *desc_addr,int size);为读函数,src_addr是nand flash上的地址,desc_addr是内存地址,size是读取文件的长度。

在nf_reset和nf_read函数中存在两个宏

NF_nFCE_L();

NF_nFCE_H();

你可以看到当每次对Nand Flash进行操作之前NF_nFCE_L()必定被调用,操作结束之时NF_nFCE_H()必定被调用。这两个宏用于启动和关闭Flash芯片的工作(片选/取消片选)。至于nf_reset()中的

rNFCONF=(1<<15)|(1<<14)|(1<<13)|(1<<12)|(1<<11)|(TACLS<<8)|(TWRPH0<<4)|(TWRPH1<<0);

这一行代码是对NandFlash的控制寄存器进行初始化配置,rNFCONF是Nand Flash的配置寄存器,各个位的具体功能请参阅s3c2410数据手册。

现在举一个例子,假设我要从Nand Flash中的第5000字节处开始读取1024个字节到内存的0x30000000处,我们这样调用read函数

nf_read(5000, 0x30000000,1024);

我们来分析5000这个src_addr.

根据

column_addr=src_addr%512;       

page_address=(src_addr>>9);   

我们可得出column_addr=5000%512=392

page_address=(5000>>9)=9

于是我们可以知道5000这个地址是在第9页的第392个字节处,于是我们的nf_read函数将这样发送命令和参数

column_addr=5000%512;

>page_address=(5000>>9);

NF_CMD=0x01;                                        从2nd half开始读取

NF_ADDR= column_addr &0xff;                   1st Cycle

NF_ADDR=page_address&0xff;                   2nd.Cycle

NF_ADDR=(page_address>>8)&0xff;          3rd.Cycle

NF_ADDR=(page_address>>16)&0xff;           4th.Cycle

向NandFlash的命令寄存器和地址寄存器发送完以上命令和参数之后,我们就可以从rNFDATA寄存器(NandFlash数据寄存器)读取数据了.

我用下面的代码进行数据的读取.

for(i=column_addr;i<512;i++)

{

       *buf++=NF_RDDATA();

}

每当读取完一个Page之后,数据指针会落在下一个Page的0号Column(0号Byte).

下面是源代码:

/*

    http://www.another-prj.com/    

    author: caiyuqing    

    本代码只属于交流学习,不得用于商业开发

*/

#include "s3c2410.h"

#include "nand_flash.h"

static unsigned char seBuf[16]={0xff};

//--------------------------------------------------------------------------------------

unsigned short nf_checkId(void)

{

    int i;

    unsigned short id;

    NF_nFCE_L();        //chip enable

   

    NF_CMD(0x90);        //Read ID

    NF_ADDR(0x0);

    for(i=0;i<10;i++);    //wait tWB(100ns)

   

    id="NF"_RDDATA()<<8;    // Maker code(K9S1208V:0xec)

    id|=NF_RDDATA();    // Devide code(K9S1208V:0x76)

   

    NF_nFCE_H();        //chip enable

    return id;

}

//--------------------------------------------------------------------------------------

static void nf_reset(void)

{

    int i;

    NF_nFCE_L();        //chip enable

    NF_CMD(0xFF);        //reset command

    for(i=0;i<10;i++);     //tWB = 100ns.

    NF_WAITRB();         //wait 200~500us;

    NF_nFCE_H();        //chip disable

}

//--------------------------------------------------------------------------------------

void nf_init(void)

{

    rNFCONF=(1<<15)|(1<<14)|(1<<13)|(1<<12)|(1<<11)|(TACLS<<8)|(TWRPH0<<4)|(TWRPH1<<0);   

    //         1     1        1         1       1      xxx     r xxx,      r xxx       

    //         En     r    r       ECCR    nFCE="H" tACLS   tWRPH0      tWRPH1

    nf_reset();

}

//--------------------------------------------------------------------------------------

void nf_read(unsigned int src_addr,unsigned char *desc_addr,int size)

{

    int i;

    unsigned int column_addr = src_addr % 512;            // column address

    unsigned int page_address = (src_addr >> 9);        // page addrress

    unsigned char *buf = desc_addr;

    while((unsigned int)buf < (unsigned int)(desc_addr) + size)

    {

        NF_nFCE_L();                    // enable chip

       

        /*NF_ADDR和NF_CMD为nand_flash的地址和命令寄存器的解引用*/

        if(column_addr > 255)                // 2end halft   

            NF_CMD(0x01);                // Read2 command.   cmd 0x01: Read command(start from 2end half page)       

        else

            NF_CMD(0x00);                // 1st halft?

       

        NF_ADDR(column_addr & 0xff);                // Column Address

        NF_ADDR(page_address & 0xff);            // Page Address

        NF_ADDR((page_address >> 8) & 0xff);        // ...

        NF_ADDR((page_address >> 16) & 0xff);        // ..

        for(i = 0; i < 10; i++);                // wait tWB(100ns)/////??????

            NF_WAITRB();                    // Wait tR(max 12us)

   

        // Read from main area

        for(i = column_addr; i < 512; i++)

        {

            *buf++= NF_RDDATA();

        }

        NF_nFCE_H();                    // disable chip

        column_addr = 0;

        page_address++;

    }

    return ;

}

【上篇】
【下篇】

抱歉!评论已关闭.