第二章 开发环境搭建:安装Vivado与PetaLinux、配置交叉编译工具链、搭建NFS与TFTP服务器

好,咱们正式开始动手了。这一章要搭建整个开发环境,说白了就是把吃饭的家伙先备齐。很多新手在这一步就卡住了,不是版本不匹配就是路径配错。我当年第一次搭Zynq环境时,光Vivado就装了三次——第一次装错版本,第二次磁盘空间不够,第三次才搞定。所以这一章我会把踩过的坑都指出来,你跟着走就行。

2.1 安装Vivado与PetaLinux

先说说这两个工具的关系。Vivado是硬件设计工具,负责生成FPGA的bitstream和硬件描述文件(XSA)。PetaLinux是软件工具链,基于Yocto项目,专门为Xilinx平台定制Linux系统。两者缺一不可。

2.1.1 版本选择与下载

我个人习惯用LTS版本,稳定。目前推荐Vivado 2023.1或2024.1,对应的PetaLinux版本必须一致。为什么?因为PetaLinux的BSP(板级支持包)是跟着Vivado版本走的,混用会出各种奇怪的问题。

注意:Vivado和PetaLinux的大版本号必须完全一致。比如Vivado 2023.1必须搭配PetaLinux 2023.1。我曾经试过用2023.1的Vivado配2023.2的PetaLinux,结果编译内核时报了一堆莫名其妙的错误,折腾了两天才发现是版本不匹配。

下载地址在AMD官网,需要注册账号。Vivado有Web版和Device版,建议下载Device版(约40GB),包含所有器件支持。PetaLinux安装包约10GB,是个.run文件。

2.1.2 安装步骤

安装Vivado其实很简单,但有几个关键点要注意:

  1. 磁盘空间:Vivado完整安装需要约100GB,PetaLinux需要约50GB。建议预留200GB以上。
  2. 安装路径:不要有中文和空格。我习惯装在/opt/Xilinx/下。
  3. 用户权限:不要用root安装,但安装后需要给目录加写权限。

安装命令如下:

# 安装Vivado
chmod +x Xilinx_Vivado_2023.1_0430_0323_Lin64.bin
./Xilinx_Vivado_2023.1_0430_0323_Lin64.bin

# 安装PetaLinux
chmod +x petalinux-v2023.1-04190155-installer.run
./petalinux-v2023.1-04190155-installer.run /opt/Xilinx/petalinux/2023.1/
小技巧:安装PetaLinux时,它会自动检测系统依赖。如果缺包,它会提示你安装。我建议提前装好这些:gcc g++ make flex bison libncurses-dev libssl-dev。Ubuntu 22.04上基本都能apt-get搞定。

2.1.3 环境变量配置

安装完成后,需要设置环境变量。每次打开终端都要source一下,或者写进.bashrc

# 在 ~/.bashrc 末尾添加
source /opt/Xilinx/Vivado/2023.1/settings64.sh
source /opt/Xilinx/petalinux/2023.1/settings.sh

嗯,这里要注意:两个source的顺序不能错。先source Vivado,再source PetaLinux。因为PetaLinux依赖Vivado的一些工具链。

2.2 配置交叉编译工具链

交叉编译,说白了就是在PC上编译ARM架构的代码。Zynq的CPU是ARM Cortex-A9,所以我们需要ARM的交叉编译器。

PetaLinux安装后自带交叉编译工具链,路径在/opt/Xilinx/petalinux/2023.1/tools/linux-i386/gcc-arm-linux-gnueabi/。但说实话,我更喜欢用Linaro的官方工具链,更新更稳定。

2.2.1 安装Linaro工具链

# 下载arm-linux-gnueabihf工具链
wget https://releases.linaro.org/components/toolchain/binaries/latest-7/arm-linux-gnueabihf/gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf.tar.xz

# 解压到 /opt
sudo tar -xvf gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf.tar.xz -C /opt/

# 添加环境变量
export PATH=/opt/gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf/bin:$PATH

验证是否安装成功:

arm-linux-gnueabihf-gcc --version
# 输出类似:arm-linux-gnueabihf-gcc (Linaro GCC 7.5.0-2019.12) 7.5.0

2.2.2 编写第一个交叉编译程序

来,写个简单的Hello World测试一下:

// hello.c
#include <stdio.h>

int main() {
    printf("Hello from Zynq!\n");
    return 0;
}
# 交叉编译
arm-linux-gnueabihf-gcc -o hello hello.c

# 查看生成的文件类型
file hello
# 输出:hello: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV)

看到ARM字样就对了。这个程序不能在PC上运行,得放到Zynq板子上跑。

避坑指南:我曾经犯过一个低级错误——用gcc编译了驱动模块,然后直接拷贝到板子上insmod,结果报错"Invalid module format"。折腾了半天才发现是编译器和内核版本不匹配。记住:驱动模块必须用与内核相同版本的编译器编译。

2.3 搭建NFS与TFTP服务器

这两个服务是嵌入式开发的标配。NFS用于挂载根文件系统,TFTP用于网络启动内核。说白了,就是让板子通过网络从PC上加载文件,省去反复插拔SD卡的麻烦。

2.3.1 安装与配置NFS服务器

NFS(Network File System)允许板子通过网络访问PC上的目录。我通常把编译好的根文件系统放在NFS共享目录下,板子启动时直接挂载。

# 安装NFS服务器
sudo apt-get install nfs-kernel-server

# 创建共享目录
sudo mkdir -p /srv/nfs/rootfs

# 配置 /etc/exports
sudo vim /etc/exports
# 添加一行:
/srv/nfs/rootfs *(rw,sync,no_subtree_check,no_root_squash)

# 重启NFS服务
sudo systemctl restart nfs-kernel-server

# 验证
showmount -e localhost
注意:no_root_squash这个选项很重要。如果不加,板子上的root用户会被映射成nobody,导致无法读写文件。我在项目中遇到过这个问题,板子启动后一直报"Permission denied",查了半天才发现是NFS权限问题。

2.3.2 安装与配置TFTP服务器

TFTP(Trivial File Transfer Protocol)用于传输内核镜像和设备树文件。它比NFS更轻量,但功能也简单——只能传文件,不能挂载目录。

# 安装TFTP服务器
sudo apt-get install tftpd-hpa

# 配置 /etc/default/tftpd-hpa
sudo vim /etc/default/tftpd-hpa
# 修改为:
TFTP_USERNAME="tftp"
TFTP_DIRECTORY="/srv/tftp"
TFTP_ADDRESS="0.0.0.0:69"
TFTP_OPTIONS="--secure --create"

# 创建TFTP目录并设置权限
sudo mkdir -p /srv/tftp
sudo chmod 777 /srv/tftp

# 重启服务
sudo systemctl restart tftpd-hpa

测试TFTP是否正常工作:

# 在TFTP目录下创建一个测试文件
echo "test" | sudo tee /srv/tftp/test.txt

# 从本机测试下载
tftp localhost
tftp> get test.txt
tftp> quit

# 查看是否下载成功
cat test.txt

2.3.3 板子端启动参数配置

当板子通过U-Boot启动时,需要设置启动参数来使用NFS和TFTP。典型的启动参数如下:

# U-Boot环境变量设置
setenv ipaddr 192.168.1.100        # 板子IP
setenv serverip 192.168.1.10       # PC(服务器)IP
setenv gatewayip 192.168.1.1       # 网关
setenv netmask 255.255.255.0       # 子网掩码

# 通过TFTP加载内核和设备树
setenv bootcmd 'tftp 0x10000000 zImage; tftp 0x20000000 devicetree.dtb; bootz 0x10000000 - 0x20000000'

# 通过NFS挂载根文件系统
setenv bootargs 'console=ttyPS0,115200 root=/dev/nfs nfsroot=192.168.1.10:/srv/nfs/rootfs,proto=tcp,nfsvers=3 ip=192.168.1.100'

# 保存并启动
saveenv
boot

网络配置要点:

  • 板子和PC必须在同一网段(比如都是192.168.1.x)
  • PC的防火墙要放行NFS(2049端口)和TFTP(69端口)
  • 建议用网线直连,避免路由器干扰

2.4 验证环境

所有东西都配好后,我们来做个综合测试:

  1. 用Vivado生成一个最简单的Zynq硬件工程(只包含PS部分)
  2. 导出XSA文件,用PetaLinux创建工程并编译
  3. 将生成的BOOT.BIN、image.ub放到TFTP目录
  4. 将根文件系统解压到NFS共享目录
  5. 板子上电,从SD卡启动U-Boot,然后通过网络加载内核

如果一切顺利,你会看到Linux启动信息,最后出现登录提示符。那一刻的感觉,嗯,挺爽的。

我的经验:第一次启动时,建议用串口线连接板子,观察启动日志。大部分问题都能从日志中找到线索。比如"VFS: Unable to mount root fs"说明NFS配置有问题,"FATAL: Module not found"说明内核模块路径不对。别慌,一个个排查就好。

好了,环境搭建就到这里。下一章我们开始真正写驱动,到时候这些工具都会用上。记住:环境搭好了,后面就顺了。如果遇到问题,回头检查一下版本匹配和路径配置,八成能解决。