嵌入式交叉编译器,uboot,kernel,根文件系统,tslib,qt编译配置

时间:2022-03-01 08:46:17


硬件设计

CPU:S5PV210

内存:1G

闪存:SLC 1G Nand

网卡:DM9000,100M

串口:2个,调试和数据通信

USB:4个,外接U盘和移动硬盘

DS18B20:温度传感器(单总线接口 1-Wire)

ADC:模数转换器,分辨率10位或者12位

独立式按键:8个

LED灯:2个

蜂鸣器:1个

AT24C02:EEPROM存储器,容量256字节

LCD显示屏:分辨率800*480

电容触摸屏:GT811

软件设计

交叉编译器

采用官方交叉编译器;

编译器版本:4.4.6

编译器路径:/workdir/toolchain/opt/S5PV210-crosstools/4.4.6

设置交叉编译器环境变量:

sudo vim /etc/environment,在“PATH”中添加如下信息:
添加之前:/usr/local/sbin: /usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games"
添加之后:
/workdir/toolchains/opt/S5PV210-crosstools/4.4.6/bin:/usr/local/sbin: /usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games"
启动交叉编译器环境变量
source /etc/environment
验证:arm-linux-gcc –v //查看是否是4.4.6版本编译器

UBOOT移植

采用官方UBOOT源码;

源码包u-boot_CW210_1.3.4.tar.bz2

源码存放路径:/opt/uboot/

源码操作:

解压源码:tar –xvf u-boot_CW210_1.3.4.tar.bz2

清除源码配置文件和目标文件:make distclean

配置源码:make cw210_config

make all

USB烧写固化u-boot.bin

Linux内核移植

采用官方Linux内核源码;

源码包Kernel_2.6.35.7_CW210_for_Linux_v1.0.tar.gz

源码存放路径:/opt/kernel

源码操作:

解压源码:tar –xvf Kernel_2.6.35.7_CW210_for_Linux_v1.0.tar.gz
清除源码配置文件和目标文件:cd /opt/kernel && make distclean
配置源码:cp config_CW210_linux_V1.0   .config
make menuconfig //保存退出
make zImage
cp arch/arm/boot/zImage    /tftpboot/

根文件系统制作

采用busybox开源软件制作

busybox源码包:busybox-1.21.1.tar.bz2

源码存放目录:/opt/busybox/

源码操作:

解压源码:tar –jxvf busybox-1.21.1.tar.bz2
cd busybox-1.21.1
配置源码:make menuconfig
重新定制模块操作命令
Linux Module Utilities  --->
          [*] Simplified modutils (NEW)  //去掉
[*]   insmod    //添加
[*]   rmmod  //添加、
[*]   lsmod//添加
[*]   modprobe   //添加
[*]     Blacklist support//添加
[*]   depmod   //添加
取出闪存flash操作命令
Miscellaneous Utilities  --->
 [*] nandwrite (NEW) //去掉
         [*] nanddump (NEW)     //去掉
保存退出
修改Makefile文件
vim Makefile
将CROSS_COMPILE ?= 修改为CROSS_COMPILE=arm-linux-
将ARCH ?= $(SUBARCH)修改为ARCH=arm
编译和安装 make && make install
默认安装当前目录的_install目录:ls  _install
用file命令检查编译结果busybox可执行文件的属性:file _install/bin/busybox,打印信息如下:ELF 32-bit LSB executable, ARM, version 1 (SYSV), dynamically linked (uses shared libs), stripped //红色字体的内容必须为ARM,而不是intel X86
进入安装目录:cd  _install
创建目录:
mkdir dev lib etc/init.dproc syshome mnt var tmp root  -p
添加系统启动配置文件
vim etc/inittab //添加如下内容

::sysinit:/etc/init.d/rcS

::respawn:-/bin/sh

::ctrlaltdel:/sbin/reboot

::shutdown:/bin/umount -a –r

保存退出
添加文件系统配置文件
vim etc/fstab //添加如下内容

 proc    /proc        proc    defaults     0  0

 tmpfs   /tmp        tmpfs  defaults     0   0

 sysfs    /sys        sysfs   defaults        0   0

 tmpfs   /dev       tmpfs  defaults        0   0

说明:sysfs,procfs,tmpfs都是虚拟文件系统,文件系统相关的信息存在内存中。

保存退出
添加系统启动服务配置脚本
vim etc/init.d/rcS //添加内容如下

/bin/mount -a

    mkdir /dev/pts

    mount -t devpts devpts /dev/pts

    echo /sbin/mdev > /proc/sys/kernel/hotplug

    mdev –s

保存退出
修改rcS文件权限

chmod 777 etc/init.d/rcS

添加 busybox运行时所需动态库

动态库添加原则:应用软件需要哪些动态库,就添加,不相关不做添加,以便节省闪存空间

应用软件编译连接需要的动态库在交叉编译器中获取:

动态库路径:/home/tarena/workdir/toolchains/opt/S5PV210-crosstools/4.4.6/arm-concenwit-linux-gnueabi/lib/

查看busybox可执行程序所需的动态库

arm-linux-readelf -a bin/busybox | grep "Shared" //提示信息如下:

0x00000001 (NEEDED) Shared library:      [libm.so.6]

0x00000001 (NEEDED) Shared library:      [libc.so.6]

可知需要动态库为:libc和libm两个动态库

拷贝所需动态库到根文件系统lib目录下

find /home/tarena/workdir/toolchains/opt/S5PV210-crosstools/4.4.6/arm-concenwit-linux-gnueabi/lib/ \( -name "libc-*"-o -name "libc.so*" \) -exec cp -frd {}  lib/  \;  //拷贝标准C库

find /home/tarena/workdir/toolchains/opt/S5PV210-crosstools/4.4.6/arm-concenwit-linux-gnueabi/lib/ \( -name "libm-*"-o -name "libm.so*" \) -exec cp -frd {}  lib/  \; //拷贝数学运算库

find /home/tarena/workdir/toolchains/opt/S5PV210-crosstools/4.4.6/arm-concenwit-linux-gnueabi/lib/ \( -name "ld-*"\) -exec cp -frd {}  lib/  \;   //拷贝动态链接库

 

测试制作好的根文件系统

备份原有的根文件系统rootf:mv /opt/rootfs /opt/rootfs_bak

cp _install /opt/rootfs –frd  //将安装制作好的根文件系统_install拷贝/opt/rootfs

注意添加NFS网络服务的支持:sudo vim /etc/exports 添加如下语句:

/opt/rootfs *(rw,sync,no_root_squash)

保存退出

重启网络服务sudo /etc/init.d/nfs-kernel-server restart

uboot中设置NFS网络启动参数
setenv bootargs root=/dev/nfs nfsroot=192.168.1.8:/opt/rootfs ip=192.168.1.110:192.168.1.8:192.168.1.1:255.255.255.0::eth0:on init=/linuxrc console=ttySAC0,115200
saveenv
重启开发板测试挂接制作的rootfs
查看根文件系统的大小: du /opt/rootfs –lh  (一般情况下为3.2M)

tslib移植

tslib作用:

在采用触摸屏的移动终端中,触摸屏性能的调试是个重要问题之一,因为电磁噪声的缘故,触摸屏容易存在点击不准确、有抖动等问题。tslib是一个开源的程序,能够为触摸屏驱动获得的采样提供诸如滤波、去抖、校准等功能,通常作为触摸屏驱动的适配层,为上层的应用(例如QT)提供了一个统一的接口。

tslib源码包:tslib.tar.gz
源码存放目录:/opt/project/source/
源码移植:
进入源码目录:cd /opt/project/source
解压源码: tar –xvf tslib.tar.gz
cd tslib
执行./autogen.sh 生成配置文件configure
执行echo  "ac_cv_func_malloc_0_nonnull=yes"> tmp.cache
执行./configure --host=arm-linux --cache-file=tmp.cache   --prefix=/opt/project/tslib  //指定安装的目录为/opt/project/tslib目录
执行make && make install //编译安装
编译安装成果: cd /opt/project/tslib && ls –lh 提示信息如下:

etc bin lib include //生成四个目录

etc:用于配置tslib

bin:tslib的测试程序,运行在ARM开发板上

lib:动态库,供QT使用,用于获取坐标等信息

include:头文件,用于编译源码

修改tslib的配置文件ts.conf

vim etc/ts.conf   //打开配置文件,进行如下操作:

在“module pthres pmin=1”前一行添加“module_raw input”语句 (需要注意的是module开头的几行前面不能有空格. )

开发板测试tslib:
编译tslib生成目标文件存放目录:/opt/rootfs/home/tslib/

mkdir /opt/rootfs/home/tslib/

cp etc  /opt/rootfs/home/tslib/ -frd    //拷贝运行时配置文件

cp bin  /opt/rootfs/home/tslib/ -frd  //拷贝触摸屏测试软件

cp lib   /opt/rootfs/home/tslib/ -frd //拷贝tslib动态库文件

连接触摸屏和开发板,获取触摸屏设备文件

开发板上执行hexdump /dev/input/event0,然后用手指点击触摸屏,看串口终端是否有打印信息,如果没有,event0不是触摸屏的设备文件,再执行:hexdump /dev/input/event1,同样点击屏幕看是否有打印信息,如果没有,再次更换设备文件为event2,直到找到触摸屏的设备文件,例如:hexdump /dev/input/event3,有打印信息,至此触摸屏的设备文件为/dev/input/event3.

添加使用tslib时的环境变量

vim /opt/rootfs/etc/profile 添加如下内容:

export TSLIBDIR=/home/tslib 

export TSLIB_CONSOLEDEVICE=none 

export TSLIB_FBDEVICE=/dev/fb0 

export TSLIB_TSDEVICE=/dev/input/event3 //根据上一步骤找触摸屏的设备文件,不能有错!

export TSLIB_CALIBFILE=$TSLIBDIR/etc/pointercal 

export TSLIB_CONFFILE=$TSLIBDIR/etc/ts.conf 

export TSLIB_PLUGINDIR=$TSLIBDIR/lib/ts

export PATH=/home/tslib/bin:$PATH

export LD_LIBRARY_PATH=/home/tslib/lib:$LD_LIBRARY_PATH

保存退出

重启开发板

添加使用tslib时的标准系统库(libdl)

find /home/tarena/workdir/toolchains/opt/S5PV210-crosstools/4.4.6/arm-concenwit-linux-gnueabi/lib/ \( -name "libdl-*"-o -name "libdl.so*"\) -exec cp -frd {}/opt/rootfs/lib/ \;重启开发板,进行触摸屏校准

开发板运行: ts_calibrate  //此时屏幕有一个十字光标,用手指精确点击光标,点击光标5次,完成校准,生成一个校准文件保存在home/tslib/etc/pointercal
开发板运行:ts_test  //点击屏幕”Draw”,写字,画画
至此tslib移植成功,触摸屏测试成功!

QT移植

QT介绍:

移植QT目的:

移植注意事项:必须先移植好tslib

源码包:qt-everywhere-opensource-src-4.8.4.tar.gz

源码包存放目录:/opt/project/source/

源码移植:

cd /opt/project/source/
解压源码
tar –xvf  qt-everywhere-opensource-src-4.8.4.tar.gz
mv qt-everywhere-opensource-src-4.8.4 qt_src
cd  qt_src
修改配置文件:
vim  mkspecs/qws/linux-arm-g++/qmake.conf 操作如下:

原先的内容:

QMAKE_CC = arm-linux-gcc 

QMAKE_CXX = arm-linux-g++

QMAKE_LINK = arm-linux-g++ 

QMAKE_LINK_SHLIB = arm-linux-g++

修改为: //添加tslib动态库的支持

QMAKE_CC = arm-linux-gcc -lts 

QMAKE_CXX = arm-linux-g++ -lts 

QMAKE_LINK = arm-linux-g++ -lts 

QMAKE_LINK_SHLIB = arm-linux-g++ -lts

编译源码:

下载build.sh编译配置脚本,放置在源码目录/opt/project/source/qt_src中

执行./build.sh

会提示输入"c"或者"o",选择"o"开始配置

make  //编译,大约3小时

make install //安装

交叉编译QT,生成的目标文件自动安装在/opt/project/qt目录中
ls /opt/project/qt/ 信息如下

bin  include  lib  mkspecs  plugins  translations

安装中文字体库

字体库文件:wqy-zenhei.ttc

删除QT自带字体库

rm /opt/project/qt/lib/fonts/* -fr

安装中文字体库

cp wqy-zenhei.ttc /opt/project/qt/lib/fonts/ 

安装编译出来的QT库到跟文件系统/opt/rootfs中

QT库的存放目录:/opt/rootfs/home/qt

mkdir /opt/rootfs/home/qt

拷贝QT库

cp /opt/project/qt/lib  /opt/rootfs/home/qt –frd

cp /opt/project/qt/plugins  /opt/rootfs/home/qt  -frd

添加QT运行时的环境变量

vim  /opt/rootfs/etc/profile, 添加如下内容

export QTDIR=/home/qt

export QWS_MOUSE_PROTO="Tslib:/dev/input/event3"  #dev/input/event3为触摸屏设备文件

export QWS_SIZE=800X480

export QT_QWS_FONTDIR=$QTDIR/lib/fonts

export QT_PLUGIN_PATH=$QTDIR/plugins

exportQWS_DISPLAY="LinuxFB:mmWidth180:0"

export LD_LIBRARY_PATH=$QTDIR/lib:$LD_LIBRARY_PATH

保存退出,重启开发板

执行env命令,查看环境变量是否生效

添加QT运行时的系统库

find /home/tarena/workdir/toolchains/opt/S5PV210-crosstools/4.4.6/arm-concenwit-linux-gnueabi/lib/ \( -name  "libpthread-*"  -o  -name  "libpthread.so*"  \)  -exec  cp  -frd  {}  /opt/rootfs/lib/  \;

find /home/tarena/workdir/toolchains/opt/S5PV210-crosstools/4.4.6/arm-concenwit-linux-gnueabi/lib/ \( -name  "libstdc++-*"  -o  -name  "libstdc++.so*"  \)  -exec  cp  -frd  {}  /opt/rootfs/lib/  \;

find /home/tarena/workdir/toolchains/opt/S5PV210-crosstools/4.4.6/arm-concenwit-linux-gnueabi/lib/ \( -name  "librt-*"  -o  -name  "librt.so*"  \)  -exec  cp  -frd  {}  /opt/rootfs/lib/  \;

find /home/tarena/workdir/toolchains/opt/S5PV210-crosstools/4.4.6/arm-concenwit-linux-gnueabi/lib/ \( -name  "libgcc_s-*"  -o  -name  "libgcc_s.so*"  \)  -exec  cp  -frd  {}  /opt/rootfs/lib/  \;

开发板上测试QT

测试源码包:美女摇奖游戏 game.tar.bz2

源码存放目录:/opt/project/game

可执行文件存放目录:/opt/rootfs/home/apptest/

mkdir /opt/project/game

cd /opt/project/game

tar –jxvf game.tar.bz2

cd game

清除源码目标和配置文件:make clean

生成pro工程文件:/opt/project/qt/bin/qmake project   //注意不要直接qmake,为什么?

生成Makefile文件:/opt/project/qt/bin/qmake

编译:make

创建可执行文件存放目录:mkdir /opt/rootfs/home/apptest

cp game  /opt/rootfs/home/apptest

开发板上运行: /home/apptest/game –qws //看QT游戏能否启动

驱动开发

需要开发的驱动如表所示:

硬件对象

2个LED

1个蜂鸣器

1个DS18B20温度传感器

1个ADC 

8个按键

1个AT24C02存储器

功能

告警指示

报警

采集室内温度

用于采样电压模拟信号,转换电压值作为模拟烟雾浓度

用于玩游戏和模拟红外传感器

存储软件和硬件版本信息

驱动文件名

led_drv.c

beep_drv.c

ds18b20_drv.c

adc_drv.c

btn_drv.c

at24c02_drv.c

源码存放路径

/opt/project/drivers/led

/opt/project/drivers/beep

/opt/project/drivers/ds18b20

/opt/project/drivers/adc

/opt/project/drivers/btn

/opt/project/drivers/eeprom

ko目标存放目录

/opt/rootfs/home/drivers

封装底层硬件操作库函数

底层硬件库函数的作用:用于图形界面QT调用库函数间接操作访问硬件设备,是连接QT和设备的桥梁

软件操作流程:

 

LED设备底层硬件操作库实现过程:

用户需求:开发板运行QT软件,能够开关灯
源码存放目录:/opt/project/hwlib/led
mkdir /opt/project/hwlib/led  -p
编写头文件led.h,源码如下:
#ifndef __LED_H
#define __LED_H
 
#ifdef __cplusplus
extern "C" {
#endif
 
/*头文件*/
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <fcntl.h>
 
/*调试宏*/
#define DEBUG
 
#ifdef DEBUG
#define pr_debug(fmt, ...) printf(fmt, ##__VA_ARGS__) //打开调试信息
#else
#define pr_debug(fmt, ...)  //关闭调试信息
#endif  //以后打印不用printf用pr_debug
 
/*设备文件名*/
#define LED_DEVFILE_NAME "/dev/myled"
 
/*LED数据结构
 应用软件利用此数据结构进行访问设备
*/
struct led_cmd {
    unsigned char whichled; //指定哪个灯,第一个灯此值为1,第二个灯此值为2
    unsigned char cmd;//亮,灭命令;开灯此值设置为1,关灯此值设置为0
    unsigned char reserved[2];
};
 
/*LED控制命令宏*/
#define LED_ON 0x100001
#define LED_OFF 0x100002
 
/*
函数功能:打开LED设备
参数:无
返回值:打开设备成功,返回设备文件描述符fd;失败返回-1 
*/
extern int led_open(void);
 
/*
函数功能:关闭LED设备
参数:
@fd:设备文件描述符
返回值:无
*/
extern void led_close(int fd);
 
/*
函数功能:控制LED亮,灭
参数:
@fd:设备文件描述符;
        @cmd:控制LED开关命令
        返回值:开,关灯结果,操作成功,返回0,否则返回-1
*/
extern int led_config(int fd, struct led_cmd *cmd);
 
#ifdef __cplusplus
}
#endif
 
#endif
编写库函数实现源文件led.c,源码如下:
#include "led.h"
 
int led_open(void)
{
int fd = open(LED_DEVFILE_NAME, O_RDWR);
if (fd < 0) {
pr_debug("open led device failed.\n");
return -1;
}
pr_debug("open led device successfully!\n");
return fd;
}
 
void led_close(int fd) 
{
pr_debug("close led device...\n");
close(fd);
}
 
int led_config(int fd, struct led_cmd *ledctrl) 
{
int ret;
 
if (fd < 0) {
pr_debug("fd is invalid.\n");
return -1;
}
 
        if (ledctrl == NULL) {
            pr_debug("ledctrl is invalid.\n");
            return -1;
        }
 
        if (ledctrl->whichled != 1 && ledctrl->whichled != 2) {
pr_debug("whichled is invalid.\n");
pr_debug("whichled value must be 1 or 2\n");
return -1;
}
 
if (ledctrl->cmd != 1 && ledctrl->cmd != 0) {
pr_debug("cmd is invalid.\n");
pr_debug("cmd value must be 1 or 0\n");
return -1;
}
 
if (ledctrl->cmd == 1)
ret = ioctl(fd, LED_ON, &ledctrl->whichled);
else 
ret = ioctl(fd, LED_OFF, &ledctrl->whichled);
if (ret == -1) {
pr_debug("ioctl led device failed.\n");
}
pr_debug("ioctl led device successfully!\n");
return ret;
}
 
制作为动态库:

arm-linux-gcc -shared -fpic -o libled.so led.c led.h

动态库存放目录:/opt/rootfs/home/applib

mkdir /opt/rootfs/home/applib

cp libled.so /opt/rootfs/home/applib/

 

编写库函数测试用例ledlib_test.c,源码如下:
#include "led.h"
 
int main(int argc, char *argv[])
{
int fd;
        struct led_cmd ledctrl;
 
if (argc != 3) {
printf("usage:\n %s <on|off><1|2>\n", argv[0]);
return -1;
}
fd = led_open();
if (fd < 0) 
return -1;
 
ledctrl.whichled = strtoul(argv[2], NULL, 0);
if (!strcmp(argv[1], "on")) { 
    ledctrl.cmd = 1;
        } else {
    ledctrl.cmd = 0;
        }
 
        if (led_config(fd, &ledctrl) == -1)
            return -1;
        led_close(fd);
 
return 0;
}
 
编译测试用例:

arm-linux-gcc -o ledlib_test  ledlib_test.c -L/opt/project/hwlib/led –lled

测试用例可执行文件存放目录:/opt/rootfs/home/apptest

mkdir /opt/rootfs/home/apptest

cp libled_test /opt/rootfs/home/apptest

 

添加动态库环境变量:

vim /opt/rootfs/etc/profile ,在文件最后添加如下内容:

export LD_LIBRARY_PATH=/home/applib:$LD_LIBRARY_PATH

重启开发板

运行测试用例:

/home/apptest/ledlib_test on 1  //开第一个灯

 

基于QT图形界面实现开关灯

图形界面包含操作元素:一个开灯按钮,一个关灯按钮

界面大小:800*480

界面图标:添加至/opt/project/ehome/images

功能:点击图形界面按钮,实现开关灯操作

源码存放目录:/opt/project/ehome

可执行文件ehome存放目录:/opt/rootfs/home/appbin

Tarena虚拟机安装QT开发环境

QT开发工具包:qt-ubuntu.tar.bz2

或者在windows下安装QT开发工具:qt-opensource-windows-x86-mingw482_opengl-5.3.2.exe

下载安装即可

ubuntu安装QT开发环境步骤:

mkdir /home/tarena/qt/
cp qt-ubuntu.tar.bz2 /home/tarena/qt
tar –xvf qt-ubuntu.tar.bz2
sudo dpkg –i  *

打开qtcreator开发工具:

创建ehome工程
添加开,关按钮控件和背景图片,参看视频
添加硬件库函数使用的头文件
添加文件描述m_fd_led定义
构造函数中可以打开设备
槽函数中开关设备
具体参看视频
交叉编译:
cd /opt/project/ehome
/opt/project/qt/bin/qmake –project //生成工程文件,只需做一次,以后不需要再生成
修改工程文件,添加动态库的支持
vim /opt/project/ehome/ehome.pro
添加如下内容:
INCLUDEPATH += /opt/project/hwlib/led  //头文件
LIBS += -L/opt/project/hwlib/led –lled  //动态库
其他库依次按此法添加,例如beep:
INCLUDEPATH += /opt/project/hwlib/beep  //头文件
LIBS += -L/opt/project/hwlib/beep –lbeep  //动态库
保存退出
执行/opt/project/qt/bin/qmake  生成Makefile文件
make 编译
cp /opt/project/ehome/ehome /opt/rootfs/home/appbin
开发板测试/home/appbin/ehome –qws //实现开关灯

统软件部署

系统软件组成部分:

u-boot.bin:系统启动软件
zImage:内核软件
根文件系统rootfs:根文件系统,包含库,命令,配置文件等
userdata目录:包含用户软件,驱动模块,脚本,自己封装的动态库,测试用例,应用软件
注意:rootfs和userdata是两个目录,最后需要制作为镜像文件

rootfs根文件系统目录组成部分:

lib:存放系统标准库,不包含QT库,tslib库和自己封装的库
etc:系统启动配置文件,fstab,profile,inittab,rcS
bin,sbin,usr:系统运行命令
home:作为nandflash分区的挂节点
mnt:作为U盘或者SD卡挂节点
dev:存放设备文件
proc,sys,tmp,var:作为procfs,sysfs虚拟文件系统的挂节点

userdata用户数据软件目录组成部分:

userdata目录只包含自己产品软件内容
目录位置:/opt/project/
创建目录:mkdir /opt/project/userdata
创建userdata目录内容:
cd /opt/project/userdata
mkdir qt  tslib appbin applib apptest scripts drivers
各个目录说明:
qt目录:包含移植生成的库文件

cp /opt/project/qt/lib  qt/  -frd  //qt标准库

cp /opt/project/qt/plugins qt/ -frd  //图形处理库

tslib目录:包含移植tslib生成的库,命令和配置文件

cp /opt/project/tslib/bin tslib/ -frd//触摸屏校准测试工具

cp /opt/project/tslib/etc tslib/ -frd //配置文件

cp /opt/project/tslib/lib tslib/ -frd //动态库

appbin目录:存放ehome可执行文件

cp /opt/project/ehome/ehome  appbin/

apptest目录:存放测试用例

find  /opt/project/hwlib/  -name  *_test  -exec cp {} apptest/  \;

applib目录:存放自己制作封装的动态库

find  /opt/project/hwlib/  -name  *.so  -exec cp {} applib/  \;

drivers目录:存放驱动目标文件

find  /opt/project/drivers/  -name  *.ko  -exec cp {} drivers/  \;

scripts目录:存放应用软件启动命令

mv /opt/rootfs/etc/profile scripts/run.sh  //复制profile脚本文件

chmod 777 scripts/run.sh

vim scripts/run.sh  在文件最后添加如下内容:

#自动加载模块

find  /home/drivers/  -name *.ko  -exec insmod {}  \;

#自动运行可执行文件

/home/appbin/ehome -qws & //后台运行

根文件系统rootfs相关配置文件修改:

vim /opt/rootfs/etc/profile 添加如下内容
.  /home/scripts/run.sh  #注意“.”后要跟空格键
保存退出

利用NFS网络文件系统测试userdata是否能使用,是否能够实现软件自启动:

备份原先根文件系统rootfs/home/下的内容:
mv  /opt/rootfs/home /opt/project/home_bak
cp /opt/project/userdata  /opt/rootfs/home  -frd
cd /opt/rootfs/home/ 
ls  //可以看到userdata中的各个目录
重启开发板
看LCD是否显示ehome的界面
ps //查看进程信息
env //查看qt,tslib的环境变量是否生效
lsmod //查看驱动模块是否加载
如果测试成功,说明userdata没有问题,将/opt/rootfs/home/下的内容删除
rm  /opt/rootfs/home/* -fr
至此rootfs和userdata彻底分开,根文件系统和用户软件彻底分开

将rootfs和userdata两个目录分别制作为镜像文件进行烧写:

镜像文件对应文件系统类型的选择,采用:
rootfs制作为rootfs.img镜像,采用的文件系统类型为cramfs,只读,用于保护根文件系统;
userdata制作为userdata.img镜像,采用的文件系统类型为yaffs2,可读写;
配置linux内核,支持两种文件系统:
cd  /opt/kernel
make menuconfig
  File Systems->
         [*] Miscellaneous filesystems  --->
<*>Compressed ROM file system support (cramfs) //支持cramfs文件系统
  File Systems->
         [*] Miscellaneous filesystems  --->
<*>   YAFFS2 file system support //已经支持
保存退出
make zImage
cp arch/arm/boot/zImage /tftpboot/
重启开发板
cat /proc/filesystems //查看是否支持cramfs和yaffs2
将rootfs和userdata分别制作为cramfs和yaffs2文件系统镜像:
目录            镜像文件              文件系统类型
rootfs        rootfs.img          cramfs
userdata    userdata.img     yaffs2
rootfs.img镜像制作步骤:

cd /opt/

mkfs.cramfs rootfs   rootfs.img

cp rootfs.img /tftpboot

userdata.img镜像制作步骤:

从ftp下载mkyaffs2image工具到虚拟机中:

sudo cp  mkyaffs2image  /usr/sbin

sudo chmod 777 /usr/sbin/mkyaffs2image

cd /opt/project

mkyaffs2image userdata userdata.img

chmod 666 userdata.img

cp userdata.img /tftpboot

至此四个软件包都准备就绪:
u-boot.bin,zImage,rootfs.img,userdata.img
存放目录:/tftpboot
nandflash分区规划,用于部署镜像文件:
0----------2M----------7M----------17M------------剩余
  uboot     zImage   rootfs.img  userdata.img
注意:镜像文件大小要小于各个分区的大小!请确认!
修改nandflash的分区表

cd /opt/kernel

vim drivers/mtd/nand/s3c_nand.c 找到分区表,修改如下分区表信息:

struct mtd_partition s3c_partition_info[ ] = {

//第一分区信息 

{

       .name           = "uboot", //分区的名称

       .offset         = (0), //分区的起始地址

       .size           = (SZ_1M*2), //分区的大小

},

//第二分区信息 

{

     .name           = "kernel", 

     .offset         = MTDPART_OFS_APPEND, //追加

     .size           = (SZ_1M*5), 

},

//第三分区信息 

{

         .name           = "rootfs",

         .offset         = MTDPART_OFS_APPEND, 

         .size           = (SZ_1M*10), 

},

//第四分区信息 

{

         .name           = "userdata",

         .offset         =MTDPART_OFS_APPEND, 

         .size           = MTDPART_SIZ_FULL //剩余

}

};

保存退出

make zImage

cp arch/arm/boot/zImage /tftpboot

重启开发板

cat /proc/mtd //查看分区表

ls /dev/mtd* -lh //查看字符设备文件和块设备文件

/dev/mtd0:第一个分区的字符设备文件

/dev/mtdblock0:第一个分区的块设备文件

将zImage,rootfs.img,userdata.img烧写到nand上:

烧写方法有两种,一种通过uboot,另一种通过mtd工具

利用uboot来进行烧写的步骤:

烧写zImage:

tftp 50008000 zImage

nand erase 200000 500000

nand write 50008000 200000 500000

烧写rootfs.img

tftp 50008000 rootfs.img

nand erase 700000 a00000

nand write 50008000 700000 a00000

烧写userdata.img

tftp 50008000 userdata.img

nand erase 1100000   

nand write.yaffs 50008000 1100000 $filesize

或者

nand write.yaffs 50008000 1100000 $(filesize)

 

设置本地启动的参数信息:

setenv bootcmd nand read 50008000 200000 500000 \; bootm 50008000

setenv bootargs root=/dev/mtdblock2 init=/linuxrc console=ttySAC0,115200 rootfstype=cramfs

saveenv

重启开发板,看rootfs是否能挂接,所在第三块分区

验证根文件系统是否为只读:

cd  /

mkdir helloworld //看是否能创建目录

手动挂接存放userdata数据的第四块分区到根文件系统home目录:

在开发板上执行:

mount -t yaffs2 /dev/mtdblock3 /home

mount //看是否挂接成功

cd /home //进入第四块分区 

ls //查看第四块分区的内容,是否有之前userdata目录的内容

.  /home/scripts/run.sh  //手动运行软件启动脚本,"."后跟一个空格

自动挂接存放userdata数据的第四块分区到根文件系统home目录:

vim /opt/rootfs/etc/init.d/rcS,在文件最后添加:

mount -t yaffs2 /dev/mtdblock3 /home

ifconfig eth0 192.168.1.110

ifcofig lo 127.0.0.1

保存退出

重新制作rootfs为rootfs.img镜像,然后重新烧写

重启开发板,看软件是否能够实现自启动

系统启动完毕,还可以手动挂接虚拟机的网络文件系统,进行软件调试:

一旦系统自启动完毕,进入开发板的终端,输入挂接命令:

mount –t nfs –o nolock 192.168.1.8:/opt/rootfs /mnt/  //挂接虚拟机的网络文件系统,挂接到开发板的mnt目录,以后开发板访问mnt目录就是在访问虚拟的/opt/rootfs目录,实现远程的软件测试,不需要为了更新一个软件而重新烧写镜像文件!

cd /mnt/

ls   

以更新ehome和rootfs.img为例:

首先将要更新的ehome和rootfs.img拷贝到/opt/rootfs

cp /opt/project/ehome/ehome  /opt/rootfs

cp /opt/rootfs.img /opt/rootfs

开发板执行mount挂接网络;

cp /mnt/ehome  /home/appbin/  //更新ehome

flash_erase /dev/mtd2 0 0

nandwrite –p  /dev/mtd2 /mnt/rootfs.img //更新rootfs.img

利用mtd工具烧写u-boot.bin,zImage,rootfs.img,userdata.img镜像文件:

mtd烧写工具:flash_erase,nandwrite,nanddump等