1: flash 的介绍
常用的flash有nor flash和nand flash两种。主要区别:由于norflash的接口与ram完全相同,所以程序可以直接在norflash上运行,无需把程序拷贝到内存中运行,nand flash 要把程序拷贝到内存中运行。norflash的读操作效率非常高,但是擦擦和写的效率非常的低。另外norflash的存储空间一般很小。nandflash的擦除和写的效率非常高。一般而言,norflash 用于程序存储,nandflash用于数据存储。 对于flash 存储器件要考虑3点。1:位反转,2:坏块, 3: 可擦除次数。
2:nandflash的物理结构
flash 引脚
I/O0~I/O7 数据输入和数据输出。从地址和数据都用IO口来传递。
CLE :命令锁使能,高电平有效,当CLE为高电平时,IO口传输的是命令 ALE : 地址使能, 高电平有效,当ALE为高电平时, IO口传输的是地址 当CLE和ALE都为低电平时候传输的是DATA CE : 当CE为低电平时,片选使能 RE:读使能,低电平有效 wE: 写使能,低电平有效 WP: 写保护,低电平有效 R/B# :就绪/输出忙信号 VCC: 电源 VSS: 接地
NC: 不接
nand flash 存储单元结构图:
1:如图所示一页中main区的容量512B,16表示spare区容量(用于读写数据操作的时候存放校验码)
2:每个块里包含很多页,老的flash页的大小是256M, 512M,这类称作small block, 地址周期只有4个。常见的nand flash页的大小正常是2K,这成为big block, 地址周期有5个。这个芯片每页512M属于小页
3:芯片写操作是以页为单位的,擦除是以块为单位的。nand flash 擦除就是把数据全变为1
4:由于nandflash 无法像norflash直接运行程序,所以一般用nandflash作为存储芯片的时候一般会在内部集成4K的ram.在启动的时候硬件会自动从nandflash 拷贝4K的空间到ram上,然后在ram上从0地址开始运行,再把NANDFLASH的程序拷贝到内存中去运行。
nand flash和2410或者2440的连接图如下:
具体引脚的含义上面已经描述过在此就不在赘述。
nand flash控制器介绍:
CPU访问nand flash时候,需要先发出命令,然后再发出地址,最后才是数据的读写。这一系列的过程需要各个使能信号来分辨是命令还是地址还是数据.nand flash提供了NFCONF, NFCMD,NFADDR,NFDATA,NFSTAT,NFECC等6个寄存器。
代码分析:
由图中可以知道TACLS = TCLS - TWP = 15 - 15 = 0
根据寄存器中描述的计算公式:Duration = HCLK x TACLS => 0ns = 10ns x TACLS => TACLS = 0
TWRPH0 的时间是 twp ,查 时间表 得到 15ns 根据寄存器中描述的计算公式: Duration = HCLK x ( TWRPH0 + 1 ) => 15ns = 10ns x (TWRPH0 + 1) => TWRPH0 = 0.5 ,由于他的取值范围是 (0~7) ,并且,时间表中的时间是最小能识别的时间,那我们取TWRPH0 = 1
TWRPH1 的时间是 tclh = 5ns 根据寄存器中描述的计算公式: Duration = HCLK x ( TWRPH1 + 1 ) => 5ns = 10ns x (TWRPH1 + 1) => TWRPH1 = 0 即能满足 nand flash的初始化:
void nand_init(void)
{
#define TACLS 0
#define TWRPH0 3
#define TWRPH1 0
NFCONF = (TACLS<<12)|(TWRPH0<<8)|(TWRPH1<<4); //设置时序
NFCONT = (1<<4)|(1<<1)|(1<<0); //使能nand flash控制器,初始化ECC,禁止片选
}
void nand_select_chip(void)
{
int i;
NFCONT &= ~(1<<1); //片选使能
for(i=0; i<10; i++);
}
void write_cmd(int cmd)
{
unsigned long *p = (unsigned long *)NFCMD;
*p = cmd; //写命令
}
void wait_idle(void)
{
int i;
volatile unsigned char *p = (volatile unsigned char *)NFSTAT;
while(!(*p & BUSY))
for(i=0; i<10; i++);
}
nand_deselect_chip(void)
{
NFCONT |= (1<<1);
}
//读取数据
unsigned char read_data(void)
{
volatile unsigned char *p = (volatile unsigned char *)NFDATA;
return *p;
}
void write_addr(unsigned int addr)
{
int i;
volatile unsigned char *p = (volatile unsigned char *)NFADDR;
*p = addr & 0xff;
for(i=0; i<10; i++);
*p = (addr >> 9) & 0xff;
for(i=0; i<10; i++);
*p = (addr >> 17) & 0xff;
for(i=0; i<10; i++);
*p = (addr >> 25) & 0xff;
for(i=0; i<10; i++);
}