加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

NandFlash操作详解(二)

发布时间:2020-12-15 20:08:30 所属栏目:百科 来源:网络整理
导读:NandFlash读操作: ???????? NandFlash的读取分为页读和随机读。页读每次读取一个page,从page的第一个数据开始读。其实也就是列号(偏移地址)为0,只提供页地址。 随机读能读取到一个page里面的某个存储单元,但是需要提供行地址和列地址。 ???????? 页读

NandFlash读操作:

???????? NandFlash的读取分为页读和随机读。页读每次读取一个page,从page的第一个数据开始读。其实也就是列号(偏移地址)为0,只提供页地址。

随机读能读取到一个page里面的某个存储单元,但是需要提供行地址和列地址。

???????? 页读和随机读的区别只是在于是否提供列号(偏移地址)。

打开NandFlash的芯片手册,找到读时序图


根据时序图可以看出,NandFlash的读取先要发送00h的命令,然后发送地址(两个周期的列地址,三个周期的行地址),发送30h命令,发送完0x30后,R/B信号会呈现忙的状态,就是说开始处理之前请求的这些命令去了。所以在R/B信号为低时要等待R/B出现高电平。

然后就可以读取数据了。在以上这些步骤之前呢,还需要先选择片选和对R/B信号做清除,然后在最后读取完数据后还要取消选择NandFlash芯片。

在2440手册中可以看到这个寄存器,它便是控制片选的:


接着是清除R/B信号,当RnB信号也就是R/B信号从低跳变成高的时候,我们就认为前面的指令正确执行可以获取数据了,而当RnB从低跳变到高时,下面这个寄存器中的[2]位会自动置位,而我们的清除工作也是对这一位操作:需要注意这个寄存器是8位的,所以定义地址时要写成char*


然后向下面这个寄存器中写入命令:这也是一个8位寄存器


向下面这个寄存器中发送地址(8位寄存器):



可以在时序图中清晰的看到需要发送两次列地址,如果是页读的访问方式,列地址便无效了,列地址直接写0x00。随机访问方式的话需要写入两次列地址信息。发送地址信息比较容易晕头,举例说明:

写入5次地址,前两次为列地址(页内偏移),后三次为行地址(相当于页号)。

如写入十进制地址8000,则需要写入的页号为:8000/2048(每页大小)=3.9页,所以写入第3页,在第三页业内偏移为:8000-3*2048=1856。

程序表示为:

void nand_addr(unsigned char addr)

{

??????? NFADDR = addr;

}

void nand_send_addr(unsigned int addr)

{

unsigned int page?? = addr / 2048;

??? unsigned int colunm = addr & (2048 - 1);//这一句和colunm =addr%2048等效

?

??? /* 这两个地址表示从页内哪里开始 */

??? nand_addr(colunm & 0xff);

??? nand_addr((colunm >> 8) & 0xff);

?

????? /* 下面三个地址表示哪一页 */

??? nand_addr(page & 0xff);

??? nand_addr((page >> 8) & 0xff);

??????? ??? nand_addr((page >> 16) & 0xff);

}

或者:

?

不要以为跟着手册的写入顺序应该这样写:

????????????????? nand_addr(addr & 0xff);???????? /* a0~a7 */

??????? ???????? nand_addr((addr >> 8) & 0x1f);?? ?/* 程序的角度: a8~a11*/

??????? ???????? nand_addr((addr >> 12) & 0xff); ??/* 程序的角度:a12~a19 */

??????? ???????? nand_addr((addr >> 20) & 0xff); ??/* 程序的角度:a20~a27*/

??????? ???????? nand_addr((addr >> 28) & 0xff); ??/* 程序的角度:a28?*/

其实应该这样写:

??????? nand_addr(addr & 0xff);???????????? /* a0~a7 */

??????? nand_addr((addr >> 8) & 0x7);?? ?????/* 程序的角度: a8~a11 */

a0-a7共8位加上a8-a10三位总共11位,2的11次方就是一页2048的大小!如果1页为4096字节,传送的两次列地址可能就是a0-a7,a8-a11了(没使用过每page4096字节的NandFlash)。

??????? nand_addr((addr >> 11) & 0xff); ??????/* 程序的角度:a12~a19 */

??????? nand_addr((addr >> 19) & 0xff); ??????/* 程序的角度:a20~a27 */

??????? nand_addr((addr >> 27) & 0xff); ??????/* 程序的角度: a28??? */

?

?

从时序图中也可以看出,发送了0x30命令后便需要去等待RnB信号由低向高的跳变。而检测的寄存器也是前面做清除的那个寄存器NFSTAT,也是第[2]位。

等待完成后便可以从NFDATA寄存器中读取到数据了。NFDATA也是一个8位寄存器。


如果想要连续读取某个地址后连续的n个字节,只需要反复读取NFDATA寄存器即可。

连续读取1000个字节:

???????? for(i=0;i<1000;i++) ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?

???????? {

???????? ?? buff[i] = NFDATA;? ? ??

???????? }

?

取得数据后,取消片选,整个读取功能便实现了

总结一下NandFlash的读操作步骤:

1、? 选中nandflash芯片

2、? 清除RnB

3、? 发送命令0x00

4、? 发送列地址

5、? 发送行地址

6、? 发送命令0x30

7、? 等待RnB

8、? 读取数据

9、? 取消选中nandflash芯片

代码实现(读取一页):

void NF_PageRead(unsigned long addr,unsigned char* buff)

{

???????? int i;

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??

???????? int col = addr % 2048; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?

int page = addr / 2048;

?

???????? //选中nandflash芯片

???????? select_chip();

????????

???????? //清除RnB

???????? clear_RnB();

????????

???????? //发送命令0x00

???????? send_cmd(0x00);

????????

???????? send_addr(col & 0xff);

???????? send_addr((col >> 8) & 0xff);

?

???????? send_addr(page & 0xff);

???????? send_addr((page >> 8) & 0xff);

???????? send_addr((page >> 16) & 0xff);

????????

???????? //发送命令0x30

???????? send_cmd(0x30);

????????

???????? //等待RnB

???????? wait_RnB();

????????

???????? //读取数据

???????? for(i=0;i<2048;i++)

???????? {

???????? ?? buff[i] = NFDATA;? ??

???????? }

????????

???????? //取消选中nandflash芯片

???????? deselect_chip();

}

?

?

NandFlash写操作:

???????? NandFlash的写操作之前需要先对NandFlash进行擦除工作,于是手册中找到擦除时序:


可以在NandFlash手册的Features中看到,NandFlash的擦除是按照页所在的块一整块来擦除的。根据时序可以得到擦除的步骤为:

1、? 选中flash芯片

2、? 清除RnB

3、? 发送命令0x60

4、? 发送行地址

5、? 发送命令D0

6、? 等待RnB

7、? 发送命令0x70

8、? 读取擦除结果

9、? 取消选中flash芯片

代码实现:

int NF_Erase(unsigned long addr) ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??

{

???????? int ret;

???????? unsigned int page = addr/2048;

????????

? //选中flash芯片

???????? select_chip();

????????

???????? //清除RnB

???????? clear_RnB();

????????

???????? //发送命令0x60

???????? send_cmd(0x60);

????????

???????? //发送行地址

???????? send_addr(page&0xff);

???????? send_addr((page>>8)&0xff);

???????? send_addr((page>>16)&0xff);

????????

???????? //发送命令D0

???????? send_cmd(0xD0);

????????

???????? //等待RnB

???????? wait_RnB();

????????

???????? //发送命令0x70

???????? send_cmd(0x70);

????????

???????? //读取擦除结果

???????? ret = NFDATA;

????????

???????? //取消选中flash芯片

???????? deselect_chip();

????????

???????? return ret;

}

擦除后就可以执行写操作,写入的时序为:


根据时序图,我们可以得到写入数据的流程:

1、? 选中Flash芯片(NandFlash芯片操作都需要先片选)

2、? 清除RnB(既然要查看RnB的跳变自然要先清除)

3、? 发送命令0x80

4、? 发送2个列地址

5、? 发送3个行地址

6、? 发送数据(往数据寄存器中写),跟读操作一样,需要连续写的话直接重复往NFDATA写入就行,不需要其他操作。

7、? 发送命令0x10

8、? 等待RnB

9、? 发送命令0x70

10、?????????????读取写入结果(在数据寄存器中读,没错,发送数据也是往数据寄存器中写的)

11、?????????????关闭片选(NandFlash操作都需要先选择Flash在关闭Flash)

代码实现:

int NF_WritePage(unsigned long addr,unsigned char *buff) ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?

{

???????? unsigned int i,ret = 0,page,col;

???????? col = addr % 2048;

???????? page = addr /2048;

???????? //选中nandflash

???????? select_chip();

????????

???????? //清除RnB

???????? clear_RnB();

????????

???????? //发送0x80命令

???????? send_cmd(0x80);

????????

???????? //发送2个列地址

???????? /* 这种写法ok

???????? send_addr(col & 0xff);

???????? send_addr((col >> 8) & 0xff);

???????? send_addr(page & 0xff);

???????? send_addr((page >> 8) & 0xff);

???????? send_addr((page >> 16) & 0xff);

???????? */

?

????????

???????? send_addr(addr & 0xff);???????? // a0~a7

???????? send_addr((addr >> 8) & 0x7);?? // 以程序角度看 a8~a10

?

???????? send_addr((addr >> 11) & 0xff); // 以程序角度看 a12~a19

???????? send_addr((addr >> 19) & 0xff); // 以程序角度看 a20~a27

???????? send_addr((addr >> 27) & 0xff); // 以程序角度看 a28???

????????

/*???? This’s wrong 移位错误

???????? send_addr(addr & 0xff);???????? // a0~a7

???????? send_addr((addr >> 8) & 0x7);?? // 以程序角度看 a8~a10

?

???????? send_addr((addr >> 12) & 0xff); // 以程序角度看 a12~a19

???????? send_addr((addr >> 20) & 0xff); // 以程序角度看 a20~a27

???????? send_addr((addr >> 28) & 0xff); // 以程序角度看 a28???

*/

???????? //发送数据

???????? for(i=0;i<2048;i++)

???????? {

???????? ?? NFDATA = buff[i];? ??

???????? }

????????

???????? //发送0x10命令

???????? send_cmd(0x10);

????????

???????? //等待RnB

???????? wait_RnB();

????????

???????? //发送0x70命令

???????? send_cmd(0x70);

????????

???????? //读取写入结果

???????? ret = NFDATA;

????????

???????? //关闭nandflash

???????? deselect_chip();

???????? ?return ret;

? }

?

当然还可以对NandFlash进行读取ID的操作,这个工作根据时序图仿造读写操作就可以实现了,在裸机中用得比较少我就不写了。


下一节NandFlash操作详解(三)

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读