zoukankan      html  css  js  c++  java
  • NandFlash

     一、概述

    1、NandFlash 

      NAND结构能提供极高的单元密度,可以达到高存储密度,比如能达到256M,并且写入和擦除的速度也很快。应用NAND的困难在于flash的管理需要特殊的系统接口。

    2、NandFlash和NorFlash对比 

    Nor/Nand Flash 的差别
      Nor  Nand
    容量 1MB~32MB 16M~512MB
    XIP Yes No
    擦除 非常慢(5S) 快(3ms)
    慢        快
    可靠性 比较高,位反转的比例小于NandFlash的10% 比较低,位反转比较常见,必须有校验措施,比如TNR必须有坏块管理措施
    可擦除次数 10000~100000               100000~1000000
    生命周期     低于NandFlash的10%              是NorFlash的10倍以上    
    接口       与RAM接口相同                    I/O接口
    访问方法 随机访问 顺序访问
    易用性 容易 复杂
    主要用途 常用于保存代码和关键数据 用于保存数据
    价格 便宜

    二、NandFlash常见引脚

    1、输入输出(I/O0~I/O7)

      数据输入/输出

    2、芯片使能(Chip Enable,CE#)

      如果没有检测到CE信号,那么NAND器件就保持待机模式,不对任何控制信号作出响应
    3、写使能(Write Enable, WE#)

      WE#负责将数据、地址或指令写入NAND之中
    4.读使能(Read Enable, RE#)

      允许输出数据缓冲器。
    5.指令锁存使能(Command Latch Enable, CLE)

       当CLE为高时,在WE#信号的上升沿,指令被锁存到NAND指令寄存器中
    6.地址锁存使能(Address Latch Enable, ALE)

      当ALE为高时,在W6.地址锁存使能(Address Latch Enable, ALE)E#信号的上升沿,地址被锁存到NAND地址寄存器中
    7.就绪/忙(Ready/Busy, R/B#)

      如果NAND器件忙,R/B#信号将变低。该信号是漏极开路,需要采用上拉电阻

    三、NandFlash的物理结构

      以下内容皆以K9F2G08U0B为例进行说明。

    1、结构框图

    2、存储结构

    1 Page = (2K+64)Bytes

    1 Block = 64 Pages

           = (128K + 4K) Byte

    1 Device= 2048 Blocks

            = 128K Pages 

        = (256M + 8M)Byte

        =  2112 Mbits

    ECC

       Linux系统中,一般叫做OOB(Out Of Band)。NandFlash在操作过程中容易出错,为了保证数据的正确性,需要有检测和纠错机制,此机制被叫做EDC(Error Detection Code)/ECC(Error Code Correction, 或者 Error Checking and Correcting),因此设计了多余的区域,用于放置数据的校验值。

    3、地址序列

    A0~A11 页内寻址 不仅可以寻址到有效数据,还能寻址到校验区

    A12~A28 页寻址

    其中:

      A12~A17 块内页寻址

      A18~A28 块寻址

    、NandFlash相对于RAM使用的特殊性 

    NandFlash相对于RAM使用的特殊性

     

    RAM

    NandFlash

    读取/写入的叫法

    读取/写入

    读取/编程(Program)

    读取/写入的最小单位

    字节

    Page/

    擦除(Erase)操作的最小单位

    字节

    Block/块②

    擦除操作的含义

    将数据删除/全部写入0

    将整个块都擦除成全是1,也就是里面的数据都是0xFF

    对于写操作

    直接写即可

    在写数据之前,要先擦除,然后再写

    注:

    ①之所以将写操作叫做编程,是因为,flash 和之前的EPROMEEPROM继承发展而来,而之前的EEPROM(Electrically Erasable Programmable Read-Only Memory),往里面写入数据,就叫做编程Program,之所以这么称呼,是因为其对数据的写入,是需要用电去擦除/写入的,就叫做编程。

    ②对于目前常见的页大小是2K/4KNand Flash,其块的大小有128KB/256KB/512KB等。而对于Nor Flash,常见的块大小有64K/32K等。

    ③在写数据之前,要先擦除,内部就都变成0xFF了,然后才能写入数据,也就是将对应位由1变成0

    五、实验代码

    1、擦除操作

    /* *********************擦除函数*******************************
    参数说明:
             block        要擦除的块
    返回参数:
            0     擦除失败
            1    擦除成功
     */
    unsigned char EraseBlock(unsigned int block)
    {
        unsigned int blockpage = 0;
        blockpage = block << 6;
        /* 选中芯片 */
        nand_select_chip();     
        /* 发出WRITE0命令 */
        write_cmd(0x60);
        /* Write Address */
         NFADDR =  blockpage & 0xff;            /* Row Address A12~A19 */
        NFADDR = (blockpage >> 8) & 0xff;    /* Row Address A20~A27 */
        NFADDR = (blockpage >> 16) & 0x01;    /* Row Address A28 */       
        write_cmd(0xD0);
        wait_idle();     
        write_cmd(0x70);
        wait_idle();   
        if(read_data()&0x1)  // Page write error
        {
             /* 取消片选信号 */
            nand_deselect_chip();  
            return 0;
        } 
        else
        {
             /* 取消片选信号 */
            nand_deselect_chip();  
            return 1;
        }     
    }

    2、页读操作

    /* *********************页读函数*******************************
    参数说明:
             buf        存放读取数据的目的地址
             addr       从nandflash中读取数据的源地址
     */
    static unsigned char ReadPage(unsigned char * buf,unsigned int addr)
    {     
        int j; 
        if (addr & NAND_BLOCK_MASK) {
            return 0;    /* 地址或长度不对齐 */
        }
        /* 选中芯片 */
        nand_select_chip();    
         
        /* 发出READ0命令 */
        write_cmd(0);
        /* Write Address */
        write_addr(addr); 
        write_cmd(0x30);    
        wait_idle();
          
        for(j=0;j < NAND_SECTOR_SIZE; j++) { 
            *buf = read_data();
            buf++;    /*i每经过一个大循环就增加NAND_SECTOR_SIZE*/
        }
        /* 取消片选信号 */
        nand_deselect_chip();    
        return 1;
    }

    3、页写操作

    /* *********************页写函数*******************************
    参数说明:
             buf        源地址
             addr       写入nandflash的目的地址
     */
    static unsigned char WritePage(unsigned char * buf,unsigned int addr)
    {     
        unsigned int i = 0; 
        if (addr & NAND_BLOCK_MASK) {
            return 0;    /* 地址或长度不对齐 */
        }
        /* 选中芯片 */
        nand_select_chip();     
        /* 发出WRITE0命令 */
        write_cmd(0x80);
        /* Write Address */
        write_addr(addr);      
        /* Write Data */               
        for(i=0;i<2048;i++)
        {
            write_data(*buf);  
            buf++;
        }
        write_cmd(0x10);
        wait_idle();     
        write_cmd(0x70);
        wait_idle();   
        if(read_data()&0x1)  // Page write error
        {
             /* 取消片选信号 */
            nand_deselect_chip();  
            return 0;
        } 
        else
        {
             /* 取消片选信号 */
            nand_deselect_chip();  
            return 1;
        }     
    }

    4、打印页内容(调试用)

    /* *********************打印出指定地址的一个页的内容********************
     */
    void nand_printf()
    {   unsigned int i;
        unsigned char block=0, page=0;
        unsigned char * downPt;    
        downPt=(unsigned char *)_NONCACHE_STARTADDRESS;
        
        printf("
    
    K9F2G08 NAND Page Read.
    ");
        printf("
    Block # to read: ");
        block = getc()-48;
        printf("%d
    
    ", block);
        printf("
    Page # to read: ");
        page = getc()-48;
        printf("%d
    
    ", page);    
     
        if(ReadPage(downPt,((block<<6)+page)<<11)==0) {
            printf("
    Read error.
    ");
        } else {
            printf("
    Read OK.
    ");
        }
        // Print data.
        printf("Read data(%d-block,%d-page)
    ", block, page);
        
        for(i=0; i<2048; i++) {
            if((i%16)==0) printf("
    
    %4x: ", i);
            printf("%02x ", *downPt++);
            }
        printf("
    ");
    }

     5、发送地址函数

    static void write_addr(unsigned int addr)
    {
        int i; 
        unsigned int col, page;
    
        col = addr & NAND_BLOCK_MASK;
        page = addr / NAND_SECTOR_SIZE;
     
        NFADDR = col & 0xff;            /* Column Address A0~A7 */    
        for(i=0; i<10; i++);  
        
        NFADDR = (col >> 8) & 0x0f;     /* Column Address A8~A11 */
        for(i=0; i<10; i++);
        
        NFADDR = page & 0xff;            /* Row Address A12~A19 */
        for(i=0; i<10; i++);  
        
        NFADDR = (page >> 8) & 0xff;    /* Row Address A20~A27 */
        for(i=0; i<10; i++); 
        
        NFADDR = (page >> 16) & 0x01;    /* Row Address A28 */
        for(i=0; i<10; i++);  
    }

      着重强调一下,“for(i=0; i<10; i++); ”延时代码绝不能省略。笔者发现,当S3C2440的主频在12MHz时,如果没有延时代码,NandFlash发送地址还能正常工作;一旦主频在400MHz,没有延时代码,地址就不能正常发送。

    参考资料:如何编写linux下nand flash驱动-1

                  nandflash内存详解

    附:实现NandFlash程序下载的代码(nand.zip

  • 相关阅读:
    lnmp环境搭建
    Git常用命令
    博客园写随笔环境搭建
    Win常用软件
    Docker环境搭建
    ESP-8266 RTOS 环境搭建
    查看Linux信息
    博客园markdown语法
    Java后台技术(TDDL)
    Java后台技术(Dubbo入门)
  • 原文地址:https://www.cnblogs.com/amanlikethis/p/3514450.html
Copyright © 2011-2022 走看看