对技术执着
分类: 嵌入式
2015-03-14 14:04:51
原文地址:ARM学习笔记--NAND Flash控制器 作者:mutes
摘自:《嵌入式Linux应用开发完全手册》——韦东山
一、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,下图为它的封装和外部引脚
* NandFlash接口信号较少
* 数据宽度只有8Bit,没有地址总线。地址和数据总线复用,串行读取
信号名称 |
信号描述 |
IO[7..0] |
数据总线 |
CE# |
片选信号(Chip Select),低电平有效 |
WE# |
写有效(Write Enable),低电平表示当前总线操作是写操作 |
RE# |
读有效(Read Enable),低电平表示当前总线操作是读操作 |
CLE |
命令锁存(Command Latch Enable)信号,写操作时给出此信号表示写命令 |
ALE |
地址/数据锁存(Address Latch Enable)信号,写操作时给出此信号表示写地址或数据 |
WP# |
写保护(Write Protect)信号 |
R/B |
忙(Read/Busy)信号 |
2)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
3)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个地址序列
NandFlash地址结构
* NandFlash设备的存储容量是以页(Page)和块(Block)为单位的。
* Page=528Byte (512Byte用于存放数据,其余16Byte用于存放其他信息,如块好坏的标记、块的逻辑地址、页内数据的ECC校验和等)。
* Block=32Page
* 容量为64MB的NandFlash存储结构为:512Byte×32Page×4096Block
* NandFlash以页为单位进行读和编程(写)操作,一页为512Byte;以块为单位进行擦除操作,一块为512Byte*32page=16KB
* 对于64MB的NAND设备,需要26根地址线,由于NAND设备数据总线宽度是8位的,因此必须经过4个时钟周期才能把全部地址信息接收下来
|
I/O7 |
I/O6 |
I/O5 |
I/O4 |
I/O3 |
I/O2 |
I/O1 |
I/O0 |
第一个周期 |
A7 |
A6 |
A5 |
A4 |
A3 |
A2 |
A1 |
A0 |
第二个周期 |
A15 |
A14 |
A13 |
A12 |
A11 |
A10 |
A9 |
A8 |
第三个周期 |
A23 |
A22 |
A21 |
A20 |
A19 |
A18 |
A17 |
A16 |
第四个周期 |
|
|
|
|
|
|
A25 |
A24 |
* 可以这么说,第一个时钟周期给出的是目标地址在一个page内的偏移量,而后三个时钟周期给出的是页地址。
* 由于一个页内有512Byte,需要9bit的地址寻址,而第一个时钟周期只给出了低8bit,最高位A8由不同的读命令(Read Mode2)来区分的。
4). NandFlash的命令
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引脚上传输的是命令还是地址。
命令字及操作方法
操作NAND Flash时,先传输命令,然后传输地址,最后读写数据,这个期间要检查Flash的状态。K9F1G08容量为128MB,需要一个27位的地址,发出命令后,后面要紧跟着4个地址序列。
下图为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:配置寄存器
用来设置NAND Flash的时序参数,设置数据位宽,设置是否支持其他大小的页等。
②NFCONT:控制寄存器
用来使能NAND Flash控制器、使能控制引脚信号nFCE、初始化ECC,锁定NAND Flash等功能
③NFCMD:命令寄存器
用来发送Flash操作命令
④NFADDR:地址寄存器
用来向Flash发送地址信号
⑤NFDATA:数据寄存器
读写此寄存器启动对NAND Flash的读写数据操作
⑥NFSTAT:状态寄存器
0:busy,1:ready
二、NAND Flash控制器操作实例:读Flash
1)读NAND Flash的步骤
①设置NFCONF
在HCLK=100Mhz的情况下,TACLS=0,TWRPH0=3,TWRPH1=0,则
NFCONF = 0x300
使能NAND Flash控制器、禁止控制引脚信号nFCE,初始化ECC
NFCONT = (1<<4) | (1<<1) | (1<<0)
②操作NAND Flash前,复位
NFCONT &= ~(1<<1) 发出片选信号
NFCMD = 0xff reset命令
然后循环查询NFSTAT位0,直到等于1,处于就绪态
最后禁止片选信号,在实际使用时再使能
NFCONT |= 0x2 禁止NAND Flash
③发出读命令
NFCONT &= ~(1<<1) 发出片选信号
NFCMD = 0 读命令
④发出地址信号
⑤循环查询NFSTAT,直到等于1
⑥连续读NFDATA寄存器,得到一页数据
⑦最后禁止NAND Flash片选信号
NFCONT |= (1<<1)
2)代码详解
本实例的目的是把一部分代码存放在NAND Flash地址4096之后,当程序启动后通过NAND Flash控制器读出代码,执行。
连接脚本 nand.lds
SECTIONS {
firtst 0x00000000 : { head.o init.o nand.o}
second 0x30000000 : AT(4096) { main.o }
}
head.o init.o nand.o三个文件运行地址为0,生成的镜像文件偏移地址也为0
main.0的运行地址为0x30000000,生成的镜像文件偏移地址为4096
@******************************************************************************
@ File:head.s
@ 功能:设置SDRAM,将程序复制到SDRAM,然后跳到SDRAM继续执行
@******************************************************************************
.text
.global _start
_start:
@函数disable_watch_dog, memsetup, init_nand, nand_read_ll在init.c中定义
ldr sp, =4096 @设置堆栈
bl disable_watch_dog @关WATCH DOG
bl memsetup @初始化SDRAM
bl nand_init @初始化NAND Flash
@将NAND Flash中地址4096开始的1024字节代码(main.c编译得到)复制到SDRAM中
@nand_read_ll函数需要3个参数:
ldr r0, =0x30000000 @1. 目标地址=0x30000000,这是SDRAM的起始地址
mov r1, #4096 @2. 源地址 = 4096,连接的时候,main.c中的代码都存在NAND Flash地址4096开始处
mov r2, #2048 @3. 复制长度= 2048(bytes),对于本实验的main.c,这是足够了
bl nand_read @调用C函数nand_read
ldr sp, =0x34000000 @设置栈
ldr lr, =halt_loop @设置返回地址
ldr pc, =main @b指令和bl指令只能前后跳转32M的范围,所以这里使用向pc赋值的方法进行跳转
halt_loop:
b halt_loop