本文参考资料:
有关MTD和JFFS2的基础知识:http://www.linux-mtd.infradead.org/tech/nand.html
uClinux下MTD和JFFS2在M5407C3开发板上的移植:
http://www.enseirb.fr/~kadionik/embedded/uclinux/mtd/howto_mtd.html
1.概述
1.1关于Nandflash
以S3C44B0X为核心的ARMSYS开发板采用的Nandflash是三星公司的K9F2808芯片。它的存储空间以页为单位。1页是由512字节的数据和16字节的备用空间组成(备用空间可以用来存储ECC(纠错码),坏块信息和文件系统相关的数据)。这里我们仅考虑数据空间即可。因此可以认为K9F2808每页大小为512字节。32页组成一个块,因此块的大小为16K(0x4小空间为0x4000字节。
对芯片的读/写/擦除命令的写入都是通过置高CLE引脚同时向I/O0~I/O7写入命令代码字节来完成。地址的写入则是通过置高ALE引脚同时写入地址字节来完成。对Nandflash的操作仅需要对几条信号线进行控制即可完成了。
/RE和 /WE信号线则可以由相应的bank选择线与CPU的/OE和/WE逻辑与来控制。在ARMSYS上是采用bank1选择线,因此Nandflash在系统中的映射地址是0x200000。
I/O 0-7联接到CPU的数据总线D0-D7(D15). /WP直接接VCC而/SE直接接地即可。
R/B,/CE,CLE ,ALE和都应当联接CPU的GPIO引脚。ARMSYS中采用了PC0~PC3。
以上都是对我们移植MTD有用的信息。可以通过查看K9F2808的Datasheet来了解关于该器件更详细的信息。
1.2关于支持Nandflash的文件系统
现在仅有少量的文件系统支持各种类型的Nandflash设备:
JFFS2 和 YAFFS 支持 NAND Flash芯片和 SmartMediaCard(智能多媒体卡)
NTFL支持 DiskOnChip 设备
来自 M-Systems的TRUEFFS支持 DiskOnChip设备
由SSFDC论坛定义的SmartMedia(智能多媒体卡)的 DOS-FAT 文件系统
其中JFFS2 是一个开源的文件系统。JFFS2支持原始的NAND芯片同时支持SmartMediaCard。关于JFFS2的详细信息可以查看http://sources.redhat.com/jffs2/ 。JFFS2还提供文件的压缩和解压服务,这对小型的flash很有用处。JFFS2中包括了对坏块的管理,纠错并提供在Nandflash上使用的可用于工业用途的可靠稳定的文件系统。
1.3软件层次
JFFS2的建立包括4个层次:
a) JFFS2:文件系统驱动
b) MTD:存储技术设备驱动Memory Technology Devices driver
c) NAND:通用Nand驱动
d) 特定的硬件驱动
其中MTD驱动提供给JFFS2一个挂载点。通用NAND驱动提供必要的识别、读、写和擦除功能。与特定的硬件相关的功能函数则由底层的硬件驱动提供。
2.准备工作
2.1解压uClinux移植包
我们还是采用uClinux在ARMSYS上的移植包:uClinux-ARMSYS-20040801.tar.gz来完成JFFS2的移植的工作。
uClinux-ARMSYS-20040801.tar.gz是移植自uClinux-dist-20040408.tar.gz,在很多方面比早先的20030522版本要完善很多,这也使我们的工作变得方便很多。这里我们使用的内核版本是Linux 2.4.24。
将uClinux-ARMSYS-20040801.tar.gz拷贝到/home/下,运行解压:
tar xvzf uClinux-ARMSYS-20040801.tar.gz
解压结束后会在/home/下生成uClinux-dist目录。
2.2安装编译环境
将arm-elf-tools-20030314.sh拷贝到根目录,运行安装:
sh arm-elf-tools-20030314.sh
3.修改drivers/mtd/nand/下的几个文件
3.1修改Config.in
在文件Linux-2.4.x/drivers/mtd/nand/Config.in查找到CONFI_CPU_S3C44B0X,在其中加入一行(以下用粗体显示)对于ARMSYS开发板的选项:
if [ "$CONFIG_CPU_S3C44B0X" = "y" ]; then
dep_tristate ' NAND Flash device on FS44B0-CORE V2.00 board' CONFIG_MTD_NAND_S3C44B0X $CONFIG_MTD_NAND
dep_tristate ' NAND Flash device on ARMSYS board' CONFIG_MTD_NAND_ARMSYS $CONFIG_MTD_NAND
fi
这样在后面进行配置(make menuconfig)时就可以看到关于ARMSYS的选项了。
3.2修改Makefile
在文件Linux-2.4.x/drivers/mtd/nand/Makefile中,加入一行(以下用粗体显示):
#
# linux/drivers/nand/Makefile
#
# $Id: Makefile,v 1.10 2002/12/01 13:23:05 gleixner Exp $
O_TARGET := nandlink.o
export-objs := nand.o nand_ecc.o nand_ids.o
obj-$(CONFIG_MTD_NAND) += nand.o nand_ecc.o
obj-$(CONFIG_MTD_NAND_SPIA) += spia.o
obj-$(CONFIG_MTD_NAND_AUTCPU12) += autcpu12.o
obj-$(CONFIG_MTD_NAND_EDB7312) += edb7312.o
obj-$(CONFIG_MTD_NAND_IDS) += nand_ids.o
obj-$(CONFIG_MTD_NAND_S3C44B0X) += s3c44b0x.o
obj-$(CONFIG_MTD_NAND_ARMSYS) += armsys_44b0x.o
include $(TOPDIR)/Rules.make
这样在运行对内核的Make时,就会编译我们待会要加入的armsys_44b0x.c文件了。
3.3加入armsys_44b0x.c文件
在Linux-2.4.x/drivers/mtd/nand/目录下加入armsys_44b0x.c文件。该文件可以在这里下载。armsys_44b0x.c文件是基于同一目录中的其它文件修改的。例如spia.c文件。armsys_44b0x.c只需要根据ARMSYS的硬件电路(参考第1.1节)在上面做一些修改就可以了。
主要做了修改的几处如下:
第一处,
#define ARMSYS_IO_BASE 0x01d20000 /*GPIO相关寄存器的起始地址*/
#define ARMSYS_FIO_BASE 0x2000000 /*Nandflash映射的起始地址*/
#define ARMSYS_PEDR 0x0014
/* 控制CLE,ALE和NCE脚的port C的数据寄存器相对于GPIO寄存器起始地址的偏移量*/
#define ARMSYS_PEDDR 0x0010
/*控制CLE,ALE和NCE脚的port C的控制寄存器相对于GPIO寄存器起始地址的偏移量*/
第二处,
#ifdef CONFIG_MTD_PARTITIONS
/*
* 定义flash设备的分区
*/
const static struct mtd_partition partition_info[] = {
{ name: "ARMSYS flash partition 1",
offset: 2*1024*1024,
size: 6*1024*1024 },
{ name: "ARMSYS flash partition 2",
offset: 8*1024*1024,
size: 6*1024*1024 }
};
#define NUM_PARTITIONS 2
#endif
第三处,
/*
* 特定硬件的控制线操作
*/
void armsys_hwcontrol(int cmd){
switch(cmd){
case NAND_CTL_SETCLE: (*(volatile unsigned *) (armsys_io_base + armsys_pedr)) |= 0x04; break;
case NAND_CTL_CLRCLE: (*(volatile unsigned *) (armsys_io_base + armsys_pedr)) &= ~0x04; break;
case NAND_CTL_SETALE: (*(volatile unsigned *) (armsys_io_base + armsys_pedr)) |= 0x08; break;
case NAND_CTL_CLRALE: (*(volatile unsigned *) (armsys_io_base + armsys_pedr)) &= ~0x08; break;
case NAND_CTL_SETNCE: (*(volatile unsigned *)(armsys_io_base + armsys_pedr)) &= ~0x02; break;
case NAND_CTL_CLRNCE: (*(volatile unsigned *) (armsys_io_base + armsys_pedr)) |= 0x02; break;
}
}
第四处,
/*设置GPIO Port C 的控制寄存器从而使得Nandflash对应的控制引脚的输入/输出配置正确 */
(*(volatile unsigned *) (armsys_io_base + armsys_peddr)) = 0x0f00ff54;
4.添加mtdX和mtdblockX设备
修改/vendors/Samsung/44B0/Makefile文件。
在DEVICES = \
………
的最后加上:
(Tab)\
(Tab)mtd0,c,90,0(Tab)mtd1,c,90,2
(Tab)\
(Tab)mtdblock0,b,30,0(Tab)mtdblock1,b,30,1
这里(Tab)表示输入Tab键
5.配置内核
下面就可以开始配置内核和用户选项了。
打开终端。
# cd /home/uClinux-dist
# make menuconfig
进入uClinux配置(uClinux v3.1.0 Configuration),选中“Kernel/Library/Defaults Selectionà”敲空格进入。选中内核设置项和用户选项:
[*] Customize Kernel Settings
[*] Customize Vendor/User Settings
建议通过直接载入我们提供的内核配置文件Config_Kernel(点击这里下载)和用户配置文件Config_User(点击这里下载)来完成配置。将Config_Kernel拷贝到uClinux-dist/Linux-2.4.x目录下,将Config_User拷贝到uClinux-dist/Config目录下。
回到终端,按下ESC键两次,敲回车退出。进入内核配置(Linux Kernel v2.4.24-uc0 Configuration),选中“Load an Alternate Configuration File”,敲空格键进入,输入Config_Kernel文件名,按回车退出。内核选项就被设置好了。
按下ESC键,敲回车保存设置。自动切换到用户选项配置。同样选中“Load an Alternate Configuration File”,敲空格键进入,输入Config_User文件名,按回车退出。用户选项就被设置好了。
也可以手动修改。手动修改的步骤如下:
进入内核配置(Linux Kernel v2.4.24-uc0 Configuration)。
5.1选择支持可载入的模块
选中“Loadable mudule supportà”,敲空格进入。选中第1项:
[*] Enable loadable module support
按ESC退出。
5.2对MTD进行配置
选中“Memory Technology Device (MTD)-->”,敲空格进入。需要选中的项目如下:
<*> Memory Technology Device (MTD) support
[*] Debugging
(0) Debugging verbosity (0= quiet, 3=noisy)
<*> MTD partitioning support
………
--- User Modules And Translation Layers
<*> Direct char device access to MTD devices
<*> Caching block device access to MTD devices
选中“NAND Flash Device Drivers -à”,敲空格进入。需要选中的项目如下:
<*> NAND Device Support
………
<*> NAND Flash device on ARMSYS board
这一条就是我们修改前面的Config.in文件的结果。
敲两次ESC退出MTD配置。
5.3对文件系统进行配置
选中“File system -->”,敲空格进入。需要选中的项目如下:
<*> Journalling Flash File System v2 (JFFS2) support
(0) JFFS2 debugging verbosity (0 = quiet, 2 = noisy )
敲两次ESC,敲回车,退出内核配置。
6.配置用户选项
进入用户选项配置。
6.1对MTD工具进行配置
选中“Flash Tools-->”,敲空格键进入。需要选中的项目如下:
[*] mtd-utils
[*] erase
[*] eraseall
………
[*] mkfs.jffs2
敲ESC键退出。
6.2对BusyBox进行配置
选中“BusyBox-->”,敲空格键进入。需要选中的项目如下:
………
[*] mount
………
[*] umount
………
[*] vi
敲2次ESC键,并回车保存。
到此为之,所需的配置选项就全部设好了。下面就开始编译了。
7.编译uClinux
按下面的步骤进行编译:
# make dep
# make lib_only
# make user_only
# make romfs
# make image
# make
编译成功后,在uClinux-dist/目录下产生images目录,其中的3个文件:image.ram, image.rom和romfs.img就是我们可以使用的二进制文件。
8.下载与启动
8.1下载
利用ARMSYS提供的Bootloader通过USB接口下载2个二进制文件:
l image.ram(文件改名为imageram.bin)下载到地址0x0c008000;
l romfs.img(文件改名为romfs.img)下载到地址0x0c600000;
8.2启动
从0xc008000地址处开始运行,可以从超级终端上观察到如下所示的输出信息:
Linux version 2.4.24-uc0 (root@localhost) (gcc version 2.95.3 20010315 (release)
(ColdFire patches - 20010318 from http://fiddes.net/coldfire/)(uClinux XIP and shared lib patches from http://www.snapgear.com/)) #108 六 9月 25 20:11:04 CST 2004
Processor: Samsung S3C44B0X revision 0
Architecture: S3C44B0X
On node 0 totalpages: 2048
zone(0): 0 pages.
zone(1): 2048 pages.
zone(2): 0 pages.
Kernel command line: root=/dev/rom0 init=/linuxrc
Calibrating delay loop... 31.84 BogoMIPS
Memory: 8MB = 8MB total
Memory: 6900KB available (970K code, 152K data, 36K init)
Dentry cache hash table entries: 1024 (order: 1, 8192 bytes)
Inode cache hash table entries: 512 (order: 0, 4096 bytes)
Mount cache hash table entries: 512 (order: 0, 4096 bytes)
Buffer cache hash table entries: 1024 (order: 0, 4096 bytes)
Page-cache hash table entries: 2048 (order: 1, 8192 bytes)
POSIX conformance testing by UNIFIX
Linux NET4.0 for Linux 2.4
Based upon Swansea University Computer Society NET3.039
Starting kswapd
JFFS2 version 2.1. (C) 2001 Red Hat, Inc., designed by Axis Communications AB.
ttyS0 at I/O 0x1d00000 (irq = 3) is a S3C44B0
ttyS1 at I/O 0x1d04000 (irq = 2) is a S3C44B0
Blkmem copyright 1998,1999 D. Jeff Dionne
Blkmem copyright 1998 Kenneth Albanowski
Blkmem 1 disk images:
0: C600000-C65FFFF [VIRTUAL C600000-C65FFFF] (RO)
RAMDISK driver initialized: 16 RAM disks of 1024K size 1024 blocksize
NAND device: Manufacture ID: 0xec, Chip ID: 0x73 (Samsung NAND 16MB 3,3V)
Creating 2 MTD partitions on "NAND 16MB 3,3V":
0x00200000-0x00800000 : "ARMSYS flash partition 1"
mtd: Giving out device 0 to ARMSYS flash partition 1
0x00800000-0x00e00000 : "ARMSYS flash partition 2"
mtd: Giving out device 1 to ARMSYS flash partition 2
VFS: Mounted root (romfs filesystem) readonly.
Freeing init memory: 36K
Shell invoked to run file: /etc/rc
Command: hostname Samsung
Command: /bin/expand /etc/ramfs.img /dev/ram0
Command: mount -t proc proc /proc
Command: mount -t ext2 /dev/ram0 /var
Command: mkdir /var/config
Command: mkdir /var/tmp
Command: mkdir /var/log
Command: mkdir /var/run
Command: mkdir /var/lock
Command: cat /etc/motd
Welcome to
____ _ _
/ __| ||_|
_ _| | | | _ ____ _ _ _ _
| | | | | | || | _ \| | | |\ \/ /
| |_| | |__| || | | | | |_| |/ \
| ___\____|_||_|_| |_|\____|\_/\_/
| |
|_|
For further information check:
http://www.uclinux.org/
Command:
Execution Finished, Exiting
Sash command shell (version 1.1.1)
/>
其中的黑体部分说明系统已经识别到了K9F2808器件,并创建了2个MTD分区。还可以到proc目录中看一下MTD分区表:
/> cd proc
/proc> cat mtd
dev: size erasesize name
mtd0: 00600000 00004000 "ARMSYS flash partition 1"
mtd1: 00600000 00004000 "ARMSYS flash partition 2"
/proc>
到dev目录下查看一下mtd设备:
/proc> cd /dev
/dev> ls
console
cua0
cua1
kmem
mem
mtd0
mtd1
mtdblock0
mtdblock1
null
ptyp0
………
urandom
zero
/dev>
有了上面的结果就说明MTD设备已经配置好了。下面我们就要创建一个JFFS2映像文件,并将它拷贝到MTD分区中。
9.创建和拷贝JFFS2映像文件
在目标板上运行以下的命令行:
/dev> cd /var/tmp
/var/tmp> mkdir jffs2
/var/tmp> c
/var/tmp/jffs2> vi file1
Hello, this is JFFS2 on Nandflash.
/var/tmp/jffs2> cat file1
Hello, this is JFFS2 on Nandflash.
/var/tmp/jffs2> mkdir folder1
/var/tmp/jffs2> mkdir folder2
/var/tmp/jffs2> mkdir folder3
/var/tmp/jffs2> cd ..
/var/tmp> mkfs.jffs2 -d jffs2 -o jffs2.img
/var/tmp> ls
jffs2
jffs2.img
/var/tmp>eraseall /dev/mtd0
………
/var/tmp> cp jffs2.img /dev/mtd0
MTD_open
MTD_write
MTD_close
/var/tmp>
同样可以使用/dev/mtd1,那么在下面的Mount中要使用mtdblock1。
10.Mount/umount JFFS2分区
10.1 Mount
在目标板上运行以下命令行:
/var/tmp> mount -t jffs2 /dev/mtdblock0 /mnt
/var/tmp>
这样就mount上/mnt了。查看proc/mounts的内容:
/mnt> cd /proc
/proc> cat mounts
rootfs / rootfs rw 0 0
/dev/root / romfs ro 0 0
/proc /proc proc rw 0 0
/dev/ram0 /var ext2 rw 0 0
/dev/mtdblock0 /mnt jffs2 rw 0 0
/proc>
我们还可以看看现在mnt下面的内容:
/var/tmp> cd /mnt
/mnt> ls
file1
folder1
folder2
folder3
/mnt> cat file1
Hello, this is JFFS2 on Nandflash.
/mnt>
这样我们就可以在/mnt下操作Nandflash中的文件内容。例如:
/mnt> rm file1
/mnt> vi file2
This is ARMSYS board.
/mnt> ls
file2
folder1
folder2
folder3
/mnt>
10.2 umount
在开发板上运行以下命令行:
/> umount /mnt
/> cd mnt
/mnt> ls
/mnt>
11.JFFS2文件系统的使用
由于Nandflash是非易失性的存储器,因此保存在其中的内容不会随掉电而消失。因此,在第一次成功完成了第9和第10步骤之后,以后只要直接运行第10步的mount即可。我们可以试试看。关闭开发板电源,再重新打开,同样下载和启动uClinux。启动后直接输入如下的命令行:
/> mount -t jffs2 /dev/mtdblock0 /mnt
/> cd /mnt
/mnt> ls
file2
folder1
folder2
folder3
/mnt>
我们看到Nandflash中的第1分区还是保存着上次操作的内容。
如果你希望再每次uClinux启动时,自动将Nandflash的第1分区mount到/mnt目录,可以在/vendors/Samsung/44B0目录下的rc文件中加入1行即可:
mount –t jffs2 /dev/mtdblock0 /mnt