NAND Flash结构及驱动函数
目标:以NAND Flash K9F2G08U0M为例介绍其结构及其驱动程序的书写
1. 结构
由芯片手册中的图可知:K9F2G08U0M大小为2112Mbits(即 256MB = 2Gb ) 共有2048Block=128K页
这里:
1个device=2048Block
1块Block=64Pages
1页Page=(2K+64)B (每个地址里都存放了一个字节,用B表示)
其中,由于Nandflash自身的位反转问题,64B用于存放OOB地址,用作ECC校验;
(注意:每个芯片的块、页的大小可能不同,要根据具体的芯片手册决定)
2. NAND Flash与S3C2440的硬件连接
连接引脚分析:
RnB: 就绪(ready)/忙(busy)输出信号,需要采用上拉电阻;(1:表示写入数据成功 0:表示正在写入)
CLE: 命令(command)锁存(latch)使能; (1: 表示当前传的是命令值 )
ALE: 地址锁存使能; ( 1:表示当前传的是地址值, 当CLE=0和ALE=0,表示传的是数据)
nCE: 芯片使能(低电平使能) (n:表示低电平有效)
nWE: 写使能 ,比如写命令时,当CLE=1,ALE=0时,当nWE来个上升沿,则会将IO数据写入flash中;
nRE: 读使能,和nWE类似;
引脚操作:
1). 从NAND FLASH芯片手册可知,要操作NAND FLASH需要先发出命令怎么传入命令?
在DATA0~DATA7上既传输数据,又传输地址,也传输命令:
a. 当ALE=1为高电平时传输的是地址。
b. 当ALE=0和CLE=0都为低电平时传输的是数据。
c. 当CLE=1为高电平时传输的是命令。
2). 2440的数据线既接到NAND FLASH,也接到NOR FLASH,还接到SDRAM、DM9000等,怎样选中,避免干扰?
这些设备,要访问之必须"选中",没有选中的芯片不会工作,相当于没接一样。
3). 假设烧写NAND FLASH,把命令、地址、数据发给它之后,NAND FLASH肯定不可能瞬间完成烧写的,怎么判断烧写完成?
通过状态引脚RnB来判断:它为高电平表示就绪,它为低电平表示正忙
3. 命令及相关操作
1)NAND Flash操作函数
a. 初始化函数nand_init()
先查看s3c2440的 芯片手册,可知:NAND Flash的初始化需要根据时序设置几个时间(寄存器);
如上图所示:对于 CLE/ALE 上的时序,我们需要设置 TACLS,TWRPH0,TWRPH1,这几个都在 NFCONF 寄存器里。
由以上2440芯片手册中的图还无法得到具体时间设置,需要参考K9F2G08U0M的芯片手册。
K9F2G08U0M芯片时间设置表:
K9F2G08U0M芯片时序图:
其中,通过对照2440 NAND Flash时序图和K9F2G08U0M芯片时序图可知:
TACLS: 属于等待WE(写信号)就绪的时间,
TACLS的时间为:tCLS- tWP
由时间表可知,tCLS=15, tWP =15,则TACLS时间0;
根据寄存器中描述的计算公式:Duration = HCLK x TACLS => 0ns = 10ns x TACLS => TACLS = 0
TWRPH0:属于WE(写信号)的时间,
TWRPH0的时间为: tWP =15nS
根据寄存器中描述的计算公式:Duration = HCLK x(TWRPH0+1) => 15=10x(TWRPH0+1) => TWRPH0 = 0.5, 由于取值范围为: (0~7) ,并且,时间表中的时间是最小能识别的时间,所以TWRPH0 = 1
TWRPH1:属于等待命令写入成功的时间,
TWRPH1的时间为:tCLH=5nS
根据寄存器中描述的计算公式:Duration = HCLK x(TWRPH1+1) => 5=10x(TWRPH1+1) => TWRPH1 = 0
(这里我们假设 开发板HCLK 为是 100MHz,,则 HCLK 的周期是 1/100MHz = 10ns)
根据以上分析,初始化函数nand_init()写为:
#define NFCONF (*((volatile unsigned long *)0x4E000000))
void nand_init(void)
{
#define TACLS 0
#define TWRPH0 1
#define TWRPH1 0
/* 设置时序 */
NFCONF = (TACLS<<)|(TWRPH0<<)|(TWRPH1<<);
/* 使能NAND Flash控制器, 初始化ECC, 禁止片选 */
NFCONT = (<<)|(<<)|(<<);
}
b. 芯片的选择和禁止函数
(让芯片操作nCE 引脚)
#define NFCONT (*((volatile unsigned long *)0x4E000004))
void nand_select(void ) //使能片选
{
NFCONT &= ~(<<); // NFCONT控制器位1置0
} void nand_deselect(void ) //取消片选
{
NFCONT |= (<<); // NFCONT控制器位1置1
}
c. 写命令
// 写命令 注意是八位的命令
#define NFCMMD (*((volatile unsigned char *)0x4E000008))
void nand_cmd(unsigned char cmd)
{
volatile int i;
NFCMMD = cmd;
for (i = ; i<; i++); // 延时一段时间
}
d. 写地址
地址序列分析:
由于Nand Flash地址引脚LDATA0-LDATA7只有8位,然而K9F2G08U0M的地址共有2048(块)*64(页)*2KB,为了读出多个地址,如下图,所以需要分5个周期来实现发送地址:
如上图,
A10~A0对应页大小(列),由于NANDFlash每页2048B,所以只用到A10~A0; (---->>这一页的第几个)
A28~A11对应页目录(行),表示共有2048块*64(每块有64页)个页目录; (---->>泛指位于第几页)
例如,4100 地址就是:
A10~A0=4100%2048= 4 (A2=1,其余为0) 第4列(个)
A28~A11=4100/2048= 2 (A12=1,其余为0) 第二行
写地址函数nand_addr()为:
void nand_addr(unsigned int addr) //发出5个周期的地址,之间需要延时一会
{ unsigned int col = addr % ;
unsigned int page = addr / ;
volatile int i;
NFADDR=(col>>)&0xff; //A7~A0,第1周期
for(i=;i<;i++);
NFADDR=(col>>)&0x0f; //A10~A8,第2周期
for(i=;i<;i++);
NFADDR=(page>>)&0xff; //A18~A11,第3周期
for(i=;i<;i++);
NFADDR=(page>>)&0xff; //A26~A19,第4周期
for(i=;i<;i++);
NFADDR=(page>>)&0xff; //A27~A28,第5周期
for(i=;i<;i++);
}
e. 读数据
K9F2G08U0M的芯片手册中的命令字:
读数据时序图:
根据以上时序图和芯片手册中的流程图可知读数据的步骤为:
(a) 使能片选CE,选中芯片;
(b) 写入读命令0x00到flash中
(b) 发送地址(分为5个周期,之间需要延时)
(c) 发送读命令0X30
(d) 判断状态,等待RnB信号为高电平
(e) 读数据
(f) 取消选中芯片
void nand_read(unsigned int addr, unsigned char *buf, unsigned int len)
{
int col = addr % ; //从该页的第几个开始读取
int i = ; nand_select(); /* 1. 选中 */
while (i < len)
{
nand_cmd(0x00); /* 2. 发出读命令00h */
nand_addr(addr); /* 3. 发出地址(分5步发出) */
nand_cmd(0x30); /* 4. 发出读命令30h */
nand_wait_ready(); /* 5. 判断状态 */
/* 6. 读数据 */
for (; (col < ) && (i < len); col++) //一行一行的读,第k页读完后,col=0,开始继续读,直到读取指定的长度len
{
buf[i] = nand_data();
i++;
addr++;
}
col = ;
}
/* 7. 取消选中 */
nand_deselect();
}
其中,判断状态(状态等待)函数nand_wait_teadynand_data,获取数据函数分别为:
#define NFSTAT (*((volatile unsigned char *)0x4E000020))
#define NFDATA (*((volatile unsigned char *)0x4E000010))
void nand_wait_teady(void)
{
while(!(NFSTAT & ))
for(i = ; i < ; i++);
}
unsigned char nand_data(void)//返回一个字节的数据
{
return NFDATA;
}
注意:/*addr:源地址,为32位地址,所以用unsigend int表示;因为每个地址里存的是一个字节,所以buf用unsigend char 型 */
f. 复位 NAND Flash 函数
根据命令的表格, 复位函数表示为:
void nand_reset(void)
{
nand_select(); /* 1. 选中芯片
nand_cmd(0xff); /* 2. 发出读命令0xff */
nand_read_ready(); /* 3, 判断状态 */
nand_deselect(); /* 4. 取消选中
}
参考:
https://blog.csdn.net/qqliyunpeng/article/details/51180276
https://www.cnblogs.com/lifexy/p/7097695.html
NAND Flash结构及驱动函数的更多相关文章
- linux下Pl353 NAND Flash驱动分析
linux的NAND Flash驱动位于drivers/mtd/nand子文件夹下: nand_base.c-->定义通用的nand flash基本操作函数,如读写page,可自己重写这些函数 ...
- nand flash详解及驱动编写
https://www.crifan.com/files/doc/docbook/linux_nand_driver/release/html/linux_nand_driver.html#nand_ ...
- nor flash和nand flash的区别
NOR和NAND是现在市场上两种主要的非易失闪存技术.Intel于1988年首先开发出NOR flash技术,彻底改变了原先由EPROM和EEPROM一统天下的局面.紧接着,1989年,东芝公司发表了 ...
- (三)NAND flash和NOR flash的区别详解
我们使用的智能手机除了有一个可用的空间(如苹果8G.16G等),还有一个RAM容量,很多人都不是很清楚,为什么需要二个这样的芯片做存储呢,这就是我们下面要讲到的.这二种存储设备我们都统称为“FLASH ...
- NOR FLASH与NAND FLASH的区别
NOR和NAND是现在市场上两种主要的非易失闪存技术.Intel于1988年首先开发出NOR flash技术,彻底改变了原先由EPROM和EEPROM一统天下的局面.紧接着,1989年,东芝公司发表了 ...
- NAND flash和NOR flash的区别详解
我们使用的智能手机除了有一个可用的空间(如苹果8G.16G等),还有一个RAM容量,很多人都不是很清楚,为什么需要二个这样的芯片做存储呢,这就是我们下面要讲到的.这二种存储设备我们都统称为“FLASH ...
- nand flash 和nor flash 区别
NOR和NAND是现在市场上两种主要的非易失闪存技术.Intel于1988年首先开发出NOR flash技术,彻底改变了原先由EPROM和EEPROM一统天下的局面.紧接着,1989年,东芝公司发表了 ...
- NOR flash和NAND flash区别,RAM 和ROM区别
ROM和RAM指的都是半导体存储器,ROM是Read Only Memory的缩写,RAM是Random Access Memory的缩写.ROM在系统停止供电的时候仍然可以保持数据,而RAM通常都是 ...
- NOR flash和NAND flash区别,RAM 和ROM区别d
ROM和RAM指的都是半导体存储器,ROM是Read Only Memory的缩写,RAM是Random Access Memory的缩写.ROM在系统停止供电的时候仍然可以保持数据,而RAM通常都是 ...
随机推荐
- IOS Google语音识别更新啦!!!
旧版本的API: —Google提供了一个在线语音识别的API接口,通过该API可以进行中文.英文等语言的识别. API地址:http://www.google.com/speech-api ...
- OpenSUSE 内核编译教程 (kernel 2.6.x)
http://cn.opensuse.org/OpenSUSE_%E5%86%85%E6%A0%B8%E7%BC%96%E8%AF%91%E6%95%99%E7%A8%8B_(kernel_2.6.x ...
- Python模块 Socket
一个简单的python socket编程 一.套接字 套接字是为特定网络协议(例如TCP/IP,ICMP/IP,UDP/IP等)套件对上的网络应用程序提供者提供当前可移植标准的对象.它们允许程序接受并 ...
- 部署Smokeping
1.环境安装 # yum -y install gcc* perl* httpd* libxml2 libxml2-devel libpng libpng-devel glib2 glib2-deve ...
- c++互斥锁的实现
class IMyLock { public: virtual ~IMyLock(){} ; ; }; class Mutex : public IMyLock { public: Mutex(); ...
- C++11新特性之 std::forward(完美转发)
我们也要时刻清醒,有时候右值会转为左值,左值会转为右值. (也许“转换”二字用的不是很准确) 如果我们要避免这种转换呢? 我们需要一种方法能按照参数原来的类型转发到另一个函数中,这才完美,我们称之为完 ...
- cs229 斯坦福机器学习笔记(一)-- 入门与LR模型
版权声明:本文为博主原创文章,转载请注明出处. https://blog.csdn.net/Dinosoft/article/details/34960693 前言 说到机器学习,非常多人推荐的学习资 ...
- context.RewritePath
context.RewritePath原理修改HttpRequest类中的Path属性
- HttpHandler使用Session
继承自IHttpHandler的类要实现两个接口:ProcessRequest和IsReusable但还不能使用Session,要使用Session需要下面的步骤处理: 1.先引用System.Web ...
- 学大伟业 Day 4 培训总结
今天讲的全是dp... 不多废话,先看一道经典的模板LIS(最长不下降子序列) 一.LIS 给定一个长度为N的数列,求最长上升子序列 例:1 7 2 8 3 4 答案:1 2 3 4 代码: #inc ...