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。