• 设为首页
  • 点击收藏
  • 手机版
    手机扫一扫访问
    hg1618|官方网站基地手机版
  • 关注官方公众号
    微信扫一扫关注
    hg1618|官方网站基地公众号
  • Nand Flash数据读写与软件编写调试

    2015-3-2 09:52| 发布者: intohard| 查看: 7243| 评论: 10|原作者: csdn

    摘要: NAND FLASH 在对大容量的数据存储需要中日益发展,到现今,所有的数码相机、多数MP3播放器、各种类型的U盘、很多PDA里面都有NAND FLASH的身影。 1. Flash的简介 NOR Flash: * 程序和数据可存放在同一 ...
    ? ?? ? NAND FLASH 在对大容量的数据存储需要中日益发展,到现今,所有的数码相机、多数MP3播放器、各种类型的U盘、很多PDA里面都有NAND FLASH的身影。
    1.? ?? ?Flash的简介

    NOR Flash:

    ? ? * 程序和数据可存放在同一片芯片上,拥有独立的数据总线和地址总线,能快速随机地读取,允许系统直接从Flash中读取代码执行,而无需先将代码下载至RAM中再执行

    ? ? * 可以单字节或单字编程,但不能单字节擦除,必须以块为单位或对整片执行擦除操作,在对存储器进行编程之前需要对块或整片进行预编程和擦除操作。


    NAND FLASH
    ? ?? ?* 以页为单位进行读写操作,1页为256B或512B;以块为单位进行擦除操作,1块为4KB、8KB或16KB。具有快编程和快擦除的功能

    ? ?* 数据、地址采用同一总线,实现串行读取。随机读取速度慢且不能按字节随机编程

    ? ?* 芯片尺寸小,引脚少,是位成本(bit cost)最低的固态存储器

    ? ?* 芯片存储位错误率较高,推荐使用 ECC校验,并包含有冗余块,其数目大概占1%,当某个存储块发生错误后可以进行标注,并以冗余块代替

    ? ?*??Samsung、TOSHIBA和Fujistu三家公司支持采用NAND技术NAND Flash。目前,Samsung公司推出的最大存储容量可达8Gbit。NAND 主要作为SmartMedia卡、Compact Flash卡、PCMCIA ATA卡、固态盘的存储介质,并正成为Flash磁盘技术的核心。

    2.? ?? ?NAND FLASH 和NOR FLASH 的比较
    1)? ?? ? 性能比较

    ? ? Flash闪存是非易失存储器,可以对称为块的存储器单元块进行擦写和再编程。任何flash器件的写入操作只能在空或已擦除的单元内进行,所以大多数情况下,在进行写入操作之前必须先执行擦除。NAND器件执行擦除操作是十分简单的,而NOR则要求在进行擦除前先要将目标块内所有的位都写为0。

    ? ? 由于擦除NOR器件时是以64~128KB的块进行的,执行一个写入/擦除操作的时间为5s,与此相反,擦除NAND器件是以8~32KB的块进行的,执行相同的操作最多只需要4ms。

    ? ? 执行擦除时块尺寸的不同进一步拉大了NOR和NADN之间的性能差距,统计表明,对于给定的一套写入操作(尤其是更新小文件时),更多的擦除操作必须在基于NOR的单元中进行。这样,当选择存储解决方案时,设计师必须权衡以下的各项因素。

    ? ?? ?  ● NOR的读速度比NAND稍快一些。

    ? ?? ?  ● NAND的写入速度比NOR快很多。

    ? ?? ?  ● NAND的4ms擦除速度远比NOR的5s快。

    ? ?? ?  ● 大多数写入操作需要先进行擦除操作。

    ? ?? ?  ● NAND的擦除单元更小,相应的擦除电路更少。

    2)? ?? ? 接口差别

    ? ? NOR flash带有SRAM接口,有足够的地址引脚来寻址,可以很容易地存取其内部的每一个字节。

    NAND器件使用复杂的I/O口来串行地存取数据,共用8位总线(各个产品或厂商的方法可能各不相同)。8个引脚用来传送控制、地址和数据信息。NAND读和写操作采用512字节的页和32KB的块为单位,这一点有点像hg1618|官方网站管理此类操作,很自然地,基于NAND的存储器就可以取代hg1618|官方网站或其他块设备。

    3)? ?? ? 容量和成本

    NAND flash的单元尺寸几乎是NOR器件的一半,由于生产过程更为简单,NAND结构可以在给定的模具尺寸内提供更高的容量,也就相应地降低了价格,大概只有NOR的十分之一。

    NOR flash占据了容量为1~16MB闪存市场的大部分,而NAND flash只是用在8~128MB的产品当中,这也说明NOR主要应用在代码存储介质中,NAND适合于数据存储,NAND在CompactFlash、Secure Digital、PC Cards和MMC存储卡市场上所占份额最大。

    4)? ?? ? 可靠性和耐用性

    采用flahs介质时一个需要重点考虑的问题是可靠性。对于需要扩展MTBF的系统来说,Flash是非常合适的存储方案。可以从寿命(耐用性)、位交换和坏块处理三个方面来比较NOR和NAND的可靠性。

    NAND闪存中每个块的最大擦写次数是一百万次,而NOR的擦写次数是十万次。NAND存储器除了具有10比1的块擦除周期优势,典型的NAND块尺寸要比NOR器件小8倍,每个NAND存储器块在给定的时间内的删除次数要少一些。

    5)? ?? ? 位交换(错误率)

    所有flash器件都受位交换现象的困扰。在某些情况下(很少见,NAND发生的次数要比NOR多),一个比特位会发生反转或被报告反转了。一位的变化可能不很明显,但是如果发生在一个关键文件上,这个小小的故障可能导致系统停机。如果只是报告有问题,多读几次就可能解决了。当然,如果这个位真的改变了,就必须采用错误探测/错误更正(EDC/ECC)算法。位反转的问题更多见于NAND闪存,NAND的供应商建议使用NAND闪存的时候,同时使用EDC/ECC算法。

    这个问题对于用NAND存储多媒体信息时倒不是致命的。当然,如果用本地存储设备来存储操作系统、配置文件或其他敏感信息时,必须使用EDC/ECC系统以确保可靠性。

    6)? ?? ? 坏块处理

    NAND器件中的坏块是随机分布的。以前也曾有过消除坏块的努力,但发现成品率太低,代价太高,根本不划算。NAND器件需要对介质进行初始化扫描以发现坏块,并将坏块标记为不可用。现在的FLSAH一般都提供冗余块来代替坏块如发现某个块的数据发生错误(ECC校验),则将该块标注成坏块,并以冗余块代替。这导致了在NAND Flash 中,一般都需要对坏块进行编号管理,让每一个块都有自己的逻辑地址。

    7)? ?? ? 易于使用

    可以非常直接地使用基于NOR的闪存,可以像其他存储器那样连接,并可以在上面直接运行代码。由于需要I/O接口,NAND要复杂得多。各种NAND器件的存取方法因厂家而异。在使用NAND器件时,必须先写入驱动程序,才能继续执行其他操作。向NAND器件写入信息需要相当的技巧,因为设计师绝不能向坏块写入,这就意味着在NAND器件上自始至终都必须进行虚拟映射。

    8)? ?? ? 软件支持

    当讨论软件支持的时候,应该区别基本的读/写/擦操作和高一级的用于磁盘仿真和闪存管理算法的软件,包括性能优化。在NOR器件上运行代码不需要任何的软件支持,在NAND器件上进行同样操作时,通常需要驱动程序,也就是内存技术驱动程序(MTD),NAND和NOR器件在进行写入和擦除操作时都需要MTD。使用NOR器件时所需要的MTD要相对少一些,许多厂商都提供用于NOR器件的更高级软件,这其中包括M-System的TrueFFS驱动,该驱动被Wind River System、Microsoft、QNX Software System、Symbian和Intel等厂商所采用。驱动还用于对DiskOnChip产品进行仿真和NAND闪存的管理,包括纠错、坏块处理和损耗平衡。

    在掌上电脑里要使用NAND FLASH 存储数据和程序,但是必须有NOR FLASH来启动。除了SAMSUNG处理器,其他用在掌上电脑的主流处理器还不支持直接由NAND FLASH 启动程序。因此,必须先用一片小的NOR FLASH 启动机器,在把OS等软件从NAND FLASH 载入SDRAM中运行才行。

    9)? ?? ? 主要供应商

    NOR FLASH的主要供应商是INTEL ,MICRO等厂商,曾经是FLASH的主流产品,但现在被NANDFLASH挤的比较难受。它的优点是可以直接从FLASH中运行程序,但是工艺复杂,价格比较贵。

    NAND FLASH的主要供应商是SAMSUNG和东芝,在U盘、各种存储卡、MP3播放器里面的都是这种FLASH,由于工艺上的不同,它比NORFLASH拥有更大存储容量,而且便宜。但也有缺点,就是无法寻址直接运行程序,只能存储数据。另外NAND FLASH非常容易出现坏区,所以需要有校验的算法。


    3.NAND Flash的硬件设计NAND FLASH是采用与非门结构技术的非易失存储器,有8位和16位两种组织形式,下面以8位的NAND FLASH进行讨论。
    1)? ?? ?接口信号
    与NOR Flash相比较,其数据线宽度只有8bit,没有地址总线,I/O接口可用于控制命令和地址的输入,也可用于数据的输入和输出,多了CLE和ALE来区分总线上的数据类别。
    001.png

    2)? ?? ?地址结构
    NAND FLASH主要以页(page)为单位进行读写,以块(block)为单位进行擦除。FLASH页的大小和块的大小因不同类型块结构而不同,块结构有两种:小块(图2)和大块(图3),小块NAND FLASH包含32个页,每页512+16字节;大块NAND FLASH包含64页,每页2048+64字节。

    002.jpg

    图2 小块类型NAND FLASH

    003.jpg
    图3??大块类型NAND FLASH

    其中,512B(或1024B)用于存放数据,16B(64B)用于存放其他信息(包括:块好坏的标记、块的逻辑地址、页内数据的ECC校验和等)。NAND设备的随机读取得效率很低,一般以页为单位进行读操作。系统在每次读一页后会计算其校验和,并和存储在页内的冗余的16B内的校验和做比较,以此来判断读出的数据是否正确。

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


    3)? ?? ?接口电路设计(以下以2410和K9F1208U为例)
    2410处理器拥有专门针对 NAND设备的接口,可以很方便地和NAND设备对接,如图9所示。虽然NAND设备的接口比较简单,容易接到系统总线上,但2410处理器针对NAND设备还集成了硬件ECC校验,这将大大提高NAND设备的读写效率。当没有处理器的ECC支持时,就需要由软件来完成ECC校验,这将消耗大量的CPU资源,使读写速度下降。

    004.jpg
    图9 S3C2410与NAND FLASH接口电路示意图

    3.NAND FLASH 的软件编写和调试
    ? ? NAND设备的软件调试一般分为以下几个步骤:设置相关寄存器、NAND 设备的初始化、NAND设备的识别、NAND设备的读擦写(带ECC校验 )
    ? ? NAND设备的操作都是需要通过命令来完成,不同厂家的命令稍有不同,以下一Samsung公司的K9F1208U0M命令表为例介绍NAND设备的软件编写。

    005.jpg

    表2??K9F1208U0M??Command Sets


    1)? ?? ?根据2410寄存器定义如下的命令宏

    #define NF_CMD(cmd) {rNFCMD=cmd;}

    #define NF_ADDR(addr)? ?{rNFADDR=addr;}

    #define NF_nFCE_L() {rNFCONF&=~(1<<11);}

    #define NF_nFCE_H() {rNFCONF|=(1<<11);}

    #define NF_RSTECC() {rNFCONF|=(1<<12);}

    #define NF_RDDATA()? ???(rNFDATA)

    #define NF_WRDATA(data) {rNFDATA=data;}

    #define NF_WAITRB()? ? {while(!(rNFSTAT&(1<<0)));}

    ? ?? ???//wait tWB and check F_RNB pin.



    2)? ?? ?NAND 设备的初始化
    1. static void NF_Init(void)? ?? ?? ?? ?? ?? ?? ?? ???//Flash 初始化
    2. {

    3. rNFCONF=(1<<15)|(1<<14)|(1<<13)|(1<<12)|(1<<11)|(TACLS<<8)|(TWRPH0<<4)|(TWRPH1<<0);? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ???//设置NAND设备的相关寄存器

    4. ? ? // 1??1? ? 1? ???1,? ?1? ?? ?xxx,??r xxx,? ?r xxx? ?? ???

    5. ? ? // En 512B 4step ECCR nFCE="H" tACLS? ?tWRPH0? ?tWRPH1

    6. ? ?

    7. ? ? NF_Reset();

    8. }

    9. static void NF_Reset(void)? ?? ?? ?? ?? ?? ?? ?? ?? ?//Flash重置
    10. {

    11. ? ? int i;

    12. ??

    13. ? ? NF_nFCE_L();

    14. ? ? NF_CMD(0xFF);? ?? ?? ?? ?? ?? ?? ? //reset command

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

    16. ? ? NF_WAITRB();? ?? ?? ?? ?? ?? ?? ?? ?//wait 200~500us;

    17. ? ? NF_nFCE_H();

    18. }
    复制代码


    3)? ?? ?NAND设备的识别? ?? ?? ?? ?? ?? ???//#define ID_K9F1208U0M??0xec76
    1. static U16 NF_CheckId(void)? ?? ?? ?? ?? ?? ?? ?? ?? ? //Id 辨别
    2. {

    3. ? ? int i;

    4. ? ? U16 id;

    5. ? ?

    6. ? ? NF_nFCE_L();

    7. ? ? NF_CMD(0x90);

    8. ? ? NF_ADDR(0x0);

    9. ? ?

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

    11. ? ?

    12. ? ? id=NF_RDDATA()<<8;? ?? ?? ?? ?? ?? ?// Maker code(K9F1208U:0xec)

    13. ? ? id|=NF_RDDATA();? ?? ?? ?? ?? ?? ???// Devide code(K9F1208U:0x76)

    14. ? ?

    15. ? ? NF_nFCE_H();

    16. ? ? return id;

    17. }
    复制代码


    4)? ?? ?NAND 的擦操作
    1. static int NF_EraseBlock(U32 block)

    2. {

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

    4. ? ? int i;

    5. ? ? NF_nFCE_L();

    6. ? ?

    7. ? ? NF_CMD(0x60[q1] );? ?? ?? ?? ?? ?? ?? ?? ?? ? // Erase one block 1st command


    8. ? ? NF_ADDR(blockPage&0xff);? ?? ?? ?? ?? ???// Page number="0"

    9. ? ? NF_ADDR((blockPage>>8)&0xff);? ?

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


    11. ? ? NF_CMD(0xd0[q2] );? ?? ?? ?? ?? ?? ?? ?? ?? ?// Erase one blcok 2nd command

    12. ? ?

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


    14. ? ? NF_WAITRB();? ?? ?? ?? ?? ?? ?? ?? ?? ? // Wait tBERS max 3ms.

    15. ? ? NF_CMD(0x70);? ?? ?? ?? ?? ?? ?? ?? ?? ?// Read status command


    16. ? ? if (NF_RDDATA()&0x1)? ?? ?? ?? ?? ?? ???// Erase error

    17. ? ? {? ?

    18. ? ?? ???NF_nFCE_H();

    19. ? ? Uart_Printf("[ERASE_ERROR:block#=%d]\n",block);

    20. ? ?? ???return 0;

    21. ? ? }

    22. ? ? else

    23. ? ? {

    24. ? ?? ???NF_nFCE_H();

    25. ? ?? ???return 1;

    26. ? ? }

    27. }
    复制代码


    5)? ?? ?NAND 的读操作
    1. static int NF_ReadPage(U32 block,U32 page,U8 *buffer)? ?? ???//读Flash

    2. {

    3. ? ? int i;

    4. ? ? unsigned int blockPage;

    5. ? ? U8 ecc0,ecc1,ecc2;

    6. ? ? U8 *bufPt=buffer;

    7. ? ? U8 se[16];? ???

    8. ? ?

    9. ? ? page=page&0x1f;? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?//32页

    10. ? ? blockPage=(block<<5)+page;? ?? ?? ?? ?? ?? ?? ? //1Bolck包含32页

    11. ? ? NF_RSTECC();? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?// Initialize ECC

    12. ? ?

    13. ? ? NF_nFCE_L();? ?

    14. ? ? NF_CMD(0x00);? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ???// Read command

    15. ? ? NF_ADDR(0);? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ? // Column = 0

    16. ? ? NF_ADDR(blockPage&0xff);? ?? ?? ?? ?? ?? ?? ?? ?//

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

    18. ? ? NF_ADDR((blockPage>>16)&0xff);? ?? ?? ?? ?? ?? ?//


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

    20. ? ?

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

    22. ? ? for(i=0;i<512;i++)

    23. ? ? {

    24. ? ?? ???*bufPt++=NF_RDDATA();? ?? ?? ?? ?? ?? ?? ???// Read one page

    25. }

    26. /************************ECC校验***************************/

    27. ? ? ecc0=rNFECC0;? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?//利用2410自带的硬件ECC校验
    28. ? ? ecc1=rNFECC1;
    29. ? ? ecc2=rNFECC2;
    30. [q3]? ???for(i=0;i<16;i++)

    31. ? ? {

    32. ? ?? ???se[i]=NF_RDDATA();? ?? ?? ?? ?? ?? ?? ?? ???// Read spare array
    33. ? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ? //读页内冗余的16B
    34. ? ? }

    35. ? ?? ? NF_nFCE_H();? ?


    36. ? ? if(ecc0==se[0] && ecc1==se[1] && ecc2==se[2])? ?//未知使用哪一种软件规范?
    37. ? ? {? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ???//比较数据结果是否正确

    38. ? ? Uart_Printf("[ECC OK:%x,%x,%x]\n",se[0],se[1],se[2]);

    39. ? ?? ???return 1;

    40. ? ? }

    41. ? ? else

    42. ? ? {

    43. ? ? Uart_Printf("[ECC ERROR(RD):read:%x,%x,%x, reg:%x,%x,%x]\n",

    44. ? ?? ???se[0],se[1],se[2],ecc0,ecc1,ecc2);

    45. ? ?? ???return 0;

    46. ? ? }? ?? ?

    47. }
    复制代码



    6)? ?? ?NAND 的写操作
    1. static int NF_WritePage(U32 block,U32 page,U8 *buffer)? ?? ?? ?? ? //写Flash
    2. {

    3. ? ? int i;

    4. ? ? U32 blockPage=(block<<5)+page;

    5. ? ? U8 *bufPt=buffer;


    6. ? ? NF_RSTECC();? ?? ?? ?? ?? ?? ?? ?? ?? ?? ???// Initialize ECC

    7. ? ?

    8. ? ? NF_nFCE_L();

    9. ? ? NF_CMD(0x0[q4] );? ?? ?? ?? ?? ?? ?? ?? ?? ?? ???//?????\\Read Mode 1
    10. ? ? NF_CMD(0x80);? ?? ?? ?? ?? ?? ?? ?? ?? ?? ? // Write 1st command,数据输入

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

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

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

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


    15. ? ? for(i=0;i<512;i++)

    16. ? ? {

    17. ? ? NF_WRDATA(*bufPt++);? ?? ?? ?? ?? ?? ???// Write one page to NFM from buffer

    18. ? ? }??

    19. ? ?

    20. ? ? seBuf[0]=rNFECC0;

    21. ? ? seBuf[1]=rNFECC1;

    22. ? ? seBuf[2]=rNFECC2;

    23. ? ? seBuf[5]=0xff;? ?? ?? ?? ?? ?? ?? ?? ???// Marking good block

    24. ? ?

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

    26. ? ? {

    27. ? ? NF_WRDATA(seBuf[i]);? ?? ?? ?? ?? ?? ???// Write spare array(ECC and Mark)

    28. ? ? }??

    29. [q5]

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

    31. ? ?

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

    33. ? ? NF_WAITRB();? ?? ?? ?? ?? ?? ?? ?? ?? ? //wait tPROG 200~500us;



    34. ? ? NF_CMD(0x70);? ?? ?? ?? ?? ?? ?? ?? ?? ?// Read status command? ?

    35. ? ?

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

    37. ? ?

    38. ? ? if (NF_RDDATA()&0x1)? ?? ?? ?? ?? ?? ???// Page write error

    39. ? ? {? ?

    40. ? ?? ???NF_nFCE_H();

    41. ? ? Uart_Printf("[PROGRAM_ERROR:block#=%d]\n",block);

    42. ? ? return 0;

    43. ? ? }

    44. ? ? else

    45. ? ? {

    46. ? ?? ???NF_nFCE_H();

    47. ? ? #if (WRITEVERIFY==1)

    48. ? ? //return NF_VerifyPage(block,page,pPage);? ?

    49. ? ? #else

    50. ? ? return 1;

    51. ? ? #endif

    52. ? ? }

    53. }
    复制代码


    以下讨论一下NAND 设备上所支持的文件系统,大概现在有以下几种:

    A.? ?? ? JFFS2(没有坏块处理,支持大容量存储的时候需要消耗大量的内存,大量的随机访问降低了NAND设备的读取效率)和YAFFS(速度快,但不支持文件的压缩和解压)

    B.? ?? ? 支持DiskOnChip设备的TRUEFFS(True Flash File System). TRUEFFS是M-Systems公司为其产品DiskOnChip开发的文件系统,其规范并不开放。

    C.? ?? ? 由SSFDC(Solid State Floppy Disk Card)论坛定义的支持SM卡的DOS-FAT。SM卡的DOS-FAT文件系统是由SSFDC论坛定义的,但它必须用在标准的块设备上。

    对于大量用在各类存储卡上的NAND 设备而言,他们几乎都采用FAT文件系统,而在嵌入式操作系统下,还没有驱动程序可以直接让NAND设备采用文件系统,就技术角度来说,FAT文件系统不是很适合NAND设备,因为FAT文件系统的文件分区表需要不断地擦写,而NAND设备的只能有限次的擦写。


    ? ? 在上面已经很明显的提到,NAND设备存在坏块,为和上层文件系统接口,NAND设备的驱动程序必须给文件系统提供一个可靠的存储空间,这就需要ECC(Error Corection Code)校验,坏块标注、地址映射等一系列的技术手段来达到可靠存储目的。

    ? ? SSFDC软件规范中,详细定义了如何利用NAND设备每个页中的冗余信息来实现上述功能。这个软件规范中,很重要的一个概念就是块的逻辑地址,它将在物理上可能不连续、不可靠的空间分配编号,为他们在逻辑空间上给系统文件提供一个连续可靠的存储空间。

    表3给出了SSFDC规范中逻辑地址的标注方法。在系统初始化的时候,驱动程序先将所有的块扫描一遍,读出他们所对应的逻辑地址,并把逻辑地址和虚拟地址的映射表建好。系统运行时,驱动程序通过查询映射表,找到需要访问的逻辑地址所对应的物理地址然后进行数据读写。? ?? ?

    表3 冗余字节定义
    006.png


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

    表4??逻辑地址格式
    007.png


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

    2. {

    3. ? ? int i;

    4. ? ? unsigned int blockPage;

    5. ? ? U8 data;

    6. ? ?

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

    8. ? ?

    9. ? ? NF_nFCE_L();? ?

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

    11. ? ? NF_ADDR(517&0xf);? ?// Read the mark of bad block in spare array(M addr="5") [q6]

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

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

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


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

    16. ? ?

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

    18. ? ?

    19. ? ? data=NF_RDDATA();


    20. ? ? NF_nFCE_H();? ?


    21. ? ? if(data!=0xff)

    22. ? ? {

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

    24. ? ?? ???return 1;

    25. ? ? }

    26. ? ? else

    27. ? ? {

    28. ? ?? ???return 0;

    29. ? ? }

    30. }


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

    32. {

    33. ? ? int i;

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



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

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

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

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

    39. ? ?

    40. ? ? NF_nFCE_L();

    41. ? ? NF_CMD(0x50);? ?? ?? ?? ?? ?? ?? ?? ?? ?? ? //????
    42. ? ? NF_CMD(0x80);? ?? ?? ?? ?? ?? ?? ?? ?? ?? ? // Write 1st command

    43. ? ?

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

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

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

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

    48. ? ?

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

    50. ? ? {

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

    52. ? ? }


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

    54. ? ?

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


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

    57. ??

    58. ? ? NF_CMD(0x70);

    59. ? ?

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

    61. ? ?

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

    63. ? ? {? ?

    64. ? ?? ???NF_nFCE_H();

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

    66. ? ? }

    67. ? ? else

    68. ? ? {

    69. ? ?? ???NF_nFCE_H();

    70. ? ? }


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

    72. ? ? return 1;

    73. }


    74. int search_logic_block(void)? ?? ?? ?? ?? ?? ???//建立物理地址到逻
    75. //辑地址的映射表
    76. {

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

    78. ? ? U8 SE[16];

    79. ? ? for(i=0;i

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

    81. ? ? logic_number=0;

    82. ? ? space_nr=0;


    83. ? ? NF_nFCE_L();

    84. ? ? zone=BLOCK_NR/1024;? ?? ?? ?? ?? ?? ?? ?? ?? ???//确定NAND设备中zone

    85. //的个数


    86. ? ? for(zone_i=0;zone_i<>

    87. ? ? {

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

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

    90. ? ?? ???{

    91. ? ?? ?? ?? ?blockPage=((block+zone_i*1024)<<>

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

    93. ? ?? ???

    94. ? ?? ???NF_CMD(0x50);? ?? ?? ?? ?? ?? ?? ?? ?? ?? ? // 读取每个block内部第

    95. //0个Page内冗余的16个字节

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

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

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

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


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

    101. ? ?? ???for(i=0;i<16;i++)??se[i]=NF_RDDATA();? ?? ? // Write spare array

    102. ? ?? ???NF_WATIRB();


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

    104. ? ?? ?? ?? ?printk("\n\rphysic block %d is bad block\n\r",block);

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

    106. ? ?? ?? ?? ?printk("block address1:%d!=block address2 %d\n\r",se[7],se[12]);

    107. ? ?? ???else if((se[6][q10] &0xf8)==0x10)

    108. ? ?? ???{

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

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

    111. ? ?? ?? ?? ?if(lg2ph[logic_no]!=0xffff)? ?? ?? ?? ? //说明有2个block拥有相
    112. //同的逻辑地址
    113. ? ?? ?? ?? ?? ? printk("physical block %d and block %d have the same logic number %d\n",lg2ph[logic_no],block,logic_no);

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

    116. ? ?? ?? ?? ?logic_number++;? ?? ?? ?? ?? ?? ?? ?? ?

    117. ? ?? ???}

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

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

    120. ? ?? ???space_nr++;

    121. ? ?? ???}

    122. ? ?? ???}

    123. ? ? }

    124. ? ? printk("there are totally %d logic blocks\n\r",logic_number);

    125. ? ? NF_nFCE_H();

    126. ? ? return logic_number;

    127. }
    复制代码


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

    --------------------------------------------------------------------------------

    [q1]发出擦除命令

    [q2]确认并擦除

    [q3]2410处理器的功能

    [q4]为什么要有一个读取的命令???

    [q5]读取ECC并写入16字节中

    [q6]参看表3

    [q7]标记块状态??517字节

    [q8]块状态

    [q9]块逻辑地址1和块逻辑地址2

    [q10]块逻辑地址1
    该文章已有10人参与评论

    请发表评论

    全部评论

    查看全部评论>>

    扫描微信二维码

    查看手机版网站

    随时了解更新最新资讯

    .

    在线客服(服务时间 9:00~18:00)

    在线QQ客服
    .
    Email:9443120@qq.com
    移动电话:13011628855

    Powered by Intohard X1.0? 2001-2013 Inhdd Inc.( 鲁ICP备09029790号 )