一路上看着n多遍的官方文档和各路大神的文档,总算编译成功,把心酸记录一下,为以后自己的使用方便
先把官方文档挂上
http://www.wiki.xilinx.com/U-boot
http://www.wiki.xilinx.com/Build+kernel
http://www.wiki.xilinx.com/Build+and+Modify+a+Rootfs
http://www.wiki.xilinx.com/Build+Device+Tree+Blob
环境为Ubuntu12.04
目标版 zedboard
目前system.bit文件尚未编译,用的是官方的版本。
目录
1 、交叉编译工具的安装
2、uboot的编译
3、NFS内核的编译
4、根文件系统的制作和修改
6、qt的编译
7、opencv的编译安装
首先安装交叉编译工具,xilinx-arm-gcc/g++
由于官方目前把工具撤了,换成了其他的东西,装那个肯定行,不过还是习惯直接安装
https://secure.xilinx.com/webreg/login.do?oamProtectedResource=wh%3Dwww.xilinx.com%20wu%3D%2Fmember%2Fmentor_codebench%2Farm-2010.09-62-arm-xilinxa9-linux-gnueabi.bin%20wo%3D1%20rh%3Dhttp%3A%2F%2Fwww.xilinx.com%20ru%3D%252Fmember%252Fmentor_codebench%252Farm-2010.09-62-arm-xilinxa9-linux-gnueabi.bin
安装时会提示会提示需要bash,而Ubuntu为了提高速度,默认把shell改成了dash,那么需要先改回来(如果在centos下则不需要那么麻烦)
sudodpkg-reconfigure dash
然后选择否
sudo./xilinx-2011.09-50-arm-xilinx-linux-gnueabi.bin
好了,接下来是一个图形安装界面,肯定很熟悉啦
安装完之后,设置环境变量吧
当前用户在~/.bashrc下。但是后面的安装需要权限,所以会造成很多问题
我就是栽在这里很多时间啊
那么直接修改 /etc/profile
sudo vi/etc/profile
在最后添加上
exportPATH=/path/to/cross/compiler/bin:$PATH #注 前面 为你的安装路径
exportCROSS_COMPILE=arm-xilinx-linux-gnueabi-
重新启动机器,再试试 arm-按下tab键会不会自动补全?
然后写一个hello world ,编译放到板子里面运行,ok吧
交叉编译工具的安装到此结束
2、uboot的编译
u-boot用来引导linux内核,这个没什么好说的,
不过我遇到过一个问题,机器id不匹配,这不是重点,我竟然没有找到他在哪里传递的参数。。。。。
1下载u-boot源码
https://github.com/Digilent/u-boot-digilent
啃爹的是里面没有saveenv这个命令,搞得我每次都要手动输入一次。
u-boot-xlnx-master/include/configs/zynq-commom.h
下面有一些描述zedboard的参数
在u-boot的include/configs/zynq_common.h文件中决定了内核、文件系统和设备树编译后的文件名。如Kernel_image决定了u-boot引导zImage还是uImage。
make zynq_zed_config
make -j4 (多线程编译更快)
mv u-boot u-boot.elf (后面制作boot.bin需要)
至此,u-boot编译结束
3、NFS内核的编译
我们自己编译内核有那么几个原因,
第一别人的始终不是自己的,自己编译的才是自己的
最重要的是,竟然不支持NFS,不可忍
下载内核
https://github.com/Digilent/linux-digilent
以下引用
http://www.eefocus.com/thinki_cao/blog/13-06/295414_bcd34.html
http://blog.163.com/thinki_cao/blog/static/83944875201439112133825/
非常感谢,如果不合适,请告知谢谢
ZEDBoard上出厂的SD卡中自带了一个较完整的linux系统,虽然是精简版,但是对于开发来说已经足够了,在嵌入式linux开发中,挂载NFS协助调试非常常见,但是Digilent给出的内核中并没有开启NFS的支持,具体可以通过/proc/filesystems中有没有nfs相关的内容,执行cat /proc/filesystems | grep nfs,没有找到nfs相关的内容证明内核没有开启对nfs的支持,接下来我们就需要手动配置一下内核,开启nfs支持:(内核源码可以在书的光盘中找到,也可以从github上克隆下来:https://github.com/Digilent/linux-3.3-digilent.git)
$ make ARCH=arm digilent_zed_defconfig
$ make menuconfig
进入File systems --->NetworkFile Systems --->可以看到默认并没有开启nfs的支持,现在我们开启nfs,相关的选项如下:
注意这里我们是要把nfs驱动编译在内核中,所以选择built-in,然后保存配置,不过现在还不能开始编译,如果现在编译根本通不过去,具体原因可能是因为保存的配置又多了额外的很多东西,所以我们只能去找根目录下的.config文件,找到nfs对应的那几行,这里主要是:
CONFIG_NETWORK_FILESYSTEMS=y
CONFIG_NFS_FS=y
CONFIG_NFS_V2=y
CONFIG_NFS_V3=y
# CONFIG_NFS_V3_ACL is not set
# CONFIG_NFS_V4 is not set
# CONFIG_NFS_SWAP is not set
CONFIG_ROOT_NFS=y
# CONFIG_NFSD is not set
CONFIG_LOCKD=y
CONFIG_LOCKD_V4=y
CONFIG_NFS_COMMON=y
CONFIG_SUNRPC=y
# CONFIG_SUNRPC_DEBUG is not set
# CONFIG_CEPH_FS is not set
# CONFIG_CIFS is not set
# CONFIG_NCP_FS is not set
# CONFIG_CODA_FS is not set
# CONFIG_AFS_FS is not set
将上面的内替换到arch/arm/configs/digilent_zed_defconfig中,不过这里先要删除掉
# CONFIG_NETWORK_FILESYSTEMS is not set这一行,并在该位置加上上面的配置内容,这样才能保证内核能够顺利编译通过
接下来执行:
$ make ARCH=arm digilent_zed_defconfig
$ make ARCH=arm
编译通过之后,内核即arch/arm/boot目录下的zImage,使用新内核启动以后,执行cat /proc/filesystems | grep nfs,可以找到nfs的设备,说明开启了nfs的支持,挂载指令:
# mount -t nfs SERVERIP:SERVER_PATHLOCAL_PATH -o proto=tcp -o nolock
对于pc机上开启nfs服务,请参考这篇帖子:
【参赛手记】NFS挂载加速程序开发,请注意,这里pc机是nfs服务的提供者,zedboard上的nfs是客户端,所以是把pc机上的目录挂载到zedboard上的linux文件系统中的目录,
其中:SERVERIP是电脑的ip,SERVER_PATH是电脑nfs的提供的挂载路径,LOCAL_PATH是zedboard上的linux文件系统中的路径
举个例子来说,比如电脑的ip是192.168.1.100提供的挂载路径是/rootfs,我们需要把电脑上的路径挂载到板子上的/mnt目录下,(请确保两者能够ping通)那么可以在usb转串口的终端中输入:
# mount -t nfs 192.168.1.100:/rootfs /mnt-o proto=tcp -o nolock
解挂载的时候输入
# umount /mnt
即可
这个时候可以把内核放到sd卡里面试试,是否可以实现nfs挂载
如果要实现nfs启动
nfs启动需要修改启动参数,在以前启动参数都是在U-Boot中以bootargs环境变量的形式传递给内核的,现在由于ZedBoard启用了设备树,所以启动参数都是从设备树中传递给Linux内核,我们先看一下设备树中默认的启动参数:
从SD卡启动Linaro:
bootargs = "console=ttyPS0,115200root=/dev/mmcblk0p2 rw earlyprintk rootfstype=ext4 rootwaitdevtmpfs.mount=1";
console
指定控制台的设备以及波特了
root
指定挂载的根文件系统,这里是/dev/mmcblk0p2,当时在创建linaro的sd卡镜像时会特别提示需要在SD卡中创建两个分区,第一个分区是FAT文件系统,存放内核,设备树,BOOT.bin等,而第二个就是存放Linaro文件系统了,这里也就是对应的mmcblk0p2设备。
rootfstype
制定跟文件系统的类型,这里是ext4
rw
rw参数告诉内核以读写方式加载根文件系统。 ro参数告诉内核以只读方式加载根文件系统,以便进行文件系统完整性检查,比如运行fsck;
earlyprintk
在console设备注册前(也就是printk注册之前)提供对打印函数的支持,这个之前就可以使用early_printk()函数来代替printk()函数
rootwait
让内核等待所有设备都被初始化完成后,再去执行root文件系统的挂载工作。这样可以避免根文件系统驱动初始化成功之前就挂载根文件系统。详细的说明可以参考http://blog.csdn.net/liujixin8/article/details/5704991
devtmpfs.mount
是否挂载devtmpfs,1是挂载,0是不挂载。Devtmpfs lets the kernel create a tmpfs very early at kernelinitialization, before any driver core device is registered. Every device witha major/minor will have a device node created in this tmpfs instance. After therootfs is mounted by the kernel, the populated tmpfs is mounted at /dev. Ininitramfs, it can be moved to the manually mounted root filesystem before/sbin/init is executed.相关的信息自己Google去吧。
设置serverip
Setenv serverip 192.168.1.11(电脑的ip,建立tftp服务器,win下可以用tftpd32)
run jtagboot
其他命令可以查看printenv
顺便记录一下uImage和zImage的区别
vmlinux是内核文件,zImage是一般情况下默认的压缩内核映像文件,压缩vmlinux,加上一段解压启动代码得到。而uImage是u-boot使用bootm命令引导的Linux压缩内核映像文件格式,是使用工具mkimage对普通的压缩内核映像文件(zImage)加工而得。它是uboot专用的映像文件,它是在zImage之前加上一个长度为 64字节的“头”,说明这个内核的版本、加载位置、生成时间、大小等信息;其0x40之后与zImage没区别。
由于bootloader一般要占用0X0地址,所以,uImage相比zImage的好处就是可以和bootloader共存。
其实就是一个自动跟手动的区别,有了uImage头部的描述,u-boot就知道对应Image的信息,如果没有头部则需要自己手动去搞那些参数。
如何生成uImage文件?首先在uboot的/tools目录下寻找mkimage文件,把其copy到系统/usr/local/bin目录下,这样就完成制作工具。然后在内核目录下运行make uImage,如果成功,便可以在arch/arm/boot/目录下发现uImage文件,其大小比zImage多64个字节。
此外,平时调试用uImage,不用去管调整了哪些东西;zImage则是一切OK后直接烧0X0。开机就运行。
uImage头部信息
使用UE打开uImage格式的内核文件,第二行倒数4个字节为05 02 02 00
查看结构体image_header得到,分别为Operating System、CPU architecture、Image Type和Compression Type,对比宏定义,发现操作系统为IH_OS_LINUX(05)、架构为IH_ARCH_ARM(02)、映像类型为IH_TYPE_KERNEL(02)、无压缩。
zImage
uImage
以上可以明显的看出头64字节为头部
zImage之前加上一个长度为64字节的“头”,说明这个内核的版本、加载位置、生成时间、大小等信息;其0x40之后与zImage没区别。
根文件系统的制作和修改
官方有提供一个8M的文件系统,基本的命令都有了,但是有时候想要对他进行更改,比如加入某些库文件或者,开机时自动启动某些程序和挂载sd卡,那么可以这么做
1解压镜像
gunzip ramdisk.image.gz
2挂载镜像
chmod u+rwx ramdisk.image
mkdir tmp_mnt/
sudo mount -o loop ramdisk.image tmp_mnt/
cd tmp_mnt/
3,这里就可以对他干嘛干嘛了,比如让开机自动挂载sd卡
cd etc/init.d/
sudo vi rcS
在最后添加上
Mount /devmmcblk0p1 /mnt
保存退出:wq
4取消挂载并重新压缩
sudo umount tmp_mnt/
gzip ramdisk.image
如果要建立一个镜像,可以这么做
To create an initrd fromscratch, tools such as Buildroot or Yocto may be used to populate thefilesystem (with BusyBox, tools, etc.).
Alternatively, an empty initrd may be createdand then populated with the desired filesystem contents as specified above. Tocreate an empty (8MB) initrd:
dd if=/dev/zero of=ramdisk.image bs=1024 count=8192
mke2fs -F ramdisk.image -L "ramdisk" -b 1024 -m0
tune2fs ramdisk.image -i 0
chmod a+rwx ramdisk.image
如果是initramfs
To modify an initramfs:
1. Extract the contents of the cpio.gz archive.
mkdir tmp_mnt/
gunzip -c initramfs.cpio.gz | sudo sh -c 'cd tmp_mnt/ && cpio -i'
cd tmp_mnt/
2. Make changes to the filesystem.
3. Repack the filesystem into a cpio.gz archive.
sh -c 'cd tmp_mnt/ && sudo find . | sudo cpio -H newc -o' | gzip -9 > new_initramfs.cpio.gz
To create an initramfs from scratch, tools suchas Buildroot or Yocto may be used to populate the filesystem (with BusyBox,tools, etc.).
Alternatively, initramfs image may be created bypopulating a directory with the desired filesystem contents and packing thesecontents into a cpio.gz archive as mentioned above.
把这个考的sd卡中,试试有没有自动挂载
6、qt的编译
我们在zedboard上使用linux平台,怎么少的了界面呢?界面可以选用qt或gtk,
不过gtk看起来就很庞大,没什么必要吧,而且qt用的也比较广泛
根据官网来制作,值得注意到是,我用官网的4.7版本编译不过换了4.8.6就可以了,如果编译4.7版本遇到问题可以试试换一个版本。
在/etc/profile下加上几句话
export ZYNQ_QT_BUILD=/path/to/qt/build
export ZYNQ_QT_INSTALL=/path/to/qt/install
export PATH=$ZYNQ_QT_INSTALL/bin:$PATH
注意上面的应该是自己的安装路径
解压源码
cp qt_build_src.tar $ZYNQ_QT_BUILD
cd $ZYNQ_QT_BUILD
tar xfv qt_build_src.tar
其中
qt-everywhere-opensource-src-4.7.3.tar.gz – Qt source archive
qmake.conf – Qt qmake configuration file
qwt-6.0.1.tar.bz2 – Qwt source archive
qwtconfig.pri – Qwt qmake project include file
交叉编译
cp $ZYNQ_QT_BUILD/qmake.confmkspecs/qws/linux-arm-gnueabi-g++
./configure \
-embeddedarm \
-xplatformqws/linux-arm-gnueabi-g++ \
-little-endian \
-opensource\
-host-little-endian \
-confirm-license \
-nomakedemos \
-nomakeexamples \
-prefix$ZYNQ_QT_INSTALL
Make
su - #ifyou need root access to be able to install
make install
编译Qwt – QtWidgets
cd $ZYNQ_QT_BUILD
tar xjfv qwt-6.0.1.tar.bz2
cd qwt-6.0.1
cp $ZYNQ_QT_BUILD/qwtconfig.pri .
qmake qwt.pro
make
su - #ifyou need root access to be able to install
make install
把运行库加入lib为制作镜像做准备
cp -P/path/to/cross/compiler/arm-xilinx-linux-gnueabi/libc/usr/lib/libstdc++.so* \
$ZYNQ_QT_INSTALL/lib
由于文件系统镜像只有8M,不可能把链接库放到目录下,所以我们需要制作一个镜像,以便挂载
6、制作镜像
cd $ZYNQ_QT_BUILD
dd if=/dev/zeroof=qt_lib.img bs=1M count=80
mkfs.ext3 -Fqt_lib.img
su - #if you need rootaccess to be able to install
chmod go+w qt_lib.img
mount qt_lib.img-o loop /mnt
cp -rf$ZYNQ_QT_INSTALL/* /mnt
chmod go-wqt_lib.img
umount /mnt
到这里qt的库编译结束了,能不能用,得找一个程序试试
主机上安装qt
到这个页面
http://download.qt.io/archive/qt/
下载你所要安装的版本
双击就安装好了,好简单 0.0
建立一个qt工程,在电脑上线运行试试,目前还没有建立交叉编译工具的路径,
所以先拷贝一份命名为zedboard
然后
qmake –project
qmake
make
应该会生成一个zedboard二进制elf文件
拷贝到sd卡
前面已经安装好了带NFS的内核,那么可以直接挂载主机的目录,把文件放大目录中,zedboard就可以读取了
把qt_lib.img也放入,
挂载到一个与主机相同路径的目录
比如主机的qt交叉编译库安装在/opt/install
那么呀挂载到开发板的这个目录下
然后执行./zedboard –qws
画面出来喽
7、opencv的编译安装
待续。。。。。
虽然做的工作就那么一点,但是都是在各种错误中走过来的,有喜悦也很累。把它记录一下,希望以后自己忘记的时候回来可以看到,要是能帮到别人就更好了。