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

NAND FLASH编程

发布时间:2020-12-15 17:30:39 所属栏目:百科 来源:网络整理
导读:NAND?FLASH编程 (2008-09-12 20:48:37) ? 1、结构分析 NAND FLASH以页(page)为单位进行读写,以块(block)为单位进行擦除。 其中,512B用于存放数据,16B用于存放其他信息(包括:块好坏的标记、块的逻辑地址、页内数据的ECC校验和等)。2410处理器针对NAND

NAND?FLASH编程

(2008-09-12 20:48:37)
?

1、结构分析

NAND FLASH以页(page)为单位进行读写,以块(block)为单位进行擦除。


其中,512B用于存放数据,16B用于存放其他信息(包括:块好坏的标记、块的逻辑地址、页内数据的ECC校验和等)。2410处理器针对NAND设备还集成了硬件ECC校验,这将大大提高NAND设备的读写效率。系统在每次读一页后会计算其校验和,并和存储在页内的冗余的16B内的校验和做比较,以此来判断读出的数据是否正确。

NAND FLASH有与页大小相同的页寄存器,用于数据缓存。当读数据时,先从NAND FLASH内存单元把数据读到页寄存器,外部通过访问NAND FLASH I/O端口获得页寄存器中数据(地址自动累加);当写数据时,外部通过NAND FLASH I/O端口输入的数据首先缓存在页寄存器,写命令发出后才写入到内存单元中。

按照k9f1208的组织方式可以分四类地址: Column Address、halfpage pointer、Page Address 、Block Address。A[0:25]表示数据在64M空间中的地址。

Column Address表示数据在半页中的地址,大小范围0~255,用A[0:7]表示;

halfpage pointer表示半页在整页中的位置,即在0~255空间还是在256~511空间,用A[8]表示;

Page Address表示页在块中的地址,大小范围0~31,用A[13:9]表示;

Block Address表示块在flash中的位置,大小范围0~4095,A[25:14] 表示;

?

2、NAND设备的软件调试步骤:

设置相关寄存器、NAND 设备的初始化、NAND设备的识别、NAND设备的读擦写(带ECC校验)

NFCONF――配置寄存器?

NFCONT――控制寄存器

NFCMD―― 命令设置寄存器

NFADDR――地址设置寄存器

NFDATA――数据寄存器

NFSTAT―― 操作状态寄存器

NFECC――?ECC?寄存器

读操作过程

K9f1208的寻址分为4个cycle。分别是:A[0:7]、A[9:16]、A[17:24]、A[25]。读操作的过程为: 1、发送读取指令;2、发送第1个cycle地址;3、发送第2个cycle地址;4、发送第3个cycle地址;5、发送第4个cycle地址;6、读取数据至页末。K9f1208提供了两个读指令,‘0x00’、‘0x01’。这两个指令区别在于‘0x00’可以将A[8]置为0,选中上半页;而‘0x01’可以将A[8]置为1,选中下半页。虽然读写过程可以不从页边界开始,但在正式场合下还是建议从页边界开始读写至页结束。

写操作过程

写操作的过程为: 1、发送写开始指令;2、发送第1个cycle地址;3、发送第2个cycle地址;4、发送第3个cycle地址;5、发送第4个cycle地址;6、写入数据至页末;7、发送写结束指令

?

3、存储检查

需要ECC(Error Corection Code)校验,坏块标注、地址映射等一系列的技术手段来达到可靠存储目的。

???????SSFDC软件规范中,详细定义了如何利用NAND设备每个页中的冗余信息来实现上述功能。这个软件规范中,很重要的一个概念就是块的逻辑地址,它将在物理上可能不连续、不可靠的空间分配编号,为他们在逻辑空间上给系统文件提供一个连续可靠的存储空间。表1给出了SSFDC规范中逻辑地址的标注方法。在系统初始化的时候,驱动程序先将所有的块扫描一遍,读出他们所对应的逻辑地址,并把逻辑地址和虚拟地址的映射表建好。系统运行时,驱动程序通过查询映射表,找到需要访问的逻辑地址所对应的物理地址然后进行数据读写。

表1 冗余字节定义

字节序号

内容

字节序号

内容

512

用户定义数据

520

后256BECC校验和

513

521

514

522

515

523

块逻辑地址

516

数据状态

524

517

块状态

525

前256BECC校验和

518

块逻辑地址1

526

519

527

表2给出了块逻辑地址的存放格式,LA表示逻辑地址,P代表偶校验位。逻辑地址只有10bit,代表只有1024bit的寻址空间。而SSFDC规范将NAND设备分成了多个zone,每个zone 内有1024块,但这物理上的1024块映射到逻辑空间只有1000块,其他的24块就作为备份使用,当有坏块存在时,就可以以备份块将其替换。

表2??逻辑地址格式

D7

D6

D5

D4

D3

D2

D1

D0

?

0

0

0

1

0

LA9

LA8

LA7

第518???523字节

LA6

LA5

LA4

LA3

LA2

LA1

LA0

P

第519???524字节

有了以上的软件规范,就可以对NAND设备写出较标准的ECC校验,并可以编写检测坏块、标记坏块、建立物理地址和逻辑地址的映射表的程序了。

static int NF_IsBadBlock(U32 block) ??????????//检测坏块

{

????int i;

????unsigned int blockPage;

????U8 data;

????blockPage=(block<<5);???????// For 2'nd cycle I/O[7:5]

????NF_nFCE_L();????

????NF_CMD(0x50);????// Spare array read command

???// Read the mark of bad block in spare array(M addr="5")

???NF_ADDR(517&0xf); ?

???NF_ADDR(blockPage&0xff); // The mark of bad block is in 0 page

???NF_ADDR((blockPage>>8)&0xff);???// For block number A[24:17]

???NF_ADDR((blockPage>>16)&0xff);??// For block number A[25]

???for(i=0;i<10;i++);??????????????// wait tWB(100ns) //?????

???NF_WAITRB();?????????????????// Wait tR(max 12us)

???data=NF_RDDATA();

???NF_nFCE_H();???

???if(data!=0xff)

????{

???????Uart_Printf("[block %d has been marked as a bad block(%x)]n",block,data);

???????return 1;

????}

????else

????{

???????return 0;

????}

}

?

static int NF_MarkBadBlock(U32 block)?????????????//标记坏块

{

????int i;

????U32 blockPage=(block<<5);

????seBuf[0]=0xff;

????seBuf[1]=0xff;???

????seBuf[2]=0xff;???

????seBuf[5]=0x44;?????????????????// Bad blcok mark="0

????NF_nFCE_L();

????NF_CMD(0x50);????????????????????????

????NF_CMD(0x80);?????????????????????????// Write 1st command

????NF_ADDR(0x0);??????????????????// The mark of bad block is???

????NF_ADDR????(blockPage&0xff); ????// marked 5th spare array

????NF_ADDR((blockPage>>8)&0xff);?????????????// in the 1st page.

????NF_ADDR((blockPage>>16)&0xff);???????????

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

????{

????NF_WRDATA(seBuf[i]);???????????????????// Write spare array

????}

????NF_CMD(0x10);?????????????????????????// Write 2nd command

????for(i=0;i<10;i++);??????????//tWB = 100ns. //??

????NF_WAITRB();??????// Wait tPROG(200~500us)

????NF_CMD(0x70);

????for(i=0;i<3;i++);?????????????????????????//twhr=60ns///

????if (NF_RDDATA()&0x1) ??????????????// Spare arrray write error

????{?

???????NF_nFCE_H();

???????Uart_Printf("[Program error is occurred but ignored]n");

????}

????else

????{

???????NF_nFCE_H();

????}

????Uart_Printf("[block #%d is marked as a bad block]n",block);

????return 1;

}

//建立物理地址到逻辑地址的映射表

int search_logic_block(void)??????????

{

????unsigned int block,i,blockPage,logic_no,zone,zone_i;

????U8 SE[16];

????for(i=0;i<BLOCK_NR;i++)???????????????????????//初始化全局变量

????lg2ph[i]=space_block[i]=0xffff;

????logic_number=0;

????space_nr=0;

????NF_nFCE_L();

????zone=BLOCK_NR/1024;??//确定NAND设备中zone的个数

????for(zone_i=0;zone_i<zone;zone_i++)

????{

???????//搜索每个zone 内逻辑地址和物理地址的映射关系

???????for(block=0;block<1024;block++)

???????{

???????????blockPage=((block+zone_i*1024)<<BLOCK_ADDRERSS_SHIFT);

???????????NF_WATIRB();??????????????????????????//等待R/B#信号有效读取每个block内部

???????????????????????????????????????????????????第0个Page?内冗余的16个字节???

???????????NF_CMD(0x50);???????

???????????NF_ADDR(0);????????????????????????????????// Column 0

???????????NF_ADDR(blockPage&0xff); ???

???????????NF_ADDR((blockPage>>8)&0xff);??????// Block & page num.

???????????NF_ADDR((blockPage>>16)&0xff);

???????????NF_WATIRB();???????????????????????????//等待R/B#信号有效

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

?????????se[i]=NF_RDDATA();?????// Write spare array

???????NF_WATIRB();

???????if(se[5]!=0xff)??????????//检测是否存在坏块

???????????printk("nrphysic block %d is bad blocknr",block);

???????else if(se[7]!=se[12])

???????????printk("block address1:%d!=block address2 %dnr",se[7],se[12]);

???????else if(se[6]0xf8)==0x10)

???????{

???????????//计算该block对应的逻辑地址

???????????logic_no=((0x7&se[6])<<7)+(se[7]>>1)+zone_i*1000;

???????????if(lg2ph[logic_no]!=0xffff)?????//说明有2个block拥有相同的逻辑地址

??????????????printk("physical block %d and block %d have the same logic number %dn",lg2ph[logic_no],logic_no);

???????????else lg2ph[logic_no]=block;?????//将该block的逻辑地址关系记入lg2ph表

???????????logic_number++;???????????????????????

???????}

???????else if(se[7]==0xff)????????????//说明该block尚未编号

???????{space_block[space_nr]=block;

???????space_nr++;

???????}

???????}

????}

????printk("there are totally %d logic blocksnr",logic_number);

????NF_nFCE_H();

????return logic_number;

}

这段代码的主要作用就是产生数组lg2ph[],这个数组的含义就是“块物理地址=lg2ph[逻辑地址]”。

(编辑:李大同)

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

    推荐文章
      热点阅读