NAND Flash读写擦除操作实现
概要:
本节主要记录开发Tiny6410自带的NAND FLASH的过程,实现了NAND FLASH的擦除,读写数据功能,但都只是简单的实现而已,并没有做精细而完整的实现,毕竟只是想学原理。
前言:
工欲善其事,必先利其器。在做开发之前,必须保证良好的环境和设备,笔者所使用的tiny6410光盘中自带的uboot版本比较老,而且其并不支持MLC2的读写操作,但是之前并不知道,写了很多次,但是总是写不到NAND FLASH中去,还以为是NAND FLASH设备的坏块太多,各种原因各种奇葩猜想,还好,最后时刻想起了友善之臂的官网,无意间看到了uboot的某一版的发行注释中写着实现了MLC2的读写,啊。。。。。有点怒了。。。。竟然是使用的uboot的问题,立即马上下载,然后烧录进去,重写NAND FLASH,写入成功!!!
为了方便,现将新版的uboot和System.map文件共享出来,版权属于友善之臂公司。
uboot-ram256M nand-flash版 与 System.map文件
具体下载目录在 /2014年资料/2月/18日/嵌入式bootloader开发Tiny6410
----- ----- ---------- ----- ----- 分割线 ----- ----- ---------- -----
详细的有关NAND FLASH设备的介绍以及一些常识请自行百度或者直接查阅S3C6410数据手册和相应的NAND FLASH数据手册,本文中以Tiny6410中使用的三星公司产的MLC的NAND FLASH芯片K9GAG08U0E(2GB MLC)为例。
具体NAND FLASH的接口电路如下:
LDATA0~LDATA7是I/O口,传输数据、命令或者地址
FWEn:NAND FLASH写数据信号,低有效
FREn:NAND FLASH读数据信号,低有效
FCLE:命令锁存信号
FALE:地址锁存信号
RnB:忙或准备好状态标志位
S3C6410本身集成有NAND FLASH控制器,若要使用只需进行相应的配置即可。
相关的寄存器如下:
//nand flash K9GAG08U0E
#define Base 0x70200000
#define NFCONF (*(volatile unsigned long *)(Base + 0x00))
#define NFCONT (*(volatile unsigned long *)(Base + 0x04 ))
#define NFCMMD (*(volatile unsigned char *)(Base + 0x08 ))
#define NFADDR (*(volatile unsigned char *)(Base + 0x0c))
#define NFDATA (*(volatile unsigned char *)(Base + 0x10))<PRE class=cpp>#define NFSTAT (*(volatile unsigned long *)(Base + 0x28))</PRE>
NAND FLASH controller的初始化主要有:
1.初始化NFCONF,配置TACLS 、TWRPH0、TWRPH1 等。
2.初始化NFCONT,使能NAND FLASH控制器
具体代码如下:
void nand_init(){
reset();//无关紧要,要不要都可以
NFCONF &=~((0x7<<4)|(0x7<<8)|(0x7<<12)|(1<<30));
NFCONF |=((TACLS<<12)|(TWRPH0<<8)|(TWRPH1<<4));
NFCONT |= 1 ;// enable controller
}
读操作的流程如下:
1.片选有效
2.发送命令0x00H
3.发送地址信号
4.发送命令0x30h
5.检测ready/busy状态标志位,若不忙,读取指定字节的数据
6.拉高片选信号,使无效
具体代码实现如下:
void nand_read(unsigned long addr,char *buf,int len)
{
NFCONT &= ~(1<<1);//片选有效
NFCMMD = 0x00; //read 1 circle
get_addr(addr);
NFCMMD = 0x30;//read 2 circle
volatile int i;
while(!(NFSTAT & 1)) //wait until ready
;
for(i=0;i<PAGE_SIZE;++i)//read a page
buf[i]=NFDATA;
NFCONF |= (1<<1);//拉高
}
写操作的流程如下:
1.片选有效
2.发送命令0x80
3.发送地址信号
4.发送命令0x10
5.检测ready/busy状态标志位,若不忙,读取指定字节的数据
6.拉高片选信号,使无效
具体代码实现如下:
void nand_write(unsigned long addr,char *buf,int len)
{
volatile int i;
NFCONT &= ~(1<<1);//片选有效
NFCMMD = 0x80; //write 1 circle
get_addr(addr);
for(i=0;i<len;++i)//write a page
NFDATA=buf[i];
for(i=len;i<PAGE_SIZE;++i)
NFDATA = 0xff;
NFCMMD = 0x10;//write 2 circle
while(!(NFSTAT & 1)) //wait until ready
;
show("nand write ok!\n");
NFCONF |= (1<<1);//拉高
}
擦除操作的流程如下:
1.片选有效
2.发送命令0x60
3.发送地址信号(注意这里的地址是页号)
4.发送命令0xd0
5.检测ready/busy状态标志位,若不忙,读取指定字节的数据
6.拉高片选信号,使无效
void nand_erase(unsigned long addr)
{
volatile int i,row;
NFCONT &= ~(1<<1);//片选有效
NFCMMD = 0x60; //write 1 circle
row = addr / PAGE_SIZE;
NFADDR = row &0xff;
NFADDR =(row>>8) &0xff;
NFADDR = (row>>16) & 0xff;
NFCMMD = 0xd0;//write 2 circle
while(!(NFSTAT & 1)) //wait until ready
;
show("nand erase ok!\n");
NFCONF |= (1<<1);//拉高
}