NAND FLASH的读操作及原理

硬件原理

上面是我使用的NAND FLASH的硬件原理图,面对这些引脚,很难明白他们是什么含义,下面直接引用韦东山老师的课程中的提问:

NAND FLASH是一个存储芯片
那么: 这样的操作很合理"读地址A的数据,把数据B写到地址A"

问1. 原理图上NAND FLASH和S3C2440之间只有数据线,
     怎么传输地址?
答1.在DATA0~DATA7上既传输数据,又传输地址
     当ALE为高电平时传输的是地址,

问2. 从NAND FLASH芯片手册可知,要操作NAND FLASH需要先发出命令
     怎么传入命令?
答2.在DATA0~DATA7上既传输数据,又传输地址,也传输命令
     当ALE为高电平时传输的是地址,
     当CLE为高电平时传输的是命令
     当ALE和CLE都为低电平时传输的是数据

问3. 数据线既接到NAND FLASH,也接到NOR FLASH,还接到SDRAM、DM9000等等
     那么怎么避免干扰?
答3. 这些设备,要访问之必须"选中",
     没有选中的芯片不会工作,相当于没接一样

问4. 假设烧写NAND FLASH,把命令、地址、数据发给它之后,
     NAND FLASH肯定不可能瞬间完成烧写的,
     怎么判断烧写完成?
答4. 通过状态引脚RnB来判断:它为高电平表示就绪,它为低电平表示正忙

读操作步骤

由上图的读操作时序图可以得到这么一个读操作的流程:

     (1)发出命令
     (2)发出地址
     (3)读数据

再结合我们的S3C2440芯片,具体操作读NAND FLASH的步骤如下(芯片是通过NAND FLASH控制器进行读写操作的):

          NAND FLASH                      S3C2440
发命令    选中芯片                   
          CLE设为高电平                   NFCMMD=命令值     
          在DATA0~DATA7上输出命令值
          发出一个写脉冲
            
发地址    选中芯片                        NFADDR=地址值
          ALE设为高电平
          在DATA0~DATA7上输出地址值
          发出一个写脉冲

发数据    选中芯片                        NFDATA=数据值
          ALE,CLE设为低电平
          在DATA0~DATA7上输出数据值
          发出一个写脉冲

读数据    选中芯片                        val=NFDATA
          发出读脉冲
          读DATA0~DATA7的数据

要注意的是,每次操作之前都要写选中NAND FLASH。

接下来我们先了解一下NAND FLASH的内部结构:

       由上图可以看到,每一页的大小为2KB,而且每一页都有64B的OOB(out of bank,主要用于坏块检测)。如果CPU读取NAND FLASH上的第2048个数据,那么将会访问到的是page 1的第一个字节(从page 0开始数),这一点很重要,OOB对于读写操作来说是透明的。另外,发出的地址给NAND FLASH是分为五个周期进行的:

有了这些基础知识后,下面马上开始写代码(下面的代码是用来重定位的作用,也就是从NAND FLASH中读取数据,然后拷贝到目的地址)

void delay_some_time(void)
{
	volatile int i;
	for(i=0; i<10; i++);
}

void nand_select(void)
{
	NFCONT &= ~(1<<1);
}

void nand_deselect(void)
{
	NFCONT |= (1<<1);
}

void nand_cmd(unsigned char cmd)
{
	NFCMMD = cmd;
	delay_some_time(); //经验判断,发出命令后需要等待一些时间
}

void nand_addr(unsigned int addr)
{
	unsigned int col = addr % 2048;
	unsigned int page = addr / 2048;
	//puts("in nand_addr\n\r");

	/*芯片手册规定要在5个周期之内分别按下面的规则发出地址*/
	NFADDR = col & 0xff;
	delay_some_time();
	NFADDR = (col >> 8) & 0xff;
	delay_some_time();

	NFADDR = page & 0xff;
	delay_some_time();
	NFADDR = (page >> 8) & 0xff;
	delay_some_time();
	NFADDR = (page >> 16) & 0xff;
	delay_some_time();
	//puts("leave nand_addr\n\r");
}

void nand_wait_ready(void)
{
	/*NFSTAT的最低位为0的时候代表NAND flash正忙*/
	while (!(NFSTAT & 1));
}

unsigned char nand_data(void)
{
	return NFDATA;
}


void nand_read(unsigned int addr, unsigned char *buf, unsigned int len)
{
	int col = addr % 2048; //有可能是从每页的中间开始读
	int i = 0;
	//puts("in nand_read function\n\r");
	
	/*1. 选中:因为NAND FLASH的数据线是复用的,所以必须先选中*/
	nand_select();

	//puts("after nand_select\n\r");

	while (i<len)
	{
		/*2.  发出读命令00h*/
		nand_cmd(0x00);

		/*3. 发出地址(分5步发出)*/
		nand_addr(addr);

		/*4. 发出读命令30h*/
		nand_cmd(0x30);

		/*5. 判断状态,确定是否已经读完*/
		nand_wait_ready();

		/*6. 读数据*/
		for(; (col < 2048) && (i < len); col++)
		{
			buf[i] = nand_data();
			i++;
			addr++;
		}
		col = 0;
	}
	/*7. 取消片选*/
	nand_deselect();
	
}

(1)每次读操作开始前都要先选中芯片

(2)读操作前都要先发出00命令

(3)按照NAND FLASH芯片手册的要求,发出的地址,要分为五个周期,分别发出:列地址的低8位、列地址的高8位、行(页)地址的0~7位、行(页)地址的8~15位和行(页)地址的15~23位。其中,列地址求余后的余数,页地址则是除法得到的商。

(4)之后是发出的30命令(就是这么规定,没有解释)

(5)NAND FLASH读数据也很简单,直接读寄存器NFDATA

(6)读完后,取消片选,整个读操作的流程就算结束

猜你喜欢

转载自blog.csdn.net/lee_jimmy/article/details/82084241
今日推荐