• 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

  • 相关阅读:
    LeetCode173. 二叉搜索树迭代器
    LeetCode172. 阶乘后的零
    电商系统 SKU 设计和优化2
    电商系统 SKU 设计和优化
    JQuery/JS插件 排列组合 前端实现
    开源框架 码云 推荐项目
    Java idea 打包 编码问题 解决
    Java 基础 MyBatis-Plus 组装查询条件
    Java 基础 list 排序
    Java 基础 list 查询 ids
  • 原文地址:https://www.cnblogs.com/klcf0220/p/3151335.html
Copyright © 2020-2023  润新知