Zybo Board 开发记录: 执行 Linux 操作系统

本文转载自:coldnew's blog
在 zybo board 开发记录: zynq 与 led 闪烁控制 一文中我们谈到了如何透过 c 语言撰写独立的程序,让它控制 zynq 的处理器系统 (processing system, ps) 去闪烁 led 的亮暗。既然 zynq 的处理器系统 (processing system, ps) 使用的是 arm cortex-a9 的处理器,那当然也可以让我们跑 linux 在 zybo board 上。
本文将简述如何自行编译 u-boot 以及 linux kernel,并搭配 busybox 制作简单的 rootfs 执行于 zybo board 上。
开发目标
在这次的开发中,我们要编译 u-boot、linux,并使用 busybox 制作简单的 rootfs 后,透过制作 sd 卡来让 zybo board 透过 sd 卡开机。
要注意到的是,由于我们要透过 sd 卡开机进入到 linux 系统,因此我们要透过 jp5 去更改开机模式。
了解开机流程
既然我们要让 zybo board 执行 linux 系统,就要先来了解一下开机流程,才知道我们大概需要准备哪些东西。从zynq-7000 all programmable soc: embedded design tutorial - a hands-on guide to effective embedded system design (ug1165)可以看到 zynq-7000 执行 linux 系统的开机流程图。
也就是说,当开始提供电源给 zynq 处理器系统 (processing system, ps) 并完成重置(reset) 后,zynq 内建的 boot rom 会去加载 第一阶段开机程序 (first stage boot loader, fsbl) ,接着加载 比特流 (bitstream) 去初始化整个 可程序逻辑(programmable logic, pl) 。 完成后,接下来就是透过 u-boot 去加载 linux kernel、device tree 以及 root file system。
了解了这个,我们就知道我们大概要准备哪些东西了。
设定好环境
在安装玩 vivado 与 xilinx sdk 后,实际上包含 zynq 在用的 arm toolchain 亦同时被安装到系统中,我们只要使用 source 命令即可让当前的环境知道 xilinx-arm toolchain 的路径。这边以 viavdo 2016.2 作为范例。
coldnew@gentoo ~ $ source /opt/xilinx/vivado/2016.2/settings64.sh
这样就可以获得 arm-xilinx-* toolchain 的命令,实际上有哪些呢? 输入个 arm-xilinx- 按下 tab 看看
如果你系统上已经有其他的 arm toolchain 的话,可以考虑跳过这一步骤,接下来要格式化 micro sd 卡。
格式化 microsd 卡
在这次的开发中,我们要设定 microsd 卡片成两个分区,第一个是 fat32 格式,第二个则使用 ext4 格式,若不会使用 fdisk 命令的话,可以透过 gparted 来进行格式化,以下是我格式化卡片的范例 (8gb 卡片)。
(实际上在本文的范例中,只会用到第一个分区,第二个分区是为了往后文章要开机到大一点的 rootfs 准备的。)
编译 u-boot
我们首先去 github 下载 digilentinc 加入 zybo board 后的 u-boot 版本,要注意这边要选择 master-next 分支。
git clone https://github.com/digilentinc/u-boot-digilent-dev.git -b master-next
完成后进入到该文件夹
coldnew@gentoo ~ $ cd u-boot-digilent-dev
编译 u-boot,记得指派编译目标为 zynq_zybo_config
coldnew@gentoo ~/u-boot-digilent-dev $ cross_compile=arm-xilinx-linux-gnueabi- make zynq_zybo_config
coldnew@gentoo ~/u-boot-digilent-dev $ cross_compile=arm-xilinx-linux-gnueabi- make
编译完成后,注意一下 u-boot 这个档案,他就是我们等等要用到的 u-boot 执行档,不过由于 xilinx tool 要找有 .elf 扩展名的档案,因此我们把它复制成 u-boot.elf 。
coldnew@gentoo ~/u-boot-digilent-dev $ cp u-boot u-boot.elf
编译 linux kernel
编译好 u-boot 后,接下来就是编译 linux kernel 了,我们一样选择 digilentinc 加入 zybo board 后的 linux kernel 版本,记得要选 master-next 分支。
git clone https://github.com/digilentinc/linux-digilent-dev.git -b master-next
接着,当然就是编译了,不过在这之前请先确定你有装 u-boot-tools 这套件,我们需要里面的 mkimage 指令,gentoo linux 可以直接用以下命令来安装。
coldnew@gentoo ~ $ sudo emerge dev-embedded/u-boot-tools
完成后进入 linux kernel 文件夹
coldnew@gentoo ~ $ cd linux-digilent-dev
编译我们需要的 uimage 文件,记得要指定 config 为 xilinx_zynq_defconfig 以及设定 uimage_loadaddr为 0x8000 。
coldnew@gentoo ~/linux-digilent-dev $ arch=arm cross_compile=arm-xilinx-linux-gnueabi- make xilinx_zynq_defconfig
coldnew@gentoo ~/linux-digilent-dev $ arch=arm cross_compile=arm-xilinx-linux-gnueabi- make
coldnew@gentoo ~/linux-digilent-dev $ arch=arm cross_compile=arm-xilinx-linux-gnueabi- make uimage_loadaddr=0x8000 uimage
coldnew@gentoo ~/linux-digilent-dev $ arch=arm cross_compile=arm-xilinx-linux-gnueabi- make zynq-zybo.dtb
编译完后,我们会需要 arch/arm/boot/uimage 以及 arch/arm/boot/dts/zynq-zybo.dtb 这两个档案,后者就是 device tree 编译出来的数据文件。
由于放入到 sd 卡上的 device tree 文件名为 devicetree.dtb ,因此这边将 zynq-zybo.dtb 改一下名。
coldnew@gentoo ~/linux-digilent-dev $ cp arch/arm/boot/dts/zynq-zybo.dtb devicetree.dtb
如果你想手动修改 device tree 并再重新编译的话,也可以这样去产生我们要的 devicetree.dtb 。
coldnew@gentoo ~/linux-digilent-dev $ ./scripts/dtc/dtc -i dts -o dtb -o devicetree.dtb arch/arm/boot/dts/zynq-zybo.dts
编译 busybox
busybox 是一个非常有趣的程序,举凡我们在 linux 下最常用的命令如 ls、cd 等到 sed、vi 他都具有相对应的简单实现,此外,这些命令实际上都只是一个软连结 (symlink) 连结到名为 busybox 的执行档,也就是说,如果我们将 busybox 进行静态编译 (static link),则制作出来的系统整体大小大约为 2 mb (kernel) + 1.4 mb (busybox),而这个系统却又可以具有许多 un*x 下的常用命令,也因此 busybox 很常用于空间有限的系统。
我们在这个开发过程中,由于只是验证执行 linux 系统的功能,因此选用 busybox 来作为我们的 rootfs。
首先先下载 busybox 的原始码,这里选用 1_25_stable 这个稳定分支
git clone git://git.busybox.net/busybox -b 1_25_stable
进行我们自己的设定
coldnew@gentoo ~/busybox $ arch=arm cross_compile=arm-xilinx-linux-gnueabi- make menuconfig
在进行设定时有以下几点要确实注意,我们要将 busybox 编译为静态链接,并且增加 init 功能,主要设定如下:
busybox settings --->
build options --->
[*] build busybox as a static binary (no shared libs)
init utilities --->
[*] init
login/password management utilities --->
[*] getty
shells --->
[*] ash
设定完成后开始进行编译
coldnew@gentoo ~/busybox $ arch=arm cross_compile=arm-xilinx-linux-gnueabi- make
编译完成后透过 make install 命令,会将编译出来的 busybox 与软连结(symlink)产生在 _install 文件夹内
coldnew@rosia ~/busybox $ arch=arm cross_compile=arm-xilinx-linux-gnueabi- make install
建立一些缺少的文件夹 (/dev、/sys …etc)
coldnew@gentoo ~/busybox $ cd _install && mkdir -p proc sys dev etc/init.d root
建立 etc/init.d/rcs 作为启动脚本,并添加以下内容
coldnew@gentoo ~/busybox/_install $
vim etc/init.d/rcs
#!/bin/sh
mount -t proc none /proc
mount -t sysfs none /sys
/sbin/mdev -s
将 etc/init.d/rcs 加入可执行权限
coldnew@gentoo ~/busybox/_install $ chmod +x etc/init.d/rcs
建立 etc/inittab ,这会让我们可以透过 uart 登入 zybo board
coldnew@gentoo ~/busybox/_install $
vim etc/inittab
#!/bin/sh
#
init script
::sysinit:/etc/init.d/rcs
#
start shell on the serial ports
::respawn:/sbin/getty -l ttyps0 115200 vt100
#
what to do when restarting the init process
::restart:/sbin/init
#
what to do before rebooting
::shutdown:/bin/umount -a -r
设定默认的 /etc/passwd 档案,我们要让 root 用户登入时不用输入密码
coldnew@gentoo ~/busybox/_install $
vim etc/passwd
root::0:0:root:/root:/bin/sh
建立 /init 并软连结到 /sbin/init ,避免 linux kernel 开机时找不到 rootfs 的 init。
coldnew@gentoo ~/busybox/_install $ ln -s /sbin/init init
接下来,由于这次我们只是要开机到 ramdisk 上的 rootfs, 因此将 busybox 做出的 rootfs 打包成 cpio 格式。
coldnew@gentoo ~/busybox/_install $ find . | cpio -h newc -o | gzip -9 > ../uramdisk.cpio.gz
再透过 mkimage 将这个 uramdisk.cpio.gz 档案转成 uboot 用的 uramdisk.image.gz
coldnew@gentoo ~/busybox/_install $ mkimage -a arm -t ramdisk -c gzip -d ../uramdisk.cpio.gz ../uramdisk.image.gz
image name:
created: sun jul 17 19:02:08 2016
image type: arm linux ramdisk image (gzip compressed)
data size: 1042106 bytes = 1017.68 kb = 0.99 mb
load address: 00000000
entry point: 00000000
在这边的这个 uramdisk.image.gz 就是我们开机会进入到的 rootfs,也是我们等等要放到 sd 卡第一个扇区的档案。
编译比特流 (bitstream)
在 zybo board 开发记录: 升级 digilent 提供的设计档 一文中,我们提到了怎样升级 digilent 提供的预先定义好接脚的配置文件 (zybo_base_system) ,这次的项目,我们就直接用这个配置文件案来进行 linux 开机的动作。
首先你必须根据该篇文章,将你的 zybo board 配置文件案升级到你用的 vivado 版本,完成后我们重新建立一个干净的项目。
首先先把先前生成的旧项目清掉:
coldnew@gentoo ~/zybo/projects/linux_bd/proj $ sh cleanup.sh
接下来用 vivado 2016.2 重新生出新的项目 ~
coldnew@gentoo ~/zybo/projects/linux_bd/proj $ /opt/xilinx/vivado/2016.2/bin/vivado -mode batch -source create_project.tcl
完成后,会看到 zybo/projects/linux_bd/proj 目录变成这样:
coldnew@gentoo ~/zybo/projects/linux_bd/proj $
tree -l 1
.
├── cleanup.cmd
├── cleanup.sh
├── create_project.tcl
├── ip_upgrade.log
├── linux_bd.cache
├── linux_bd.hw
├── linux_bd.ip_user_files
├── linux_bd.sim
├── linux_bd.srcs
├── linux_bd.xpr
├── vivado.jou
└── vivado.log
5 directories, 7 files
我们使用 vivado 打开 linux_bd.xpr 这个专案。
如果你有兴趣看他生出来的 block design 是怎样的,也可以切到 block design 那页看看
我们直接点选 program and debug -> generate bitstream 产生我们要的比特流 (bitstream)
建立 fsbl
到此,我们除了 第一阶段开机程序 (first stage boot loader, fsbl) 外,其他的程序都已经编译出执行档了,让我们来处理 fsbl 吧。
首先点选 file -> export -> export hardware
记得要勾选 include bitstream
完成后,执行 xilinx sdk
透过 file -> new -> application project 去建立我们的新项目
设定这个项目为 standalone 的项目
选择样板为 zynq fsbl
选择我们刚刚建立的 fsbl 项目,按下右键选择 build project 进行编译
建立 boot.bin
编译完 fsbl 后,选择 xilinx tools -> create boot image 去建立我们的 boot.bin
在 boot image partitions 那边,加入我们的 bitstream 以及 u-boot 档案,记得要按照顺序加入。
完成后,点选 create image 就会产生我们要的 boot.bin 到指定路径。
在这个步骤中,如果你是指令控的话,我们也可以在产生 fsbl.elf 后,建立一个名为 boot.bif 的档案,其内容如下
//arch = zynq; split = false; format = bin
the_rom_image:
{
[bootloader]/path/to/fsbl-build/fsbl.elf
/path/to/linux_bd/linux_bd.sdk/linux_bd_wrapper.bit
/path/to/u-boot/u-boot.elf
}
接下来透过 bootgen 这个命令去产生 boot.bin
coldnew@gentoo ~ $ bootgen -image boot.bif -w on -o i boot.bin
将档案复制到 micro sd 卡
好了,我们已经完成了所有准备动作,是时候将档案放到 micro sd 卡并看看结果了,在本文中我们会将以下几个档案放到 第一个分割区 (fat32) 。
coldnew@gentoo /tmp/sdc1 $
tree -l 1
.
├── boot.bin
├── devicetree.dtb
├── uimage
└── uramdisk.image.gz
0 directories, 4 files
也就是说我们的 sd 卡有的东西,要像the zynq bookp.439 这张图那样
测试开机与结果
是时候来测试结果了,要注意到你的 zybo board 的 jp5 要设定成下面这样,这样给电时,zynq 才会读取 sd 卡上面的 u-boot 并将比特流 (bitstream) 刻录到 fpga 中。
插入刚刚建立好的 sd 卡,并提供电源后,我们可以使用可以接收 uart 相关的程序,如 gtkterm、teraterm、screen、emacs 等,启动它并开启 /dev/ttyusb1 后,设定 baudrate 为 115200 ,就可以看到开机到 rootfs 的状态。
取得程序代码
本文的范例已经放置于github上,你可以到以下的 repo 去寻找,具体项目对应的教学名称,则请参考readme.md档案
延伸阅读 [1]zynq-7000 all programmable soc: embedded design tutorial - a hands-on guide to effective embedded system design (ug1165)
[2]zybo zync-7000 development board work - booting linux on the zybo
[3]the zynq book

擎朗机器人无接触送餐 真正做到免接触、避免交叉感染
华硕ZenFone Live L1发布 搭载AndroidGo
GARMIN佳明Forerunner235评测 值不值得买
基于FPGA Cyclone EP1C20实现CT机扫描控制系统的应用方案
绕线型异步电动机的调速
Zybo Board 开发记录: 执行 Linux 操作系统
母差保护中电流绕组的选择
DCM技术加持汽车雷达,推进更精准自动驾驶传感实现
什么是KNI/Instruction Issue/Instr
一种高精度、测量快速又易于使用的激光测距仪
RFID访客智能管理系统的特点及应用
安捷伦科技推出针对先进射频和微波应用的高性能信号分析仪
2020世界人工智能大会将采用线上活动为主的形式举办
这次厉害了!iPhone8不仅取消Hmoe键实现全身屏,也提升了防水性能!
三星S8什么时候上市最新消息:三星S8打“骨折”出售只卖1200元?还是韩国人会搞事情
美国先进制造战略给我国制造业起到了怎样的作用
苹果A17属于什么档次?苹果A17提升大吗?
利用SSM2603的立体声数字音频CODEC方案
电信运营商在网络虚拟化中的挑战
传统SMD封装与COB封装对比区别在哪?