2. 搭建可复现的Zynq Linux驱动开发环境

说实话,很多刚接触Zynq的朋友,第一步就卡在PetaLinux工程创建上。不是工具不会用,而是对整个流程缺乏一个全局认知。今天我就带你走一遍完整的创建与配置流程,把我这些年踩过的坑、总结的经验都抖出来。

2.1 PetaLinux工程创建流程

创建PetaLinux工程,说白了就是告诉工具:我要为哪个硬件平台做系统,内核用什么版本,文件系统要多大。整个过程分三步走。

核心流程:硬件描述(XSA)→ 创建工程 → 配置子系统 → 编译生成

2.1.1 准备工作:获取硬件描述文件

在Vivado中完成硬件设计后,你需要导出硬件描述文件(XSA)。这个文件包含了Zynq处理器的配置信息,比如DDR大小、外设接口、时钟频率等。

# Vivado Tcl Console中执行
write_hw_platform -fixed -include_bit -force zynq_hw.xsa

我个人习惯在导出前,先检查一下硬件配置是否正确。曾经有一次,我忘了勾选UART1的MIO分配,结果系统启动后串口没输出,排查了半天才发现是硬件描述文件的问题。

2.1.2 创建PetaLinux工程

拿到XSA文件后,就可以创建PetaLinux工程了。这里我建议用命令行方式,比GUI更可控。

# 设置PetaLinux环境
source /opt/Xilinx/PetaLinux/2023.1/settings.sh

# 创建工程
petalinux-create --type project --template zynq --name my_zynq_project

# 导入硬件描述
cd my_zynq_project
petalinux-config --get-hw-description ../zynq_hw.xsa

执行petalinux-config后,会弹出配置菜单。这里有几个关键项需要你注意:

配置项 说明 我的建议
Subsystem AUTO Hardware Settings 自动检测硬件配置 保持默认,除非你有特殊需求
Memory Settings DDR大小、地址映射 与Vivado工程保持一致
Boot Options 启动方式(QSPI/SD卡/Flash) 开发阶段选SD卡,量产选QSPI
U-Boot Configuration U-Boot相关设置 默认即可,后续可单独配置

小技巧:第一次配置时,建议把Subsystem AUTO Hardware Settings -> Advanced bootable images storage settings中的boot image settings设为primary sd,这样调试阶段会方便很多。

2.2 内核配置:裁剪你的Linux

内核配置是PetaLinux工程中最灵活也最容易被忽视的环节。默认配置会包含大量你不需要的驱动,导致镜像臃肿、启动缓慢。

2.2.1 进入内核配置界面

petalinux-config -c kernel

这会打开一个基于menuconfig的内核配置界面。嗯,这里要注意,配置项非常多,但你不必全部看完。我一般只关注三类配置:

  • 驱动相关:确保你硬件上用到的外设驱动被选中
  • 文件系统支持:比如ext4、FAT、NFS等
  • 调试功能:开发阶段开启,量产时关闭

2.2.2 关键配置项

以Zynq-7000系列为例,以下是我常用的配置路径:

功能 配置路径 说明
UART驱动 Device Drivers -> Character devices -> Serial drivers -> Xilinx UART 串口通信必备
SPI驱动 Device Drivers -> SPI support -> Xilinx SPI controller SPI外设通信
I2C驱动 Device Drivers -> I2C support -> Xilinx I2C controller I2C外设通信
GPIO驱动 Device Drivers -> GPIO Support -> Xilinx GPIO 通用GPIO控制
网络驱动 Device Drivers -> Network device support -> Ethernet driver support -> Xilinx EMAC 以太网通信

避坑指南:我曾经在配置内核时,为了省空间把CONFIG_EXT4_FS去掉了,结果根文件系统挂载失败,系统直接panic。所以,文件系统相关的配置一定要谨慎,建议先保持默认,确认能启动后再逐步裁剪。

2.3 根文件系统配置:选对方案事半功倍

根文件系统(RootFS)决定了你的Linux系统能跑什么应用。PetaLinux支持多种根文件系统类型,我根据项目经验整理了一个对比表:

类型 大小 灵活性 适用场景
initramfs 小(几MB) 低 快速启动、内存运行
SD卡ext4 大(GB级) 高 开发调试、原型验证
NFS网络挂载 取决于服务器 极高 驱动开发、频繁修改
Yocto自定义 可定制 最高 量产产品、定制化需求

2.3.1 配置根文件系统

petalinux-config -c rootfs

在配置界面中,你可以选择预置的根文件系统模板,也可以手动添加软件包。我个人习惯在开发阶段选择petalinux-image-minimal,然后根据需要添加包:

  • 开发工具:gcc、gdb、make、vim
  • 网络工具:openssh、curl、wget、iperf
  • 调试工具:strace、ltrace、perf、devmem2
  • 文件系统工具:e2fsprogs、dosfstools

经验之谈:如果你在做驱动开发,强烈建议在根文件系统中加入devmem2和i2c-tools。这两个工具能帮你快速验证硬件寄存器读写是否正确,省去反复编译内核的麻烦。

2.4 设备树生成:硬件与软件的桥梁

设备树(Device Tree)是Zynq平台Linux驱动开发的核心。它描述了硬件资源如何映射到Linux内核。PetaLinux会根据你导入的XSA文件自动生成设备树,但往往需要手动调整。

2.4.1 设备树文件结构

在PetaLinux工程中,设备树文件位于project-spec/meta-user/recipes-bsp/device-tree/files/目录下。主要包含:

  • system-user.dtsi:用户自定义设备树片段,用于添加或覆盖硬件节点
  • pl.dtsi:PL(可编程逻辑)部分生成的设备树,由Vivado自动生成
  • pcw.dtsi:PS(处理系统)部分配置生成的设备树

2.4.2 手动添加设备节点

假设你在PL中添加了一个自定义的AXI GPIO外设,地址为0x40000000,需要在设备树中这样描述:

// system-user.dtsi
/include/ "system-conf.dtsi"
/ {
    my_gpio: gpio@40000000 {
        compatible = "xlnx,xps-gpio-1.00.a";
        reg = <0x40000000 0x10000>;
        #gpio-cells = <2>;
        gpio-controller;
        xlnx,gpio-width = <32>;
    };
};

&amba {
    my_gpio: gpio@40000000 {
        compatible = "xlnx,xps-gpio-1.00.a";
        reg = <0x40000000 0x10000>;
        #gpio-cells = <2>;
        gpio-controller;
        xlnx,gpio-width = <32>;
    };
};

注意:设备树中的reg属性必须与Vivado中的地址分配一致。我曾经因为地址写错了一位,导致驱动加载时ioremap失败,系统直接oops。排查了整整一天才发现是设备树的问题。

2.5 知识体系总览

为了让你对整个流程有个直观的认识,我画了一张流程图:

PetaLinux工程创建与配置流程 PetaLinux工程创建与配置流程 Vivado硬件设计 导出XSA文件 petalinux-create 导入XSA配置 内核配置 根文件系统配置 设备树生成与修改 petalinux-build 生成BOOT.BIN 关键文件 • system-user.dtsi • pl.dtsi / pcw.dtsi • image.ub / BOOT.BIN

2.6 编译与验证

所有配置完成后,执行编译命令:

petalinux-build

编译成功后,生成的文件在images/linux/目录下:

  • image.ub:包含内核、设备树、根文件系统的统一镜像
  • BOOT.BIN:包含FSBL、U-Boot、bitstream的启动镜像
  • system.dtb:编译后的设备树二进制文件

验证方法:将BOOT.BIN和image.ub拷贝到SD卡,插入Zynq开发板,上电后通过串口观察启动日志。如果看到VFS: Mounted root (ext4 filesystem) on device 179:2,说明你的系统已经成功启动了。

好了,以上就是PetaLinux工程创建与配置的完整流程。从硬件描述到系统启动,每一步都有它的意义。你可能会觉得步骤有点多,但相信我,当你第一次看到自己的Zynq板子打印出Linux启动信息时,那种成就感会让你觉得一切都值得。