一、NAND Flash介绍和NAND Flash控制器的使用
NAND Flash在嵌入式系统中的作用,相当于PC上的硬盘
常见的Flash有NOR Flash和NAND Flash,NOR Flash上进行读取的效率非常高,但是擦除和写操作的效率很低,容量一般比较小;NAND Flash进行擦除和写操作的效率更高,并且容量更大。一般NOR Flash用于存储程序,NAND Flash用于存储数据。
1)NAND Flash的物理结构
笔者用的开发板上NAND Flash型号是K9F1G08,大小为128M,下图为它的封装和外部引脚
I/O0-I/O7
CLE
ALE
CE
RE
WE
WP
R/B
Vcc
Vss
N.C
K9F1G08功能结构图如下
K9F1G08内部结构有下面一些功能部件
①X-Buffers Latches & Decoders:用于行地址
②X-Buffers Latches & Decoders:用于列地址
③Command Register:用于命令字
④Control Logic & High Voltage Generator:控制逻辑及产生Flash所需高压
⑤Nand Flash Array:存储部件
⑥Data Register & S/A:数据寄存器,读、写页时,数据存放此寄存器
⑦Y-Gating
⑧I/O Buffers & Latches
⑨Global Buffers
⑩Output Driver
NAND Flash 存储单元组织结构图如下:
K9F1G08容量为1056Mbit,分为65536行(页)、2112列,每一页大小为2kb,外加64字节的额外空间,这64字节的额外空间的列地址为2048-2111
命令、地址、数据都通过IO0-IO7输入/输出,写入命令、地址或数据时,需要将WE、CE信号同时拉低,数据在WE信号的上升沿被NAND FLash锁存;命令锁存信号CLE、地址锁存信号ALE用来分辨、锁存命令或地址。
K9F1G08有128MB的存储空间,需要27位地址,以字节为单位访问Flash时,需要4个地址序列
2)NAND Flash访问方法
NAND Flash硬件连接如下图:
NAND Flash和S3C2440的连线包括,8个IO引脚,5个使能信号(nWE、ALE、CLE、nCE、nRE)、1个状态引脚(R/B)、1个写保护引脚(nWP)。地址、数据和命令都是在这些使能信号的配合下,通过8个IO引脚传输。写地址、数据、命令时,nCE、nWE信号必须为低电平,它们在nWE信号的上升沿被锁存。命令锁存使能信号CLE和地址锁存使能信号ALE用来区别IO引脚上传输的是命令还是地址。
命令字及操作方法
下图为K9F1G08的命令字
下图为K9F1G08的地址序列
K9F1G08有2112列,所以必须使用A0-A11共12位来寻址,有65535行,所以必须使用A12-A27共16位来寻址。
3)S3C2440 NAND Flash控制器介绍
NAND Flash的读写操作次序如下:
①设置NFCONF配置NAND Flash
②向NFCMD寄存器写入命令
③向NFADDR寄存器写入地址
④读写数据:通过寄存器NFSTAT检测NAND Flash的状态,在启动某个操作后,应该检测R/nB信号以确定该操作是否完成、是否成功。
下面介绍这些寄存器:
①NFCONF:配置寄存器
②NFCONT:控制寄存器
③NFCMD:命令寄存器
④NFADDR:地址寄存器
⑤NFDATA:数据寄存器
⑥NFSTAT:状态寄存器
二、NAND Flash控制器操作实例:读Flash
1)读NAND Flash的步骤
①设置NFCONF
②操作NAND Flash前,复位
③发出读命令
④发出地址信号
⑤循环查询NFSTAT,直到等于1
⑥连续读NFDATA寄存器,得到一页数据
⑦最后禁止NAND Flash片选信号
本实例的目的是把一部分代码存放在NAND Flash地址4096之后,当程序启动后通过NAND Flash控制器读出代码,执行。
连接脚本 nand.lds
SECTIONS {
}
head.o init.o nand.o三个文件运行地址为0,生成的镜像文件偏移地址也为0
main.0的运行地址为0x30000000,生成的镜像文件偏移地址为4096
@******************************************************************************
@ File:head.s
@ 功能:设置SDRAM,将程序复制到SDRAM,然后跳到SDRAM继续执行
@******************************************************************************
.text
.global _start
_start:
halt_loop:
init.c 用于初始化操作
#define
#define
void disable_watch_dog();
void memsetup();
void disable_watch_dog()
{
}
void memsetup()
{
}
nand.c 用于操作nand flash
#define BUSY
#define NAND_SECTOR_SIZE_LP
#define NAND_BLOCK_MASK_LP
typedef unsigned int S3C24X0_REG32;
typedef struct {
} S3C2440_NAND;
typedef struct {
}t_nand_chip;
static S3C2440_NAND * s3c2440nand = (S3C2440_NAND *)0x4e000000;
static t_nand_chip nand_chip;
void nand_init(void);
void nand_read(unsigned char *buf, unsigned long start_addr, int size);
static void nand_reset(void);
static void wait_idle(void);
static void nand_select_chip(void);
static void nand_deselect_chip(void);
static void write_cmd(int cmd);
static void write_addr(unsigned int addr);
static unsigned char read_data(void);
static void s3c2440_nand_reset(void);
static void s3c2440_wait_idle(void);
static void s3c2440_nand_select_chip(void);
static void s3c2440_nand_deselect_chip(void);
static void s3c2440_write_cmd(int cmd);
static void s3c2440_write_addr(unsigned int addr);
static unsigned char s3c2440_read_data(void);
static void s3c2440_nand_reset(void)
{
}
static void s3c2440_wait_idle(void)
{
static void s3c2440_nand_select_chip(void)
{
}
static void s3c2440_nand_deselect_chip(void)
{
}
static void s3c2440_write_cmd(int cmd)
{
}
static void s3c2440_write_addr_lp(unsigned int addr)
{
}
static unsigned char s3c2440_read_data(void)
{
}
static void nand_reset(void)
{
}
static void wait_idle(void)
{
}
static void nand_select_chip(void)
{
}
static void nand_deselect_chip(void)
{
}
static void write_cmd(int cmd)
{
}
static void write_addr(unsigned int addr)
{
}
static unsigned char read_data(void)
{
}
void nand_init(void)
{
#define TACLS
#define TWRPH0
#define TWRPH1
}
void nand_read(unsigned char *buf, unsigned long start_addr, int size)
{
}
main.c 很简单,点灯
#define
#define
#define
#define
#define
#define
void
{
}
int main(void)
{
}
最后是Makefile
objs := head.o init.o nand.o main.o
nand.bin : $(objs)
%.o:%.c
%.o:%.S
clean: