基于smdk2410 开发板u-boot-1.2.0 nand flash读写操作及其命令的实现
2014-05-08 12:20
579 查看
基于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
Flash于1988年由Inter
公司开发出来,存储器的市场开始被Nor Flash掌控。Nor Flash凭借读写操作简单,不需要额外的驱动就可以实现读写功能,雄霸存储器市场。但是其最大的缺点就是价格太高。也许正是由于日本人看到了Nor Flash的软肋,日立公司于1989年打着“提高每一笔特性价比”的旗号,推出了Nand
Flash。尽管Nand Flash的读写操作相对于Nor Flash要复杂一些但是,其海量存储和低廉的价格还是让各大开发商趋之若鹜。随着嵌入式市场对于大容量存储器需求的增长,Nand Flash必将有更大的发展空间。
2.
网上有很多比较的文档。偷下懒:)
3.
首先,我们来看一下三星S3C2410用户手册中对nand flash的描述。
手册中把nand flash的工作模式分为两种:自启动模式和一般的nand flash读写操作模式。在自启动模式下,由于nand flash自身的特点不能够直接在芯片内部执行程序,因此在在cpu内核中内置了一片SRAM配合nand
flash实现自启动系统。系统加电,nand flash存储空间的前4kB数据(也就是u-boot第一阶段)以硬件的方式被拷贝到SRAM中;然后SRAM中的u-boot代码开始执行,运行到第二阶段把nand
flash中u-boot的全部拷贝到SDRAM中继续执行,然后引导内核的启动和根文件系统的挂载。
对于nand flash的基本读写操作模式,主要是关于nand flash的读写操作。我们可以知道,在S3C2410中cpu将nand
flash看作一个外设,通过nand flash控制器控制nand flash。对其的读写操作都是通过向特定的寄存器中读写数据实现的。下面是在手册中切下来的两张图。
图表 1 nand flash
控制器的块状图
图表 2 nand flash操作原理图
3.1.
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.
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-boot
nand 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 */
同smdk2410一样都是基于S3C2410,而且实现了nand flash读写操作,遂借鉴之。:)
2007-07-20 16:12:46
分类:
基于smdk2410
开发板u-boot-1.2.0 nand flash读写操作及其命令的实现
1.
前言
对于一个完整的嵌入式系统,除了cpu、电源、晶振以外,存储器是必不可少的。以前存储器都是用可读写操作的EEPROM系列芯片,由于其暴露出来的缺陷,读写操作复杂,缓慢等原因,随着NorFlash于1988年由Inter
公司开发出来,存储器的市场开始被Nor Flash掌控。Nor Flash凭借读写操作简单,不需要额外的驱动就可以实现读写功能,雄霸存储器市场。但是其最大的缺点就是价格太高。也许正是由于日本人看到了Nor Flash的软肋,日立公司于1989年打着“提高每一笔特性价比”的旗号,推出了Nand
Flash。尽管Nand Flash的读写操作相对于Nor Flash要复杂一些但是,其海量存储和低廉的价格还是让各大开发商趋之若鹜。随着嵌入式市场对于大容量存储器需求的增长,Nand Flash必将有更大的发展空间。
2.
Nand Flash VS Nor Flash
网上有很多比较的文档。偷下懒:)3.
Nand Flash在u-boot的读写实现
首先,我们来看一下三星S3C2410用户手册中对nand flash的描述。手册中把nand flash的工作模式分为两种:自启动模式和一般的nand flash读写操作模式。在自启动模式下,由于nand flash自身的特点不能够直接在芯片内部执行程序,因此在在cpu内核中内置了一片SRAM配合nand
flash实现自启动系统。系统加电,nand flash存储空间的前4kB数据(也就是u-boot第一阶段)以硬件的方式被拷贝到SRAM中;然后SRAM中的u-boot代码开始执行,运行到第二阶段把nand
flash中u-boot的全部拷贝到SDRAM中继续执行,然后引导内核的启动和根文件系统的挂载。
对于nand flash的基本读写操作模式,主要是关于nand flash的读写操作。我们可以知道,在S3C2410中cpu将nand
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.0中nand flash读写操作源码分析
3.2.1.
涉及文件
Lib_arm/board.cBoard/smdk2410/smdk2410.c
Board/smdk2410/smdk2410.h
Driver/Nand_legacy/ Nand_legacy.c
Include/configs/smdk2410.h
3.2.2.
具体分析
Lib_arm/board.cu-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-boot
nand 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无意中发现一块板Vcam9同smdk2410一样都是基于S3C2410,而且实现了nand flash读写操作,遂借鉴之。:)
相关文章推荐
- 基于smdk2410 开发板u-boot-1.2.0 nand flash读写操作及其命令的实现(续)
- 在基于OMAP3530的DevKit8000开发板上实现Linux操作系统下的GPIO读写操作
- 基于优龙FS2410开发板u-boot-1.1.6的移植(NAND FLASH) (一)
- 手把手教你写Linux设备驱动---input子系统(一)--input事件应用程序的读写实现(基于友善之臂4412开发板)
- 嵌入式bootloader开发之八----NAND Flash读写擦除操作实现(Tiny 6410)
- 基于优龙FS2410开发板u-boot-1.1.6的移植(NAND FLASH) (一)
- 基于优龙FS2410开发板u-boot-1.1.6的移植(NAND FLASH) (二)
- Python之Fabric模块 Fabric是基于Python实现的SSH命令行工具,简化了SSH的应用程序部署及系统管理任务,它提供了系统基础的操作组件,可以实现本地或远程shell命令,包括:
- u-boot移植总结(三)(转)S3C2440对Nand Flash操作和电路原理(基于K9F2G08U0A)
- u-boot移植总结(三)(转)S3C2440对Nand Flash操作和电路原理(基于K9F2G08U0A)
- 基于Native.js实现Android文件的读写操作
- C#实现的基于二进制读写文件操作示例
- 基于优龙FS2410开发板u-boot-1.1.6的移植(NAND FLASH)
- 手把手教会基于Android实现最简单的计算器操作
- 无需第三方软件实现Mac支持ntfs读写的最简单操作
- xp 命令cmd 基于 网络 操作
- 详述Android照相功能的实现(基于飞凌S3C6410开发板+单独编译安卓模块)
- [转]MFC实现excel的读写操作
- AdapterView及其子类之三:基于ListView及ArrayAdapter实现列表
- stm32f4基于spi用fatfs读写SD卡的实现