本文仅为踩坑记录,非完整教程
正常工作的外设:
0)系统可正确识别到双核A53以及2GB DDR4
1)千兆以太网通信正常(使用iper3进行内网测试,可跑到960mbps左右)
2)dp1.4接口输出正常,可支持到最高4K30hz RGB输出
3)4个USB3.0接口正常,测试过USB2.0的键鼠以及USB3.0的U盘
4)调试串口工作正常,115200 8n1
未测试的外设:
1)PCIE X1,无相应设备测试
2)MIPI CSI接口
3)按键(修改设备树能用?)
4)仅测试SD卡其他,EMMC启动未测试,能读取EMMC内容
编译命令记录
1、使用Ubuntu 18.04.4虚拟机,分配的CPU建议8核以上,内存建议16GB以上,硬盘建议200GB以上,建议使用全局科学,petalinux用的akamai cdn跟shit一样。
下载地址:https://old-releases.ubuntu.com/releases/18.04.4/ubuntu-18.04.4-desktop-amd64.iso
记得不要打开自动更新
2、根据黑金教程安装Vitis和petalinux全家桶
3、设置PYNQ环境
3.1 克隆PYNQ源码,由于黑金采用的是vivado 2020.1,这里配置对应的PYNQ版本v2.6
git clone https://github.com/Xilinx/PYNQ.git pynq_port
cd pynq_port
git checkout image_v2.6
这里贴上各个vivado版本对应的PYNQ版本
Release version | Xilinx Tool Version |
---|---|
v1.4 | 2015.4 |
v2.0 | 2016.1 |
v2.1 | 2017.4 |
v2.2 | 2017.4 |
v2.3 | 2018.2 |
v2.4 | 2018.3 |
v2.5 | 2019.1 |
v2.6 | 2020.1 |
v2.7 | 2020.2 |
v3.0 | 2022.1 |
3.2 安装编译依赖,使用黑金的脚本(host_env_setup.sh)安装petelinux依赖
#!/bin/bash
set -x
script_dir=$(cd $(dirname ${BASH_SOURCE[0]}) && pwd)
# This script sets up a Ubuntu host to be able to create the image by
# installing all of the necessary files. It assumes a host with
# passwordless sudo
# Install a bunch of packages we need
read -d '' PACKAGES <<EOT
iproute2
gcc
g++
net-tools
libncurses5-dev
zlib1g:i386
libssl-dev
flex
bison
libselinux1
xterm
autoconf
libtool
texinfo
zlib1g-dev
gcc-multilib
build-essential
screen
pax
gawk
python3
python3-pexpect
python3-pip
python3-git
python3-jinja2
xz-utils
debianutils
iputils-ping
libegl1-mesa
libsdl1.2-dev
ninja-build
pylint3
cpio
EOT
set -e
sudo apt-get update
if [[ $(lsb_release -rs) == "16.04" ]]; then
echo "Install packages on Ubuntu 16.04..."
sudo apt purge -y libgnutls-dev
elif [[ $(lsb_release -rs) == "18.04" ]]; then
echo "Install packages on Ubuntu 18.04..."
else
echo "Error: current OS not supported."
exit 1
fi
sudo dpkg --add-architecture i386
sudo apt-get update
sudo apt-get install -y $PACKAGES
echo "Now install Vivado, SDK, and Petalinux."
echo "Re-login to ensure the enviroment is properly set up."
安装PYNQ依赖,脚本会用apt安装各种需要的包,以及下载QEMU和CrossTool-NG。
cd pynq_port/sdbuild/scripts
./setup_host.sh
3.3 设置环境变量,修改家目录下的.bashrc文件,该文件为隐藏文件,将下面几行命令加入到最后面。这样一来,就可以在命令行中运行这些软件了。
source /tools/Xilinx/Vivado/2020.1/settings64.sh
source /tools/Xilinx/Vitis/2020.1/settings64.sh
source /opt/pkg/petalinux/settings.sh
export PATH=/opt/qemu/bin:/opt/crosstool-ng/bin:$PATH
3.4 添加自定义开发板
下列内容转载自Haozhe Zhu的博客:EdgeBoard的PYNQ移植 - Haozhe Zhu's Blog
感谢!
PYNQ在boards
文件夹下预置了Pynq-Z1
、Pynq-Z2
、ZCU104
三个与对应开发板同名的文件夹。它们的内部结构大同小异,主要分成以下五个部分:
notebooks
;petalinux_bsp
;packages
;base
、logictools
等Overlay
文件夹;<board_name>.spec
下面简单介绍下这些文件和文件夹的功能,具体的细节(如果你需要定制一些复杂的东西)还请自行阅读PYNQ的编译脚本源代码。
notebooks
文件夹会原样复制到最终的用户目录下,每次大家打开Jupyter Notebook后看到的就是它。这个文件夹里的内容不是很重要,一般都是放些教程。
petalinux_bsp
文件夹用于PetaLinux生成BSP,它只在sdbuild/scripts/create_bsp.sh
脚本中用到。该文件夹里边包括两个文件夹meta-user
、hardware_project
。其中,meta-user
文件夹会被复制到PetaLinux项目文件夹下的project-spec/meta-user
,里面放设备树文件、各种用户配置等(如果你对PetaLinux项目的目录结构不了解的话可以参考UG1144)。hardware_project
里需要放.xsa
硬件描述文件(该文件由Vivado导出),或者也可以放一些脚本(至少包括一个Makefile)供PetaLinux实时地生成.xsa
文件。如果用户在<board_name>.spec
中指定了BSP,那么hardware_project
不会被用到。这里一个文档中一个没有注明的是,meta-user
总是会起作用,即使你指定了BSP,它也会覆盖掉里边的meta-user
并重新打包。
packages
文件夹的结构和sdbuild/packages
的结构类似,这两个目录下的每个文件夹对应一个个的组件,在编译过程中会被安装到RootFS中。安装过程主要是在sdbuild/scripts/install_packages.sh
中进行。如果你需要增加组件,建议阅读此脚本和sdbuild/packages/README.md
了解更多细节。
其他文件夹中如果存在Makefile文件,就会被认为是Overlay
文件夹。在编译pynq
本身时,<pynq_repo_dir>/build.sh
脚本会试图进入这些文件夹,并挨个检查是否存在.bit
、.hwh
、.xsa
等文件。这些文件夹不是必须的,主要是为用户提供一些针对该开发板的预置Overlay
。
<board_name>.spec
文件描述了针对该开发板的各种配置和文件路径。它的格式如下所示:
ARCH_<board_name> := aarch64 # Zynq的CPU架构,可以是aarch64或arm
BSP_<board_name> := ... # 开发板的BSP文件(如果有的话)
BITSTREAM_<board_name> := ... # 默认的比特流文件
FPGA_MANAGER_<board_name> := 1
STAGE4_PACKAGES_<board_name> := pynq ethernet ...
注意这里的board_name
要和文件夹的名字一致。
接下来我们可以依样画葫芦为自己的开发板配置这些文件了。
这里贴上我的spec文件
peta@peta:~/pynq_port/boards/Alinx$ cat Alinx.spec
ARCH_Alinx := aarch64
BSP_Alinx :=
BITSTREAM_Alinx := base/base.bit
FPGA_MANAGER_Alinx := 1
STAGE4_PACKAGES_Alinx := xrt pynq ethernet
将vivado导出的xsa文件放置在对应的目录下,并且重命名为板子名字
peta@peta:~/pynq_port/boards/Alinx/petalinux_bsp/hardware_project$ ls
Alinx.xsa
如果需要自定义设备树,修改对应位置的system-user.dtsi文件
peta@peta:~/pynq_port/boards/Alinx/petalinux_bsp/meta-user/recipes-bsp/device-tree/files$ ls
system-user.dtsi
如果需要自定义U-Boot配置,修改对应位置的platform-top.h文件
peta@peta:~/pynq_port/boards/Alinx/petalinux_bsp/meta-user/recipes-bsp/u-boot/files$ ls
platform-top.h
下载xilinx官方预先编译好的pynq rootfs,避免重复编译
链接:http://www.pynq.io/board.html
我们用的是v2.6版本,下载对应版本:http://bit.ly/pynq_rootfs_aarch64_v2_6
得到pynq_rootfs_aarch64.zip,解压后得到bionic.aarch64.2.6.0_2020_10_19.img
放置在~/pynq_port/sdbuild/prebuild目录下
理论上,我们可以开始进行漫长的编译了,过程顺利的话,可以在output目录下得到相应的镜像
Alinx-2.6.0.img
cd ~/pynq_port/sdbuild
make BOARDS=Alinx PREBUILT=./prebuild/bionic.aarch64.2.6.0_2020_10_19.img
如果需要修改petalinux相关的配置,可以在第一次编译完成后,进入~/pynq_port/sdbuild/build/Alinx/petalinux_project目录下
运行
PYNQ_BOARDNAME=Alinx FPGA_MANAGER=1 petalinux-config -c kernel #修改Linux内核配置
PYNQ_BOARDNAME=Alinx FPGA_MANAGER=1 petalinux-config -c u-boot #修改u-boot配置
PYNQ_BOARDNAME=Alinx FPGA_MANAGER=1 petalinux-config -c rootfs #修改rootfs配置
踩坑记录
1、内核在初始化SMP核心时卡死
这是在最开始学习移植petalinux时遇到的问题,最后发现是vivado在导出xsa时未选择包括bitstream导致的
2、无法从SD卡启动,找不到RootFS
这个是比较常见的错误,由于xilinx的工程师在开发pynq时写死了一些参数
Kernel Panic - not syncing: VFS: Unable to mount root fs on unknown-block(179,10)
可能原因1:SD卡的写保护
在黑金的教程中,提供了修改设备树的方法,即使在block design内关闭了SD卡的WP,也要进行这项配置
/include/ "system-conf.dtsi"
/ {
};
/* SD */
&sdhci1 {
disable-wp;
no-1-8-v;
};
/* USB */
&dwc3_0 {
status = "okay";
dr_mode = "host";
};
可能原因2:设备树bootargs参数中设置了错误的root
分区位置
PYNQ默认总是从/dev/mmcblk0
(这个路径是PYNQ上的,不是你的宿主Ubuntu上的)启动系统,即它如果它有多个SD外设的话,SD卡要连在PS_SD0
上。不幸的是,我这块黑金板子有两个SD设备,一个是一颗eMMC Flash芯片,另一个是我们的TF卡槽。eMMC 连在PS_SD0上,TF卡连在PS_SD1上。
默认情形下,PYNQ总是会尝试从前者启动,而我们的系统实际存放在SD卡上。
PetaLinux的Boot参数是通过设备树中的/chosen/bootargs
条目进行配置的。默认情况下,最后镜像使用的设备树中该条目会是这样的(每个字段的先后顺序不重要):
cat system-user.dtsi
bootargs = "root=/dev/mmcblk0p2 rw earlyprintk rootfstype=ext4 rootwait devtmpfs.mount=1 uio_pdrv_genirq.of_id=\"generic-uio\" clk_ignore_unused";
但我们希望其中的字段root=/dev/mmcblk0p2
变成root=/dev/mmcblk1p2
。直觉上,首先想到的是很上文一样修改system-user.dtsi
文件,从而影响最终生成的设备树。实验会告诉你完全不起作用,最后输出也就是实际使用的设备树里还是上面这行默认值。这里大家就会遇到PYNQ这个编译流程设计的很糟糕的一点:system-user.dtsi
这个文件中的只有一部分会起作用,至于想弄清哪部分,要么做实验,要么看懂编译源代码。比如上面对&sdhci1
节点的修改就能生效,对/chosen/bootargs
对修改就不起作用。
生成设备树是制作BSP文件的中一部分,接下来我们来弄清楚PYNQ是如何生成最终的BSP文件的。我们先考虑用户没有提供预编译的BSP文件的情形,此时PYNQ内部会依次做这些事:
- 建立一个空的PetaLinux项目
- 拷贝用户的
petalinux_bsp/meta-user
到该项目下; - 读入硬件配置即
petalinux_bsp/hardware_project
中的XSA文件,生成Config文件; - 构建并打包成BSP文件;
- 利用上一步获得的BSP文件建立一个新的PetaLinux项目;
- 直接在脚本中修改Config文件,加入一些配置;
- 重新运行
petalinux-config
生成新的Config文件; - 开始各种build,最终生成我们需要的BOOT.bin。
其中步骤1、2、3、4在sdbuild/scripts/create_bsp.sh
脚本中进行,步骤5、6、7、8在sdbuild/Makefile
中进行。如果用户指定了预编译的BSP文件,就把上文中的第1步换成“利用用户提供的BSP文件建立一个新的PetaLinux项目”。这里最令人困惑的地方是,为什么要进行两次“create-config-build”的流程,至少我没有看出它这么做的必要性。这样一通操作之后,用户在petalinux_bsp/meta-user
的子目录下的system-user.dtsi
文件中修改的一些设备树节点(对应上文步骤2),会在步骤6中被新引入的一些设备树文件冲刷掉。步骤6通过CONFIG_USER_LAYER_0
这一设置混入了一些新的设备树文件,这些额外的设备树文件位于sdbuild/boot/meta-pynq/recipes-bsp/device-tree
。就Boot参数而言,这里边的pynq_bootargs.dtsi
文件提供了前述的默认/chosen/bootargs
。因此无论我们在system-user.dtsi
文件中如何修改/chosen/bootargs
,最终都会被覆盖掉。
因此,我们的解决方案很简单,修改下pynq_bootargs.dtsi
文件,将其中的root=/dev/mmcblk0p2
变成root=/dev/mmcblk1p2
。除了修改pynq_bootargs.dtsi
,我们还需要修改sdbuild/Makefile
,将下面这行代码中的mmcblk0p2
变成mmcblk1p2
。
echo 'CONFIG_SUBSYSTEM_SDROOT_DEV="/dev/mmcblk0p2"' >> $$(PL_CONFIG_$1)
3、网络不工作
黑金使用的是ksz9031 phy芯片,这里提供两种设备树,放在system-user.dtsi内,供参考
第一种是在U-boot下网络可以正常工作,但是在Linux下工作异常
&gem3 {
status = "okay";
local-mac-address = [00 0a 35 00 02 90];
phy-mode = "rgmii-id";
phy-handle = <&phy0>;
phy0: phy@1 {
reg = <1>;
compatible = "micrel,ksz9031";
device_type = "ethernet-phy";
};
};
第二种是在Linux下网络可以正常工作,但是在U-boot下工作异常
&gem3 {
status = "okay";
phy-mode = "rgmii-id";
phy-handle = <&phy0>;
local-mac-address = [00 0a 35 00 22 01];
mdio: mdio {
#address-cells = <1>;
#size-cells = <0>;
phy0: ethernet-phy@1 {
compatible = "ethernet-phy-ieee802.3-c22";
reg = <1>;
reset-names = "phy-ksz9031";
};
};
};
4、PYNQ系统启动时卡mmcblk0p1
在PYNQ系统启动时,会按照/etc/fstab文件挂载各个分区,我们的SD卡为mmcblk1,而PYNQ写死的mmcblk0,导致无限尝试挂载,系统进入emergency模式,最终卡死,烧写好后将SD卡挂载进虚拟机中修改即可
/dev/mmcblk1p1 /boot vfat defaults 0 2
5、SD卡扩容失败
在PYNQ系统第一次启动时,systemd会运行扩容脚本,但是不幸的是扩容脚本写死的扩容目标分区为mmcblk0p2,导致扩容失败,修改/usr/local/bin/resizefs.sh文件即可
将TGTDEV修改为/dev/mmcblk1
将TGTPART修改为/dev/mmcblk1p2
若是已经启动过系统,则将/etc/environment中的RESIZED=1字段删除,重启即可