zoukankan      html  css  js  c++  java
  • S5PV210 NAND Flash

    NAND Flash

    关于NAND Flash
    S5PV210的NAND Flash控制器有如下特点:
    1) 支持512byte,2k,4k,8k的页大小
    2) 通过各种软件模式来进行NAND Flash的读写擦除等
    3) 8bit的总线
    4) 支持SLC和MCL的NAND Flash
    5) 支持1/4/8/12/16bit的ECC
    6) 支持以字节/半字/字为单位访问数据/ECC寄存器,以字为单位访问其他寄存器。
    注意:在此使用的Mini210S的NAND Flash类型为SLC,大小为1G,型号为K9K8G08U0A。所以本章的内容是针对SLC类型的NAND Flash(包括256M/512M/1GB等),并不适用MLC类型的NAND Flash。

    程序例子:(完整代码见链接)
    代码多了nand.c这个文件,里面包含了对NAND Flash的相关操作。
    /*nand.c*/
    <1> NAND Flash初始化函数nand_init(),代码如下
    void nand_init(void)
    {
    // 1. 配置NAND Flash
    NFCONF = (TACLS<<12)|(TWRPH0<<8)|(TWRPH1<<4)|(0<<3)|(0<<2)|(1<<1)|(0<<0);
    NFCONT =(0<<18)|(0<<17)|(0<<16)|(0<<10)|(0<<9)|(0<<8)|(0<<7)|(0<<6)|(0x3<<1)|(1<<0);
    // 2. 配置引脚
    MP0_1CON = 0x22333322;
    MP0_2CON = 0x00002222;
    MP0_3CON = 0x22222222;
    // 3. 复位
    nand_reset();
    }
    共3个步骤:
    第一步 配置NAND Flash
    主要是设置NFCONF和NFCONT两个寄存器

    image

    NFCONF寄存器

    AddrCycle = 1,When page size is 2K or 4K, 1 = 5 address cycle,Mini210S的NAND Flash的页大小为2k,所有是5个地址周期;
    PageSize = 0,When MLCFlash is 0, the value of PageSize is as follows: 0 = 2048 Bytes/page,Mini210S使用的是SLC NAND Flash且每页大小为2k;
    MLCFlash = 0,在此使用的是SLC NAND Flash;
    TWRPH1/TWRPH0/TACLS是关于访问时序的设置,需对照NAND Flash芯片手册设置,这里不再详细解释,分别取TWRPH1=1,TWRPH0=4,TACLS=1;
    ECCType0/MsgLength,我们的裸机代码没有使用到ECC,所有不用设置这两个标志。

    image

    image

    MODE = 1,使能NAND Flash控制器;
    Reg_nCE0 = 1,取消片选,需要操作NAND Flash时再发片选;
    Reg_nCE1 = 1, 取消片选,需要操作NAND Flash时再发片选;
    InitMECC/InitSECC/SECCLock/MECCLock,我们的裸机代码不涉及ECC,这4个标志位随便设置即可;
    RnB_TransMode = 0,Detect rising edge,RnB是NAND Flash的状态探测引脚,我们使用上升沿触发;
    EnbRnBINT = 0 ,禁止RnB中断;
    EnbIllegalAccINT = 0,禁止Illegal access 中断 ;
    EnbMLCDecInt/EnbMLCEncInt为MCL相关,不用设置;
    LOCK = 0,我们没有用到Soft Lock,所以禁止Soft Lock;
    LockTight = 0,我们没有用到Lock-tight,所有禁止Lock-tight;
    MLCEccDirection,MLC相关,可不用设置
    第二步 配置引脚
    用于NAND Flash相关功能;
    第三步 复位
    复位函数nand_reset的相关代码如下:
    static void nand_reset(void)
    {
        nand_select_chip();
        nand_send_cmd(NAND_CMD_RES);
        nand_wait_idle();
        nand_deselect_chip();
    }
    NAND Flash的复位操作共4个步骤:
    1) 发片选,实质就是NFCONT &= ~(1<<1);往NFCONT的bit[1]写0;
    2) 发命令复位命令NAND_CMD_RES (0xff);实质就是NFCMMD = cmd;将命令写到NFCMMD寄存器;完整的NAND Flash命令信息见下图:

    image

    3) 等待NAND Flash 就绪;实质就是while( !(NFSTAT & (BUSY<<4)) ),读NFSTAT的bit[4]检查NAND Flash是否就绪;
    4) 取消片选,实质就是NFCONT |= (1<<1); 往NFCONT的bit[1]写1;

    <2> NAND Flash读ID函数nand_read_id(),代码如下
    void nand_read_id(void)
    {
    nand_id_info nand_id;
    // 1. 发片选
    nand_select_chip();
    // 2. 读ID
    nand_send_cmd(NAND_CMD_READ_ID);
    nand_send_addr(0x00);
    nand_wait_idle();
    nand_id.IDm = nand_read();
    nand_id.IDd = nand_read();
    nand_id.ID3rd = nand_read();
    nand_id.ID4th = nand_read();
    nand_id.ID5th = nand_read();
    printf("NANDFlash: makercode = %x,devicecode = %x ",nand_id.IDm,nand_id.IDd);
    nand_deselect_chip();
    }

    image

    NAND Flash 读ID操作

    根据上图,NAND Flash的读ID操作共4个步骤:
    第一步 发片选;
    第二步 发读ID命令NAND_CMD_READ_ID(0x90);
    第三步 发地址0x00;调用函数nand_send_addr();
    第四步 等待NAND Flash 就绪;
    第五步 读ID;调用了nand_read()函数,实质就是读NFDATA寄存器;
    下面解释一下函数nand_send_addr(),核心代码如下:
    {
    // 列地址,即页内地址
    col = addr % NAND_PAGE_SIZE;
    // 行地址,即页地址
    row = addr / NAND_PAGE_SIZE;
    // Column Address A0~A7
    NFADDR = col & 0xff;
    for(i=0; i<10; i++);
    // Column Address A8~A11
    NFADDR = (col >> 8) & 0x0f;
    for(i=0; i<10; i++);
    // Row Address A12~A19
    NFADDR = row & 0xff;
    for(i=0; i<10; i++);
    // Row Address A20~A27
    NFADDR = (row >> 8) & 0xff;
    for(i=0; i<10; i++);
    // Row Address A28~A30
    NFADDR = (row >> 16) & 0xff;
    for(i=0; i<10; i++);
    }
    首先根据页大小来获取页地址和页内偏移地址,然后通过5个周期将地址发送出去,实质就是写NFADDR寄存器,具体每个周期如何发送,查阅NAND Flash芯片手册可知,见下图:

    image

    发送地址后,就可以连续读出5个ID了,其中第一个是MAKDER CODE, 第二个是DEVICE CODE。

    <3> NAND Flash擦除函数nand_erase(),核心代码如下:
    {
    // 获得row地址,即页地址
    unsigned long row = block_num * NAND_BLOCK_SIZE;
    // 1. 发出片选信号
    nand_select_chip();
    // 2. 擦除:第一个周期发命令0x60,第二个周期发块地址,第三个周期发命令0xd0 nand_send_cmd(NAND_CMD_BLOCK_ERASE_1st);
    for(i=0; i<10; i++);
    // Row Address A12~A19
    NFADDR = row & 0xff;
    for(i=0; i<10; i++);
    // Row Address A20~A27
    NFADDR = (row >> 8) & 0xff;
    for(i=0; i<10; i++);
    // Row Address A28~A30
    NFADDR = (row >> 16) & 0xff;
    NFSTAT = (NFSTAT)|(1<<4);
    nand_send_cmd(NAND_CMD_BLOCK_ERASE_2st);
    for(i=0; i<10; i++);
    // 3. 等待就绪
    nand_wait_idle();
    // 4. 读状态
    unsigned char status = read_nand_status();
    }

    image

    根据上图,NAND Flash的擦除操作共6个步骤:
    第一步 发片选;
    第二步 发擦除命令1 NAND_CMD_BLOCK_ERASE_1(0x60);
    第三步 发页地址,只需发页地址;
    第四步 发擦除命令2 NAND_CMD_BLOCK_ERASE_2st(0xD0);
    第五步 等待NAND Flash就绪;
    第六步 读状态,判断擦除是否成功。若擦除失败,则打印是坏块再取消片选;否则直接直接取消片选即可。读状态调用了函数read_nand_status(),它的实质就是nand_send_cmd(NAND_CMD_READ_STATUS);ch = nand_read();先发读状态命令NAND_CMD_READ_STATUS,然后再读状态值。   

    <4> NAND Flash读函数copy_nand_to_sdram(),从NAND Flash中读数据到DRAM,核心代码如下:
    {
    // 1. 发出片选信号 nand_select_chip();
    // 2. 从nand读数据到sdram,第一周期发命令0x00,第二周期发地址nand_addr,第三个周期发命令0x30,可读一页(2k)的数据
    while(length)
    {
    nand_send_cmd(NAND_CMD_READ_1st);
    nand_send_addr(nand_addr);
    NFSTAT = (NFSTAT)|(1<<4);
    nand_send_cmd(NAND_CMD_READ_2st);
    nand_wait_idle();
    // 列地址,即页内地址
    unsigned long col = nand_addr % NAND_PAGE_SIZE;
    i = col;
    // 读一页数据,每次拷1byte,共拷2048次(2k),直到长度为length的数据拷贝完毕
    for(; i<NAND_PAGE_SIZE && length!=0; i++,length--)
    {
    *sdram_addr = nand_read();
    sdram_addr++; nand_addr++;
    }
    }
    // 3. 读状态
    unsigned char status = read_nand_status();
    }

    image

    NAND Flash 读操作

    根据上图,NAND Flash的读操作共7个步骤:
    第一步 发片选;
    第二步 发读命令1 NAND_CMD_READ_1st(0x00);
    第三步 发地址,调用函数nand_send_cmd(),发5个地址周期;
    第四步 发读命令2 NAND_CMD_READ_2st(0xD0);
    第五步 等待NAND Flash就绪;
    第六步 从页内偏移地址开始读,读到页结尾即结束,每次读1byte;
    第七步 读状态,判断是否读成功。

    <5> NAND Flash写函数copy_sdram_to_nand (),从DRAM写数据到NAND Flash,核心代码如下:
    {
    // 1. 发出片选信号
    nand_select_chip();
    // 2. 从sdram读数据到nand,第一周期发命令0x80,第二周期发地址nand_addr,第三个周期写一页(2k)数据,第四周期发0x10
    while(length)
    {
    nand_send_cmd(NAND_CMD_WRITE_PAGE_1st);
    nand_send_addr(nand_addr);
    // 列地址,即页内地址
    unsigned long col = nand_addr % NAND_PAGE_SIZE;
    i = col;
    // 写一页数据,每次拷1byte,共拷2048次(2k),直到长度为length的数据拷贝完毕
    for(; i<NAND_PAGE_SIZE && length!=0; i++,length--)
    {
    nand_write(*sdram_addr);
    sdram_addr++;
    nand_addr++;
    }
    NFSTAT = (NFSTAT)|(1<<4);
    nand_send_cmd(NAND_CMD_WRITE_PAGE_2st);
    nand_wait_idle();
    }
    // 3. 读状态
    unsigned char status = read_nand_status();

    }

    image

    根据上图,NAND Flash的写操作共7个步骤:
    第一步 发片选;
    第二步 发写命令1 NAND_CMD_WRITE_PAGE_1st (0x80);
    第三步 发地址地址,调用函数nand_send_cmd(),发5个地址周期;
    第四步 发读命令2 NAND_CMD_WRITE_PAGE_2st (0x10);
    第五步 等待NAND Flash就绪;
    第六步 从页内偏移地址开始写,读到页结尾即结束,每次写1byte;
    第七步 读状态,判断是否读成功。

    2. main.c
    在main.c中,首先会调用nand_init()来初始化NAND Flash,然后打印一个菜单,提供4种选择测试NAND Flash:
    读ID功能(nand_read_id());
    擦除功能(nand_erase());
    读功能(copy_nand_to_sdram());
    写功能(copy_sdram_to_nand());

    完整代码下载链接:http://download.csdn.net/detail/klcf0220/5636167

  • 相关阅读:
    mojo 接口示例
    MojoliciousLite: 实时的web框架 概述
    接口返回json
    centos 6.7 perl 版本 This is perl 5, version 22 安装DBI DBD
    centos 6.7 perl 5.22 安装DBD 需要使用老的perl版本
    商业智能改变汽车行业
    商业智能改变汽车行业
    读MBA经历回顾(上)目的决定手段——北漂18年(48)
    perl 升级到5.20版本
    Group Commit of Binary Log
  • 原文地址:https://www.cnblogs.com/klcf0220/p/3151335.html
Copyright © 2011-2022 走看看