NAND FLASH学习笔记之nand flash基础转

Posted sky

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了NAND FLASH学习笔记之nand flash基础转相关的知识,希望对你有一定的参考价值。

转自:https://blog.csdn.net/wang_zheng_kai/article/details/18984873

我入职以来接触的第一个实践内容就是MTD下的NAND FLASH的驱动,下面我将从nand flash的基础和驱动程序两个方面来探讨该知识点,同时最后我会把自己的

动手实验也展示出来,我学习是基于jz4780grus开发板来学习的,使用的nandflash的型号是MT29F32G08CBACA,我的大致学习结构如目录所示:

 

一、NAND FLASH概述

二、NAND FLASH的参数及物理结构

三、NAND FLASH的地址访问方法

四、 NAND FLASH的操作方法

五、 NAND FLASH的其他一些补充


(一)Nand Flash的概述

1、Nand Flash的定义:

NAND Flash 在嵌入式系统中的地位与PC机上的硬盘是类似的。用于保存系统运行所必需的操作系统,应用程序,用户数据,运行过程中产生的各类数据,系统掉电后数据不会丢失。

2、 Nand Flash的几个重要的基本特性:

a、NandFlash的IO接口

对于Norflash、dram 之类的存储设备,CPU 可以直接通过地址总线对其进行访问,而 Nand Flash 没有这类的总线,只有 IO 接口,只能通过复用的 IO接口发送命令和地址,从而实现对 Nand Flash 内部数据进行访问。(端口的复用)

b、 NandFlash的读、写、擦除操作:

读写是以页为单位的,擦除是以块为单位的。

对于Nand的写操作,只能由1变成0,而不能由0变成1。所以必须先对nand执行erase操作,即将0变成1,然后再写(使对应的1变成0)

c、存储在Nand中的数据容易发生错误,所以采取一定的算法对数据进行编码和解码很有必要。在数据存储到nand flash之前进行编码,连同校验数据一同存储到nand之中;在数据从nand读出之后进行解码,以验证数据是否出错。(BCH)

3、与Nand Flash相关的名词术语:

1. ONFI标准

ONFI(Open NAND Flash Interface,开放式NAND闪存接口)规范是一种Flash闪存接口的标准,它是Intel为统一当初混乱的闪存接口所倡导的标准。因为在此之前,市场上销售的NAND闪存芯片在引脚定义上都不完全相同。这就使得为一家公司设计的控制器,很有可能无法用在另一家公司的产品上。比如为东芝芯片设计的控制器,就无法用在三星或海力士的产品上,这就给上游的主控设计商以及最终的产品设计人员带来了很大的困难。

为此,Intel联合多家NAND Flash厂商制定了ONFI标准,统一NAND Flash芯片的引脚定义,并在此基础上采用新的技术以实现新的功能。

2. Block Management(坏)块管理

NandFlash 由于其物理特性,只有有限的擦写次数,超过那个次数,基本上就是坏了。在使用过程中,有些 Nand Flash 的 block 会出现被用坏了,当发现了,要及时将此 block 标注为坏块,不再使用。于此相关的管理工作,属于 Nand Flash 的坏块管理的一部分工作。

3. Wear-Leveling 负载平衡

NandFlash 的 block 的管理,还包括负载平衡。

正是由于 Nand Flash 的 block,都是有一定寿命限制的,所以如果你每次都往同一个 block擦除然后写入数据,那么那个 block 就很容易被用坏了,所以我们要去管理一下,将这么多次的对同一个 block 的操作,平均分布到其他一些 block 上面,使得在 block 的使用上,相对较平均,这样相对来说,可以更能充分利用 Nand Flash。

4. ECC 错误校验码

NandFlash 物理特性上使得其数据读写过程中会发生一定几率的错误,所以要有个对应的错误检测和纠正的机制,于是才有此 ECC,用于数据错误的检测与纠正。Nand Flash 的 ECC,常见的算法有海明码和BCH,这类算法的实现,可以是软件也可以是硬件。不同系统,根据自己的需求,采用对应的软件或者是硬件。

5.SLC 和MLC

SLC(Single Level Cell)

单个存储单元,只存储一位数据,表示 1 或 0。

对于数据的表示,单个存储单元中内部所存储电荷的电压,和某个特定的阈值电压 Vth相比,如果大于此 Vth 值,就是表示 1,反之,小于 Vth,就表示 0.

MLC(Multi Level Cell)

与 SLC 相对应的,就是单个存储单元,可以存储多个位,比如 2 位,4位等。其实现机制,说起来比较简单,

就是通过控制内部电荷的多少,分成多个阈值,通过控制里面的电荷多少,而达到我们所需要的存储成不同的数据。比如,假设输入电压是 Vin=4V(实际没有这样的电压,此处只是为了举例方便),那么,可以设计出 2 的 2 次方=4 个阈值, 1/4 的 Vin=1V,2/4 的 Vin=2V,3/4 的 Vin=3V,Vin=4V,分别表示 2 位数据 00,01,10,11,对于写入数据,就是充电,通过控制内部的电荷的多少,对应表示不同的数据。

4、Nand Flash的数据存储:

NAND flash的数据是以bit的方式保存;对于SLC而言,一个cell只能存储一个bit,而对于MLC而言,一个cell可以存储2个bit;这些cell以8个或者16个为单位连成bit line,形成所谓的byte(x8)/word(x16),即我们所说的NAND device的位宽。

NAND flash以页(后面会介绍到)为单位读写数据,而以块为单位擦出数据。

 

(二)Nand Flash的参数及结构

1、MT29F32G08CBACA型号分析

 

2、MT29F32G08CBACA的封装及设备结构

 

3、MT29F32G08CBACA存储单元组织结构


Organization

– Page size : 4320bytes (4096 + 224 bytes)

– Block size: 256pages (1024K + 56K bytes)

– Plane size: 2 planesx 2048 blocks per plane

– Device size: 32Gb:4096 blocks

NANDFLASH存储器MT29F32G08CBACA的总容量为34560Mb(4G+224M),其中包括两个plane,每个plane由2048个block (块) ,每个block又由256 pages组成,而每个page包含了大小为4K字节的Data area(数据存储区域) 和224字节的Spare area(备用区域)

OOB:每页还有一块区域,在Linux 系统中,称为OOB(Out Of Band),这个区域最初基于Nand Flash在读写数据时容易错误的特性,为了保证数据的正确性,采用相应的检测和纠错机制(EDC/ECC),而设计的用于放置数据的校验值的区域。

关于 oob具体用途,总结起来有:

1、标记是否是坏块

2、存储ECC数据

3、存储一些和文件系统相关的数据。如jffs2就会用到这些空间存储一些特定信息,而yaffs2文件系统,会在oob中,存放很多和自己文件系统相关的信息。


4、MT29F32G08CBACA功能框图


由于,I/O线是数据地址和命令复用的,所以要根据ALE和CLE的高低电平可以判断I/O线上传递过来的是地址,命令还是数据。
————————————————
版权声明:本文为CSDN博主「中華田園犬」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/wang_zheng_kai/article/details/18984873

【作者】张昺华
【大饼教你学系列】https://edu.csdn.net/course/detail/10393
【新浪微博】 张昺华--sky
【twitter】 @sky2030_
【微信公众号】 张昺华
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利.

LCD实验学习笔记:NAND FLASH

s3c2440 CPU内置NAND FLASH控制器。相关寄存大器起始地址为0x4e000000。

通过设置NFCONF寄存器,设置NAND FLASH 时序。

通过设置NFCONT寄存器,使能NAND FLASH、初始化ECC等。

代码:


 

#define GSTATUS1 (*(volatile unsigned int *)0x560000B0) //读此寄存器可以知道CPU芯片型号
#define BUSY 1

#define NAND_SECTOR_SIZE_LP 2048 //大页每页2048字节
#define NAND_BLOCK_MASK_LP (NAND_SECTOR_SIZE_LP - 1) //大页掩码???

typedef unsigned int S3C24X0_REG32;

//s3c2440 NAND FLASH相关寄存器
typedef struct {
  S3C24X0_REG32 NFCONF;
  S3C24X0_REG32 NFCONT;
  S3C24X0_REG32 NFCMD;
  S3C24X0_REG32 NFADDR;
  S3C24X0_REG32 NFDATA;
  S3C24X0_REG32 NFMECCD0;
  S3C24X0_REG32 NFMECCD1;
  S3C24X0_REG32 NFSECCD;
  S3C24X0_REG32 NFSTAT;
  S3C24X0_REG32 NFESTAT0;
  S3C24X0_REG32 NFESTAT1;
  S3C24X0_REG32 NFMECC0;
  S3C24X0_REG32 NFMECC1;
  S3C24X0_REG32 NFSECC;
  S3C24X0_REG32 NFSBLK;
  S3C24X0_REG32 NFEBLK;
} S3C2440_NAND;

static S3C2440_NAND * s3c2440nand = (S3C2440_NAND *)0x4e000000;//s3c2440 Nand flash 相关寄存器起始地址

//供外部调用的函数声明
void nand_init(void); //初始化
void nand_read(unsigned char *buf, unsigned long start_addr, int size);//读取数据到缓冲区

/* S3C2440的NAND Flash处理函数 */
static void s3c2440_nand_reset(void);
static void s3c2440_wait_idle(void);
static void s3c2440_nand_select_chip(void);
static void s3c2440_nand_deselect_chip(void);
static void s3c2440_write_cmd(int cmd);
static void s3c2440_write_addr_lp(unsigned int addr);
static unsigned char s3c2440_read_data(void);

//复位
static void s3c2440_nand_reset(void)
{
  s3c2440_nand_select_chip();//选片选
  s3c2440_write_cmd(0xff); //复位命令
  s3c2440_wait_idle(); //等待就绪
  s3c2440_nand_deselect_chip(); //取消片选
}

//等待就绪信号
static void s3c2440_wait_idle(void)
{
  int i;
  volatile unsigned char *p = (volatile unsigned char *)&s3c2440nand->NFSTAT;
  //最后一位为1表示忙,忙就一直等
  while (!(*p & BUSY))
  for (i = 0; i < 10; i++);
}

//片选
static void s3c2440_nand_select_chip()
{
  s3c2440nand->NFCONT &= ~(1 << 1); //NFCONT寄存器[1]位Reg_nCE置0
  int i ;
  for (i = 0; i < 10; i++); //等待片选?
}


//取消片选
static void s3c2440_nand_deselect_chip()
{
  s3c2440nand->NFCONT |=(1<<1); //NFCONT寄存器[1]位Reg_nCE置1
}

//发送命令
static void s3c2440_write_cmd(int cmd)
{
  volatile unsigned char *p = (volatile unsigned char *)&s3c2440nand->NFCMD; //p指向NFCMD寄存器
  *p = cmd; //命令写入命令寄存器
}

//发送地址
static void s3c2440_write_addr_lp(unsigned int addr)
{
  int i;
  volatile unsigned char *p = (volatile unsigned char *)&s3c2440nand->NFADDR;
  int col, page;
  col = addr & NAND_BLOCK_MASK_LP; //得到页内地址。 每页2K,页内地址为bit[0-10]
  page = addr / NAND_SECTOR_SIZE_LP; //得到页号。256M为2的28次方,地址总位数为27,即bit[11-27]为页号,共17位
  *p = col & 0xff; //地址后8位 ,A0-A7;
  for (i = 0; i < 10; i++);
  *p = (col >> 8) & 0x0f; //A8-A10
  for (i = 0; i < 10; i++);
  *p = page & 0xff; //页号后后位 A11-A18
  for (i = 0; i < 10; i++);
  *p = (page >> 8) & 0xff;//A19-A26
  for (i = 0; i < 10; i++);
  *p = (page >> 16) & 0x1; //A27
  for (i = 0; i < 10; i++);}

//读数据
static unsigned char s3c2440_read_data(void)
{
  volatile unsigned char *p = (volatile unsigned char *)&s3c2440nand->NFDATA;
  return *p;
}


//初始化Nand Flash
void nand_init(void)
{
  //设置时序
  //这里假设cpu频率100MHz,即一个时钟周期为10ns
  #define TACLS 0
  #define TWRPH0 3 //nand flash手册 twp最低要求12ns,即2个时钟周期以上,所以这里可以取1的,3可以保证400MHz时可用
  #define TWRPH1 0 //nand flash手册 tCLH最低要求5ns,取值0要求CPU频200Mhz以下
  s3c2440nand->NFCONF = (TACLS << 12) | (TWRPH0 << 8) | (TWRPH1 << 4);
  //使能Nand Flash,禁止片选,初始化ECC
  s3c2440nand->NFCONT = (1 << 4) | (1 << 1) | (1 << 0);
  s3c2440_nand_reset(); //复位
}

//读数据
void nand_read(unsigned char *buf, unsigned long start_addr, int size)
{
  //Nand Flash的读取单位最小是page,长度必须是page的整数倍。所以必须对齐
  if ((start_addr & NAND_BLOCK_MASK_LP)||(size & NAND_BLOCK_MASK_LP))
  {
    return;
  }
  s3c2440_nand_select_chip();//发出片选信号

  int i, j;
  for (i = start_addr; i < (start_addr+size);)
  {
    s3c2440_write_cmd(0); //发出READ0命令
    s3c2440_write_addr_lp(i);
    s3c2440_write_cmd(0x30);
    s3c2440_wait_idle();
    //读取页数据
    for ( j = 0; j <NAND_SECTOR_SIZE_LP;j++,i++)
    {
      *buf = s3c2440_read_data();
      buf++;
    }

  }

  s3c2440_nand_deselect_chip();//取消片选
}


 

以上是关于NAND FLASH学习笔记之nand flash基础转的主要内容,如果未能解决你的问题,请参考以下文章

Linux学习 : 裸板调试 之 配置使用NAND FLASH

什么是MTD分区和NAND flash

nand flash nor flash mcp flash 的区别

Tiny6410之NAND FLASH驱动

Serial flash 和 nor flash nand flash 有啥区别

NAND flash学习所获----(Zac)