一、Nandflash原理介绍
-
Nandflash的内部结构
(1)Nandflash由2048Block组成,每个Block包含64个Page,每个Page大小为2KB+64B;
(2)Page是由2KB的存储区域+64Byte的oob区域组成,oob区的作用是存储ECC校验码,不存储数据,CPU会自动忽略掉oob区的存在。
(3)ECC校验是升级版的奇偶校验,8bit数据需要5bitECC校验码,此后数据位每增加1倍,ECC校验码就增加1位; -
Nandflash的电路图
(1)LDATA0 ~ LDATA7:8位数据总线,一次性可以传输1Byte数据,Nandflash不含地址总线,所以8条线可以CLE和ALE的不同来传输命令、地址、数据;
(2)CLE、ALE:CLE拉高——传输命令;ALE拉高——传输地址;CLE、ALE同时拉低——传输数据
(3)RnB、nFCE、nFWE、nFRE:状态信号、片选引脚、读信号、写信号是由Nandflash控制器来控制的,当CPU发出地址/读/写信号后,Nandflash会自动控制这些引脚拉底或升高。
(4)nandflash是8bit设备,I/O0直接与LDATA0相连无需错开。 -
操作原理
(1)Nandflash是有8根总线,因此一次可以传输8bit数据,但Nandflash容量为128M,因此当CPU发出地址后,Nandflash需要将地址拆分后多次传给Nandflash;
(2)Nandflash同Norflash一样都是外接设备,但Norflash可以向内存一样读,所以可以通过指针间接获取数据,而Nandflash无法向内存一样读写,因此CPU对Nandflash的操作都需要参考Nandflash的芯片手册向Nandflash发出命令;
(3)由于Nandflash是8bit设备,I/O0直接与LDATA0相连,因此可以直接向Nandflash发送地址而无需左移;
二、实验编程
- 命令函数
(1)于操作Nandflash是外设,因此对Nandflash的操作需要参考芯片手册
int nand_cmd(char cmd) //命令函数
{
NFCMMD = cmd;
}
int nand_addr(int addr) //地址函数
{
NFADDR = addr;
}
char nand_data() //数据函数
{
return NFDATA;
}
(2)由于Norflash是外部设备,因此在擦除和写命令发出后,CPU需要等待Norflash工作完成,才能进行下一步操作。
while(!(NFSTAT & 1)); //操作等待
2、初始化Nandflash控制器
包括:设置时序、使能Nandcon、禁止片选、使能ECC
NFCONF = (0<<12) | (1<<8) | (0<<4); //设置时序
NFCONT = (1<<4) | (1<<1) | (1<<0); //初始化NFCONT
- 扫描ID
nand_select(); //片选信号
nand_cmd(0x90); //发出命令
nand_addr(0x00); //发出地址
//获取数据
str[0] = nand_data();
str[1] = nand_data();
str[2] = nand_data();
str[3] = nand_data();
str[4] = nand_data();
- 读取数据
由于Nandflash的读和写一次只能操作1Page的数据,因此需要考虑要读取的数据长度是否大于1Page,如果大于1Page就需要换Page;
//获取地址
int addr = get_uint();
int col = addr & 2047;
int row = addr / 2048;
//片选信号
nand_select();
//发出命令、地址
nand_cmd(0x00);
nand_addr(col & 0xff);
nand_addr((col>>8) & 0xff);
nand_addr(row & 0xff);
nand_addr((row>>8) & 0xff);
nand_addr((row>>16) & 0xff);
nand_cmd(0x30);
//等待操作
nand_wait();
//得到数据
while((i < len) && (col < 2048))
{
data[i++] = nand_data();
col ++;
}
if(i == len)
{
break;
}
row++;
col = 0;
}
//取消片选
nand_deselect();
- 写数据
写数据同样需要考虑操作的范围问题,如若大于1Page就需要Page+1。
//发出命令、地址
nand_cmd(0x80);
nand_addr(col & 0xff);
nand_addr((col>>8) & 0xff);
nand_addr(row & 0xff);
nand_addr((row>>8) & 0xff);
nand_addr((row>>16) & 0xff);
//发送数据
while((i < len) && (col < 2048))
{
NFDATA = data[i];
i++;
col++;
}
//发送命令
nand_cmd(0x10);
- 擦除命令
Nandflash一次即便只想擦除1Byte数据,也必须擦除1个blocks(2048642)
//发出命令、地址
nand_cmd(0x60);
nand_addr(row & 0xff);
nand_addr((row>>8) & 0xff);
nand_addr((row>>16) & 0xff);
nand_cmd(0xD0);
//等待操作
nand_wait();