☰
ZYNQ裸芯片开发与PetaLinux实战:从裸机到Linux的软硬件协同
2026/10/20 1:09:27 网站建设 项目流程

1. 为什么ZYNQ的裸芯片开发和PetaLinux要放在一起学

1.1 从一颗芯片的两副面孔说起

ZYNQ这个平台有意思的地方在于,它本质上是一颗把FPGA和ARM核塞进同一块硅片里的异构芯片。PL端(Programmable Logic)是传统FPGA的可编程逻辑资源,PS端(Processing System)是硬核的ARM Cortex-A9双核处理器。两者之间通过AXI总线互联,共享DDR控制器和外设。这种架构带来的直接好处是:你可以在PL端做高速数据采集和实时信号处理,在PS端跑Linux做上层调度和网络通信,两边各干各擅长的事。

但问题也恰恰出在这里。很多做FPGA出身的工程师,PL端逻辑写得飞起,一到PS端就懵了——启动流程怎么走、FSBL是什么、设备树怎么配、内核怎么裁,全是新东西。反过来,做嵌入式Linux的工程师,看到Vivado里那些Block Design、约束文件、时序报告,也觉得头大。所以市面上大部分培训要么只讲PL端逻辑设计,要么只讲PS端Linux开发,能把两边打通、讲清楚“裸芯片怎么一步步跑起来、Linux怎么一步步跑起来”的课程,确实不多。

这个研修班的标题里,“裸芯片应用”和“PetaLinux”是两个并列的关键词。裸芯片应用指的是不依赖任何操作系统,直接在ZYNQ的PS端跑裸机程序(Bare-metal),或者PL端逻辑配合PS端做最底层的硬件控制。PetaLinux则是Xilinx官方提供的嵌入式Linux开发套件,用来构建、定制和部署Linux系统。两者放在一起,覆盖的是从最底层硬件到上层操作系统的完整链路。

1.2 谁适合来啃这块硬骨头

如果你满足以下任意一条,这个方向的内容就值得你花时间:

  • 做过纯FPGA开发,想往SoC方向转,但不知道PS端怎么入门
  • 做过STM32等MCU裸机开发,想升级到带FPGA的异构平台
  • 做过嵌入式Linux,但用的是现成开发板,想自己从零构建一个ZYNQ系统
  • 项目里需要用ZYNQ做高速数据采集、实时控制、图像处理等任务,但卡在软硬件协同上

不适合的人群也很明确:完全没接触过数字电路和C语言的同学,直接上ZYNQ会非常痛苦。至少得先搞明白什么是寄存器、什么是中断、什么是时钟域。

1.3 两天时间能学到什么程度

坦白说,ZYNQ的完整开发链路非常长,从Vivado建工程到PetaLinux启动到应用开发,正常自学至少需要两三个月才能跑通一个完整流程。两天的研修班不可能让你变成专家,但可以帮你做三件事:第一,把整个开发流程的框架搭起来,知道每一步在干什么、为什么这么干;第二,把最容易踩坑的地方提前标出来,省掉大量试错时间;第三,拿到一套可复现的工程模板,回去之后能直接照着改。

下面我就按这个思路,把ZYNQ裸芯片开发和PetaLinux两条线拆开讲,再讲怎么把它们串起来。

2. 裸芯片开发:不跑Linux时ZYNQ怎么用

2.1 裸机开发的典型场景和优势

很多人一提到ZYNQ就想到跑Linux,其实相当多的场景根本不需要操作系统。比如:

  • 高速数据采集系统:PL端做ADC接口和FIFO缓存,PS端裸机程序直接读FIFO数据并通过DMA搬到DDR,延迟可以做到微秒级
  • 实时电机控制:PWM输出和编码器采集在PL端实现,PS端裸机跑控制算法,中断响应时间确定
  • 简单的人机交互设备:PS端裸机驱动LCD和触摸屏,PL端做显示加速,不需要Linux的图形栈

裸机开发的最大优势是确定性。没有操作系统调度带来的不确定性,中断延迟可预测,内存访问可控。对于硬实时任务,这是刚需。另一个优势是资源占用小,不需要DDR跑Linux内核和根文件系统,一片小容量DDR甚至片内RAM就能跑起来。

但裸机也有明显短板:没有文件系统、没有网络协议栈(除非自己移植lwIP)、没有多任务调度。所以裸机适合做单一功能的专用系统,不适合做复杂的通用计算平台。

2.2 启动流程:从上电到main函数

ZYNQ的启动流程是裸机开发必须搞明白的第一件事。上电后,PS端首先执行片内BootROM里的固化代码,这段代码做的事情是:根据启动模式引脚(MIO[8:2])确定从哪里加载FSBL(First Stage Boot Loader),然后从QSPI Flash或SD卡读取FSBL到OCM(On-Chip Memory)并执行。

FSBL是用户自己编写的第一阶段启动代码,它负责初始化DDR控制器、配置PL端(如果用到)、加载第二阶段程序(裸机程序或U-Boot)到DDR并跳转执行。在裸机开发中,FSBL和应用程序可以合并成一个ELF文件,也可以分开。

这里有个关键点:FSBL的代码量必须控制在OCM容量以内(192KB),因为它运行在OCM里,此时DDR还没初始化。所以FSBL里不能放太大的数组或复杂的库函数。

启动模式的选择通过MIO引脚的上拉/下拉电阻决定,常见的有:

启动模式MIO[8:2]说明
JTAG0000000调试用,不固化
QSPI0000001从QSPI Flash启动
SD卡0000010从SD卡启动
NAND0000100从NAND启动

实际开发中,前期用JTAG调试最方便,产品化时切换到QSPI或SD卡。

2.3 裸机工程的创建和关键配置

在Vitis(旧版叫SDK)里创建裸机工程,有几个地方必须注意:

第一,硬件平台(XSA文件)的导出。在Vivado里完成Block Design后,必须导出XSA文件,这个文件包含了PS端的配置信息和PL端的硬件描述。Vitis导入XSA后会自动生成对应的BSP(Board Support Package)。

第二,BSP的配置。BSP里可以选择需要的外设驱动,比如UART、GPIO、Timer、DMA等。不需要的驱动可以去掉,减小代码体积。stdin/stdout默认指向UART,方便打印调试信息。

第三,链接脚本的调整。默认的链接脚本把代码放在DDR的某个地址,但如果你的程序需要在FSBL阶段就运行,或者DDR容量有限,就需要手动调整。比如把堆栈放在OCM里,把大数据缓冲区放在DDR的特定区域。

第四,Cache的配置。ZYNQ的PS端有L1和L2 Cache,PL端通过AXI访问DDR时不经过Cache。如果PS端和PL端共享内存区域,必须注意Cache一致性问题。裸机下常用的做法是把共享区域设为Non-cacheable,或者手动执行Cache刷新操作。

// 示例:将共享内存区域设为Non-cacheable #define SHARED_MEM_BASE 0x10000000 #define SHARED_MEM_SIZE 0x00100000 Xil_SetTlbAttributes(SHARED_MEM_BASE, NORM_NONCACHE);

这段代码通过修改MMU的页表属性,把指定地址范围设为非缓存,确保PS端和PL端看到的数据一致。

2.4 PL端与PS端的数据交互方式

裸机开发中,PL和PS的数据交互主要有三种方式:

第一种是AXI GP接口。PS端通过M_AXI_GP接口访问PL端的寄存器或BRAM,适合小数据量的控制和状态读取。比如PL端做一个PWM控制器,PS端通过AXI-Lite读写占空比寄存器。

第二种是AXI HP接口。PS端通过S_AXI_HP接口让PL端直接访问DDR,适合大数据量的高速传输。比如PL端做图像预处理,处理完的数据直接通过HP接口写入DDR,PS端再从DDR读取。

第三种是中断。PL端产生中断信号,通过IRQ_F2P接口送到PS端的GIC(Generic Interrupt Controller),PS端在中断服务函数里处理。裸机下中断配置需要手动设置GIC寄存器和异常向量表。

实际项目中,这三种方式往往组合使用。比如一个高速采集系统:PL端采集数据写入BRAM,通过中断通知PS端;PS端在中断里启动DMA,通过HP接口把BRAM数据搬到DDR;搬完后PS端处理数据,通过GP接口控制PL端的采集启停。

2.5 裸机调试的实用技巧

裸机调试最大的痛苦是没有printf。虽然可以通过UART打印,但在中断里打印会严重影响实时性。几个实用的调试手段:

  • GPIO翻转法:在关键代码段前后翻转一个GPIO,用示波器测时间。这是最不影响实时性的方法。
  • 内存日志法:在DDR里划一块区域做环形缓冲区,把调试信息写进去,程序跑完后通过JTAG读出来。
  • JTAG断点:Vitis支持JTAG调试,可以设断点、看变量、单步执行。但注意断点会暂停CPU,可能影响PL端的时序。
  • ILA核:在Vivado里插入ILA(Integrated Logic Analyzer)核,抓PL端的信号。这是调试PL逻辑的利器。

注意:在FSBL阶段调试时,DDR还没初始化,不能使用DDR相关的调试功能。建议先把FSBL调通,再调应用程序。

3. PetaLinux:让ZYNQ跑起完整的Linux系统

3.1 PetaLinux到底是什么

PetaLinux是Xilinx基于Yocto Project构建的一套嵌入式Linux开发工具。它把Linux内核、设备树、根文件系统、U-Boot等组件的配置和构建过程封装成简单的命令行操作,让不熟悉Yocto的工程师也能快速构建一个可启动的Linux系统。

和传统的嵌入式Linux开发相比,PetaLinux的优势在于:

  • 与Vivado硬件平台无缝对接,自动生成设备树
  • 一条命令完成内核、根文件系统、U-Boot的构建
  • 支持SD卡、QSPI、NFS等多种启动方式
  • 内置大量常用软件包,可以直接勾选

但PetaLinux也不是银弹。它的构建过程依赖大量开源组件,首次构建需要下载几个GB的源码,网络环境不好时会非常痛苦。另外,PetaLinux的版本和Vivado版本必须严格匹配,混用版本会出现各种奇怪的问题。

3.2 环境搭建和工程创建

PetaLinux的安装本身不复杂,下载安装包后运行安装脚本即可。但有几个坑必须提前避开:

第一,依赖包。PetaLinux依赖大量的系统库,在Ubuntu上需要提前安装。官方文档里有完整的依赖列表,但实际安装时经常漏掉几个。建议直接运行petalinux-util --webtalk off之前,先把常见的依赖装齐:

sudo apt-get install tofrodos iproute2 gawk gcc g++ git make net-tools \ libncurses5-dev tftpd zlib1g-dev libssl-dev flex bison libselinux1 \ gnupg wget diffstat chrpath socat xterm autoconf libtool tar unzip \ texinfo zlib1g-dev gcc-multilib build-essential libsdl1.2-dev \ libglib2.0-dev zlib1g:i386 screen pax gzip

第二,Shell环境。PetaLinux的工具链和构建系统对Shell有要求,必须用bash,不能用dash。在Ubuntu上需要把默认Shell从dash改成bash:

sudo dpkg-reconfigure dash # 选择"No"

第三,安装路径。PetaLinux不能安装在有空格或特殊字符的路径下,建议放在/opt或用户主目录下。

创建工程的命令很简单:

petalinux-create --type project --template zynq --name my_zynq_project

创建后进入工程目录,导入Vivado导出的XSA文件:

cd my_zynq_project petalinux-config --get-hw-description=/path/to/xsa_directory

这一步会弹出配置菜单,主要配置启动方式、串口、内存地址等。配置完成后,PetaLinux会自动生成设备树和U-Boot配置。

3.3 设备树的定制和修改

设备树是Linux内核识别硬件的关键。PetaLinux根据XSA自动生成的设备树通常只包含基本的外设,实际项目中往往需要手动添加或修改节点。

比如,PL端有一个自定义的IP核,需要在设备树里添加对应的节点:

my_ip: my_ip@43c00000 { compatible = "my-company,my-ip-1.0"; reg = <0x43c00000 0x10000>; interrupt-parent = <&intc>; interrupts = <0 29 4>; clocks = <&clkc 15>; };

这个节点告诉内核:在地址0x43c00000处有一个兼容"my-company,my-ip-1.0"的设备,使用中断号29,时钟源是clkc的第15路输出。内核启动时会根据compatible属性匹配对应的驱动。

设备树的修改在project-spec/meta-user/recipes-bsp/device-tree/files/system-user.dtsi文件里进行。修改后需要重新构建设备树:

petalinux-build -c device-tree

注意:设备树里的地址和中断号必须和Vivado里的配置完全一致,否则内核启动时会报错或驱动无法加载。

3.4 内核配置和根文件系统定制

PetaLinux的内核配置通过petalinux-config -c kernel进入菜单。常见的修改包括:

  • 添加自定义驱动到内核
  • 修改内核启动参数
  • 裁剪不需要的驱动和功能,减小内核体积
  • 开启内核调试选项

根文件系统的配置通过petalinux-config -c rootfs进入。PetaLinux提供了几种预置的根文件系统模板:最小系统、带网络功能的系统、带图形界面的系统等。也可以手动勾选需要的软件包,比如Python、OpenCV、MySQL等。

如果预置的软件包不够用,还可以通过Yocto的recipe机制添加自定义软件。在project-spec/meta-user/recipes-apps/目录下创建recipe文件,描述软件的源码位置、编译方式、安装路径等。

3.5 启动方式的配置和镜像生成

PetaLinux支持多种启动方式,最常用的是SD卡启动和QSPI启动。

SD卡启动的配置相对简单:在petalinux-config里选择"SD"作为启动设备,构建完成后会生成BOOT.BIN和image.ub两个文件。把这两个文件放到SD卡的FAT分区,插入ZYNQ板卡,设置启动模式为SD卡,上电即可启动。

QSPI启动需要把镜像烧录到QSPI Flash里。PetaLinux生成的BOOT.BIN包含了FSBL、PL配置文件和U-Boot,可以直接烧录。但根文件系统如果比较大,QSPI容量可能不够,这时可以把根文件系统放在SD卡或NFS上,QSPI只放BOOT.BIN。

构建完整镜像的命令:

petalinux-build

构建完成后,在images/linux/目录下会生成:

文件说明
BOOT.BINFSBL + PL比特流 + U-Boot
image.ub内核 + 设备树 + 根文件系统
system.dtb设备树二进制文件
zImage内核镜像

打包BOOT.BIN:

petalinux-package --boot --fsbl --fpga --u-boot --force

3.6 应用程序的交叉编译和部署

PetaLinux工程里可以创建应用程序模板:

petalinux-create -t apps --name my_app --enable

然后在project-spec/meta-user/recipes-apps/my_app/files/目录下编写源码。构建时PetaLinux会自动用交叉编译器编译,并把可执行文件打包到根文件系统里。

如果不想重新构建整个根文件系统,也可以单独编译应用程序,然后通过SD卡或scp拷贝到板子上运行。PetaLinux的交叉编译器在tools/linux-i386/aarch64-xilinx-linux/目录下,可以手动调用:

source /opt/petalinux/settings.sh aarch64-xilinx-linux-gcc -o my_app my_app.c

4. 软硬件协同:把两条线串起来

4.1 硬件平台的设计和导出

整个开发流程的起点是Vivado里的硬件设计。一个典型的ZYNQ系统Block Design包含:

  • ZYNQ Processing System:配置PS端的外设、DDR型号、时钟频率等
  • 自定义IP核:PL端的功能模块,通过AXI接口与PS端互联
  • 互联模块:AXI Interconnect,负责多个主从设备之间的路由
  • 时钟和复位模块:为PL端提供时钟和复位信号

设计完成后,必须做两件事:第一,生成比特流(Bitstream);第二,导出XSA文件。XSA文件包含了硬件平台的所有信息,是Vitis和PetaLinux的输入。

注意:导出XSA之前,确保Block Design通过了验证(Validate Design),没有未连接的接口或地址冲突。

4.2 裸机程序和Linux驱动的分工

在实际项目中,PL端的功能模块通常需要两种软件配合:裸机程序用于前期验证和调试,Linux驱动用于最终产品。

裸机程序的优势是简单直接,不需要考虑内核框架,直接读写寄存器即可。适合在硬件调试阶段快速验证PL端逻辑是否正确。

Linux驱动则需要遵循内核的框架,注册字符设备或平台设备,实现file_operations里的open、read、write、ioctl等接口。驱动的优势是可以在用户空间通过标准文件操作访问硬件,方便上层应用开发。

一个实用的做法是:先用裸机程序把PL端逻辑调通,确认寄存器读写、中断、DMA都正常,然后再移植到Linux驱动。这样可以把硬件问题和软件问题分开排查,效率更高。

4.3 中断和DMA的协同处理

中断和DMA是ZYNQ软硬件协同中最容易出问题的两个点。

中断方面,PL端产生的中断通过IRQ_F2P接口送到PS端的GIC。在Linux下,需要在设备树里声明中断,驱动里通过request_irq()注册中断处理函数。注意中断号在设备树里是GIC的SPI编号,不是PL端的引脚编号。

DMA方面,ZYNQ PS端内置了DMA控制器(DMA0和DMA1),可以通过HP接口在PL端和DDR之间搬数据。Linux下使用DMA需要配置DMA引擎,申请DMA通道,准备DMA缓冲区。DMA缓冲区的物理地址必须连续,通常用dma_alloc_coherent()分配。

一个常见的坑是Cache一致性。如果DMA缓冲区是可缓存的,CPU写入的数据可能还在Cache里没写到DDR,DMA搬走的是旧数据。解决办法是使用dma_alloc_coherent()分配非缓存内存,或者在DMA传输前后手动执行Cache刷新。

4.4 调试工具和手段的配合

软硬件协同调试时,单靠一种工具往往不够。常用的组合是:

  • Vivado ILA:抓PL端信号,确认逻辑时序
  • Vitis调试器:调试裸机程序,看PS端寄存器
  • Linux内核日志:通过dmesg看驱动加载和运行信息
  • 逻辑分析仪:抓PL和PS之间的AXI总线信号
  • 示波器:测时钟、复位、中断等关键信号的时序

实际调试时,建议先确认PL端逻辑单独工作正常(用ILA抓信号),再确认PS端能正确读写PL端寄存器(用裸机程序),最后再上Linux驱动。每一步都确认无误后再进行下一步,避免问题叠加。

5. 常见问题与排查技巧实录

5.1 启动失败类问题

问题一:上电后串口无输出。

排查思路:先确认启动模式引脚是否正确,用万用表测MIO[8:2]的电平。然后确认BOOT.BIN是否烧录成功,QSPI启动时可以用JTAG读Flash内容验证。最后确认串口线是否接对,ZYNQ的调试串口通常是PS端的UART1,波特率115200。

问题二:FSBL卡死。

常见原因是DDR配置错误。FSBL里DDR的初始化参数必须和实际板卡的DDR型号匹配,包括容量、位宽、时序参数等。如果DDR配置不对,FSBL在初始化DDR时会卡住。可以用Vivado里的DDR配置工具生成正确的参数。

问题三:内核启动到一半卡住。

通常是设备树里的内存地址或外设地址配置错误。检查设备树里的memory节点是否和实际DDR容量一致,检查PL端IP的地址是否和Vivado里分配的一致。另外,如果根文件系统挂载失败,也会卡住,检查启动参数里的root=是否正确。

5.2 驱动加载类问题

问题一:驱动probe函数不被调用。

首先确认设备树里的compatible属性和驱动里的of_device_id表是否匹配。然后确认设备树节点是否被内核解析,可以通过/proc/device-tree/目录查看。最后确认驱动是否被编译进内核或作为模块加载。

问题二:ioremap失败。

检查设备树里的reg属性地址范围是否和实际硬件一致。如果地址范围超出了内核的映射区域,ioremap会失败。另外,如果该地址区域已经被其他驱动占用,也会失败。

问题三:中断不触发。

检查设备树里的interrupts属性,第一个数字是中断类型(0表示SPI),第二个是中断号,第三个是触发方式(4表示高电平触发)。确认PL端的中断信号是否正确连接到IRQ_F2P接口,可以用ILA抓中断信号。

5.3 性能优化类问题

问题一:DMA传输速度不达标。

检查DMA缓冲区的对齐方式,AXI HP接口对地址对齐有要求。检查DMA的突发长度(burst length)设置,太短会影响效率。检查DDR的带宽是否被其他主设备占用。

问题二:中断延迟太大。

Linux下的中断延迟受内核调度影响,通常在几十微秒量级。如果要求更低的延迟,可以考虑用裸机程序处理中断,或者使用PL端的中断控制器。另外,关闭内核的调试选项和不需要的驱动可以减少延迟。

问题三:CPU占用率过高。

检查是否有轮询操作,尽量用中断代替轮询。检查DMA是否正常工作,如果DMA没起来,CPU要亲自搬数据,占用率自然高。检查是否有死循环或频繁的系统调用。

5.4 版本兼容类问题

PetaLinux和Vivado的版本必须严格匹配,比如Vivado 2023.2对应PetaLinux 2023.2。混用版本会导致XSA文件无法导入,或者设备树生成错误。

另外,PetaLinux的不同版本之间,命令和配置文件的位置可能有变化。比如早期版本的petalinux-config菜单结构和新版就不一样。建议固定使用一个版本,不要频繁升级。

问题类型典型现象排查方向
启动失败串口无输出、卡死启动模式、BOOT.BIN、DDR配置
驱动加载probe不调用、ioremap失败设备树、compatible、地址范围
中断异常不触发、频繁触发中断号、触发方式、PL连接
DMA异常数据错乱、速度慢Cache一致性、地址对齐、突发长度
版本兼容导入失败、构建报错Vivado和PetaLinux版本匹配

6. 从研修班回去之后怎么继续深入

两天的研修班能帮你把框架搭起来,但真正的功夫在课后。我的建议是:回去之后第一件事,把课上讲的工程从头到尾自己重建一遍,不要直接拷贝现成的工程。重建的过程中你会遇到各种问题,解决这些问题的过程就是真正掌握的过程。

第二件事,找一个实际的小项目练手。比如用ZYNQ做一个简单的数据采集系统:PL端做一个ADC接口,PS端裸机程序读数据通过串口发送。跑通之后,再把裸机程序换成Linux驱动和应用程序。这个项目虽然简单,但涵盖了硬件设计、裸机开发、Linux驱动、应用开发完整链路。

第三件事,养成看官方文档的习惯。Xilinx的文档体系非常完善,UG585(ZYNQ Technical Reference Manual)是必读的,里面详细描述了PS端的每个寄存器。UG1144(PetaLinux Tools Documentation)是PetaLinux的官方指南。遇到问题先查文档,比在网上搜答案靠谱得多。

最后分享一个我自己的习惯:每次调试ZYNQ系统时,我都会准备一个Excel表格,记录每一步的操作和结果。比如“2024-05-23,修改设备树中断号从29改为30,重新构建,中断正常触发”。这个表格在后期排查问题时非常有用,可以快速定位是哪次修改引入了问题。ZYNQ的开发链路长、涉及工具多,好记性不如烂笔头。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询