虽然 petalinux 功能很全面,但是其编译速度较慢,不适用于驱动调试阶段(因为驱动调试阶段会频繁修改驱动模块、内核、设备树等),因此本章将采用分步编译的方式来编译启动开发板所需要的各种镜像文件,虽然步骤比较繁琐,但灵活性比较高,方便在驱动调试过程中单独对某一部分进行修改。
对于 Zynq 而言,一个完整的 linux 系统包含 PS 和 PL 两个构件,其中 PS 构件包含 fsbl、uboot(包括可选的boot.scr)、设备树文件、linux内核、根文件系统共 5 要素,PL 构件包含 bit 文件一个要素(当不使用 PL 的时候,该要素非必须)。
利用 Petalinux 构建根文件系统和 BOOT.BIN
这里主要是利用 Petalinux 工具构建根文件系统、fsbl、uboot(fsbl 和 uboot 最终打包到 BOOT.BIN 中),同时在编译过程中还能生成设备树源文件。
- 创建在创建 Vivado 硬件平台的时候必须包含ZYNQ IP核,且配置ZYNQ的如下外设:
- flash,若采用flash模式启动则必须配置
- ENET,一般Linux都需要有网络
- SD或EMMC,用于存放Linux根文件系统等,若从SD0启动则必须要配置SD0
- UART,Linux的终端需要使用串口
- DDR,Linux运行时需要DDR
- 如果使用了带中断信号的IP核需确保中断信号正确连接
配置完成后生成Products,然后编译工程,编译完成后导出xsa文件,如果工程中包含PL资源,在到处xsa时需要选择包含比特模式。
- 创建 petalinux 工程
#加载petalinux工作环境
source /opt/pkg/petalinux2020.2/settings.sh
#创建空的petalinux工程
petalinux-create -t project --template zynq -n alientek-pelainux
- 配置petalinux工程
#进入工程目录
cd alientek-pelainux/
#导入xsa文件,并打开配置菜单
petalinux-config --get-hw-description ../xsa-alientek/
进行如下配置:
-*- Subsystem AUTO Hardware Settings ---> Serial Settings ---> FSBL Serial stdin/stdout (ps7_uart_0) ---> #根据硬件选择正确的串口号,我这里选择ps7_uart_0DTG Serial stdin/stdout (ps7_uart_0) ---> #根据硬件选择正确的串口号,我这里选择ps7_uart_0[*] Advanced bootable images storage Settings ---> #为了方便调试,全部选择primary sd,调试完成后根据需求重新进行配置boot image settings --->image storage media (primary sd) --->u-boot env partition settings --->image storage media (primary sd) --->kernel image settings --->image storage media (primary sd) ---> dtb image settings --->image storage media (primary sd) --->
Yocto Settings --->Add pre-mirror url ---> pre-mirror url path #将pre-mirror url path设置为file://downloads_2020.2.tar.gz解压后的目录,我这里是 file:///opt/pkg/petalinux2020.2/downloadsLocal sstate feeds settings--->()local sstate feeds url #将local sstate feeds url设置为sstate_arm_2020.2.tar.gz解压后得到的arm路径下,我这里是/opt/pkg/petalinux2020.2/sstate_arm_2020.2/arm[ ] Enable Network sstate feeds #取消此项选择[*] Enable BB NO NETWORK #选中此选项
- 配置根文件系统
#打开根文件系统配置界面
petalinux-config -c rootfs
进行如下配置:
Filesystem Packages ---> base --->e2fsprogs ---> #使能mkfs.vfat指令[*] e2fsprogs-mke2fsmisc --->gcc-runtime ---> #使能C++支持[*] libstdc++
- 编译 petalinux 工程
//进行一次全编译
petalinux-build
- 打包 BOO.BIN
#--dtb no表示不将设备树打包到BOO.BIN中,因此这个BOO.BIN只包含./images/linux/zynq_fsbl.elf和./images/linux/u-boot.elf,其它内容均在后面通过uboot去加载
petalinux-package --boot --fsbl --u-boot --dtb no --force
- 进行启动测试
将打包好的 BOOT.BIN 拷贝到 SD 中,通过 SD 卡启动开发板,若配置正确可看到 uboot 输出的信息,说明 BOOT.BIN 编译成功,至于根文件系统则需要在内核编译完成后才能进行测试。
注意:此时缺乏系统镜像、根文件系统等,所以不能进入Linux系统 - 编译 sdk
对于 2019.1 之前版本的 Petalinux,设置 Petalinux 工作环境变量后可以直接使用 arm 的 linux 交叉编译工具链,然而此后版本的 Petalinux 在设置环境变量后只能得到裸机的交叉编译工具链,无法获得 linux 交叉编译工具链,此时我们可以利用Yocto提供的 SDK 生成方案编译出 Linux 交叉编译环境(petalinux 基于 Yocto)
#在使用petalinux-build编译完工程后可以使用如下命令生成SDK
petalinux-build --sdk
- 安装SDK
编译完成后在 images/linux 目录下会有一个名为 sdk.sh 的文件,这便是编译生成的 SDK,其中包含了 Linux 交叉编译工具链、根文件系统、以及构建根文件系统时所编译的第三方库(如根文件系统配置中选择了QT这里面便会包含QT相关的动态库)。
此时只需要运行sdk.sh便可完成 Linux 交叉编译工具链的安装
#运行SDK安装脚本,默认安装在/opt/petalinux/2020.2目录
./sdk.sh
10. 加载 Linux 交叉编译工具链环境变量
安装完成后在新打开的终端中执行如下命令便可加载 Linux 交叉编译工具链环境变量
#加载 Linux 交叉编译工具链环境变量
source /opt/petalinux/2020.2/environment-setup-cortexa9t2hf-neon-xilinx-linux-gnueabi
每次都输入命令比较麻烦,为了方便可以为此命令创建别名,以后通过别名加载 Linux 交叉编译工具链环境变量
#以后通过petalinux2020-linux便可完成 Linux 交叉编译工具链环境变量的加载
echo "alias petalinux2020-linux='source /opt/petalinux/2020.2/environment-setup-cortexa9t2hf-neon-xilinx-linux-gnueabi'" >> ~/.bashrc
加载完 Linux 交叉编译工具链环境变量后在终端输入 arm- ,然后在按 tab 键便可出现 arm-xilinx-linux-gnueabi- 相关的编译工具链命令
提示:
除了使用 petalinux 构建 Linux 交叉编译工具链外还可以使用 vitis 中提供的 Linux 交叉编译工具链(vitis 中分别包含了逻辑交叉编译工具链和 Linux 交叉编译工具链),具体使用方法参考02-ZYNQ linux开发环境安装,基于Petalinux2020.2和Vitis2020.2中安装 Vitis 部分内容,但是在使用 Vitis 交叉编译工具链时若需要用到一些第三方库则需要自行移植编译,然后采用指定外部链接库的方式进行使用。
获取Linux设备树文件
在 Petalinux 工程中执行 petalinux-build 后会在工程的 components/plnx_workspace/device-tree/device-tree/ 目录下生成设备文件
此外还有一个用户配置设备树文件,位于工程的 project-spec/meta-user/recipes-bsp/device-tree/files 目录下
- zynq-7000.dtsi :ZYNQ7000系列PS侧外设设备节点,非常不建议修改
- pcw.dtsi :配置ZYNQ7000系列PS侧的外设,主要是引用zynq-7000.dtsi中的设备节点,并修改或添加一些属性,一般不修改
- pl.dtsi :PL侧外设设备节点,一般不修改
- system-conf.dtsi :一些配置信息,如网卡MAC地址、flash分区等,一般不修改
- system-user.dtsi :用户配置文件,若用户想在设备树中增加节点或者修改某个节点均在此文件中实现
- system-top.dts :顶层设备树文件,该文件在最后包含 “system-user.dtsi” 文件,所以 system-user.dtsi 能覆盖zynq-7000.dtsi 、pcw.dtsi 、pl.dtsi 、system-conf.dtsi、system-top.dts 中的内容。
编译Linux内核
- 获取内核源码
Xilinx 提供的 Linux 源码可以在 https://github.com/Xilinx/linux-xlnx 网站上下载,打开网站,然后切换到 xlnx_rebase_v5.4_2020.2 标签,接下来在点击 Code 图标,在展开菜单中点击 Download ZIP 按钮开始进行下载,如果网络良好也可以选择克隆整个 git 工程,然后切换到xlnx_rebase_v5.4_2020.2 分支。
git克隆命令如下:
#克隆GIT项目
git clone https://github.com/Xilinx/linux-xlnx.git
#进入源码目录
cd linux-xlnx/
#切换到 xlnx_rebase_v5.4_2020.2 标签,并创建 branch_xlnx_rebase_v5.4_2020.2 分支
git checkout -b branch_xlnx_rebase_v5.4_2020.2 tags/xlnx_rebase_v5.4_2020.2
- 添加设备树文件到内核源码目录
将前面得到的设备树文件(pcw.dtsi、pl.dtsi、system-conf.dtsi、system-top.dts、system-user.dtsi、zynq-7000.dtsi)拷贝到内核源码的 arch/arm/boot/dts 目录下,然后修改 Makefile 在 CONFIG_ARCH_ZYNQ 编译选项下增加 system-top.dtb
- 修改设备树文件
修改 system-user.dtsi 设备树文件,这个设备树在顶层设备树的最后一行被包含,所以可以在这个设备中修改已有的节点或者增加新的节点,下面是根据原理图和vivado配置所增加的内容,主要包含led、按键、网口相关内容(设备树需要结合硬件设计和vivado配置进行修改)。
/include/ "system-conf.dtsi"
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/input/input.h>
#include <dt-bindings/phy/phy.h>/ {model = "Alientek Navigator Zynq Development Board";compatible = "xlnx,zynq-zc702", "xlnx,zynq-7000";leds {compatible = "gpio-leds";gpio-led1 {label = "pl_led0";gpios = <&gpio0 63 GPIO_ACTIVE_HIGH>;default-state = "on";};gpio-led2 {label = "ps_led0";gpios = <&gpio0 7 GPIO_ACTIVE_HIGH>;default-state = "on";};gpio-led3 {label = "ps_led1";gpios = <&gpio0 8 GPIO_ACTIVE_HIGH>;linux,default-trigger = "heartbeat";};};keys {compatible = "gpio-keys";autorepeat;gpio-key1 {label = "pl_key0";gpios = <&gpio0 64 GPIO_ACTIVE_LOW>;linux,code = <KEY_LEFT>;gpio-key,wakeup;autorepeat;};gpio-key2 {label = "ps_key1";gpios = <&gpio0 12 GPIO_ACTIVE_LOW>;linux,code = <KEY_UP>;gpio-key,wakeup;autorepeat;};gpio-key3 {label = "ps_key2";gpios = <&gpio0 11 GPIO_ACTIVE_LOW>;linux,code = <KEY_DOWN>;gpio-key,wakeup;autorepeat;};};
};&uart0 {u-boot,dm-pre-reloc;status = "okay";
};&sdhci0 {u-boot,dm-pre-reloc;status = "okay";
};
- 运行 defconfig 配置
#加载 Linux 交叉编译工具链环境变量,这里使用前面构建根文件系统过程中得到的 SDK 中的 Linux 交叉编译工具链
source /opt/petalinux/2020.2/environment-setup-cortexa9t2hf-neon-xilinx-linux-gnueabi
#清除之前的配置和编译缓存
make ARCH=arm CROSS_COMPILE=arm-xilinx-linux-gnueabi- distclean
#使用默认配置文件进行配置
make ARCH=arm CROSS_COMPILE=arm-xilinx-linux-gnueabi- xilinx_zynq_defconfig
- menuconfig 配置
#安装运行 menuconfig 所依赖的软件,第一次执行 menuconfig 时才需要
sudo apt-get install libncurses5-dev libncursesw5-dev
#打开 menuconfig 菜单,在 menuconfig 菜单中根据需求进行配置
make ARCH=arm CROSS_COMPILE=arm-xilinx-linux-gnueabi- menuconfig
- 编译内核
#开始编译内核,编译完成后内核镜像是 arch/arm/boot/ 目录中的 zImage 文件,设备树是 arch/arm/boot/dts 目录中的 system-top.dtb 文件。
make ARCH=arm CROSS_COMPILE=arm-xilinx-linux-gnueabi- all -j8
- 制作 SD 卡启动盘
- 把 SD 卡插入电脑,链接到虚拟,在连接到虚拟机时要通过ls /dev/sd*查看设备变化,一般sd卡的设备文件名都是 sdb
- SD卡分区
#取消挂载
umount /dev/sdb*
#使用 fdisk 命令进行分区
sudo fdisk /dev/sdb
- 格式化 SD 卡
#将分区1格式化为FAT格式
sudo mkfs.vfat -F 32 -n boot /dev/sdb1
#将分区二格式化为EXT4格式
sudo mkfs.ext4 -L rootfs /dev/sdb2
- 将 BOOT.BIN、system-top.dtb、zImage、PL端bit文件拷贝到分区1的FAT文件系统中,BOOT.BIN位于 Petalinux 工程的 images/linux/ 目录中,system-top.dtb 位于 Linux 源码工程的 arch/arm/boot/dts 目录中,zImage 位于 Linux 源码工程的 arch/arm/boot 目录中,PL端bit文件位于 Petalinux 工程的 components/plnx_workspace/device-tree/device-tree 目录中。
- 将 Petalinux 工程的 images/linux/ 目录下的 rootfs.tar.gz 文件解压到分区2的ext4文件系统中。
- 弹出 SD 卡,将 SD 卡插入开发板,然后设置为 SD 启动模式。
- 进行启动测试
启动开发板,在倒计时结束前按下任意键,进入 uboot 命令行界面,然后依次输入如下命令
#设置 bootargs 环境变量,指定 Linux console 终端为 serial0(即uart0),指定根文件系统在 MMC0 的分区2
setenv bootargs 'console=ttyPS0,115200 earlyprintk root=/dev/mmcblk0p2 rw rootwait'
#加载bit文件到内存
fatload mmc 0:1 0x00800000 arm_system_wrapper.bit
#配置 FPGA 的 bit
fpga loadb 0 0x00800000 ${filesize}
#加载内核镜像
fatload mmc 0:1 0x00200000 zImage
#加载设备树
fatload mmc 0:1 0x00100000 system-top.dtb
#启动 Linux
bootz 0x00200000 - 0x00100000
每次启动都输入命令比较麻烦,它可以通过以下命令重新设置并保存 uboot 的默认启动命令和 bootargs 环境变量,设置完成后每次上电默认采用上面的步骤启动
#设置默认启动命令
setenv bootcmd 'fatload mmc 0:1 0x00800000 arm_system_wrapper.bit;fpga loadb 0 0x00800000 ${filesize};fatload mmc 0:1 0x00200000 zImage;fatload mmc 0:1 0x00100000 system-top.dtb;bootz 0x00200000 - 0x00100000'
#设置 bootargs
setenv bootargs 'console=ttyPS0,115200 earlyprintk root=/dev/mmcblk0p2 rw rootwait'
#保存设置
saveenv
**提示:**zynq的uboot默认启动方式是依次从mmc0、mmc1、qspi、nand、nor中去遍历 boot.scr,然后通过 boot.scr 中的命令去启动系统
使用 TFTP 加 NFS 根文件系统
在 Linux 驱动开发过程中可能会修改到内核、设备树、根文件系统、PL端BIT,采用 TFTP 加 NFS 根文件系统启动则只需要开发板上烧写一个 BOOT.BIN即可,其他的内容均可部署在 PC 的 Linux 中,这样可以避免频繁烧写开发板,也省去了开发板和 PC 之间频繁拷贝文件的问题。
- 部署 TFTP 服务器和 NFS 服务器,关于这部分内容可以参考01-ZYNQ linux开发环境安装,基于Petalinux2023.2和Vitis2023.2章节的TFTP 服务器配置和NFS 服务器配置相关内容
- 将system-top.dtb、zImage、PL端bit文件拷贝到 TFTP 服务器工作目录
- 将 rootfs.tar.gz 解压到 NFS 工作目录
- 给 PC 设置一个固定 IP,这样可以确保每次开机 PC 的 IP 一样
- 依然需要将 BOOT.BIN 拷贝到分区1的FAT文件系统中
- 采用 SD 模式启动开发板,在 uboot 倒计时结束前按任意键进入 uboot 命令行
- 在 uboot命令行中输入如下命令
#设置 uboot IP 地址
setenv ipaddr 192.168.2.10
#设置 MAC 地址
setenv ethaddr 00:0a:35:00:1e:53
#设置网关
setenv gatewayip 192.168.2.1
#设置子网掩码
setenv netmask 255.255.255.0
#设置 TFTP 服务器 IP
setenv serverip 192.168.2.66
#设置默认启动命令,从TFTP服务器下载bit、镜像、设备树,有时网卡第一次初始化会失败,所以最开始 ping 了因此服务器
setenv bootcmd 'ping 192.168.2.66;tftpboot 0x00800000 arm_system_wrapper.bit;fpga loadb 0 0x00800000 ${filesize};tftpboot 0x00200000 zImage;tftpboot 0x00100000 system-top.dtb;bootz 0x00200000 - 0x00100000'
#设置 bootargs,其中192.168.2.66是NFS服务器IP,192.168.2.10是开发板IP,192.168.2.1是网关,255.255.255.0是掩码,/home/lf/workspace/nfs-rootfs是NFS服务器工作目录
setenv bootargs 'console=ttyPS0,115200 root=/dev/nfs rw nfsroot=192.168.2.66:/home/lf/workspace/nfs-rootfs,nfsvers=3 ip=192.168.2.10:192.168.2.66:192.168.2.1:255.255.255.0::eth0:off'
#保存设置
saveenv
- 重启开发板,此时开发板通过TFTP服务器下载 system-top.dtb、zImage、PL端bit,然后启动 Linux 系统,并挂载 NFS 根文件系统,此时便可实现开发板和 PC 通过 NFS 共享文件(即 PC 端对 NFS 根文件系统的修改可以实时同步到开发板)。
**提示:**若在驱动开发过程中不会频繁修改Linux内核、设备树、PL 的 BIT 则可以使用 SD 卡启动加 NFS 根文件系统模式