看看,我們組里的那塊板子是不是 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。