目标:以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)   取消选中芯片

 读数据函数nand_read()为:
 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结构及驱动函数的更多相关文章

  1. linux下Pl353 NAND Flash驱动分析

    linux的NAND Flash驱动位于drivers/mtd/nand子文件夹下: nand_base.c-->定义通用的nand flash基本操作函数,如读写page,可自己重写这些函数 ...

  2. nand flash详解及驱动编写

    https://www.crifan.com/files/doc/docbook/linux_nand_driver/release/html/linux_nand_driver.html#nand_ ...

  3. nor flash和nand flash的区别

    NOR和NAND是现在市场上两种主要的非易失闪存技术.Intel于1988年首先开发出NOR flash技术,彻底改变了原先由EPROM和EEPROM一统天下的局面.紧接着,1989年,东芝公司发表了 ...

  4. (三)NAND flash和NOR flash的区别详解

    我们使用的智能手机除了有一个可用的空间(如苹果8G.16G等),还有一个RAM容量,很多人都不是很清楚,为什么需要二个这样的芯片做存储呢,这就是我们下面要讲到的.这二种存储设备我们都统称为“FLASH ...

  5. NOR FLASH与NAND FLASH的区别

    NOR和NAND是现在市场上两种主要的非易失闪存技术.Intel于1988年首先开发出NOR flash技术,彻底改变了原先由EPROM和EEPROM一统天下的局面.紧接着,1989年,东芝公司发表了 ...

  6. NAND flash和NOR flash的区别详解

    我们使用的智能手机除了有一个可用的空间(如苹果8G.16G等),还有一个RAM容量,很多人都不是很清楚,为什么需要二个这样的芯片做存储呢,这就是我们下面要讲到的.这二种存储设备我们都统称为“FLASH ...

  7. nand flash 和nor flash 区别

    NOR和NAND是现在市场上两种主要的非易失闪存技术.Intel于1988年首先开发出NOR flash技术,彻底改变了原先由EPROM和EEPROM一统天下的局面.紧接着,1989年,东芝公司发表了 ...

  8. NOR flash和NAND flash区别,RAM 和ROM区别

    ROM和RAM指的都是半导体存储器,ROM是Read Only Memory的缩写,RAM是Random Access Memory的缩写.ROM在系统停止供电的时候仍然可以保持数据,而RAM通常都是 ...

  9. NOR flash和NAND flash区别,RAM 和ROM区别d

    ROM和RAM指的都是半导体存储器,ROM是Read Only Memory的缩写,RAM是Random Access Memory的缩写.ROM在系统停止供电的时候仍然可以保持数据,而RAM通常都是 ...

随机推荐

  1. IOS Google语音识别更新啦!!!

      旧版本的API:   —Google提供了一个在线语音识别的API接口,通过该API可以进行中文.英文等语言的识别.  API地址:http://www.google.com/speech-api ...

  2. 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 ...

  3. Python模块 Socket

    一个简单的python socket编程 一.套接字 套接字是为特定网络协议(例如TCP/IP,ICMP/IP,UDP/IP等)套件对上的网络应用程序提供者提供当前可移植标准的对象.它们允许程序接受并 ...

  4. 部署Smokeping

    1.环境安装 # yum -y install gcc* perl* httpd* libxml2 libxml2-devel libpng libpng-devel glib2 glib2-deve ...

  5. c++互斥锁的实现

    class IMyLock { public: virtual ~IMyLock(){} ; ; }; class Mutex : public IMyLock { public: Mutex(); ...

  6. C++11新特性之 std::forward(完美转发)

    我们也要时刻清醒,有时候右值会转为左值,左值会转为右值. (也许“转换”二字用的不是很准确) 如果我们要避免这种转换呢? 我们需要一种方法能按照参数原来的类型转发到另一个函数中,这才完美,我们称之为完 ...

  7. cs229 斯坦福机器学习笔记(一)-- 入门与LR模型

    版权声明:本文为博主原创文章,转载请注明出处. https://blog.csdn.net/Dinosoft/article/details/34960693 前言 说到机器学习,非常多人推荐的学习资 ...

  8. context.RewritePath

    context.RewritePath原理修改HttpRequest类中的Path属性

  9. HttpHandler使用Session

    继承自IHttpHandler的类要实现两个接口:ProcessRequest和IsReusable但还不能使用Session,要使用Session需要下面的步骤处理: 1.先引用System.Web ...

  10. 学大伟业 Day 4 培训总结

    今天讲的全是dp... 不多废话,先看一道经典的模板LIS(最长不下降子序列) 一.LIS 给定一个长度为N的数列,求最长上升子序列 例:1 7 2 8 3 4 答案:1 2 3 4 代码: #inc ...