第16课Nand Flash

1.简介

引导启动时,NAND FLASH存储器开始的4K字节将被加载到Steppingstone中并且执行加载到Steppingstone的引导代码。
通常引导代码会复制NAND FLASH的内容到SDRAM中,通过使用硬件ECC,有效地检查NAND FLASH的数据在赋值完成的基础上,将在SDRAM中执行主程序。
注:
    当自动引导启动期间,ECC不会去检测,所以,NAND FLASH的开始4KB不应当包含位相关的错误。

2.原理图

第16课Nand Flash_第1张图片

第16课Nand Flash_第2张图片

3.启动的引脚配置

第16课Nand Flash_第3张图片

第16课Nand Flash_第4张图片

4.操作原理

1.原理图上NAND FLASH和S3C2440之间只有数据线,怎么传输地址?
    DATA0~DATA7上既传输数据,又传输地址
        ALE为高电平时传输的是地址
        CLE为高电平时传输的是命令
        ALE,CLE都为低电平时传输的是数据
    RnB为高表示就绪,为低表示正忙
2.怎么操作NAND FLASH呢?
    根据NAND FLASH的芯片手册,一般的过程是:
        a.发出命令
            选中芯片
            CLE设为高电平
            在DATA0~DATA7上出输出命令值
        b.发出地址
            选中芯片
            ALE设为高电平
            在DATA0~DATA7上输出地址值
            发出一个写脉冲
        c.发出数据/读数据
            Ⅰ.发出数据
                选中芯片
                ALE,CLE设为低电平
                在DATA0~DATA7上输出数据值
                发出一个写脉冲
            Ⅱ.读数据
                选中芯片
                发出读脉冲
                读DATA0~DATA7的数据

第16课Nand Flash_第5张图片

第16课Nand Flash_第6张图片

5.ID与地址编码

第16课Nand Flash_第7张图片

第16课Nand Flash_第8张图片

第16课Nand Flash_第9张图片

第16课Nand Flash_第10张图片

1.选中芯片
2.发出命令 0x90
3.发出地址 0x00
4.读数据得到    0xEC
5.读数据得到device code  (DAh)
6.读数据得到             (10h)
7.读数据得到页大小,块大小(15h)
8.读数据得到             (44h)
9.退出读ID状态

6.读NAND FLASH

第16课Nand Flash_第11张图片

1.选中芯片
2.发出0x00命令
3.发出地址    col(低8bit)
4.发出地址    col(高)
5.发出地址    page(低)
6.发出地址    page(中)
7.发出地址    page(高)
8.发出命令0x30
9.wait_ready
10.读数据
11.退出读状态    

7.写NAND FLASH

第16课Nand Flash_第12张图片

1.选中芯片
2.发出0x80命令
3.发出地址    col(低8bit)
4.发出地址    col(高)
5.发出地址    page(低)
6.发出地址    page(中)
7.发出地址    page(高)
8.发出命令0x10
9.发出数据

8.擦除

第16课Nand Flash_第13张图片

擦除的最小单位(block)
1.选中芯片
2.发命令0x60
3.发出地址    page(低)
4.发出地址    page(中)
5.发出地址    page(高)
6.发命令0xD0
7.wait_ready

9.NAND FLASH的结构

第16课Nand Flash_第14张图片

1block = 64page
1page = 2048col
OOB为了解决Nand的位反转的缺点而存在的。
2k的page data CPU使用addr寻址。其后的64bit的OOB区CPU无法访问。
eg:
    CPU访问Nand Flash上的第2048位数据实际上是访问Page1的第0位

10.寄存器解析

NFCONF:Nand Flash配置寄存器
第16课Nand Flash_第15张图片

被用来设置NAND FLASH的时序参数TACLS、TWRH0、WERPH1、设置数据位宽;还有一些只读位,用来指示是否支持其他大型的页。

NFCONT: Nand Flash控制寄存器
第16课Nand Flash_第16张图片

被用来使能/禁止NAND FLASH控制器、使能/禁止控制引脚信号nFCE、初始化ECC。它还有一些其他功能,在一般的应用中用不到,比如锁定NAND FLASH

NFCMMD: 命令寄存器
第16课Nand Flash_第17张图片

NFADDR: 地址寄存器
第16课Nand Flash_第18张图片

NFDATA: 数据寄存器
第16课Nand Flash_第19张图片

只用到了低8位,读写此寄存器将对NAND FLASH的读数据、写数据操作

NFSTAT: 状态寄存器
第16课Nand Flash_第20张图片

只用到了[0]:0:buys    1:ready

11.代码实现

nand_flash.h

#ifndef _NAND_FLASH_H
#define _NAND_FLASH_H

extern void nand_init(void);
extern void nand_flash_test(void);

#endif  /*  _NAND_FLASH_H   */

nand_flash.c

#include "s3c2440_soc.h"
#include "my_printf.h"

void nand_init(void)
{
#define  TACLS   0
#define  TWRPH0  1
#define  TWRPH1  0
    /*设置NAND FLASH的时序*/
    NFCONF = (TACLS<<12) | (TWRPH0<<8) | (TWRPH1<<4);
    /*使能NAND FLASH控制器,初始化ECC,禁止片选*/
    NFCONT = (1<<4) | (1<<1) | (1<<0);
}

void nand_select(void)
{
    /*使能片选*/
    NFCONT &=~(1<<1);
}

void nand_deselect(void)
{
    /*禁止片选*/
    NFCONT |= (1<<1);
}

void nand_cmd(unsigned char cmd)
{
    volatile int i;
    NFCCMD = cmd;
    for(i=0; i<10; i++);
}

void nand_addr_byte(unsigned char addr)
{
    volatile int i;
    NFADDR = addr;
    for(i=0; i<10; i++);
}

unsigned char nand_data(void)
{
    return  NFDATA;
}

void nand_w_data(unsigned char val)
{
    NFDATA = val;
}


void wait_ready(void)
{
    while (!(NFSTAT & 1));
}

void nand_chip_id(void)
{ 
    unsigned char buf[5]={0};
    
    nand_select(); 
    nand_cmd(0x90);
    nand_addr_byte(0x00);

    buf[0] = nand_data();
    buf[1] = nand_data();   
    buf[2] = nand_data();
    buf[3] = nand_data();
    buf[4] = nand_data();   
    nand_deselect();    

    printf("maker   id  = 0x%x\n\r",buf[0]);
    printf("device  id  = 0x%x\n\r",buf[1]);    
    printf("3rd byte    = 0x%x\n\r",buf[2]);        
    printf("4th byte    = 0x%x\n\r",buf[3]);            
    printf("page  size  = %d kb\n\r",1  <<  (buf[3] & 0x03));   
    printf("block size  = %d kb\n\r",64 << ((buf[3] >> 4) & 0x03)); 
    printf("5th byte    = 0x%x\n\r",buf[4]);


}


void nand_read(unsigned int addr, unsigned char *buf, unsigned int len)
{
    int i = 0;
    int page = addr / 2048;
    int col  = addr & (2048 - 1);
    
    nand_select(); 

    while (i < len)
    {
        /* 发出00h命令 */
        nand_cmd(00);

        /* 发出地址 */
        /* col addr */
        nand_addr_byte(col & 0xff);
        nand_addr_byte((col>>8) & 0xff);

        /* row/page addr */
        nand_addr_byte(page & 0xff);
        nand_addr_byte((page>>8) & 0xff);
        nand_addr_byte((page>>16) & 0xff);

        /* 发出30h命令 */
        nand_cmd(0x30);

        /* 等待就绪 */
        wait_ready();

        /* 读数据 */
        for (; (col < 2048) && (i < len); col++)
        {
            buf[i++] = nand_data();         
        }
        if (i == len)
            break;

        col = 0;
        page++;
    }
    
    nand_deselect();    
}


int nand_erase(unsigned int addr, unsigned int len)
{
    int page = addr / 2048;
            
            /*  addr是page的起始地址,长度为一个page的长度 */

    if (addr & (0x1FFFF))
    {
        printf("nand_erase err, addr is not block align\n\r");
        return -1;
    }
    
    if (len & (0x1FFFF))
    {
        printf("nand_erase err, len is not block align\n\r");
        return -1;
    }
    
    nand_select(); 

    while (1)
    {
        page = addr / 2048;
        
        nand_cmd(0x60);
        
        /* row/page addr */
        nand_addr_byte(page & 0xff);
        nand_addr_byte((page>>8) & 0xff);
        nand_addr_byte((page>>16) & 0xff);

        nand_cmd(0xD0);

        wait_ready();

        len -= (128*1024);
        if (len == 0)
            break;
        addr += (128*1024);
    }
    
    nand_deselect();    
    return 0;
}

void nand_write(unsigned int addr, unsigned char *buf, unsigned int len)
{
    int page = addr / 2048;
    int col  = addr & (2048 - 1);
    int i = 0;

    nand_select(); 

    while (1)
    {
        nand_cmd(0x80);

        /* 发出地址 */
        /* col addr */
        nand_addr_byte(col & 0xff);
        nand_addr_byte((col>>8) & 0xff);
        
        /* row/page addr */
        nand_addr_byte(page & 0xff);
        nand_addr_byte((page>>8) & 0xff);
        nand_addr_byte((page>>16) & 0xff);

        /* 发出数据 */
        for (; (col < 2048) && (i < len); )
        {
            nand_w_data(buf[i++]);
        }
        nand_cmd(0x10);
        wait_ready();

        if (i == len)
            break;
        else
        {
            /* 开始下一个循环page */
            col = 0;
            page++;
        }
        
    }
    
    nand_deselect();    
}

void do_read_nand_flash(void)
{
    unsigned int addr;
    volatile unsigned char *p;
    int i, j;
    unsigned char c;
    unsigned char str[16];
    unsigned char buf[64];
    
    /* 获得地址 */
    printf("Enter the address to read: ");
    addr = get_uint();

    nand_read(addr, buf, 64);
    p = (volatile unsigned char *)buf;

    printf("Data : \n\r");
    /* 长度固定为64 */
    for (i = 0; i < 4; i++)
    {
        /* 每行打印16个数据 */
        for (j = 0; j < 16; j++)
        {
            /* 先打印数值 */
            c = *p++;
            str[j] = c;
            printf("%02x ", c);
        }

        printf("   ; ");

        for (j = 0; j < 16; j++)
        {
            /* 后打印字符 */
            if (str[j] < 0x20 || str[j] > 0x7e)  /* 不可视字符 */
                putchar('.');
            else
                putchar(str[j]);
        }
        printf("\n\r");
    }
}

void do_erase_nand_flash(void)
{
    unsigned int addr;
    
    /* 获得地址 */
    printf("Enter the address of sector to erase: ");
    addr = get_uint();

    printf("erasing ...\n\r");
    nand_erase(addr, 128*1024);
}


void do_write_nand_flash(void)
{
    unsigned int addr;
    unsigned char str[100];
    int i, j;
    unsigned int val;
    
    /* 获得地址 */
    printf("Enter the address of sector to write: ");
    addr = get_uint();

    printf("Enter the string to write: ");
    gets(str);

    printf("writing ...\n\r");
    nand_write(addr, str, strlen(str)+1);

}


void nand_flash_test(void)
{
    char c;

    while (1)
    {
        /* 打印菜单, 供我们选择测试内容 */
        printf("[s] Scan nand flash\n\r");
        printf("[e] Erase nand flash\n\r");
        printf("[w] Write nand flash\n\r");
        printf("[r] Read nand flash\n\r");
        printf("[q] quit\n\r");
        printf("Enter selection: ");

        c = getchar();
        printf("%c\n\r", c);

        /* 测试内容:
         * 1. 识别nand flash
         * 2. 擦除nand flash某个扇区
         * 3. 编写某个地址
         * 4. 读某个地址
         */
        switch (c)       
        {
            case 'q':
            case 'Q':
                return;
                break;
                
            case 's':
            case 'S':
                nand_chip_id();
                break;

            case 'e':
            case 'E':
                do_erase_nand_flash();
                break;

            case 'w':
            case 'W':
                do_write_nand_flash();
                break;

            case 'r':
            case 'R':
                do_read_nand_flash();
                break;
            default:
                break;
        }
    }
}

你可能感兴趣的:(第16课Nand Flash)