基于smdk2410 开发板u-boot-1.2.0 nand flash读写操作及其命令的实现

来源:互联网 发布:网络控制器 编辑:程序博客网 时间:2024/06/06 06:30
基于smdk2410开发板u-boot-1.2.0 nand flash读写操作及其命令的实现(1)2007-07-20 16:12:46

分类:

基于smdk2410开发板u-boot-1.2.0 nand flash读写操作及其命令的实现

 

1.    前言

对于一个完整的嵌入式系统,除了cpu、电源、晶振以外,存储器是必不可少的。以前存储器都是用可读写操作的EEPROM系列芯片,由于其暴露出来的缺陷,读写操作复杂,缓慢等原因,随着Nor Flash1988年由Inter公司开发出来,存储器的市场开始被Nor Flash掌控。Nor Flash凭借读写操作简单,不需要额外的驱动就可以实现读写功能,雄霸存储器市场。但是其最大的缺点就是价格太高。也许正是由于日本人看到了Nor Flash的软肋,日立公司于1989年打着“提高每一笔特性价比”的旗号,推出了Nand Flash。尽管Nand Flash的读写操作相对于Nor Flash要复杂一些但是,其海量存储和低廉的价格还是让各大开发商趋之若鹜。随着嵌入式市场对于大容量存储器需求的增长,Nand Flash必将有更大的发展空间。

 

2.    Nand Flash VS Nor Flash

网上有很多比较的文档。偷下懒:)

 

3.    Nand Flashu-boot的读写实现

首先,我们来看一下三星S3C2410用户手册中对nand flash的描述。

手册中把nand flash的工作模式分为两种:自启动模式和一般的nand flash读写操作模式。在自启动模式下,由于nand flash自身的特点不能够直接在芯片内部执行程序,因此在在cpu内核中内置了一片SRAM配合nand flash实现自启动系统。系统加电,nand flash存储空间的前4kB数据(也就是u-boot第一阶段)以硬件的方式被拷贝到SRAM中;然后SRAM中的u-boot代码开始执行,运行到第二阶段把nand flashu-boot的全部拷贝到SDRAM中继续执行,然后引导内核的启动和根文件系统的挂载。

对于nand flash的基本读写操作模式,主要是关于nand flash的读写操作。我们可以知道,在S3C2410cpunand flash看作一个外设,通过nand flash控制器控制nand flash。对其的读写操作都是通过向特定的寄存器中读写数据实现的。下面是在手册中切下来的两张图。

图表 1 nand flash 控制器的块状图

 

图表 2 nand flash操作原理图

 

3.1. Nand flash 读写模式下的寄存器

NFCONF : nand flash的配置寄存器

NFCMD : nand flash命令寄存器,cpu通过此寄存器向nand flash传递控制命令

NFADDR : nand flash地址寄存器,cpu通过此寄存器向nand flash传递地址

NFDATA : nand flash数据寄存器,cpu通过此寄存器向nand flash传递数据

NFSTAT : nand flash状态寄存器,cpu通过读取该寄存器获取nand flash当前状态

NFECC : nand flash ECC寄存器,实现循环校验功能

 

Nand flash读写模式下的管脚配置

D[7:0] :数据/命令/地址输入/输出端口(三线共享)

CLE :   Command Latch Enable   (output)

ALE :   Address Latch Enable     (output)

nFCE :  NAND Flash Chip Enable  (output)

nFRE :  NAND Flash Read Enable  (output)

nFWE :  NAND Flash Write Enable  (output)

R/nB :   NAND Flash Ready/nBusy  (input)

 

:各寄存器的每个比特的具体含义不再赘述,参看S3C2410手册。

 

3.2. u-boot-1.2.0nand flash读写操作源码分析

3.2.1.涉及文件

Lib_arm/board.c

Board/smdk2410/smdk2410.c

Board/smdk2410/smdk2410.h

Driver/Nand_legacy/ Nand_legacy.c

Include/configs/smdk2410.h

 

3.2.2.具体分析

Lib_arm/board.c

u-boot运行至第二阶段进入start_armboot()函数。其中nand_init()函数是对nand flash的最初初始化函数。Nand_init()函数在两个文件中实现。其调用与CFG_NAND_LEGACY宏有关,如果没有定义这个宏,系统调用drivers/nand/nand.c中的nand_init();否则调用自己在board/smdk2410/smdk2410.c中的nand_init()函数。这里我们选择第二种方式。

 

Board/smdk2410/smdk2410.h

 

这个头文件中实现了对nand flash各个寄存器的设置工作。把原程序列出来更直观些。

 

static inline void NF_Conf(u16 conf)   /*控制寄存器设置 */

{

       S3C2410_NAND * const nand = S3C2410_GetBase_NAND();

 

       nand->NFCONF = conf;

}

 

static inline void NF_Cmd(u8 cmd)   /*命令寄存器传递命令 */

{

       S3C2410_NAND * const nand = S3C2410_GetBase_NAND();

 

       nand->NFCMD = cmd;

}

 

static inline void NF_CmdW(u8 cmd)   /*命令寄存器写操作 */

{

       NF_Cmd(cmd);

       udelay(1);

}

 

static inline void NF_Addr(u8 addr)    /*地址寄存器设置 */

{

       S3C2410_NAND * const nand = S3C2410_GetBase_NAND();

 

       nand->NFADDR = addr;

}

 

static inline void NF_SetCE(NFCE_STATE s)   /*设置nand flash的片选信号 */

{

       S3C2410_NAND * const nand = S3C2410_GetBase_NAND();

 

       switch (s) {

              case NFCE_LOW:

                     nand->NFCONF &= ~(1<<11);

                     break;

 

              case NFCE_HIGH:

                     nand->NFCONF |= (1<<11);

                     break;

       }

}

 

static inline void NF_WaitRB(void)     /*等待 nand flash处于 Ready状态 */

{

       S3C2410_NAND * const nand = S3C2410_GetBase_NAND();

 

       while (!(nand->NFSTAT & (1<<0)));

}

 

static inline void NF_Write(u8 data)    /*写数据操作 */

{

       S3C2410_NAND * const nand = S3C2410_GetBase_NAND();

 

       nand->NFDATA = data;

}

 

static inline u8 NF_Read(void)   /*读数据操作 */

{

       S3C2410_NAND * const nand = S3C2410_GetBase_NAND();

 

       return(nand->NFDATA);

}

 

static inline void NF_Init_ECC(void)  /*初始化ECC */

{

       S3C2410_NAND * const nand = S3C2410_GetBase_NAND();

 

       nand->NFCONF |= (1<<12);

}

 

static inline u32 NF_Read_ECC(void)  /*读取ECC */

{

       S3C2410_NAND * const nand = S3C2410_GetBase_NAND();

 

       return(nand->NFECC);

}

 

Board/smdk2410/smdk2410.c

前面提到了nand_init()函数的实现就是在smdk2410.c中,下面我们就来看看nand flash是怎么初始化的。

 

void

nand_init(void)

{

       S3C2410_NAND * const nand = S3C2410_GetBase_NAND();

 

       NF_Init();      

#ifdef DEBUG

       printf("NAND flash probing at 0x%.8lX\n", (ulong)nand);

#endif

       printf ("%4lu MB\n", nand_probe((ulong)nand) >> 20);

}

 

static inline void NF_Init(void)

{

#if 0 /* a little bit too optimistic */

#define TACLS   0

#define TWRPH0  3

#define TWRPH1  0

#else

#define TACLS   0

#define TWRPH0  4

#define TWRPH1  2

#endif

 

    NF_Conf((1<<15)|(0<<14)|(0<<13)|(1<<12)|(1<<11)|(TACLS<<8)|(TWRPH0<<4)|(TWRPH1<<0));

    /*nand->NFCONF = (1<<15)|(1<<14)|(1<<13)|(1<<12)|(1<<11)|(TACLS<<8)|(TWRPH0<<4)|(TWRPH1<<0); */

    /* 1  1    1     1,   1      xxx,  r xxx,   r xxx */

    /* En 512B 4step ECCR nFCE=H tACLS   tWRPH0   tWRPH1 */

 

    NF_Reset();

}

 

 

static inline void NF_Reset(void)

{

    int i;

 

    NF_SetCE(NFCE_LOW);

    NF_Cmd(0xFF);           /* reset command */

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

    NF_WaitRB();        /* wait 200~500us; */

    NF_SetCE(NFCE_HIGH);

}

 

可以看到nand_init()调用 NF_Init()函数,使能nand flash控制器和nand flash;调用NF_Reset()函数置位,NF_WaitRB()查询nand flash的状态,最后在调用nand_probe((ulong)nand)函数探测nand flash.

 

Driver/Nand_legacy/ Nand_legacy.c

这个文件中对nand flash操作的函数被u-bootnand flash 操作的命令函数(do_nand())调用, 这些nand flash操作的函数调用具体的nandflash的读写操作的函数--由开发人员实现。这样nand_legacy.c中的nand flash操作函数向开发人员在uboot的nand flash操作命令和具体的nand flash硬件驱动之间提供一个接口。这个接口一般定义在开发板的config文件中也就是 include/configs/xxxxx.h.

注意:如果有些接口功能被硬件完成,可以定义一个空宏实现。

 

 

do_nand()->| ->WRITE_NAND_COMMAND(d, adr)             | ->NF_Cmd(d)

                       | ->WRITE_NAND_COMMANDW(d, adr)          |  ->NF_CmdW(d)

                       | ->WRITE_NAND_ADDRESS(d, adr)                 | ->NF_Addr(d)

                       | ->WRITE_NAND(d, adr)                                     | ->NF_Write(d)

                       | ->READ_NAND(adr)                                           | ->NF_Read()

                       | /* the following functions are NOP's because           |

                       |S3C24X0 handles this in hardware*/                        |

                       | ->NAND_CTL_CLRALE(nandptr)                      |

                       | ->NAND_CTL_SETALE(nandptr)                       |

                       | ->NAND_CTL_CLRCLE(nandptr)                      |

                       | ->NAND_CTL_SETCLE(nandptr)                       |

 

更详细的表述:


 

 

 

eg:

 

Include/configs/smdk2410.h

此文件中主要是对nand flash相关的一些参数进行设置。贴出来看下,有些感性的认识。

/*-----------------------------------------------------------------------

 * NAND flash settings

 */

#if (CONFIG_COMMANDS & CFG_CMD_NAND)

 

#define CFG_NAND_LEGACY

#define CFG_MAX_NAND_DEVICE   1     /* Max number of NAND devices        */

#define SECTORSIZE 512

 

#define ADDR_COLUMN 1

#define ADDR_PAGE 2

#define ADDR_COLUMN_PAGE 3

 

#define NAND_ChipID_UNKNOWN   0x00

#define NAND_MAX_FLOORS 1

#define NAND_MAX_CHIPS 1

 

#define NAND_WAIT_READY(nand)   NF_WaitRB()

 

#define NAND_DISABLE_CE(nand)    NF_SetCE(NFCE_HIGH)

#define NAND_ENABLE_CE(nand)     NF_SetCE(NFCE_LOW)

 

 

#define WRITE_NAND_COMMAND(d, adr)      NF_Cmd(d)

#define WRITE_NAND_COMMANDW(d, adr)   NF_CmdW(d)

#define WRITE_NAND_ADDRESS(d, adr) NF_Addr(d)

#define WRITE_NAND(d, adr)            NF_Write(d)

#define READ_NAND(adr)                 NF_Read()

/* the following functions are NOP's because S3C24X0 handles this in hardware */

#define NAND_CTL_CLRALE(nandptr)

#define NAND_CTL_SETALE(nandptr)

#define NAND_CTL_CLRCLE(nandptr)

#define NAND_CTL_SETCLE(nandptr)

 

#define CONFIG_MTD_NAND_VERIFY_WRITE     1

#define CONFIG_MTD_NAND_ECC_JFFS2      1

 

#endif     /* CONFIG_COMMANDS & CFG_CMD_NAND */

 

 

 

 

 

3.3.  小结

按照上面文件修改就可以实现对nand flash的读写操作。笔者的能够这么顺利的实现移植主要是和一同事kyo无意中发现一块板Vcam9smdk2410一样都是基于S3C2410,而且实现了nand flash读写操作,遂借鉴之。:)

 

0 0