看看,我们组里的那块板子是不是 ZedBoard!!
转自 http://blog.michiru.me/posts/zedboard-bring-up-guide.html
一份简单而完整的ZedBoard启动教程,如果凑巧你也在折腾这块板子,希望能帮助你少花些时间在这些SB的工作上。大概分成三个部分:
- 使用编译好的文件和ramdisk
- 使用编译好的文件和Linaro Ubuntu Linux
- 自行编译需要的文件
0.基础
ZedBoard是一块不错的板子,价格便宜,外设丰富,还有Xilinx的官方支持,性能也还说的过去……其的核心是Xilinx的Zynq-7000系列AP SoC(All Programmable System on Chip)芯片,型号是Zynq-7020。简单来说其由两部分组成:ARM双核Cortex-A9和Artix-7 Fabric,也就是ARM和FPGA集成在一块芯片上啦。ARM部分被Xilinx称作PS,FPGA部分则被称作PL。
ZedBoard板子可以从JTAG(电脑辅助)或者由SD卡启动,或者其它的一些奇怪的启动方式。这里我们专注与从SD卡启动,这时FPGA的配置是在开机时,由ARM来完成的。也就是说,即使只想用FPGA,空转也好,也要让ARM启动起来。如果有JTAG辅助,想使用FPGA就只需要bitstream文件了。整个启动过程是:
- 开机
- 写死在板上BootROM中的程序启动,读启动方式设置的跳线,如果是SD模式启动电话,读SD卡第一分区,寻找Boot.bin文件。
- Boot.bin中应该包含FSBL(First stage boot loader)程序,它接管CPU。
- FSBL初始化开发板。如果有bitstream文件,那么初始化FPGA。之后将CPU交给Boot.bin中第二块代码接管。它可以是用户自己的程序,或者是SSBL(Second stage boot loader)。一般是SSBL。
- SSBL(通常是U-Boot)接管CPU。它可以做一些准备工作之后启动Linux内核,也可以启动用户自己的程序。一般是Linux内核。
- 内核做很多很多工作,比如加载驱动,加载Rootfs(文件系统)等等。
- 用户可以开始使用操作系统了
所以,启动这块板子,我们需要的数据有:FSBL程序、bitstream文件(可选,如果你不想使用FPGA端的资源的话,但HDMI输出需要FPGA来实现)、U-Boot、Linux Kernel、Rootfs。并且我们采用SD卡的方式启动。
关于Rootfs
Rootfs也就是文件系统,有两种可供选择:
-
ramdisk:非常小,几乎没什么功能,运行在ram里,任何修改在重启之后就会丢失。
-
完整的Linux文件系统,比如Linaro Ubuntu。全功能,可能非常庞大,需要SD卡多分出一个区来放置,任何修改也都保存在SD卡里。另外一个可以选择的是Arch。
我们可以从Xilinx和Linaro的官网上直接下载已经编译好的文件,或者从源代码编译出它们。
关于自己编译
自己编译也只是使用别人的代码,别人的工具,在自己的计算机里运行一遍。就结果来看,这和使用别人已经编译好的文件,直接启动板子没什么不同。不过从头开始做一遍,可以让你了解哪些部分有修改的余地。
我的操作系统是Ubuntu 14.10,搭建编译环境比较方便,安装好Xilinx的开发工具套件Vivado编译环境就差不多了。对Windows,要得到好的编译环境不容易,我不知道怎么搞定。但是,Linux下,那个USB-JTAG芯片的驱动又不是很容易装上。考虑到这些破事儿,Windows宿主+Linux虚拟机是一个推荐的方案。编译都在Linux下完成,如果需要JTAG就回到Win。
1.简单的方式
首先使用最快最简单的方式:使用编译好的文件,并且使用ramdisk来启动。首先去Xilinx的官网下载到已经编译好的文件。目前最新的是Zynq 2014.4 Release (latest),里面包括了所有启动需要的文件。使用
tar xf 2014.4-release.tar.xz
来解压。有用的文件是:
- uImage:Linux内核
- uramdisk.image.gz:ramdisk
- zed/bing.bin:启动文件
- zed/devicetree.dtd:设备树文件
- zed/fsbl.elf:FSBL
- zed/u-boot.elf:SSBL
格式化SD卡
我们需要准备SD卡,用来启动ZedBoard。这需要一个4G或者以上容量的SD卡来装载所有启动所需要的文件。
-
使用ramdisk时可以简单的把整个SD卡分为一个区,格式化成FAT格式。不过我建议依旧按张下面的方式分区,免去后续的折腾。
-
使用完整的Linux文件系统时,需要将SD卡分为两个分区:第一分区格式为FAT32,大小足够装下启动用的文件,50MB绰绰有余。第二个分区为ext4,占剩下的所有空间,用来装Ubuntu什么的文件系统。因为Windows自带的磁盘工具是没有办法格式化和读写ext4格式的磁盘,所以你需要Linux。
插入SD卡到读卡器再到电脑上,然后在终端运行:
lsblk
这会列出硬盘、USB、SD卡等储存设备。从输出中找出SD卡的设备名,一般是/dev/mmcblk0
。我们用fdisk
程序来分区:
sudo fdisk /dev/mmcblk0
输入o来清除现在有的分区(会丢掉所有数据)
输入p来查看所有的分区,应该是空的。
接下来按n新建第一个分区,按p选择使用主分区,按1表示这是第一个分区,按回车来使用默认的开始扇区,输入+50M来分配分区大小。
输入n新建第二个分区,按p选择使用主分区,按1表示这是第二个分区,回车两次来使用默认的大小。
参考输入输出:
Command (m for help): n
Partition type:
p primary (0 primary, 0 extended, 4 free)
e extended
Select (default p): p
Partition number (1-4, default 1): 1
First sector (2048-15759359, default 2048):
Using default value 2048
Last sector, +sectors or +size{K,M,G} (2048-15759359, default 15759359): +50M
Command (m for help): n
Partition type:
p primary (1 primary, 0 extended, 3 free)
e extended
Select (default p): p
Partition number (1-4, default 2): 2
First sector (411648-15759359, default 411648):
Using default value 411648
Last sector, +sectors or +size{K,M,G} (411648-15759359, default 15759359):
Using default value 15759359
接下来设置启动标志和分区类型:
Command (m for help): a
Partition number (1-4): 1
Command (m for help): t
Partition number (1-4): 1
Hex code (type L to list codes): c
Changed system type of partition 1 to c (W95 FAT32 (LBA))
Command (m for help): t
Partition number (1-4): 2
Hex code (type L to list codes): 83
写入之前查看确认一下:
Command (m for help): p
Disk /dev/mmcblk0: 8068 MB, 8068792320 bytes
249 heads, 62 sectors/track, 1020 cylinders, total 15759360 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0x920c958b
Device Boot Start End Blocks Id System
/dev/mmcblk0p1 * 2048 411647 204800 c W95 FAT32 (LBA)
/dev/mmcblk0p2 411648 15759359 7673856 83 Linux
最后确认写入SD卡:
Command (m for help): w
The partition table has been altered!
Calling ioctl() to re-read partition table.
WARNING: If you have created or modified any DOS 6.x
partitions, please see the fdisk manual page for additional
information.
Syncing disks.
分区完成之后需要格式化各个分区:
mkfs.vfat -F 32 -n boot /dev/mmcblk0p1
mkfs.ext4 -L root /dev/mmcblk0p2
挂载第一个分区:
mkdir boot
mount /dev/mmcblk0p1 boot
将2014.4-release.tar.xz中解压缩出的zed/boot.bin、zed/devicetree.dtb、uImage、uramdisk.image.gz四个文件复制到SD卡第一个分区的根目录中(注意不要保留文件结构)。
取消挂载:
sudo umount boot
启动Zedboard
现在已经可以使用SD卡来启动板子。将开发板上控制启动模式的跳线设置为:
MIO[5]:1
MIO[4]:1
MIO[3]:0
这代表着从SD卡启动(顺便,3个全部0表示从JTAG启动)。从电脑上拔出准备好的SD卡,然后插在ZedBoard的读卡器上。用一根USB线缆将电脑和板上的USB-UART口相连,接通电源。打开电脑的串口终端工具(比如Windows下的teraterm,Linux下的minicom),Windows找设备名COMx的设备,Linux找ttyACMx。设置串口参数为:115200,8N1(波特率115200bps,数据位8位,不校验,停止位1位,硬件软件握手协议都是无)。如果一切顺利的话,就能看到从串口来的输出了。
默认用户名是root
,密码也是root
。
这里有个小问题,ZedBoard开机之后,终端程序才能打开设备。
2.稍复杂一点的方式
这次我们使用Linaro Ubuntu。在上面准备好的SD卡的基础上,去Linaro的下载页下载Linaro Ubuntu文件系统。我的选择是15.03的nano版本,即linaro-utopic-nano-20150220-698.tar.gz文件。其他版本比nano更大,东西也更多。
SD卡第一个分区中保留boot.bin、devicetree.dtb、uImage三个文件,可以删掉ramdisk免得不小心启动进去了。按照下面的步骤将Linaro Ubuntu复制到sd卡的第二个分区(mmcblk0p2
)中:
1.解压缩压缩包:
sudo tar zxf flinaro-utopic-nano-20150220-698.tar.gz
2.插入SD卡,你的OS可能将其自动挂载了,取消掉挂载。
sudo umount /dev/mmcblk0p2
3.将SD卡的第二个分区挂载
mkdir rootfs
sudo mount /dev/mmcblk0p2 rootfs
4.使用rsync
来拷贝文件系统到SD卡,这可能得花一点时间,你得一直等到终端恢复响应:
sudo rsync –a binary rootfs
sync
5.解除SD卡的挂载:
sudo umount rootfs
从电脑拔出SD卡,插入ZedBoard开机,不过这时U-Boot仍然会试图从ramdisk启动,我们需要设置一下它:
1.ZedBoard启动过程中按下任何键来阻止U-Boot启动。
2.设置新的U-Boot环境变量
setenv bootargs \'console=ttyPS0,115200 root=/dev/mmcblk0p2 rw rootwait\'
setenv sdboot \'echo Copying Linux from SD to RAM... && mmcinfo && fatload mmc 0 0x3000000 ${kernel_image} && fatload mmc 0 0x2A00000 ${devicetree_image} && bootm 0x3000000 - 0x2A00000\'
3.保存环境变量:
saveenv
4.输入boot
来启动。
3.最复杂的方式
下面我们会试图编译任何可以编译的东西
3.0 需要的文件
需要的源代码大部分可以在Xilinx的GitHub页面上找到。xlnx的后缀代表这是Xilinx的分支。可以使用git来下载。或者到GitHub下载zip。
需要关注的项目:
注意这几个项目都挺大,包括历史记录就更大了。使用Git下载那庞大无用的.git文件夹可能会让你掀桌子,推荐下载zip压缩包。分别解压到某目录。
3.1 编译环境
首先是需要的开发软件和工具们,感谢Xilinx,只需要安装一个套件Xilinx Vivado,它的WebPACK版本是免费的。
根据你的操作系统和版本选择下载。主要需要的是Vivado和Software Development Kit(SDK),Documentation Navigator和License Management Tools随意。推荐最大的All OS and SDK Full Installer。
安装
解压tar压缩包到任意目录,打开目录。对于windows,双击运行xsetup.exe
;对于Linux,./xsetup
,如果要安装到默认目录/opt/Xilinx
下,你可能需要root权限(sudo ./xsetup
)。
跟随安装向导,在其询问软件版本时,选择Xilinx Vivado WebPACK(免费!);在其询问是否安装Cable驱动时,对Linux应该不勾选,因为一般都会失败(起码我失败了),最后还得自己处理;其他选项随意。
安装略消耗时间。
运行
Windows下不需要特别做什么,就可以从开始菜单或者桌面的快捷方式运行。Linux下需要一点点配置:
source /opt/Xilinx/Vivado/2013.4/settings32.sh
如果是64位系统:
source /opt/Xilinx/Vivado/2013.4/settings64.sh
sh文件会为你配置好环境变量,然后在终端就能在终端中运行开发工具了(主要是vivado
和xsdk
)。每次打开一个新的终端,都需要这么做一次,觉得太麻烦的话可以把这句写在你的~/.bashrc
里。不过这样每次启动终端都会看到sh文件的输出,还可能会造成别的什么问题。可以修改sh文件,注释掉所有echo
的行。
许可证书
尽管WebPACK是免费的,仍需要从Xilinx官网取得许可证书。大概是提供邮箱,个人信息等注册账户;生成一个WebPACK的证书;email给自己或者直接下载;得到文件Xilinx.lic
。
运行xlcm
来导入证书,或者将其放在~/.Xilinx
文件夹下。
关于驱动
目前我还没有搞定Digilent USB-JTAG线的Linux驱动,没有办法用JTAG下载和调试,所以我滚去了Win。如果你用什么方法搞定了,请告诉我。
3.2 编译FSBL
FSBL即第一阶段启动器,它负责初始化开发板,配置FPGA,之后将CPU交给第二阶段启动器(SSBL)接管。对于我们,SSBL就是U-Boot。
打开Xilinx SDK(快捷方式或者xsdk
),新建一个项目,类型是New Application Project。填写好项目名称(比如myfsbl)目录、硬件平台(zed_hw_platform)、处理器(PS7_cortexa9_0)、OS平台(Standalone)、语言(C)、版支持包(New一个!)之后不要直接结束,选择下一步,使用Zynq FSBL
模板。
SDK会产生3个项目:myfsbl、myfsbl_bsp、zed_hw_platform,并且自动编译,生成二进制文件myfsbl.elf
(在myfsbl/Debug/
下)。我的Ubuntu13在这一步报错了,因为没有找gmake——为此你得把gmake
指向make
cd /usr/bin
sudo ln -s make gmake
一般来说,这里自动生成的FSBL代码不需要特别修改就能直接使用,不过你可能希望FSBL输出一些信息用于debug(或者单纯因为好奇)。修改src下的fsbl.h
文件,在大篇注释后,合理的位置增加一行:
define FSBL_DEBUG_INFO
重新编译文件!这样FSBL在启动过程中,就会向串口(USB-UART)输出信息。关于此详细的解释看那大篇注释。
生成的myfsbl.elf
就可以用来替换下载得到的fsbl.elf
。
3.3 编译bitstream文件
bitsteam文件,或者叫比特流文件(*.bit
),被fsbl用来配置FPGA。对于Zedboard的启动来说,这个是可选的。如果要使用Zedboard的FPGA部分,就得写HDL代码,来得到这个文件。这肯定是整个工程很大部分的工作量,好好努力吧。
或者下载一个别人已经写好的bitstream文件。
3.4 编译U-Boot
U-Boot也是一个bootloader,在ZedBoard启动的第二阶段,被用来启动linux内核。适用于ZedBoard的U-Boot源代码可以在Xilinx的U-Boot项目找到。
为了得到u-boot二进制文件,我们得编译它。在Linux,打开终端,cd
到u-boot文件夹下。确保编译环境(source了Vivado的sh文件,有gcc能make)。
首先要配置使用什么交叉编译器:
export CROSS_COMPILE=arm-xilinx-linux-gnueabi-
注意最后的-
。编译可以分为两步:
make zynq_zed_config
make
或者一步:
make zynq_zed
漫长的编译过程之后,会得到两个有用的东西:u-boot
文件(在u-boot-xlnx/
下,大约1.4MB)和mkimage
工具(u-boot-xlnx/tools
下)。将u-boot
文件复制到boot_image
文件夹,改名为u-boot.bin
。
mkimage
小工具在之后的步骤中会用到,将其添加到PATH环境变量中。
cd tools
export PATH=`PWD`:$PATH
3.5 将FSBL、bitstream、U-Boot合成启动镜像:
在boot_image
文件夹下新建一个文本文件boot.bif
,写入以下内容:
image : {
[bootloader]fsbl.elf
bitstream.bit
u-boot.elf
}
使用bootgen小工具(Vivado附带)来生成启动镜像boot.bin
bootgen -image boot.bif -o i boot.bin
3.6 编译Linux Kernel
编译Linux内核。同样需要配置好编译环境,cd
到linux-xlnx
目录下:
export CROSS_COMPILE=arm-xilinx-linux-gnueabi-
export ARCH=arm
之后先做配置:
make xilinx_zynq_defconfig
make menuconfig #可选
编译需要用到上节中生成的mkimage
小工具,确保已将其所在目录添加到PATH。如果你使用已经编译好的U-Boot文件而跳过了上节,那么你应该从源里安装它:
sudo apt-get install u-boot-tools
开始编译:
make UIMAGE_LOADADDR=0x8000 uImage
漫长的编译之后,在<some-path>/linux-xlnx/arch/arm/boot/
下,会生成Image
、zImage
两个文件。如果你在上一步中为mkimage
小工具配置好了环境变量,第三个文件uImage
也会出现。如果忘记了,也可以手动生成:
mkimage -A arm -O linux –T kernel -d zImage uImage
得到uImage
可以用来替换下载得到的文件。
3.7 修改BusyBox Ramdisk:
已经编译好的Ramdisk我们没有办法从头做这个文件,只能修改它:
解压缩文件系统镜像:
gunzip ramdisk.image.gz
挂载镜像:
chmod u+rwx ramdisk.image
mkdir tmp/
sudo mount -o loop ramdisk.image tmp/
cd tmp/
修改文件内容,比如hostname
取消挂载:
sudo umount tmp/
gzip ramdisk.image
最后需要将已经其添加上U-Boot字头。mkimage
小工具会为你做这件事情:
mkimage -A arm -T ramdisk -C gzip -d ramdisk.image.gz uramdisk.image.gz
3.8 编译Device Tree Blob
Device Tree描述了整个板子的硬件结构,是Linux内核启动必不可少的部分。它主要涉及2个文件:dts
、dtb
、和一个小工具:dtc
。其中dts
是文本文件, 实用人类可读的格式描述了硬件结构。dtb
是二进制文件。两者之间的转换工具是dtc
。
需要注意的是,设备树文件需要和bitstream文件对应,如果没有设计FPGA,也就是没有.bit
文件的话,可以使用linux-xlnx下已经有的dts
。如果要使用Linaro Ubuntu,并且不想第一次开机时手动配置U-Boot的话,打开zedboard.dts
文件,将其中的:
bootargs = "console=ttyPS0,115200 root=/dev/ram rw earlyprintk";
修改为:
bootargs = "console=ttyPS0,115200 root=/dev/mmcblk0p2 rw earlyprintk rootfstype=ext4 rootwait devtmpfs.mount=0";
这句定义了U-Boot将会传递给Linux Kernel的参数,console=ttyPS0,115200
设置了系统的输出将会送入ttyPS0这个设备,也就是USB-UART接口。而root=/dev/mmcblk0p2
则是说明文件系统是SD卡的第二个分区。
在linux-xlnx
目录下,
make zynq-zed.dtb
具体来说./scripts/dtc/dtc
这个小工具将zrch/arm/boot/zynq-zed.dts
编译成了Device Tree Blob文件(在linux-xlnx/arch/arm/boot/dts/
下),它可以用来替换下载得到的文件。
它也可以反向转换dtb到dts文件:
./scripts/dtc/dtc -I dtb -O dts -o <devicetree name>.dts <devicetree name>.dtb
如果你设计FPGA生成了bitstream文件,就需要编译得到对应的dts文件。这挺复杂,你得参考Xilinx的教程。
至此我们自己编译或者修改了所有能编译和修改的文件。
4.DEBUG
如果顺利,Zedboard应该直接启动到Linux,提示符会告诉你OS已经准备好了:
zynq>
如果不那么顺利的话……首先FSBL会输出Debug信息,比如正在初始化开发板,正在配置FPGA等。FPGA配置完成之后,板上的蓝灯会亮起。之后,如果成功启动SSBL,在终端会看到SUCCESS HANDOFF
(打开了FSBL的Debug信息)。接下来是U-Boot的输出,默认情况下,U-Boot会在等待3秒钟后,再次读入MIO的设置来选择启动方式(第一次是BootROM上的启动程序读取的)。可以按下任意键取消自动启动,这时能看到U-Boot的命令行界面(u-boot>
提示)。键入help
来查看可以使用的指令,使用env list
来查看现在的环境参数。
U-Boot环境参数
注意U-Boot在启动时会从Zedboard的SPI Flash(断电不会丢失)读取环境参数配置,如果Flash上已经被写过了一些错误的配置(比如另一个U-Boot写下的),可能会导致启动错误,kernal panic等。使用env reset
来重置这些参数为默认(默认参数在U-Boot代码里),使用env save
来覆盖在Flash上。
U-Boot使用一些列环境参数来控制启动过程,比如modeboot
由U-Boot读取启动配置跳线来决定(sdboot、jtagboot、netboot等),bootargs
是将会传递给Linux Kernel的参数(如果有,会覆盖devicetree中定义的内容)。
U-Boot指令
Xilinx的wiki中,boot.bif
文件是这样写的:
image : {
[bootloader]fsbl.elf
bitstream.bit
u-boot.elf
[offset=0x3000000]uImage.bin
[offset=0x2000000]devicetree.dtb
[offset=0x2A00000]ramdisk.image.gz
}
这样,在制作boot.bin文件时,boot.bin文件将会包含uImage等3个文件(体积会大很多),并且FSBL将会把它们加载到SPI Flash中。这样SD中就只需Boot.bin,不用再放这3个文件了。
但是即使不怎么做,如果你看过U-Boot的环境变量就会知道——U-Boot也会从SD卡中寻找这3个文件,加载到同样的地址中。这时,就可以使用U-Boot的命令:
bootm 0x3000000 0x2000000 0x2A000000
来启动Linux内核。这也是U-Boot自动启动执行的最后一句命令。如果使用Linaro,那么我们没有ramdisk。上面的启动命令应该改成
bootm 0x3000000 - 0x2A000000
5.JTAG启动
如果在处理了U-Boot之后,你还是没有成功激动到Linux,那么可以尝试从JTAG启动:
将ZedBoard设置为JTAG启动(MIO[3~5]都是0),从电脑连接两条USB线缆到ZedBoard:USB-UART和USB-JTAG口。考虑到USB-JTAG驱动的问题,推荐Windows。
打开Xilinx SDK,在tools菜单中找到skd console,运行。它看起来和普通的cmd一样。
cd
到存放这些乱七八糟文件的文件夹,运行:
XMB
接下来:
connent hw
load fsbl.elf
con
等待一会儿,fsbl会完成初始化。
stop
fpga -s bitstream.bit #可选
load u-boot.elf
load -data uImage 0x3000000
load -data devicetree.dtb 0x2000000
load -data ramdisk.image.gz 0x2a00000
con
U-Boot将会运行,并且在终端输出信息。按任意键停止U-Boot自动启动。然后
bootm 0x3000000 0x2000000 0x2A00000
来启动Linux。