S3C2440中Nand flash的使用

Nand flash的使用

1、Nand flash的硬件连接
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
Nand flash芯片为K9F2G08U0A,大小为2048块=2048*64(128K)页=256MB=2Gb(1B=8bit),具体信息如下图所示:
在这里插入图片描述
S3C2440内部集成了一个Nand flash控制器,在复位期间,Nand flash控制器首先通过与Nand flash相连的4个配置引脚的状态,获取外接的Nand flash的配置信息,4个配置引脚如下:
NCON:页的大小为2K Bytes,需要用Advanced Nand flash,所以设置为1(通过上拉电阻与3.3V相连);
GPG13:页的大小为2K Bytes,所以设置为1(通过上拉电阻与3.3V相连);
GPG14:Nand flash芯片地址线只有8条,但是地址共有2048(块)*64(页)*2K,为了读出多个地址,需要分5个周期来实现地址的发送,所以设置为1(通过上拉电阻与3.3V相连);
GPG15:总线宽度为8位,所以设置为0(通过下拉电阻与GND相连);
在这里插入图片描述
2、Nand flash的初始化

#define		NFCONF		(*(volatile unsigned int *)(0x4E000000))              
#define		NFCONT		(*(volatile unsigned int *)(0x4E000004))   

#define 	TACLS	 	0
#define		TWRPH0 		1
#define 	TWRPH1 		0
void nand_init(void)
{
	NFCONF = ((TACLS << 12) | (TWRPH0 << 8) | (TWRPH1 << 4));
	NFCONT = ((1 << 0) | (1 << 1) | (1 << 4));
}

NFCONF寄存器(Nand flash配置寄存器)的地址为0x4E000000,初始化NFCONF寄存器只涉及到3个参数:TACLS、TWRPH0、TWRPH1;
在这里插入图片描述
以上3个参数的设置要根据Nand flash的时序图进行设置:
在这里插入图片描述
之前已经设置了系统时钟,HCLK=100MHz,所以T=10ns;
TACLS:发出CLE/ALE信号之后,经过多长时间后才能发出nWE信号,从Nand手册知道CLE/ALE和nWE信号可以同时发出,所以TACLS=0;
TWRPH0:nWE的脉冲宽度=T*(1+TWRPH0),最小12ns,所以TWRPH0>=1;
TWRPH1:nWE变为高电平后多长时间CLE/ALE变为低电平,最小5ns,所以TWRPH1>=0;

NFCONT寄存器(Nand flash控制寄存器)的地址为0x4E000004,初始化NFCONT寄存器只需要设置第0位、第1位和第4位即可;
在这里插入图片描述
3、Nand flash 的读写操作

#define     NFCMMD     (*(volatile unsigned char *)(0x4E000008))  /*NAND flash 发送命令寄存器,命令只有8位*/ 
#define     NFADDR     (*(volatile unsigned char *)(0x4E00000C))  /*NAND flash 发送地址寄存器,地址只有8位*/ 
#define     NFDATA     (*(volatile unsigned char *)(0x4E000010))  /*NAND flash 读/写数据寄存器,数据只有8位*/
#define     NFSTAT     (*(volatile unsigned char *)(0x4E000020))  /*NAND flash 运行状态寄存器,用于判断RnB脚*/

void nand_select(void)
{
	int i;
	/*使能片选信号,bit1置0*/
	NFCONT &= ~(1 << 1);	
	/*延时,等待芯片使能成功*/
	for(i = 0; i < 10; i++);
}

void nand_deselect(void)
{
	int i;
	/*禁止片选信号,bit1置1*/
	NFCONT |= (1 << 1);	
	/*延时,等待芯片禁止成功*/
	for(i = 0; i < 10; i++);
}

void nand_command(unsigned char command)
{
	int i;
	NFCMMD = command;
	/*延时,等待写入命令成功*/
	for(i = 0; i < 10; i++);	
}

void nand_send_address(unsigned int address)
{
	volatile int i;
	unsigned int col = address % 2048;			/*某一页的第几列*/
	unsigned int page = address / 2048;			/*第几页,也就是第几行*/

	/*先发送2个列地址,再发送3个行地址*/
	NFADDR = (col >> 0) & 0xFF;					/*低8位,A7~A0,第一个周期*/
	for(i = 0; i < 10; i++);					/*延时,等待写入地址成功*/
	
	NFADDR = (col >> 8) & 0x0F;					/*高4位,A11~A8,第二个周期*/
	for(i = 0; i < 10; i++);				
	
	NFADDR = (page >> 0) & 0xFF;				/*低8位,A19~A12,第三个周期*/
	for(i = 0; i < 10; i++);
	
	NFADDR = (page >> 8) & 0xFF;				/*高8位,A27~A20,第四个周期*/
	for(i = 0; i < 10; i++);
	
	NFADDR = (page >> 16) & 0x01;				/*第17位,A28,第五个周期*/
	for(i = 0; i < 10; i++);
}

unsigned char nand_read_data(void)
{
	/*读取数据*/
	unsign char p = NFDATA;
	return p;
}

void nand_wait_idel(void)
{	
	/*NFSTAT寄存器中的bit1,表示RnB引脚的高低电平:
	为0:Nand flash中数据还没有准备好,一直循环;
	为1:Nand flash中数据准备好,退出循环;*/
	while(!(NFSTAT & 0x01));
}

void nand_read(unsigned int *src, unsigned char *dest, unsigned int len)
{
	/*src:源地址,为32位,所以用unsigned int表示*/
	/*dest:目的地址,由于Nand flash上每一个地址存放一个字节的内容,所以用unsigned char表示*/
	int i = 0;
	/*第一次读,可能不是某一页的0地址处,需要记录在当前页中的列位置*/
	int Col  = src % 2048;
	nand_select(); 						/*使能片选信号*/

	while (i < len)
	{
		nand_command(00);				/*发送读命令0x00H*/
		nand_send_address(src);			/*分5个周期发送源地址*/
		nand_command(0x30);				/*发送读命令0x30H*/
		nand_wait_idel();				/*等待数据准备就绪*/

		/*连续读取页内数据*/
		for (; (Col < 2048) && (i < len); Col++)
		{
			dest[i] = nand_read_data();
			i++;
			src++;
		}
		Col = 0;
	}
	nand_deselect(); 					/*读完数据后,禁止片选信号*/
}

在这里插入图片描述
一个设备(device) = 2048块(block)
一块(block) = 64页(page)
一页(page) = (2K + 64)B
在这里插入图片描述
一个地址,存放一个字节(8位)的内容,64B是ECC的OOB地址(ECC:存放判断位反转的校验码)。Nand flash有一个缺点,读数据时容易位反转,可以通过ECC编码器的值来判断读取的数据是否位反转,若反转则重新读取数据。
读取OOB的方法:
读整个Nand flash时,是读不出页里面的OOB地址,比如读第2048个地址的数据时,对应的是page1上的第一个地址的数据;
只有读某一页时,才能读出这个页里面的OOB地址,比如读page0的第2048个地址的数据时,对应的是page0的OOB的第一个地址。

Nand flash芯片只有8条地址线,但是地址共有2048(块)*64(页)*2K,为了读出多个地址,需要分5个周期来实现地址的发送。当我要访问某一个地址的数据,首先我要确定它在哪一行(Row)、哪一列(Col)上面,列的范围就是0-2047,如果大于2047,访问的就是OOB区。
在这里插入图片描述
A10–A0对应每一页的列,每一页有2048(2K)B,所以只需要A10~A0(2^11=2048);
A28~A11对应所有的页(也就是行),2048(块)*64页;
对于地址发送就是:先发出2个列地址(先发送低8位,再发送高4位),再发出3个行地址(先发送低8位,再发送高8位,最后发送第17位)。
在这里插入图片描述
从时序图可以看出,Nand flash读数据分为以下几个步骤:
1)使能片选CE,将CLE置1,等待发送命令;
2)将WE置低,将IO置为0x00H然后拉高WE,触发一次上升沿,将0x00H写入flash中;
3)将CLE置0,表示发送地址(分5个周期发送);
4)发送读命令0x30H;
5)等待RnB信号为高电平;
6)读取数据;
在同一页里数据可以连续读,读到下一页时,需要重新发送新的地址才可以读,例如地址1000到2050地址的数据时:
a、发出1000地址,到达第0页的1000地址处,然后连续读(2048-1000)次数据,直到到达第0页的2047地址处;
b、再发出2048地址,到达第1页的0地址处,然后连续读(2051-2048)次数据,直到读到2050地址处为止。
7)取消片选nCE。

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值