三十五.Nandflash的操作

1.nandflash就是嵌入式系统的硬盘

2.分类
(1)MLC:存储单元格存储两位,慢,偏移,寿命短,容量大
(2)SLC:存储一位。快,寿命长,容量小,昂贵


3访问;
(1)独立编址,有专用的控制器,控制器里有相应的寄存器,先送地址,然后命令,最后数据
(2)地址组成:行地址(页编号),列地址(在页中的偏移),一个nand可以有很多块,每一块可以很多页,每一页的两个部分可以不同规格

(3)信号引脚:


4.初始化nand控制器,(搜索关键字operation)
(1)初始化NFCONF,配置三个重要的与HCLK有关的时间参数
(2)初始化NGCONT,一开始要disable chip select 以及使能控制器
(3)复位:选中nandflash,清除RB标志,发送0xff命令,等待RB信号,取消选中RB信号


5.按页读
(1)选中nandflash
(2)清除RB标志
(3)写入0x00命令
(4)发送列地址,两次(但是由于是页读的方式,所以列地址,即页中的偏移量就是0)
(5)发送页编号,即行地址,分三次完成
(6)发送0x30命令
(7)等待RB信号变为ready
(8)读出数据,每次都取出数据寄存器的值,他会自动更新自己的值
(9)取消选中nandflash

6.修改之前的代码拷贝启动代码(之前只从iram复制到内存)
(1)时钟初始化有问题,错把UPLL当MPLL
(2)汇编和C语言的参数传递,不超过4个的时候,直接用r0--r3传递,且顺序和从函数的形参一致
(3)注意保存lr,否则连续两次跳转,会破坏lr,导致在执行完复制函数以后,不能返回到应执行的初始化后续代码部分
(4)注意在调用c函数之前进行栈的初始化

7.拷贝函数的三个参数,页的起始地址r0,(ulong,但是由于是页读方式,所以要去掉低12位,低12位是列地址,这里我们要去页编号,即行地址),内存起始地址r1(目标起始地址,uchar*),数据大小r3,每一页对应2048个字节(2K,视具体nandflash而言,每一个循环,大小减小2048)

8.一旦要去读取(等待)RB信号,之前就要对其进行清除;
一旦有选中操作,在结束之后要取消选中。


9.写入之前要擦除,参数是要擦除的页地址,擦除的是指定的页所在的块:
(1)选中nandflash
(2)清除RB标志
(3)写入0x60命令
(4)发送页编号,即行地址,分三次完成
(5)发送0xD0命令
(6)等待RB信号变为ready
(7)发送命令0x70
(8)读取擦出结果
(9)取消选中nandflash
(10)返回擦除结果

10.按页写
(1)选中nandflash
(2)清除RB标志
(3)写入0x80命令
(4)发送列地址,两次(但是由于是页读的方式,所以列地址,即页中的偏移量就是0)
(5)发送页编号,即行地址,分三次完成
(6)写入数据,用循环
(7)发送0x10命令
(8)等待RB信号变为ready
(9)发送命令0x70,
(10)读取写入结果,从数据寄存器读
(11)取消选中nandflash
(12)返回写入结果

11.代码实现
(1)寄存器宏定义
/*nandflash相关寄存器定义*/
#define NFCONF  0x70200000 
#define NFCONT  0x70200004 
#define NFCMMD  0x70200008 
#define NFADDR  0x7020000C 
#define NFDATA  0x70200010 
#define NFDATA8 (*(volatile unsigned char *)0x70200010) 
#define NFSTAT  0x70200028

int nand_erase(unsigned int block_addr);
int Nand_PageWrite(unsigned long start_addr,char *buf);

(2)nand驱动文件

/****************************
@File:nand.c
@
@Tiny6410裸机上学期代码
@nandflash变硬盘
@Author:小君君
@****************************/

#include "common.h"

#define NF_SetCommand(cmd)	{(vi NFCMMD) = (cmd);}
#define NF_SetAddr(addr)	{(vi NFADDR) = (addr);}
#define NF_SetData(data)	{NFDATA8 = (data);}

#define Chip_Select()		{(vi NFCONT) &= ~(1 << 1);} 
#define Chip_DisSelect()	{(vi NFCONT) |= (1 << 1);} 

#define NF_EnableRB()		{(vi NFSTAT) |= (1 <<2);}
#define NF_ChekBusy()		{while(!((vi NFSTAT) & (1 <<0)));}

/*复位函数*/
void nand_reset()
{
	/*1.选中nandflash*/
	Chip_Select();
	
	/*2.清除RB标志位,开启忙信号检测功能*/
	NF_EnableRB();
	
	/*3.发送0xff复位命令*/
	NF_SetCommand(0xFF);
	
	/*4.等待RnB信号,检测忙信号*/
	NF_ChekBusy();
	
	/*5.取消选中nandflash,为了省电*/
	Chip_DisSelect();	
}

/*初始化nandflash控制器*/
void nand_init()
{
	/*0.引脚功能配置*/
	
	/*1.初始化NFCONF,设置时序参数*/
	(vi NFCONF) = ( (0x2<<12)|(0xf<<8)|(0x7<<4) );
	
	/*2.初始化NFCONT,取消片选,使能nandflash控制器*/
	(vi NFCONT) = (0x3<<0);
	
	/*3.清除状态寄存器*/
	(vi NFSTAT) = 0;
	
	/*4.复位操作*/	
	nand_reset();
	
}

/*按页读取函数*/
void Nand_PageRead(unsigned long start_addr,char *buf)
{
	int i;
	int page_size = 2048;
	/*(1)选中nandflash*/
	Chip_Select();
	
	/*(2)清除RB标志*/
	NF_EnableRB();
	
	/*(3)写入0x00读数据命令*/
	NF_SetCommand(0x00);
	
	/*(4)发送列地址,两次(但是由于是页读的方式,所以列地址,即页中的偏移量就是0)*/
	NF_SetAddr(0x00);
	NF_SetAddr(0x00);
	
	/*(5)发送页编号,即行地址,分三次完成*/
	NF_SetAddr((start_addr) & 0xFF);
	NF_SetAddr((start_addr >> 8) & 0xFF);
	NF_SetAddr((start_addr >> 16) & 0xFF);
	
	/*(6)发送0x30命令*/
	NF_SetCommand(0x30);
	
	/*(7)等待RB信号变为ready*/
	NF_ChekBusy();
	
	/*(8)读出数据,每次都取出数据寄存器的值,他会自动更新自己的值*/
	for(i=0; i < page_size; i++)
	{
		*buf++ = NFDATA8;
	}
	
	/*(9)取消选中nandflash*/
	Chip_DisSelect();
	
}


/* 从NAND中拷贝代码到DRAM*/
int copy2ddr(unsigned int nand_start, unsigned long ddr_start, unsigned int len)
{
	char *buf = (char *)ddr_start;
	unsigned int i;
	unsigned int page_shift = 11;

	// 1.发片选
	Chip_Select();

	// 2.使len为2048的整数倍
	len = (len/2048+1)*2048;

	// 3.循环拷贝,每次拷贝一页数据
	for (i = nand_start; i < nand_start + (len>>page_shift); i++, buf+=(1<<page_shift))
	{
		// 读一页,即2048byte
		Nand_PageRead(i, buf);
	}

	return 0;
}


/*写入之前要擦除,参数是要擦除的页地址,擦除的是指定的页所在的块*/
int nand_erase(unsigned int block_addr)
{
	unsigned int start_addr;
	
	int ret;
	
	start_addr = block_addr << 6;
	
	/*(1)选中nandflash*/
	Chip_Select();
	
	/*(2)清除RB标志*/
	NF_EnableRB();
	
	/*(3)写入0x60命令*/
	NF_SetCommand(0x60);
	
	/*(4)发送页编号,即行地址,分三次完成*/
	NF_SetAddr((start_addr) & 0xFF);
	NF_SetAddr((start_addr >> 8) & 0xFF);
	NF_SetAddr((start_addr >> 16) & 0xFF);
	
	/*(5)发送0xD0命令*/
	NF_SetCommand(0xD0);

	/*(6)等待RB信号变为ready*/
	NF_ChekBusy();
	
	/*(7)发送命令0x70*/
	NF_SetCommand(0x70);
	
	/*(8)读取擦出结果*/
	ret = (NFDATA8);
	
	/*(9)取消选中nandflash*/
	Chip_DisSelect();
	
	/*(10)返回擦除结果*/
	return ret;
	
}

int Nand_PageWrite(unsigned long start_addr,char *buf)
{
	int i = 0,ret;
	/*(1)选中nandflash*/
	Chip_Select();
	
	/*(2)清除RB标志*/
	NF_EnableRB();
	
	/*(3)写入0x80命令*/
	NF_SetCommand(0x80);
	
	/*(4)发送列地址,两次(但是由于是页读的方式,所以列地址,即页中的偏移量就是0)*/
	NF_SetAddr(0x00);
	NF_SetAddr(0x00);
	
	/*(5)发送页编号,即行地址,分三次完成*/
	NF_SetAddr((start_addr) & 0xFF);
	NF_SetAddr((start_addr >> 8) & 0xFF);
	NF_SetAddr((start_addr >> 16) & 0xFF);
	
	/*(6)写入数据,用循环*/
	for(i = 0; i < 2048;i++)
		NF_SetData(*buf++);
	
	/*(7)发送0x10命令*/
	NF_SetCommand(0x10);
	
	/*(8)等待RB信号变为ready*/
	NF_ChekBusy();
	
	/*(9)发送命令0x70,*/
	NF_SetCommand(0x70);
	
	/*(10)读取写入结果,从数据寄存器读*/
	ret = (NFDATA8);
	
	/*(11)取消选中nandflash*/
	Chip_DisSelect();
	
	/*(12)返回写入结果*/
	return ret;

}

12.相关时序图以及关键表格




13.测试文件

/****************************
@File:main.c
@
@Tiny6410裸机上学期代码
@Nandflash测试文件
@Author:小君君
@****************************/

#include "common.h"

int main(void)
{
	unsigned int i = 500000;
	char buf[2048];
	//mmu_init();//MMU初始化,这里不使用MMU
	
	led_init();//LED的GPIO初始化
	
	button_init();//按键初始化
	
	irq_init();//中断初始化
	
	led_on();//点亮4颗LED
	
	
	while(i--);
	
	buf[1] = 100;
	
	nand_erase(5);//擦除第五块
	
	Nand_PageWrite(64*5+1,buf);//每一块有64页,这里我们给的是页地址,所以要乘64,+1与否都是可以的。+1以后是第五块的第二页,否则是第五块的第一页
	
	buf[1] = 10;
	
	Nand_PageRead(64*5+1,buf);//验证读取出来的数据是不是之前写进去的100,是的话就闪烁LED
	
	if(100 == buf[1]){
		for(i = 0; i < 1000;i++){
			led_off();
			i = 500000;	
			while(i--);
			
			
			led_on();
			i = 500000;
			while(i--);
			
		}
	}
	
	while(1)
	;
	return 0;	
}

14.在start.s调用代码搬移子函数

@将bin文件从_start开始到bss_start结束的数据搬移到_start指定的链接地址(0x50008000)
copy_to_ddr:
	mov	r0,	#0x00
	ldr	r1,	=_start
	ldr	r2,	=bss_start
	sub 	r2,r2,r1
	
	mov	ip,lr
	bl	copy2ddr
	mov	lr,ip
	mov	pc,lr
	


你可能感兴趣的:(三十五.Nandflash的操作)