ZedBoard启动教程 (转)

时间:2024-02-23 15:07:09

看看,我们组里的那块板子是不是 ZedBoard!!

转自 http://blog.michiru.me/posts/zedboard-bring-up-guide.html

一份简单而完整的ZedBoard启动教程,如果凑巧你也在折腾这块板子,希望能帮助你少花些时间在这些SB的工作上。大概分成三个部分:

  1. 使用编译好的文件和ramdisk
  2. 使用编译好的文件和Linaro Ubuntu Linux
  3. 自行编译需要的文件

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也就是文件系统,有两种可供选择:

  1. ramdisk:非常小,几乎没什么功能,运行在ram里,任何修改在重启之后就会丢失。

  2. 完整的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卡来装载所有启动所需要的文件。

  1. 使用ramdisk时可以简单的把整个SD卡分为一个区,格式化成FAT格式。不过我建议依旧按张下面的方式分区,免去后续的折腾。

  2. 使用完整的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.binzed/devicetree.dtbuImageuramdisk.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.bindevicetree.dtbuImage三个文件,可以删掉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文件会为你配置好环境变量,然后在终端就能在终端中运行开发工具了(主要是vivadoxsdk)。每次打开一个新的终端,都需要这么做一次,觉得太麻烦的话可以把这句写在你的~/.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内核。同样需要配置好编译环境,cdlinux-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/下,会生成ImagezImage两个文件。如果你在上一步中为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个文件:dtsdtb、和一个小工具: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。

6.参考

  1. Xilinx官方Wiki
  2. Analog的教程
  3. Archlinux ARM的教程
  4. Digilent的教程