? | Nor | Nand |
---|---|---|
接口 | 引脚多,类似于RAM | 引脚较少 |
容量 | 小(1-32MB) | 大(128-512MB) |
读操作 | 简单,和RAM相同 | 简单,和RAM相同 |
写操作 | 发出特定命令才能写入 | 发出特定命令才能写入 |
价格 | 贵 | 便宜 |
比较 | 无坏块 | 有坏块 |
XIP | 可以 | 不可以 |
应用场合 | 存储关键性代码(比如uboot,kernel) | 存储海量数据(允许错误) |
JZ2440开发板上板载了一个Nand Flash,型号为K9F2G08U0C
,大小为256MB,连接在S3C2440的nand控制器上,原理图如下:
3.1. 控制信号
Nand Flash相较于Nor Flash,引脚比较少,它是如何做到的呢?
Nand Flash将地址数据,读写数据,命令数据全部放在了8条数据线上(上图中的LDATA0-7),然后使用控制信号CLE、ALE、WE、RE来区分数据线上的数据,具体如下:
数据线上的数据含义 | ALE(地址/数据) | CLE(命令/数据) | WE(写使能) | RE(读使能) |
---|---|---|---|---|
地址 | 高 | ? | ? | ? |
命令数据 | 低 | 高 | ? | ? |
写入数据 | 低 | 低 | 低 | ? |
读出数据 | 低 | 低 | ? | 低 |
除此之外,还有三个控制引脚,它们的意义如下:
- CE:片选引脚(LDATA0-7总线复用,用片选信号防止互相干扰)
- WP:写保护引脚
- R/B:Flash当前状态引脚(高 -> 空闲或者就绪,低 -> 忙)
3.2. 操作命令
Nand Flash的本质还是Flash,所以操作流程和Nor Flash基本相同,都是:发命令 -> 发地址 - >发数据的流程。
这款Nand Flash的命令列表如下:
3.3. Nand Flash控制器
S3C2440内部有一个Nand Flash控制器,与板载Nand Flash相连,专门负责接收发出Nand Flash的控制信号脉冲,其结构如下:
Nand Flash大大简化了我们的编程工作,在操作之前首先按照这款Nand Flash的性能配置Nand Flash控制器的时序参数,然后只要操作Nand Flash控制器即可。
本文中利用uboot已经配置好Nand Flash控制器中的时序参数这一条件,直接借助uboot读写内存的能力来操作Nand Flash控制器的寄存器,来测试Nand Flash的读写。
因为数据线是共用的,uboot启动之后不会一直将Nand Flash使能,首先需要设置NFCONT
寄存器,将片选信号使能:
要发送给Nand Flash的命令需要写入到Nand 控制器的 NFCMMD
寄存器中:
要发送给Nand Flash的地址需要写入到Nand 控制器的 NFADDR
寄存器中:
要发送给Nand Flash的数据需要写入到Nand 控制器的 NFDATA
寄存器中,从 Nand Flash 中读取出的数据也保存在 NFDATA
寄存器中:
实验前提:烧录uboot.bin到Nor Flash,并且板子设置为Nor Flash启动方式。
知识准备:uboot | uboot内存操作指令mw和md详解。
4.1. 读取ID值(ManufacturerID和DeviceID)
查看Nand FLash芯片数据手册,可知读ID的时序如下:
图中表示的读取ID流程如下:
- ① 写命令90h
- ② 写地址00h
- ③ 读数据得到manufacturer code为ECH
- ④ 读数据得到device code为DAh、10h、15h、44h
设置 Nand Flash 寄存器 NFCONT,首先使能Nand Flash片选信号:
md.l 0x4E000004 1 //先将NFCONT中的值读出来
mw.l 0x4E000004 1 //写入0x01,bit2设置为0,开启片选信号
md.l 0x4E000004 1 //再次读出,检查是否设置成功
发出读ID的一系列流程:
mw.b 0x4E000008 0x90 //写命令90h
mw.b 0x4E00000C 0x00 //写地址00h
md.b 0x4E000010 1 //读取数据
复位,退出该模式:
mw.b 0x4E000008 0xff //写入命令ff
这5个ID每个都有含义,如下:
读出的第三个ID是0x10,对应信息如下:
读出的第四个ID是0x95,其含义如下:
读出的第五个ID是0x44,其含义如下:
4.2. 读某个地址处的数据
查看芯片手册,时序图如图:
图中表示的读取某个地址处数据的流程如下:
- ① 写命令00h
- ② 写Col地址1
- ③ 写Col地址2
- ④ 写Row地址1
- ⑤ 写Row地址2
- ⑥ 写Row地址3
- ⑦ 写命令30h
- ⑧ 读数据
因为Nand Flash的容量有256MB,但是数据线只有8条,所以地址要分为5次来发送,如图:
(暂定)
首先使用uboot命令将0地址处的数据读出,方便后续检验读取的是否正确:
设置 Nand Flash 寄存器 NFCONT,首先使能Nand Flash片选信号:
md.l 0x4E000004 1 //先将NFCONT中的值读出来
mw.l 0x4E000004 1 //写入0x01,bit2设置为0,开启片选信号
md.l 0x4E000004 1 //再次读出,检查是否设置成功
发出读0地址处数据的一系列流程:
mw.b 0x4E000008 0x00 //写命令00h
mw.b 0x4E00000C 0x00 //写地址00h
mw.b 0x4E00000C 0x00
mw.b 0x4E00000C 0x00
mw.b 0x4E00000C 0x00
mw.b 0x4E00000C 0x00
mw.b 0x4E000008 0x30 //写命令00h
md.b 0x4E000010 1 //读取数据
复位,退出该模式:
mw.b 0x4E000008 0xff //写入命令ff
5. Nand Flash操作代码
上述uboot的操作中,发命令、发地址、发数据、读数据只需要访问Nand Flash控制器的三个寄存器即可,非常简单,在程序中操作nand flash也是访问这三个寄存器即可。
但是在uboot中,nand flash控制器已经被初始化好了,所以在自己编写程序时,需要根据nand flsh的时序参数来初始化nand flash控制器。
5.1. 时序参数初始化
在S3C2440的芯片手册中,首先是CLE(命令/数据)控制信号和ALE控制信号(地址/数据)的时序,如图:
再查找nand flash芯片手册中相对应的时序参数:
所以,从CLE信号发出之后,经过tCLS - tWP
时间之后,才能发出WE信号,在芯片手册中查找具体的值:
从时序的具体值中得出,tCLS - tWP = 0
,也就是Nand Flash控制器的TACLS参数可以设置为0,设置对应的寄存器,该值可以设置为0:
同样的方法,nand flash控制器中的参数TWRPH0对应着nand flash中的tWP参数(min = 12ns),HCLK=100Mhz,周期为10ns,则TWRPH0的寄存器要设置为1(20ns):
同样的方法,nand flash控制器中的参数TWRPH1对应着nand flash中的tCLH参数(min = 5ns),HCLK=100Mhz,周期为10ns,则TWRPH1的寄存器要设置为0(10ns):
5.2. nand flash控制器使能
在nand flash 控制器的控制寄存器中:
nand flash控制器使能设置如下(其中片选信号在操作时再打开):
5.3. 编写nand flash控制器初始化代码
//nand flash控制器初始化
void nand_init(void)
{
//时序参数初始化
NFCONF = (0<<12)|(1<<8)|(0<<4);
//nand flash控制器使能
//禁止片选,片选信号在操作时再打开
//初始化ECC
NFCONT = (1<<4)|(1<<1)|(1<<0);
}
?