OK6410裸机简单的NANDFLASH读写及擦

来源:互联网 发布:编程工具下载 编辑:程序博客网 时间:2024/05/17 01:38

OK6410裸机简单的NANDFLASH读写及擦

文章转载请注明出处:http://blog.csdn.net/wf395962475/article/details/8221250

今天完成了OK6410裸机简单的NANDFLASH读写及擦除,那么直接进入正题。

我的操作环境是:

主机:WIN7系统, VMware RHEL5  8.0 虚拟机。

开发板:OK6410,A板,256M+2G 。

LCD :飞凌4.3 寸TFT ,WXCAT43, 480*272

Uboot:飞凌体统的Uboot。

移植内核版本:Linux-3.0.1。

参考内核: 飞凌提供的Linux-3.0.1

如果你是参考这篇博文来移植的话,我还是要强调一下上面的开发板环境移植内核的版本,这很重要,因为不同的硬件有不同的要求和

说明,而不同的内核版本之间又有着不同的差异性。当然这些也并不是绝对的。其他的环境也可以参考这篇博文。

个人认为要学会使用NAND FLASH的读写等操作,则必须对NAND FLASH的结构以及存储方式、访问时序等做进一步的了解!下面开始学习。

1、NAND FLASH的基本结构

本人采用飞凌OK6410-A+256M+2G开发板上的NAND FLASH芯片,型号是K9GAG08U0D。可以去谷歌搜索它的datasheet。

下面先介绍NAND FLASH引脚以及内部存储器组织结构。

NAND FLASH(K9GAG08U0D)引脚图如下,图1.1

上图简单翻译如下:
1. I/O0 ~ I/O7:用于输入地址/数据/命令,输出数据
2. CLE:Command Latch Enable,命令锁存使能,在输入命令之前,要先在模式寄存器中,设置CLE使能
3. ALE:Address Latch Enable,地址锁存使能,在输入地址之前,要先在模式寄存器中,设置ALE使能
4. CE#:Chip Enable,芯片使能,在操作Nand Flash之前,要先选中此芯片,才能操作
5. RE#:Read Enable,读使能,在读取数据之前,要先使CE#有效。
6. WE#:Write Enable,写使能,在写取数据之前,要先使WE#有效。
7. WP#:Write Protect,写保护
8. R/B#:Ready/Busy Output,就绪/忙,主要用于在发送完编程/擦除命令后,检测这些操作是否完成,忙,表示编程/擦除操作仍在进行中,就绪表示操作完成.
9. Vcc:Power,电源
10. Vss:Ground,接地
11. N.C:Non-Connection,未定义,未连接。
[小常识]
    在数据手册中,你常会看到,对于一个引脚定义,有些字母上面带一横杠的,那是说明此引脚/信号是低电平有效,比如你上面看到的RE头上有个横线,就是说明,此RE是低电平有效,此外,为了书写方便,在字母后面加“#”,也是表示低电平有效,比如我上面写的CE#;如果字母头上啥都没有,就是默认的高电平有效,比如上面的CLE,就是高电平有效。还有的是在字母前面加个小n,例如nRE,这也是表示低电平有效的。

1.1 NAND FLASH(K9GAG08U0D)内部存储器组织结构图如下

 图1.2

NAND FLASH(K9GAG08U0D)主的存储器主要有2部分组成:页(Page)、块(Block)。

●    每页大小为:(4K+218)字节,4K用来存储数据,218字节主要用于存储控制信息。如图1.2,每页末尾都有218字节的额外空间,主要是为了便于管理每一页。Eg,使用这218位中的某一位表示该页是否已经写满数据的标志位。如果该位为1,则表示该页写满。反之,表示该页为空。只需要查询该位即可知道该页是否存满数据。

●   每块大小为:128个页

整个NAND FLASH(K9GAG08U0D)由4K(4096)个块组成。

NAND FLASH容量=块的数目*每块的容量

                                =块的数目*(每块包含页的数目*每页的容量)

                  =4KBlocks*(128Pages*(4k+218b))

                  =4KBlocks*128Pages*4k+4KBlocks*128Pages*218b

                  =2048MBytes+109Mbytes

经过计算知,前面的2048M表示该NAND FLASH可以存储2G个字节数据,后面109M字节的数据主要用于保存每一页的控制信息

 

(a,k,a) NAND FLASH类似与整个小区,每块(Block)类似于小区里面的一栋楼,每个页(Page)类似于每一层楼。

1.2 Nand Flash中的特殊硬件结构

由于nand flash相对其他常见设备来说,比较特殊,所以,特殊的设备,也有特殊的设计,所以,有些特殊的硬件特性,就有必要解释一下:
页寄存器(Page Register):由于Nand Flash读取和编程操作来说,一般最小单位是页,所以,nand flash在硬件设计时候,就考虑到这一特性,对于每一片,都有一个对应的区域,专门用于存放,将要写入到物理存储单元中去的或者刚从存储单元中读取出来的,一页的数据,这个数据缓存区,本质上就是一个buffer,但是只是名字叫法不同,datasheet里面叫做Page Register,此处翻译为页寄存器,实际理解为页缓存,更为恰当些。而正是因为有些人不了解此内部结构,才容易产生之前遇到的误解:以为内存里面的数据,通过Nand Flash的FIFO,写入到Nand Flash里面去,就以为立刻实现了实际数据写入到物理存储单元中了。而实际上,只是写到了这个页缓存中,只有等你发了对应的编程第二阶段的确认命令0x10之后,实际的编程动作才开始,才开始把页缓存中的数据,一点点写到物理存储单元中去。这也是为什么发完命令0x10之后需要等待一段时间的原因。
所以,简单总结一下就是,对于数据的流向,实际是经过了如图1.3下步骤:

2. NAND FLASH接口电路

因为S3C6410处理器内部已经集成了NAND FLASH控制器。接口电路比较简单,只需将S3C6410的引脚和NAND FLASH对应的引脚接上即可。如图2.1

图2.1

S3C6410处理器与NAND Flash硬件连线(如图2.2)

I/O0- I/O78位命令、地址、数据复用总线。

CLE:命令锁存使能。

ALE:地址锁存使能。

/WE:写使能。在写命令输入后,数据在/WE脉冲的控制下依次从数据寄存器写入存储单元。

/WP:硬件写保护。在系统上电或断电时保持低电平。

/RE:读使能。在读命令输入后,数据在/RE脉冲的控制下依次从存储单元读出到数据寄存器。

CE:芯片使能,高电平有效。

R/B:芯片Ready/Busy状态检测。

如图2.2

【为何需要ALE和CLE】突然想明白了,Nand Flash中,为何设计这么多的命令,把整个系统搞这么复杂的原因了:
比如命令锁存使能(Command Latch Enable, CLE)和地址锁存使能(Address Latch Enable,ALE),那是因为,Nand Flash就8个I/O,而且是复用的,也就是,可以传数据,也可以传地址,也可以传命令,为了区分你当前传入的到底是啥,所以,先要用发一个CLE(或ALE)命令,告诉nand Flash的控制器一声,我下面要传的是命令(或地址),这样,里面才能根据传入的内容,进行对应的动作。否则,nand flash内部,怎么知道你传入的是数据,还是地址,还是命令啊,也就无法实现正确的操作了.

3 S3C6410 NAND Flash控制器原理

S3C6410 NAND Flash控制器支持的主要特征有:

a. 支持512字节页和2K字节页。

b. 软件模式:可以直接访问NAND Flash存储器。

c. 接口:支持8NAND Flash接口。

d. 硬件ECC产生、检错和表示,软件纠错。

e. 支持SLCMLCNAND Flash存储器:1位、4位和8位的ECC(推荐对SLC NAND Flash使用1ECC,对MLC NAND Flash使用4位和8ECC)。

f. 支持对数据寄存器和ECC数据寄存器的字节、半字和字访问,对其它寄存器进行按字访问。

g. Steppingstone支持字节、半字和字访问。

 

3.1 NAND FLASH控制器的工作机制。

NAND FLASH控制器的工作机制如下图3.1所示。在上电复位时,NAND FLASH控制器将通过XOM引脚状态来获得关于连接NAND FLASH的信息。在上电或系统复位后,NAND FLASH控制器自动加载4K的启动代码。加载完成后,启动代码将在Stepping Stone中被执行。如图3.1

如图3.1

NOTE:在自动导入期间,ECC是未被选中状态。因此,前4K的NAND FLASH绝不能有错位。

3.2 NAND FLASH MEMORY TIMING

如图3.2

3.3 NAND FLASH ACCESS

6410 does not support NAND flash access mechanism directly. It only supports signal control mechanism for NAND flash access. Therefore software is responsible for accessing NAND flash memory correctly.

 

S3C6410 仅支持软件模式访问。

1. Writing to the command register (NFCMMD) = the NAND Flash Memory command cycle

2. Writing to the address register (NFADDR) = the NAND Flash Memory address cycle

3. Writing to the data register (NFDATA) = write data to the NAND Flash Memory (write cycle)

4. Reading from the data register (NFDATA) = read data from the NAND Flash Memory (read cycle)

5. Reading main ECC registers and Spare ECC registers (NFMECCD0/1, NFSECCD) = read data from the

In NAND flash access, you must check the RnB status input pin by polling the signal or using interrupt.

(1)写命令寄存器=NAND FLASH 存储器命令周期。

(2)写地址寄存器=NAND FLASH 存储器地址周期。

(3)写数据寄存器=写数据到NAND FLASH 存储器(写周期)。

(4)读数据寄存器=从NAND FLASH 存储器读数据(读周期)。

(5)读主ECC 寄存器和备用ECC 寄存器=从NAND FLASH 存储器读数据。

在软件模式下,必须通过利用检测和中断来检查RnB 输入引脚的状态。

3.4 数据寄存器的配置

图3.3所示 A 字访问 B半字访问 C字节访问

 

图3.3

3.5 NAND FLASH MEMORY CONFIGURATION

NAND FLSAH 存储器结构图(图3.4)

3.4

NOTE:NAND 控制器可以支持2个NAND FLASH 存储器,如果想要从NAND启动,则必须使用Xm0CSn[2]进行导入。

3.5 NAND FLASH 控制寄存器列表

本次只配置以下和本次几个相关的寄存器(如图),ECC基本都不用管。以后需要再说。配置寄存器会在初始化时一起设置。

如图3.5

4 NAND FLASH 读写的相关配置

通过以上对NAND FLASH 相关介绍,对NAND FLASH有一定了解,但具体的操作步骤还是很模糊,以下提供一个简单操作步骤,不一定适合所有的,但基本原理都是这样。实际情况根据自己的芯片具体设置,在此只供参考学习!

访问NAND FLASH操作步骤:

1.    片选:选中NAND FLASH

2.    发命令:命令数据、命令锁存、写使能

3.    发地址:地址数据、地址锁存、写使能

4.    发数据:写数据、写使能

5.    读写

6.    取消片选

相关解释:(理解的可以不用看了 嘿嘿..)

2.发命令,即对NAND FLASH 采取哪种操作,读、写还是擦除?

3.发地址,即对NAND FLSAH的哪一页进行上述操作?

4.发数据,在此期间也要检测NAND FLASH 的内部状态。

在本次的实验中只用到以下常用的几个需要发送的命令 Read 、Page Program、Block Erase、Reset如图4.1所示。用到后会做解释。

如图4.1

4.1 NAND Flash的初始化

在以后的讲解中会用的实验中的函数,使用时请注意修改!

按照NAND Flash读写操作步骤:

1.    片选:Xm0CSn2引脚设为nand flash cs0片选 nand使用memory subsystem port 0  如图4.2寄存器配置

如图4.2

MEM_SYS_CFG &=~(1<<1);//选中Xm0CSn2

2.    配置NFCONF

如图4.3所示需要设置以下几个参数:

图4.3

对NFCONF初始化主要是确定TACLS、TWRPH0、TWRPH1三个位的值。在设置之前,先讲一下TACLS、TWRPH0、TWRPH1代表什么意思和他们的关系。

如图4.4所示

 

如图4.4

●    TACLS表征了从CLE/ALE锁存信号有效到写信号使能经过的时间,具体时间=HCLK时钟周期*TACLS。

●    TWRPH0表征了写有效持续时间,具体时间=HCLK时钟周期*(TWRPH0+1)。

●    TWRPH1表征了写无效到锁存无效之间的时间,具体时间=HCLK时钟周期*(TWRPH1+1)。

三个值的初始化需要与数据手册的时序关系联系起来看。如图4.5

如图4.5

 

对比如图4.4和如图4.5两图可以得到如下关系:

●    TACLS表征的锁存到写有效时间与K9GAG08U0D手册中的tCLS-Twp对应

●    TWRPH0表征的写有效的持续时间与K9GAG08U0D手册中的tWP对应。

●    TWRPH1表征的写无效到锁存无效之间的时间与K9GAG08U0D手册中的TCLH对应。

因此只有确定tCLS、Twp、TCLH三个参数,就可以确定TACLS、 TWRPH0 、TWRPH1。

结合K9GAG08U0D手册中的时序参数进行计算。如图4.6所示

如图4.6

在系统初始化阶段,HCLK=133MHz

有上面公式计算知,TWRPH0最小值为1,TACLS和TWRPH1都为0均可。但根据飞凌官方给的资料,时间应当延长一些,这样会更稳定,刚才那是算出的最小值!因此可以如下设置:

[cpp] view plaincopy
  1. #define TACLS    7//0 //  
  2.   
  3. #define TWRPH0   7//大于1  小于7  
  4.   
  5. #define TWRPH1   7//0 //大于0 小于7  
  6.   
  7.  NFCONF &=~((0x7<<4)|(0x7<<8)|(0x7<<12)|(1<<30));  
  8.   
  9.  NFCONF |=((TACLS<<12)|(TWRPH0<<8)|(TWRPH1<<4));  

3.    配置NFCONT

寄存器NFCONT,用于开启NAND FLASH控制器

如图4.7所示需要配置。

如图4.7

//使能 nand flash controller

NFCONT |=1;

  NFCONT&=~(1<<16);//选中Soft Disable lock

4.    复位

[cpp] view plaincopy
  1. void reset()  
  2.   
  3. {  
  4.   
  5.   nand_select();//选中  
  6.   
  7.   nand_cmd(0xFF);//发出0xff命令  
  8.   
  9.   nand_ready();//等待就绪  
  10.   
  11.   nand_deselect();//取消选中  
  12.   
  13. }  
  14.   
  15. void nand_select()  
  16.   
  17. {  
  18.   
  19.    NFCONT &=~(1<<1);  
  20.   
  21. }  
  22.   
  23.    
  24.   
  25. void nand_deselect()  
  26.   
  27. {  
  28.   
  29.   NFCONT |=1<<1;  
  30.   
  31. }  
  32.   
  33. void nand_cmd(unsigned char cmd)  
  34.   
  35. {  
  36.   
  37.   NFCMMD = cmd;  
  38.   
  39. }  
  40.   
  41. void nand_ready()  
  42.   
  43. {  
  44.   
  45.   while(!(NFSTAT&1));//读取状态值,检测NAND FLASH是否处于忙状态。  
  46.   
  47. }  


5.    NAND FLASH 页写入函数

NAND FLASH主要用于大路数据段的存取,因此向NAND FLASH写入数据是以页为单位的。NAND FLASH页写入函数的功能是向某一页写入数据。NAND FLASH由不同的块组成,每块包含128页,因此,要想写入某一页,首先需要确定该页属于哪一个块。类似前面将的小区的例子,向某一页写数据,就像给某一层楼的所有用户送快递,首先要找到哪栋楼,然后在确定是哪层。

NAND FLASH页写入命令有2个,分别是0x80和0x10。

页写入步骤为:

A.    发送页写命令0x80

B.    发送页地址

C.    发送要写入的数据

D.    发送页写入确定命令0x10

E.    检测忙信号

F.    取消选中

NOTE:为什么需要发送2次命令?很多人应该也没有注意到此问题,最开始我也没有明白什么意思。参看数据手册和相关资料才明白。当发送页写入确认命令0x10之前,并没有将数据写入NAND FLASH的存储单元,仅仅是将数据写入了NAND FLASH的数据寄存器(Data Register & S/A)里,如下图4.8所示。只有收到页写入命令0x10后,NAND FLASH才会自动将数据寄存器中的数据写入对应的存储单元中。这样做的主要目的是为了降低页的写入时间。

图4.8

在发送页写入命令后,NAND FLASH会自动将数据寄存器中的数据写入对应的存储单元中,这需要一定的时间。因此,在发送完页写入确定命令0x10之后,需要不断地检测忙信号,只有NAND FLASH真正写完数据后,才能对其进行后续的操作。

[cpp] view plaincopy
  1. int nand_write_page(unsigned int addr,unsigned char *buf)  
  2.   
  3. {  
  4.   
  5.   int i = 0;  
  6.   
  7.   unsigned char RdDat[4096];  
  8.   
  9.   if(addr%4096!=0)// 输入必须是页的开始地址  
  10.   
  11.   {  
  12.   
  13.     printf("error:nand write must start with page addr");  
  14.   
  15.     return -1;  
  16.   
  17.   }  
  18.   
  19.   nand_select();//选中  
  20.   
  21.   nand_cmd(0x80);//发页写命令  
  22.   
  23.   nand_write_addr(addr);//写地址  
  24.   
  25.   for(i = 0;i<4096;i++)//判断是那一页地址  
  26.   
  27.   {  
  28.   
  29.     write_data(buf[i]);  
  30.   
  31.   }  
  32.   
  33.   nand_cmd(0x10); //发送页写入确定命令  
  34.   
  35.   nand_ready();//检测忙信号  
  36.   
  37.   nand_deselect();//取消片选  
  38.   
  39.   nand_read(addr,RdDat,4096);//读刚才写进去的数据  
  40.   
  41.   for(i = 0 ;i<4096;i++)  
  42.   
  43.   {  
  44.   
  45.     if(RdDat[i]!=buf[i])  
  46.   
  47.     {  
  48.   
  49.       printf("%d   0x%x:0x%x\n",i,RdDat[i],buf[i]);  
  50.   
  51.       printf("check error:addr:0x%x,offsize:0x%x\n",addr,i);  
  52.   
  53.       return -1;  
  54.   
  55.     }  
  56.   
  57.   }  
  58.   
  59.   return 0;  
  60.   
  61. }  
  62.   
  63. void nand_write_addr(unsigned int addr)  
  64.   
  65. {  
  66.   
  67.   unsigned int colum = 0;  
  68.   
  69.   unsigned int page = 0;  
  70.   
  71.    
  72.   
  73.   colum = addr%4096;//地址所处哪列  
  74.   
  75.   page  = addr/4096;//地址所处哪页  
  76.   
  77. //这两个地址表示从页内哪里开始  
  78.   
  79.   NFADDR = colum&0xFF;  
  80.   
  81.   NFADDR = (colum>>8&0xFF);  
  82.   
  83. //  下面三个地址表示哪一页  
  84.   
  85.   NFADDR = page&0xFF;  
  86.   
  87.   NFADDR = (page>>8&0xFF);  
  88.   
  89.   NFADDR = (page>>16&0xFF);  
  90.   
  91. }  

6.    NAND FLASH 页读取函数

相对NAND FLASH 页写入函数,NAND FLASH 页读取函数变得较简单,页读取命令也需要2个命令:页读取发起命令0x00和页读取确认命令0x30。

基本原理:当发送页读取0x00命令后,需要紧接着发送需要读的页的绝对地址,然后发送页读取确认命令0x30,NAND FLASH收到第2个命令0x30后,自动将数据从内部存储单元复制到了NAND FLASH的数据寄存器(Data Register & S/A)里,在此期间需要检测忙信号(如果忙信号有效,说明NAND FLASH存储单元中的数据还没有全部复制到数据寄存器),数据复制完毕后,可以通过读取S3C6410内部的的特殊功能寄存器NFDATA来得到所需要的数据。

NAND FLASH页读取命令有2个,分别是0x00和0x30。

页读取操作步骤:

A.    发送页读取发起命令0x00

B.    发送地址

C.    发送页读取确认命令0x30

D.    检测忙信号

E.    从S3C6410处理器寄存器NFDATA中读取数据

F.    取消选中

 

[cpp] view plaincopy
  1. void nand_read(unsigned int start_addr,unsigned char *buf,int len)  
  2.   
  3. {  
  4.   
  5.    int i = 0;  
  6.   
  7.    int readsum = 0;  
  8.   
  9.      
  10.   
  11.    i = start_addr%4096;  
  12.   
  13.    nand_select();//片选  
  14.   
  15.    while(readsum<len)  
  16.   
  17.    {  
  18.   
  19.      //读一次  
  20.   
  21.      nand_cmd(0x00);//发送页读取发起命令0x00  
  22.   
  23.      nand_write_addr(start_addr);//写开始地址  
  24.   
  25.      nand_cmd(0x30);//发送页读取确认命令0x30  
  26.   
  27.      nand_ready();//等待检测忙信号,即是否读取完全  
  28.   
  29.      for(;i < 4096&&readsum<len;i++)  
  30.   
  31.      {  
  32.   
  33.        *buf = read_data();  
  34.   
  35.        buf++;  
  36.   
  37.        start_addr++;  
  38.   
  39.        readsum++;  
  40.   
  41.      }  
  42.   
  43.      i = 0;  
  44.   
  45.    }  
  46.   
  47.    nand_deselect();//取消片选  
  48.   
  49. }  


 

7. NAND FLASH块擦除函数

前面讲过NAND FLASH的读、写函数,但对NAND FLASH写之前,需要先进行擦除,这是由NAND FLASH自身的存储器结构决定的。对某一个存储单元来说,只能向该单元写0,无法向其写1。所谓擦除是将所有的存储单元全部写1,然后再对其进行写操作,0可以写入,1虽然无法写入,但由于擦除时该单元已经为1,所以该存储单元保留1.因此,利用擦除操作达到间接地向存储单元写1的目的。

擦除操作是以块为单位进行的,无法对一页进行擦除操作。

小提示:结合前面的例子,NAND FLASH擦除操作就像在小区里面打扫卫生,NAND FLASH的一个块就像小区里面的一栋楼,擦除只能以块为单位进行,就像打扫卫生时,只能整栋楼都打扫。

块擦除基本原理:发出块擦除发起命令0x60后,需要发送三个地址周期的块地址(注意,因为块地址只使用A13-A31,所以需要三个地址周期),最后发送块擦除确认命令0xd0,NAND FLASH接收到块擦除命令后会启动内部的擦除过程。可以通过检测忙信号来确认擦除是否成功。

 前面讲到,每个页面大小事4K+218Bytes,因此,页内地址使用A0-A12来寻找;每块包含128页,因此,使用地址A13-A19来寻址,整个NAND FLASH包含4K个块,(但有2片Plane0和Plane1,使用A20来寻址,)所以单个使用A21-A31(也就是2K)来寻址。

块擦除操作需要2个命令:块擦除发起命令0x60和块擦除确认命令0xd0.

块擦除操作步骤:

A.块擦除发起命令0x60

B.发送块地址

C.块擦除确认命令0xd0

D.检测忙信号

E.取消选中

[cpp] view plaincopy
  1. int nand_erase_block(unsigned int addr)  
  2.   
  3. {  
  4.   
  5.   unsigned int page = 0;  
  6.   
  7.    
  8.   
  9.   page  = addr/4096;//查找所在块  
  10.   
  11.   if(addr%4096*128!=0)//必须按块擦除  
  12.   
  13.   {  
  14.   
  15.     printf("error:nand erase must start with block addr");  
  16.   
  17.     return -1;  
  18.   
  19.   }  
  20.   
  21.   nand_select();//选中  
  22.   
  23.   nand_cmd(0x60);//发块擦除发起命令  
  24.   
  25. //发送三个地址周期的块地址  
  26.   
  27.   NFADDR = page&0xFF;  
  28.   
  29.   NFADDR = (page>>8&0xFF);  
  30.   
  31.   NFADDR = (page>>16&0xFF);  
  32.   
  33.   nand_cmd(0xd0);//发送块擦除确认命令  
  34.   
  35.   nand_ready();//检测忙信号,即是否擦除完成  
  36.   
  37.   nand_deselect();//取消选中  
  38.   
  39. }  
0 0