nand flash的读操作详解(4)

R/nB为低电平这段时间就是 在处理这些命令(实际上是根据命令将你定位的那一页数据读到内部寄存器中),

        R/nB变成高电平了,就指示命令处理完毕,现在数据也就可以读出来了

综上我们从手册中我们就知道了读操作的具体步骤,

1 首先nand flash 也是一个外设,要访问他就需要片选它,所以在执行时序图上的步骤之前需要片选nand flash.

2 看后面就是安装时序图来了,看时序图! 第一步先是发送一个命令 0x00.

3 看时序图! 然后发送五个地址序列(先发送两个列地址,在发送三个行地址(即页地址))

4 看时序图! 接着再是一个命令 0x30.

5 看时序图!  R/nB 引脚为低表示现在正忙,正在处理这些命令,那就要等待 R/nB 引脚变为高电平

6 看时序图! 这个时候就可以读数据了

7 一次读操作结束了 nand flash 暂时是不需要使用了,那么别忘了应该 取消片选信号。

至于这每一个步骤中具体的时序,cpu中的nand flash控制器会帮我们完成。我们要做就是设置几个时间参数

这里我们反复强调了要看时序图。其实学嵌入式前期对数据手册一定要多看,看多了你就回知道,什么东西的你重点要看的,什么是和你的编程操作无关的你不需要关心。这样后面你才能,拿到一个外设 就能写出他的操作。而不用跟着书背步骤。只要手册在就行了。

上面的步骤,是一个具体的读操作的步骤,不过在使用一个器件之前我们需要初始化一下它。至于初始化也就是设置我们上面多次提到的

我们说过 s3c2440已经帮我做了很多底层的单元操作,我们只需设置几个时间参数 片内的 nand flash就会自动发出相应操作的时序操作

那么到底设置那几个时间呢。 

s3c2440 手册上给出了 需要我们设置的几个参数。

nand flash的读操作详解

nand flash的读操作详解

从中我们可以看出 第一幅时序图是 命令和地址锁存的时序,第二幅是 数据读取和写入的时序。
可以看出,他们要设置的时间都是一样的。前面分析了那么多,这里应该不难 看出


1 TACLS 很明表示的是 CLE/ALE 的建立时间(这里并不准确,其实是 CLE/ALE有效到 WE 变成低电平之间的时间,但 WE 却是在上升沿才锁存命令/地址)

2 TWRPH0 代表的是 WE 的脉冲宽度,即有效时间

3 TWRPH1 代表的是 CLE/ALE 的保持时间


那到底设置成什么数字呢。既然 上图中读/写/命令/地址 操作需要的时间参数都是一样的

那么我们从 nand flash中随便找一个 命令时序来对照不就行了

就拿上面我们说过的 命令锁存时序来对比

nand flash的读操作详解


那么我们就能得到下面的关系

TWRPH0 = tWP 

TWRPH1 = tCLH

TACLS  = tCLS - tWP


然后设置成多少呢? 看手册啊,手册中对 tWP  tCLH  tCLS 都会至少给出 需要的最小时间


这款芯片nand flash手册中这三个参数要求是

nand flash的读操作详解

所以 TWRPH0 = tWP  >=12ns

TWRPH1 = tCLH >=5ns

TACLS  = tCLS - tWP >=0;

而这三个参数在s3c2440的数据手册中说明为

nand flash的读操作详解

当然这里的时间都是以 HCLK 为单位的,这几个参数 是在 nand flash控制寄存器中的 NFCONF中设置的

这里我没用使用MPLL 所以HCLK是 12MHZ

所以 TWRPH0 = 0 TWRPH1 =0 TACLS =0; (如果你的时钟频率比较高,那就要设别的数了。当然有是有你真不知道,设置大点总没错,只不过速度可能会慢点。)

所以 NFCONF =0;(NOFCONF其他位数据手册中有说明,这里只是简单读操作,其他位可以不设置)

然后是初始化一下 ECC 使能nand flash控制器(我们只是设置了几个时间参数,时序的具体操作就是靠他来完成的,所以要使能他)

然后先 取消片选nand flash 因为我们现在还没有操作它啊,只是初始化一下。所以还是应该先取消片选,等真正读的时候再使能片选信号

NFCONT = (1<<4) | (1<<1) (1<<0);

(数据手册中有对应位的说明)

最后,第一次使用nand flash 我们需要复位操作一下。

综上,nand flash 的初始化代码如下

void nand_init(void){

NFCONF =0;

NFCONT = (1<<4) | (1<<1) | (1<<0);

nand_reset();  //nand reset代码在后面

}

下面代码一些地址的写法是与 nand flash 型号有关的。具体需要参考芯片手册

void select_chip(void){

NFCONT  &= (~(1<<1)) ;   

int i;

for(i=10;i>0;i--);

}

void deselect_chip(void){

NFCONT |= (1<<1);

int i;

for(i=10;i>0;i--);

}

void write_command(unsigned char command){

NFCMMD = command;

int i;

for(i=10;i>0;i--);

}

/*

这款nand flash 的页大小是 2K

五个地址周期  (2个列地址 和3和行地址(页地址))

*/

void write_address(unsigned int address){

unsigned int page = address/2048;

unsigned int col  = address&2048;

int i;

NFADDR = col & 0xff;

for(i=5;i>0;i--);

NFADDR = (col >>8) & 0x0f;

for(i=5;i>0;i--);

NFADDR = page & 0xff;

for(i=5;i>0;i--);

NFADDR = (page >>8)& 0xff;

for(i=5;i>0;i--);

NFADDR = (page >>16)&0x01;

for(i=5;i>0;i--);

}

unsigned char read_one_data(void){

return NFDATA;

int i;

for(i=10;i>0;i--);

}

void wait_ready(void){

while(!(NFSTAT & 1));

int i;

for(i=10;i>0;i--);

}

static void nand_reset(void){

select_chip();

write_command(0xff);

wait_ready();

deselect_chip();

}

void nand_init(void){

NFCONF =0;

NFCONT = (1<<4) | (1<<1) | (1<<0);

nand_reset();

}

/*

nand flash 的读操作是以页为单位的。

des: nand flash中读出的数据放到哪

start_addr: 从哪里开始读

size: 读多大

*/

void nand_read(unsigned char *des,unsigned int start_addr,unsigned int size){

unsigned int col  = start_addr & 2048;

select_chip();

unsigned int start = start_addr;

unsigned int end  = start_addr + size;

while(start < end){                            //每读一页需要发一次命令

write_command(0x00);

write_address(start);

write_command(0x30);

wait_ready();

while((col<2048) && (start<end)){  //在一页中读,我用的型号一页大小为2K

*des = read_one_data();

des++;

col++;

start++;

}

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/6788998dd6384ef098cf282b902e3ff3.html