加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

裸板之NAND FLASH

发布时间:2020-12-15 17:39:59 所属栏目:百科 来源:网络整理
导读:1) 先从硬件上来了解一下nand flash k9f2g08r0a??256M*8??需要28线地址线,但原理图上只有8根线,所以是 数据、地址利用,地址多个周期发出 。 CLE?命令、ALE?地址,都为0是传输数据。 nand flash不能像内存一样直接读写,要先发出命令,再发地址,再读写数

1) 先从硬件上来了解一下nand flash
k9f2g08r0a??256M*8??需要28线地址线,但原理图上只有8根线,所以是数据、地址利用,地址多个周期发出
CLE?命令、ALE?地址,都为0是传输数据。
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,还接到SDRAMDM9000等等,?那么怎么避免干扰?
答3.?这些设备,要访问之必须"选中",
?????没有选中的芯片不会工作,相当于没接一样
问4.?假设烧写NAND?FLASH,把命令、地址、数据发给它之后,? ? NAND?FLASH肯定不可能瞬间完成烧写的,?怎么判断烧写完成?
答4.?通过状态引脚RnB来判断:它为高电平表示就绪,它为低电平表示正忙
问5.?怎么操作NAND?FLASH呢?
答5.?根据NAND?FLASH的芯片手册,一般的过程是:

? ? ?发出命令
? ? ?发出地址
? ? ?发出数据/读数据

?? ? ? ? ? NAND?FLASH??????????????????????S3C2440
1)发命令????选中芯片???????????????????
??????????CLE设为高电平???????????????????NFCMMD=命令值?????
??????????在DATA0~DATA7上输出命令值
??????????发出一个写脉冲? ? ? ? ? ??
2)发地址????选中芯片????????????????????????NFADDR=地址值
??????????ALE设为高电平
??????????在DATA0~DATA7上输出地址值
??????????发出一个写脉冲?
3)发数据????选中芯片????????????????????????NFDATA=数据值
??????????ALE,CLE设为低电平
??????????在DATA0~DATA7上输出数据值
??????????发出一个写脉冲?
4)读数据????选中芯片????????????????????????val=NFDATA
??????????发出读脉冲
??????????读DATA0~DATA7的数据

2) nand flash的地址


1> ?nand flash里面有一个Page Register(页寄存器),上面的立方体表示它的实体,当我们发出读命令的时候,nand?flash控制器会选中实体的某一页,把内容放到Page Register中去,然后我们就可以继续发读命令,把数据源源不断的读出来。
2> ?nand flash有一个缺点:就是位反转,就是去读里面的某一位,可能会反转。一页里面可能有一位是错误的,为了弥补这个缺点,nand flash加入了一个OOB(out of bank)区, 一页后面有64位的区间,里面一般放校验码。如果出错,可以通过这个校验码通过一个比较复杂的算法找到是哪一位出错。

3> 可以看到,nand flash的地址有5个周期。
第1、2个周期发出的是Column Address(列地址),所谓列地址就是页内地址:0~(2048+64-1).
第3、4、5个周期发出的是Row Address(行地址),就是去访问哪一页。
?假如我们要访问的地址是 addr=8000,那访问哪一页呢?
8000/2048=3.9;那么我们要访问的是第3页。 那第3页里哪个地址呢? ? 8000-3*2048=1856. 所以要访问的是第3页的1856地址。

3) 代码(以15th_nand为例)
1> start.S

<span style="font-family:Microsoft YaHei;">	/* 重定位 */
/* 把程序的代码段、数据段复制到它的链接地址去 */	
	adr r0,_start   /* 获得_start指令当前所在的地址 : 0*/
	ldr r1,=_start  /* _start的链接地址 0x51000000 */
	
	ldr r2,=bss_start      /* bss段的起始链接地址 */
	sub r2,r2,r1
	
	cmp r0,r1
	beq clean_bss
	
	bl copy2ddr
	cmp r0,#0
	bne halt</span>
重定位部分与以前有些不一样,以前是从6410的片上内存拷贝到链接地址,现在是从nand flash拷贝到链接地址去执行。
2>nand.c

#define MEM_SYS_CFG     (*((volatile unsigned long *)0x7E00F120))
#define NFCONF          (*((volatile unsigned long *)0x70200000))
#define NFCONT          (*((volatile unsigned long *)0x70200004))
#define NFCMMD          (*((volatile unsigned long *)0x70200008))
#define NFADDR          (*((volatile unsigned long *)0x7020000C))
#define NFDATA          (*((volatile unsigned char *)0x70200010))
#define NFSTAT          (*((volatile unsigned long *)0x70200028))
void nand_select(void)
{
	NFCONT &= ~(1<<1);
}
void nand_deselect(void)
{
	NFCONT |= (1<<1);
}
void nand_cmd(unsigned char cmd)
{
	NFCMMD = cmd;
}
void nand_addr(unsigned char addr)
{
	NFADDR = addr;
}
unsigned char nand_get_data(void)
{
	return NFDATA;
}
void wait_ready(void)
{
	while ((NFSTAT & 0x1) == 0);
}
void nand_reset(void)
{
	/* 选中 */
	nand_select();	
	/* 发出0xff命令 */
	nand_cmd(0xff);
	/* 等待就绪 */
	wait_ready();	
	/* 取消选中 */
	nand_deselect();
}
void nand_init(void)
{
	/* 让xm0csn2用作nand flash cs0 片选引脚 */
	MEM_SYS_CFG &= ~(1<<1);

	/* 设置时间参数 */
#define TACLS     0
#define TWRPH0    1
#define TWRPH1    0
	NFCONF &= ~((1<<30) | (7<<12) | (7<<8) | (7<<4));
	NFCONF |= ((TACLS<<12) | (TWRPH0<<8) | (TWRPH1<<4));
	/* 使能nand flash controller */
	NFCONT |= 1;
	nand_reset();
}

void nand_send_addr(unsigned int addr)
{
#if 0	
	unsigned int page = addr / 2048;
	/* 这两个地址表示从页内哪里开始 */
	nand_addr(addr & 0xff);
	nand_addr((addr >> 8) & 0xff);

	/* 下面三个地址表示哪一页 */
	nand_addr(page & 0xff);
	nand_addr((page >> 8) & 0xff);
	nand_addr((page >> 16) & 0xff);
#else
	nand_addr(addr & 0xff);         /* a0~a7 */
	nand_addr((addr >> 8) & 0x7);   /* 程序的角度: a8~a10 */

	nand_addr((addr >> 11) & 0xff); /* 程序的角度: a11~a18 */
	nand_addr((addr >> 19) & 0xff); /* 程序的角度: a19~a26 */
	nand_addr((addr >> 27) & 0xff); /* 程序的角度: a27~    */
	
#endif
}

int nand_read(unsigned int nand_start,unsigned int ddr_start,unsigned int len)
{
	unsigned int addr = nand_start;
	int i,count = 0;
	unsigned char *dest = (unsigned char *)ddr_start;
	
	/* 选中芯片 */
	nand_select();
	while (count < len)
	{
		/* 发出命令0x00 */
		nand_cmd(0x00);

		/* 发出地址 */
		nand_send_addr(addr);

		/* 发出命令0x30 */
		nand_cmd(0x30);

		/* 等待就绪 */
		wait_ready();

		/* 读数据 */
		for (i = 0; i < 2048 && count < len; i++)
		{
			dest[count++] = nand_get_data();
		}

		addr += 2048;			
	}
	/* 取消片选 */
	nand_deselect();
	return 0;
}

int copy2ddr(unsigned int nand_start,unsigned int len)
{
	int ret;	
	/* 初始化nand flash controller */
	nand_init();	
	/* 读nand flash */
	ret = nand_read(nand_start,ddr_start,len);	
	return ret;
}
3>看看应用程序main.c

#include "uart.h"
int main()
{
	char c;
	int a,b;	
	init_uart();
	printf("hello,worldnr");
	while (1)
	{
		printf("please enter two number: nr");
		scanf("%d %d",&a,&b);
		printf("nr");
		printf("the sum is: %dnr",a+b);
	}
	return 0;
}
在main中做一个简单的计算。运行代码后,结果正确,说明程序已经从nand flash中拷贝到DDRAM中去了。

16th_nand_all中增加了擦除和写操作。

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读