嵌入式系统开发lab1试验小结
1.VIVI移植
在移植VIVI之前,必须先保证交叉编译器的正确性。因为张老师已经给了一个标准的基于gcc的交叉编译器,在此就不重复crosstool的生成过程。在VIVI和kernel的Makefile中需要指定交叉编译器的位置,所以在正式移植以前先把交叉编译器copy到指定的位置
/usr/local/arm/…
1.1 修改Makefile文件
Makefile中主要修要修改三处:
1. LINUX_INCLUDE_DIR
设置为LINUX_INCLUDE_DIR = /usr/local/arm/4.3.2/arm-none-linux-gnueabi/libc/usr/include
2. CROSS_COMPILE
设置为CROSS_COMPILE = /usr/local/arm/4.3.2/bin/arm-linux-
3. ARM_GCC_LIBS
设置为ARM_GCC_LIBS = /usr/local/arm/4.3.2/arm-none-linux-gnueabi/libc/armv4t/lib
其实在张老师给的VIVI版本中Makefile 的修改已经完成了,如果是用这个版本的VIVI,那么不用做任何的修改就可以直接移植了,如果是自己下载的,也只需要更改这三个地方。
1.2 修改arch/s3c2440/smdk.c
Smdk.c是VIVI移植中最重要的一个文件,主要是分区表的建立和启动参数的设置
1. 分区表的建立
将s3c2440_NAND_BOOT时对应的分区数据结构修改为如下结构
#ifdef CONFIG_S3C2440_NAND_BOOT
mtd_partition_t default_mtd_partitions[] = {
{
/*
add by xwc
2010-04-15
*/
name: "supervivi",
offset: 0,
size: 0x00030000,
flag: 0
}, {
name: "kernel",
offset: 0x00050000,
size: 0x00200000,
flag: 0
}, {
name: "root",
offset: 0x00250000,
size: 0x03Dac000,
flag: 0
}
};
#endif
在这里,我并没有采取张老师上课上提倡的5个分区的方法,甚至这里根本就没有param分区,不过需要注意的是supervivi 分区的结束点是0x00030000,kernel分区的开始点事0x00050000,这中间差的size大小是0x00020000,所以param其实还是可以利用这一段空间。
2. 启动参数的设置
启动参数主要是指这一行
char linux_cmd[] = "noinitrd root=/dev/mtdblock2 init=/linuxrc console=ttySAC0";
在我最开始做实验的时候,因为不知道param save 无法保存的bug是怎么回事(详见下文),所以选择在代码里修改,之后解决了那个问题,就选择用默认的参数,在启动的时候可以手动设置。
1.3 配置选项
主要是用 make menuconfig的方式对VIV进行配置,不过一般在make menuconfig之前最好先执行make distclean 确保系统处于clean的状态,不然有时候会无法生成config界面
各个部分大致做的工作如下
System Type ---> [系统配置:主要设置芯片、平台类型 底层启动选项等]
General setup---> [通用设置:vivi基地址、系统缓存、电源管理等 ]
Private Data ---> [私有数据设置:vivi的私有数据 启动的一些用户私有数据]
Serial Port ---> [串口:是否支持串口(vivi只支持串口,怎么敢不选),串口传输协议]
Memory Technology Devices(MTD)--> [存储设备相关选项]
Add Built-in Commands ----> [vivi支持命令]
System hacking ----> [系统调试相关选项]
Debugging messages ---> [调试信息相关]
----
Load and Alternate Configuration File [载入配置文件,vivi自带一个sdmk的配置文件]
Save Configuration to an Alternate File [保存自己的配置信息]
有如下几个地方需要注意:
System type 要选对,而且要保证支持NAND启动方式
I-cache D-cache 要选中,要不然启动很慢
要启动串口支持
1.4 做实验过程中遇到的问题
VIVI的移植相对而言很简单,最开始在make menuconfig的时候没有编辑界面跳出来,不过我平时弄linux-kernel比较多,linux kernel menuconfig的时候有时也会报错,主要是因为以前编辑过,有些残留的文件,要清除掉才可以,于是打开Makefile文件,查找果然有distclean:
clean:
find . /( -name '*.o' -o -name core -o -name ".*.flags" /) -type f -print /
| grep -v lxdialog/ | xargs rm -f
rm -f $(CLEAN_FILES)
distclean: clean
于是我就知道肯定是要先make distclean一下。
还有一个问题就是mach_type, 这里经过我的研究,发现只要linux kernel和vivi中对应就可以了,不修改也是没有问题的,所以我选择了不修改。
2. linux 内核移植
内核的移植其实本质上跟VIVI差不多,主要是做一些配置,一是使用gcc-arm交叉编译器,二是与vivi上的分区表保持一致。
2.1修改Makefile
主要是修改成使用arm-gcc交叉编译器进行编译,下面是我makefile中修改的地方
第一处:
#========================================================================
#SUBARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ /
# -e s/arm.*/arm/ -e s/sa110/arm/ /
# -e s/s390x/s390/ -e s/parisc64/parisc/ /
# -e s/ppc.*/powerpc/ -e s/mips.*/mips/ /
# -e s/sh.*/sh/ )
#========================================================================
# add by xwc
# 2010-4-15
SUBARCH := arm
#========================================================================
第二处:
#===============================
#CROSS_COMPILE ?=
#==============================
# add by xwc
# 2010-4-15
CROSS_COMPILE ?= arm-linux-
#==============================
2.2 ~/.bashrc 修改
为了能够更方便的使用arm-gcc交叉编译器,将其加入到Path中,可以利用修改.bashrc的方式:
export PATH=$PATH:/usr/local/arm/4.3.2/bin
然后source .bashrc 一下,或者重新登录就可以了。这样就没有必要再Makefile中指定全局的路径。
2.3 时钟配置
对应于arch/arm/mach-s3c2440/mach-smdk2440.c
将
S3c24xx_init_clocks(16934400);
改为:
S3c24xx_init_clocks(12000000);
这没什么说的,直接按照张老师的ppt改一下就可以了,要不然,时钟频率设置不对,超级终端中会出现乱码
2.4 分区信息修改
分区的信息要保持跟VIVI中一致,其实理论上说,不保持一致也是OK的,不过为了防止意外,最好还是copy一下。
修改 arch/arm/plat-s3c24xx/common-smdk.c 文件
static struct mtd_partition smdk_default_nand_part[] = {
/*
add by xwc
2010-04-15
*/
[0] = {
.name = "supervivi",
.size = 0x00030000,
.offset = 0,
},
[1] = {
.name = "kernel",
.offset = 0x00050000,
.size = 0x00200000,
},
[2] = {
.name = "root",
.offset = 0x00250000,
.size = 0x03dac000,
}
};
2.5 禁用software ECC 校验
修改 drivers/mtd/nand/s3c2410.c
else {
//chip->ecc.mode = NAND_ECC_SOFT;
/*
* add by xwc
* 2010-4-15
*/
chip->ecc.mode = NAND_ECC_NONE;
}
2.6 配置内核选项
这里也是make menuconfig 和vivi的menuconfig差不多,当然这样说可能不太对,我记得好像meke menuconfig这种模式最早就是用在linux kernel中的。这里配置的选项比较多,我是依据自己的经验勾选了一些,除了跟s3c2440非常相关的一些选项之外,其余的选项我做了最精简的配置,主要是为了减少编译的时间,和减小编译后kernel的大小。
2.7 做实验过程中遇到的问题
主要有2个方面:
一个是mach_type的修改,可以不用改成782,而是使用默认的与vivi一致的就OK,不过这样的话有一个问题,就是在vivi中选择boot the kernel的时候启动不起来,如果直接启动的话,应该是没有任何问题。
另一个是我最开始kernel的选项选的比较多,最后编出来的zImage 大于2M,烧不上去,就把kernel精简了一下,后来想了一下,可以增大kernel分区。
3. DM9000网卡驱动移植
3.1 修改DM9000使用的资源列表
这部分主要集中在arch/arm/plat-s3c24x/comman-smdk.c中
修改方式如下,
1. 头文件,加上
#if defined(CONFIG_DM9000) || defined(CONFIG_DM9000_MODULE)
#include <linux/dm9000.h>
#endif
2. 然后修改s3c_dm9k_resource
static struct resource s3c_dm9k_resource[] = {
[0] = {
.start = S3C2410_CS4, //0x20000000, base address(band)
.end = S3C2410_CS4+3,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = S3C2410_CS4 + 4, //0x20000004
.end = S3C2410_CS4 + 4 + 3,
.flags = IORESOURCE_MEM,
},
[2] = {
.start = IRQ_EINT7,//EINT7 pin
.end = IRQ_EINT7,
.flags = IORESOURCE_IRQ | IRQF_TRIGGER_RISING,
}
};
主要应该注意的是BANK4基地址为0x20000000,也就是S3C2410_CS4
3. 修改DM9000与开发板相关的数据,指定访问DM9000时,数据位宽为16
static struct dm9000_plat_data s3c_dm9k_platdata = {
.flags = DM9000_PLATF_16BITONLY,
};
static struct platform_device s3c_device_dm9k = {
.name = "dm9000",
.id = 0,
.num_resources = ARRAY_SIZE(s3c_dm9k_resource),
.resource = s3c_dm9k_resource,
.dev = {
.platform_data = &s3c_dm9k_platdata,
}
};
4. 在smdk_devs结构体中添加以下代码:
#if defined(CONFIG_DM9000) || defined(CONFIG_DM9000_MODULE)
&s3c_device_dm9k,
#endif
3.2设置dm9000的mac地址
主要是修改 drivers/net/dm9000.c这个文件
在dm9000_probe函数中的变量声明之后添加以下代码:
#if defined(CONFIG_ARCH_S3C2410)
unsigned int oldval_bwscon;
unsigned int oldval_bankcon4;
#endif
在dev_dbg(&pdev->dev, "dm9000_probe()/n");语句之后添加以下代码:
#if defined(CONFIG_ARCH_S3C2410)
oldval_bwscon=*((volatile unsigned int *)S3C2410_BWSCON);
*((volatile unsigned int *)S3C2410_BWSCON)=(oldval_bwscon & ~(3<<16))| S3C2410_BWSCON_DW4_16 | S3C2410_BWSCON_WS4 | S3C2410_BWSCON_ST4;
oldval_bankcon4=*((volatile unsigned int *)S3C2410_BANKCON4);
*((volatile unsigned int *)S3C2410_BANKCON4)=0x1f7c;
#endif
将platform_set_drvdata(pdev, ndev);之前的if判断语句改为:
if (!is_valid_ether_addr(ndev->dev_addr))
{
dev_warn(db->dev, "%s: Invalid ethernet MAC address. Please "
"set using ifconfig/n", ndev->name);
#if defined(CONFIG_ARCH_S3C2410)
printk("Now use the default MAC address: 08:90:90:90:90:90/n");
ndev->dev_addr[0]=0x08;
ndev->dev_addr[1]=0x90;
ndev->dev_addr[2]=0x90;
ndev->dev_addr[3]=0x90;
ndev->dev_addr[4]=0x90;
ndev->dev_addr[5]=0x90;
#endif
}
在dev_err(db->dev, "not found (%d)./n", ret);之后添加以下代码:
#if defined(CONFIG_ARCH_S3C2410)
*((volatile unsigned int *)S3C2410_BWSCON)=oldval_bwscon;
*((volatile unsigned int *)S3C2410_BWSCON)=oldval_bankcon4;
#endif
这里主要参考了网上的设置,选择指定mac地址,应该是用默认的也是没有问题的。(猜测,个人没有验证)
3.3配置内核
启动kernel对于DM9000的支持
Device Drivers --->
Network device support --->
[*] Network device support --->
Ethernet (10 or 100Mbit) --->
<*> DM9000 support
3.4设置ip,netmast,gateway,ping测试
配置的命令比较简单,如下:
/ $ cd sbin
/sbin $ ifconfig lo up
/sbin $ ifconfig eth0 10.131.250.65 netmask 255.255.255.0 up
/sbin $ route add default gw 10.131.250.1
/sbin $ inetd
然后ping一下,ping通就OK
3.5 做实验过程中遇到的问题
1. 最开始的时候gw没有设置好,所以ping外网ping不通
2. 我有一个同学没有设置gw就可以直接ping通外网,后来查了一下,发现时netmask设置成了 255.0.0.0,这样,很显然,只要是10网段都没有问题
3. 网线问题,由于我自己使用的网线不是太好,所以明明所有的东西都配好了,就是ping 不通
第一个包返回时间很长就是因为网线不好,后面的我自己拿手按住就正常了
4. Yaff2文件系统移植
4.1 内核增加yaffs2支持
下载最新的yaffs2源代码,张老师给的源代码与2.6.29不匹配
执行 ./patch-ker.sh c /2440/linux-2.6.29
上面命令完成下面三件事情
(1)修改内核fs/Kconfig 增加一行:source "fs/yaffs2/Kconfig"
(2)修改内核fs/Kconfig
增加一行:ojb-$(CONFIG_YAFFS_FS) +=yaffs2/
(3)在内核fs/目录下创建yaffs2目录
将yaffs2源码目录下面的Makefile.kernel文件复制为内核fs/yaffs2/Makefie;
将yaffs2 源码目录的Kconfig文件复制到内核fs/yaffs2目录下;
将yaffs2源码目录下的*.c *.h文件复制到内核fs/yaffs2目录下.
然后make menuconfig 添加支持
File systems --->
Miscellaneous filesystems --->
<*>YAFFS2 file system support
4.2 创建yaffs文件系统
这部分主要参考了张老师给的材料,做的过程比较顺利,大概过程如下
1. 创建必须的文件夹及设备文件
# mkdir rootfs
# cd rootfs
# mkdir bin dev etc lib mnt proc sbin sys root
# mkdir /etc/var
# mkdir /etc/tmp
2. 创建设备文件系统
# mknod -m 660 dev/console c 5 1
# mknod -m 660 dev/null c 1 3
3. 建立动态运行库
由于linux只安装上了arm-linux-gcc 4.3.2没有glibc的库文件,只好把友善之臂提供的
yaffs2文件系统下的lib文件拷贝过来。
4. 交叉编译busybox
解压缩tar -zxf busybox1.13.3.tar
解压后修改Makefile,指明交叉编译器:
ARCH ?= arm
CROSS_COMPILE ?= arm-linux-
5.执行make CONFIG_PREFIX=/2440/rootfs install
在/2440/rootfs目录下生成sbin,usr目录和linuxrc文件
6.创建etc目录下文件
在rootfs/etc目录下创建一个inittab文件
内容如下:
# /etc/inittab
::sysinit:/etc/init.d/rcS
s3c2410_serial0::askfirst:-/bin/sh
::ctrlaltdel:/sbin/reboot
::shutdown:/bin/umount -a -r
创建etc/init.d/rcS文件
#!/bin/sh
ifconfig eth0 192.168.1.17
mount –a
mkdir /dev/pts
mount -t devpts devpts /dev/pts
echo /sbin/mdev > /proc/sys/kernel/hotplug
mdev –s
最后还要改变它的属性使它能够执行。
chmod +x etc/init.d/rcS
创建etc/fstab文件
#device mount-point type options dump fack order
proc /proc proc defaults 0 0
tmpfs /tmp tmpfs defaults 0 0
sysfs /sys sysfs defaults 0 0
tmpfs /dev tmpfs defaults 0 0
7.构建其他目录
mkdir proc mnt tmp sys root
8.使用mkyaffsimgae命令生成yaffs映像文件
mkyaffsimage rootfs rootfs.yaffs
9.通过supervivi将内核映像zImage和rootfs.yaffs下载到开发板上
4.3 遇到的问题
因为资料上很详细,所以做这部分移植很顺利,并没有出现什么问题,唯一的一个问题就是用yaffs2给kernel打patch之后,kernel一直编不过,当时查代码查了好长时间,发现确实存在数据结构没有定义的情况,于是到网上下载了一个最新的版本,然后就没有问题了。
5. NFS 文件系统server端架设
5.1 server 设置方法
我把nfsserver搭建在arch-linux上,这是我自己实验室的机器,因为nfs我自己在实验室一直在用,所以,这部分问题不大,主要是修改/etc/exports这个文件,添加诸如
/nfs *(rw,sync)的语句。注意一下路径和权限设置对就可以了。这里需要注意的就是要起相关的服务,像RPC service,nfs service,portmap等,这个在不同系统的linux版本上稍微有些不同,需要注意。
这里需要注意,(rw,sync)中间一定不能有空格,否则会报格式不正确。
5.2遇到的问题
这部分没遇到什么问题,因为自己的机器上本来就有nfs server,各项服务也有起着,所以比较顺利。
6. NFS文件系统 client 端设置
6.1 client 端设置方法
首先肯定要启动kernel对nfs的支持,通过make menuconfig,配置,上文已经多次提到,具体的方法在此就不赘余,具体的配置脚本是 mount –o nolock 10.131.251.151:/nfs
6.2遇到的问题
遇到的问题主要是脚本的参数上,我以前在自己机器上mount的时候都没有用过nolock这个参数,所以最开始的时候一直挂不上,后来查了下资料,加上去就OK了。
7. 从NFS 启动
7.1 设置方法
其实nfs系统挂载成功之后,如果要从nfs启动,那就只是启动参数上设置的问题了,只要设置对了,就OK,在实验室做项目的时候,由于要进行kernel的更改,开发,经常要重启机器,于是我们也采用netboot的方法,不过我们是把kernel放在远端,然后启动的时候下载到本地。
具体的启动参数设置如下:
linux_cmd_line
"console=ttySAC0 root=nfs nfsroot=10.131.251.151:/nfs
ip=10.131.250.65:10.131.251.151:10.131.250.1:255.255.255.0:ppi-151:eth0:off init=/linuxrc"
其中 设置根文件系统启动方式为NFS方式,10.131.251.151为主机地址,/nfs为根文件系统路径 , 10.131.250.65是开发板ip地址,10.131.250.1是主机网关地址,255.255.255.0是子网掩码,ppi-151是主机名称,eth0是网卡, init=
设置为文件系统启动执行根目录下的初始化文件。
7.2 遇到的问题
主要是启动的参数,参数设置对了问题就不大。
8. 修改VIVI param save 无法保存参数bug
这个bug其实修改起来比较简单,我修改这个bug的过程也比较简单,因为,我发现vivi make menuconfig的时候的参数很少,于是我就一个一个看下来,后来发现有private data,于是打开,发现有支持use user-define parameter block 这个选项,选上,果然就可以保存了。
9. 感想,收获以及对课程的建议
在做lab1的过程中,收获颇多,
首先,就是对嵌入式系统有了一个大致的了解,以前一直听说烧板子,烧板子,但是就是不明白具体是怎么烧的,现在自己做了一把,豁然开朗。而且对加深PC机的了解也有很大的帮助,因为我以前也没有重新烧制BIOS,装完系统后也没有更改过bootloader,对磁盘进行分区也都是在装系统的时候一并完成,并不了解具体的过程。现在做完lab1,对很多事情都有了清晰的了解,包括bootloader是怎么烧制的,系统启动的时候bootloader是如何工作的,bootloader是如何把kernel加载进系统,并且把控制权转交给kernel。再有,就是对磁盘分区具体做了哪些工作,文件系统具体是怎么建立起来的,以及文件系统在kernel启动时的作用,等等。这些都对我有极大的帮助。
做lab1的过程中,感触比较深的就是,要多做探索,因为本来嵌入式开发对我而言就是一个全新的领域,所以要多探索,才能多有收获。
比如说mach_type, 张老师上课的时候说必须要改一下,那么我就自己试验了一下,发现如果不修改,只要kernel里面的设置和vivi里面的设置一样,就都可以启动起来。不过我又继续研究发现,如果不修改的话,用vivi 直接boot kernel会起不来,报mach_type不匹配的错误。
第二点就是要细心,就比如说修复private param 不能保存的问题,因为我一开始就很自己的研究vivi的menuconfig设置,所以很快就发现了这个问题所在,从根本上解决了。
再有,就是,做lab的过程是跟已经掌握的知识相互印证的过程。因为毕竟都是linux操作系统,很多东西都是相似的,做lab的过程就相当于是对已经掌握的知识做了一个补足,提升。使我对很多东西的了解更加深入了。