S3C2440开发板裸机程序系列07—NAND FLASH存储器

1.     概述

我的TQ2440开发板上安装有2M的NOR FLASH和512M的NAND FLASH。

NOR FLASH 的特点是芯片内执行(XIP, eXecute In Place),应用程序可以直接在 NOR FLASH 里运行,不必再把代码读到系统RAM中(可以节约SRAM的成本)。NOR的传输效率很高,在1~4MB的小容量时具有很高的成本效益,但是很低的写入和擦除速度大大影响了它的性能。

NAND FLASH的特点是有很高的存储密度,并且写入和擦除速度也很快,但是无法直接寻址运行程序,接口上需要专门的控制器。另外NAND FLASH 非常容易出现坏区,所以需要有校验的算法。

因此,NOR FLASH一般保存启动代码和系统固件,相当于BISO。NAND FLASH用于存储数据,相当于硬盘。

可参照这篇文章: 

RAM、NAND Flash、NOR Flash的区别详解

 下面从硬件连接、NANDFLASH内部结构、读写操作、控制器寄存器设置、编程例子等几个方面进行展开。

 

2.     NANDFLASH的硬件连接

我的TQ2440开发板上的NAND FLASH型号是K9F4G08U0B,最后的B代表第3代--3rd Generation

NAND FLASH的命名规则详见: Nand Flash 命名规则  

 

硬件连接关系如下图所示。

  

GPA接口复用如下:

经查” TQ2440_V2核心板原理图”,GPA21未连接,如下图:

S3C2440提供OM[1:0],NCON,GPG13,GPG14,GPG15这5个信号来选择NAND FLASH启动,参见S3C2440中文手册,可知:

TQ2440核心板提供的连接关系:

由上图可知,电阻NR5未焊接,即NCON与GND是断路,所以:NCON=1,GPG13=1,GPG14=1,GPG15=0。即,先进NAND Flash,每个页面2K字节,需要5个地址周期,8位宽度。

 

3.     NANDFLASH内部组织结构

如下图所示:

由上图可知K9F4G08结构:

共4096个块,每个块有64个页,因此共有4096x64 = 256K 个页,每个页有效存储数据是2K字节,因此总共有效存储容量512M字节。

访问一个数据需要共5个周期(Cycle):

第1,2个周期访问列(A0—A11),即访问页内,2^11=2K

第3,4,5个周期访问行(A12—A29),即访问块, 2^(29-11)=2^18=256K。

具体到程序代码中是这样:

NF_Send_Addr(0x00); 
NF_Send_Addr(0x00); 
NF_Send_Addr((page_number) & 0xff); 
NF_Send_Addr((page_number >> 8) & 0xff); 
NF_Send_Addr((page_number >> 16) & 0x3); 
分5个周期。因为读写一般是按页为单位进行,所以前2行发0x00,后面3行把页号分3次发到A12--A19上。


4.     读写操作

对NAND FLASH的访问操作(读,写,擦除)可按照下面的步骤:

a.发送命令:是哪种操作,读,写,擦除?

b.发送地址:对哪一个地址操作

c. 发送数据。

 

5.     控制器寄存器设置

简单读写编程需要设置的寄存器包括:

GPACON : 将GPA17—GPA22设置为NAND FLASH控制器信号;
NFCONF : 主要确定TACLS、TWRPH0、TWRPH1的值;
NFCONT:用于开启NAND FLASH控制器,设置是否使能软件上锁;
NFCMD:用于写入命令;
NFADDR:用于写入要访问的地址;
NFDATA:要写入的数据放到这里;
NFSTAT: 用于检测NAND FLASH是否处于忙状态。

对于GPACON设置如下 (虽然GPA21未用到):

rGPACON &=~(0X3F << 17) ;
rGPACON |= (0X3F<< 17) ;

对于NFCONF,需要了解各参数对应关系。 S3C2440手册中如下图:

NAND FLASH的datasheet的时序关系:

由上图可知,TWRPH0 = tWP ,TWRPH1 = tCLH(= tALH)

 

例程中,FCLK=200MHz,HCLK=100MHz,PCKL=50MHz,因此:

tCLH = 5ns,Duration = 10ns *(TWRPH1+1)   ==> TWRPH1=0

tWP = 12ns,Duration = 10ns *(TWRPH0+1) = 12min  ==> TWRPH0>=1即可

tCLS - tWP = TACLS= 0ns,==> TACLS>=0,取TACLS=1.

 

NFCONT控制的第0位

NFCMMD

 NFADDR

NFDATA(只使用了低8位)

NFSTAT

 定义如下宏定义:

#define NF_Send_Cmd(cmd)   {rNFCMD  = (cmd); }

#define NF_Send_Addr(addr)  {rNFADDR = (addr); }

#define NF_Send_Data(data)  {rNFDATA8 = (data); }      

#define NF_Enable()                            {rNFCONT &= ~(1<<1); }           //nand flash控制器使能

#define NF_Disable()                 {rNFCONT |= (1<<1); }

#define NF_Enable_RB()           {rNFSTAT |= (1<<2); }                  //开启RnB监视模式;

#define NF_Check_Busy()                  {while(!(rNFSTAT&(1<<0)));} 

#define NF_Read_Byte()          (rNFDATA8)

 

6.     读器件ID程序

读器件ID的命令是90H,接下来5个周期读到产品信息码:

 

由上图可知,发送Address后有一个tREA延时。

读ID的程序如下:

void NF_ReadID(unsigned char *buf)
{
	int	i;

	NF_Enable();    
	NF_Enable_RB();
	NF_Send_Cmd(CMD_READID);	// read id command
	NF_Send_Addr(0x0);
	for ( i = 0; i < 100; i++ );
								
        *buf 		= NF_Read_Byte();
	*(buf+1)	= NF_Read_Byte();
	*(buf+2)    = NF_Read_Byte();
	*(buf+3)	= NF_Read_Byte();
	*(buf+4)	= NF_Read_Byte();
	NF_Disable();
}

主程序如下:

 

#define	ESC_KEY		0x1b
unsigned char table[]={0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,
		0x38,0x39,0x41,0x42,0x43,0x44,0x45,0x46};
		
int Main()
{
	int i;
	unsigned char key ;
	unsigned char nandID[5];
	
	Uart0_Init(115200);
	
	NF_Init();
	NF_ReadID(nandID);
	
	Uart0_Printf( "\nNand Flash ID:\n" );
	for(i=0;i<5;i++){
			Uart0_Putc(table[nandID[i]>>4]);
			Uart0_Putc(table[nandID[i]&0x0f]);
			Uart0_Printf(" \t");
	}
		
	Uart0_Printf( "\nPress 'ESC' key to Exi \n" );
	while(1)
	{
		key = Uart0_Getc();
		if( key == ESC_KEY ) {	return 1; }
	}	
	return 0;
}

7.     写入/读出 一个Block

先向第17个Block写入00—FF,然后把第17个Block中的数据读出来,并从串口0输出。

主程序如下: 

#define	ESC_KEY		0x1b
unsigned char table[]={0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,
			0x38,0x39,0x41,0x42,0x43,0x44,0x45,0x46};
		
int Main()
{
	unsigned char key ;
	unsigned char srcbuf[2048],dstbuf[2048] ;
	unsigned int i=1 ;
	
	Uart0_Init(115200);	
	NF_Init();
	
	for(i = 0 ; i < 2048 ; i++)
	{
		srcbuf[i] = i ;
	}
	
	NF_EraseBlock(17) ;
	
	Uart0_Printf( "\nWrite 0-FF to block[17] of NandFlash \n" );	
	NF_WritePage(17,4,srcbuf) ;
	
	Uart0_Printf( "\nRead block[17] of NandFlash :\n" );
	NF_ReadPage(17,4, dstbuf);
	
	for(i = 0 ; i < 2048 ; i++)
		{
			Uart0_Putc(table[dstbuf[i]/16]) ;
			Uart0_Putc(table[dstbuf[i]%16]) ;
			Uart0_Putc(' ') ;
		}
	Uart0_Printf( "\nPress 'ESC' key to Exi \n" );
	while(1)
	{
		key = Uart0_Getc();
		if( key == ESC_KEY ){	return 1; }	
	}
	return 0 ;
}

上述程序的完整代码:点击打开链接

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值