ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

ZynqMP自定义板卡开发实战:Vivado与Petalinux全流程解析

ZynqMP自定义板卡开发实战:Vivado与Petalinux全流程解析 1. 方案选型与整体流程拆解1.1 为什么选ZynqMP而不是Zynq-7000做自定义PCB开发板第一件事不是画原理图而是先想清楚到底用哪颗芯片。ZynqMPUltraScale MPSoC和上一代Zynq-7000看起来都是“ARMFPGA”组合但实际差距非常大。ZynqMP的PS侧是四核Cortex-A53加双核Cortex-R5主频能跑到1.5GHz左右还带Mali-400 GPU和VPU硬核编解码DDR接口也从DDR3/DDR3L升级到了DDR4带宽翻了一倍多。我这次做的是带视频采集、千兆网和高速数据接口的板卡需要Linux系统跑应用又要PL侧做实时信号预处理算下来Zynq-7000的667MHz双核A9已经不够用所以直接上了ZynqMP。另一个原因是生态成熟度。Petalinux对ZynqMP的支持路径非常清晰Xilinx官方从2018.3版本开始对UltraScale MPSoC的BSPBoard Support Package支持就已经很完善设备树、U-Boot、内核都有现成模板。相比之下用纯Yocto从头构建要处理大量layer配置和源码版本对齐工作量会成倍增加。如果你只是做一块自有板卡不是要给整个产品线搭一套标准化构建流水线Petalinux是更务实的起点。还有一点容易被忽略的是PS-PL互联性能。ZynqMP的AXI接口可以配置成AXI-HP、AXI-HPC、AXI-ACP等多通道组合带宽与延迟特性比Zynq-7000好得多。做DMA大批量传输时PL侧逻辑不需要等PS长时间占用总线基本可以做到双通道并行读写。这个特性对视频帧搬运、高速ADC采样数据上传这类场景非常关键。1.2 Petalinux和手工Yocto怎么选很多人在选构建方式时纠结Petalinux能不能上生产Yocto是不是更自由我的看法是如果你只有一块或者几块板而且是自研非量产直接用Petalinux最省事。Petalinux本质上就是Yocto的一个封装底层还是OpenEmbedded那套但Xilinx帮你把机器配置、内核源码、U-Boot源码、设备树生成脚本都打好了包一条命令就能从头构建一个完整镜像。实际测试下来在干净环境里从HDF导出到生成BOOT.BIN和image.ub大概30到50分钟就能跑通中间几乎不用手动改任何东西。Yocto的优势在于组件版本锁定和定制深度。Petalinux默认会跟着发布版本走一套固件版本组合比如2020.2版本配的内核是5.4U-Boot是2020.01。如果你要换内核版本、打厂商补丁、集成自研Yocto层Petalinux可以通过创建sdk和external layer的方式扩展但配置复杂度会上升。对于首次接触ZynqMP开发板的工程师我建议先老老实实用官方Petalinux流程跑通一次再考虑个性化的Yocto改造。另外要说一下版本对齐问题。Petalinux、Vivado、以及你板上的硬件配置三者必须匹配。Vivado导出的XSA/HDF文件里包含了PS配置、PL比特流和地址映射Petalinux通过这个文件自动匹配U-Boot配置和内核设备树。如果你用新版本Petalinux去导入旧版本Vivado生成的HDF经常会在设备树生成阶段报错或者生成的MIO引脚映射和实际板卡对不上。所以我的习惯是每做一块新板卡先固定一套VivadoPetalinux版本组合然后在项目说明文档里写清楚防止后面换机器换环境时版本漂移。1.3 整体开发流水线从硬件设计到系统跑起来标准流程可以拆成五大阶段。阶段工具链主要产物常见坑点硬件原理图/PCB设计Altium/Cadence网表、管脚约束MIO复用冲突、DDR管脚分配错误FPGA工程构建VivadoXSA/HDF、比特流PS配置错误、DDR IP参数不匹配、生成比特流失败Linux系统构建PetalinuxBOOT.BIN、image.ub、设备树dtb设备树与硬件不匹配、U-Boot环境变量错误启动与驱动适配U-Boot/kernel启动日志、设备节点bootargs错误、PHY芯片驱动未启用应用集成与调试交叉编译工具链可执行程序、系统镜像根文件系统空间不足、依赖库缺失整个流水线里面最容易出问题的不是某个具体工具而是阶段之间的接口。Vivado导出的XSA如果没包含正确的地址映射Petalinux生成的设备树就会缺PL侧节点U-Boot的环境变量如果没设对bootargs内核就起不来。所以开发过程中每一步都要留好日志和配置文件版本不然到最后排错会非常痛苦。我用的是Vivado 2020.2加Petalinux 2020.2的组合这套组合对ZynqMP的支持已经很稳定网上资料也多遇到问题基本都能搜到解决方案。如果你用的是Vivado 2018.3或者2019.1流程完全一样就是小版本差异需要注意后面我会专门提几个版本相关的问题。2. Vivado硬件工程设计与实操细节2.1 PS侧配置DDR、MIO和启动方式Vivado工程里PS配置是做ZynqMP板卡最先要确认的部分这部分出错往往要到上板阶段才能发现排错成本非常高。DDR配置是最容易踩坑的地方。ZynqMP的DDR控制器支持DDR4和LPDDR4不同颗粒的时序参数、地址映射、总线位宽都要在Vivado里正确设置。我这块板卡用的是两片DDR4颗粒组成32bit总线的rank1配置容量2GB。配置时要在Zynq UltraScale MPSoC的DDR Configuration页面里选对Memory Part比如MT40A512M16然后确认数据位宽、Bank Group使能和地址映射方式。这里不建议自己手填所有时序参数直接用Vivado提供的颗粒库匹配最稳妥手填漏一个tRFC参数板子DDR初始化就会卡死在U-Boot阶段。MIO配置也要在PS配置界面里提前规划。ZynqMP一共有118个MIO引脚但并不是所有外设都能随便映射UART、SDIO、I2C、SPI这些都有固定的MIO范围。我做这块板时把UART1放在MIO48/49SDIO0放在MIO40到MIO47I2C0放在MIO14/15然后把Boot Mode配置为SD启动。这里要注意的是MIO信号如果同时被两个外设要求占用Vivado会直接报错而且在PS配置里看不到具体冲突位置只能逐个核对。我的建议是在原理图阶段就用表格把每个MIO的复用情况理清楚画到PS配置之前先做一次硬拷贝比对。还有一个经常被忽略的是PS端时钟和复位。ZynqMP需要外部提供PS_REF_CLK一般接33.333MHz的晶振或者有源振荡器。如果你板子上没有这个时钟PS系统压根不会启动U-Boot也进不去。另外PS_POR_B复位引脚要接上可靠的复位芯片不能直接用一个简单的RC电路糊弄过去上电时序不稳轻则启动随机失败重则DDR训练过不去。我第一版样板就吃过这个亏后来加了一颗专用电源监控复位芯片才稳定。2.2 PL侧自定义IP与管脚约束PL侧的逻辑设计这次主要做一个自定义DMA IP负责把ADC采样数据通过AXI-Stream搬进PS侧DDR。在Vivado里用Block Design方式把这个IP和ZynqMP PS核连起来注意AXI接口的连接位宽和时钟域。ZynqMP的AXI-HP接口有128bit数据位宽如果你的自定义IP是32bit或者64bit老老实实加上AXI Data Width Converter不要试图在自定义IP里自己处理位宽转换既麻烦又容易出时序问题。管脚约束文件XDC里要特别留意物理引脚分配和I/O标准。ZynqMP的PL侧引脚支持多种电平标准我板上的ADC输出接口用的是LVDS在XDC里要明确写成set_property IOSTANDARD LVDS否则上板后信号幅度不对采集数据全是乱的。还有一点是PL侧的配置引脚和PS侧的MIO不要冲突比如SPI Flash的片选、JTAG信号这些都有固定位置需要对照原理图逐项检查。这里补充一个实用技巧Vivado的管脚分配界面可以导入CSV格式的管脚列表用Excel整理好引脚名、封装引脚号、I/O标准之后一次性导入比自己手动一个引脚一个引脚点要快得多也减少了人为选错引脚的风险。我第一次做ZynqMP板时就是在GUI里手动分配了上百个引脚结果有两处I/O标准写漏了后期检查花了大半天。2.3 生成比特流失败排查与工程清理习惯Vivado生成比特流失败是我被问得最多的问题尤其是ZynqMP这种大工程。常见的失败原因有几个逐个说。第一是综合Synthesis阶段的时序违例。ZynqMP的PL侧时钟频率经常上到200MHz甚至更高如果自定义IP逻辑没做好流水线很容易出现setup time violation。排查方法是打开综合报告查看最差负余量WNS和总负余量TNS如果WNS是负值就要找到对应的时序路径加寄存器打拍或者降低时钟频率。很多人习惯直接勾掉时序约束的检查强行出比特流这种操作板子基本不工作别这么干。第二是实现Implementation阶段的布局布线失败。最典型的是全局时钟资源不够比如你在设计中用了太多BUFG或者某些复杂时钟结构。ZynqMP的全局时钟资源是有上限的如果报告里明确提示BUFG limit exceeded要么用区域时钟/布线时钟替代要么调整时钟生成方案把多个同频同相时钟合并到一个BUFG下。第三是比特流写入阶段报错提示无法连接器件。这个问题九成是JTAG链路或者下载器接触不良。先在Hardware Manager里看能不能识别到芯片如果识别不到检查Vivado版本和下载器的兼容性还要看驱动是否安装。老版本的Vivado在Windows上容易遇到WinPcap安装失败导致JTAG下载异常解决办法是在安装Vivado组件时勾选对应的网络驱动组件或者单独重装WinPcap兼容版本。工程清理也是一个好习惯。Vivado跑综合、实现之后会产生大量中间文件一个ZynqMP工程能膨胀到几十GB。长期维护时每次修改只做增量实现不用每次都全量跑。建议定期用reset_project清理中间结果保留最后一次综合和实现的checkpoint。另外如果要把工程发给别人或者归档只保留.xpr、.srcs、.xdc和IP核备份目录甚至可以导出成Tcl脚本重建整个工程比打包整个工程目录干净得多。2.4 Vivado安装、License与版本降级的血泪经验很多新人在Vivado安装阶段就走不下去了。先说安装Vivado大版本每年更新一次每个版本可以单独安装不同的子版本但同一版本的用户许可证是独立识别的。安装时如果提示a fatal error has been detected by the Java runtime environment多半是安装包路径有中文、安装目录有空格或者磁盘空间不足解压安装包时尤其容易出现这个错误英文路径重试基本能解决。License方面如果你有合法的企业授权直接加载许可证文件即可。网上流传的各种本地license生成方式我不建议用Vivado会不定时校验License合法性而且ZynqMP全系列都需要UltraScale的授权试用版或者基础版功能受限严重。我个人的建议是如果是公司项目就让公司买正版授权如果是学习用途用Vivado WebPACK免费版本能覆盖ZynqMP大部分功能。版本降级是另一个高频需求。有人拿到一个高版本Vivado工程但自己机器上装的是低版本直接打开肯定报错。正确做法是让有高版本的人把工程另存为低版本兼容格式Vivado在File - Save Project As里有target version选项导出后还要检查IP核是否能在低版本中重新生成尤其是ZynqMP相关的IP版本差异大时IP就不能直接用得在低版本里重新配置一遍。还有一个办法是从Tcl脚本重建工程但IP配置参数复杂时工作量也不小。3. Petalinux工程构建与设备树深入解析3.1 Petalinux环境搭建与工程创建Petalinux的安装比Vivado省心一些但还是有几点要注意。首先它只支持指定版本的Ubuntu/CentOS等系统官方文档明确写了支持列表。我用的Ubuntu 20.04配Petalinux 2020.2完全兼容。如果你用Ubuntu 22.04需要手动安装一些兼容库最常缺的是libncurses5和libtinfo5这类32位运行库装完之后还要处理一下/bin/sh指向dash的问题改成bash才能跑petalinux命令。创建工程前先从Vivado里导出硬件描述文件。在Vivado的File - Export Hardware里选择包含比特流输出XSA文件名字不要用中文路径也尽量不要有空格否则后面Petalinux解析阶段会莫名奇妙报错。然后创建Petalinux工程source /opt/petalinux/2020.2/settings.sh petalinux-create --type project --template zynqMP --name my_board cd my_board petalinux-config --get-hw-description/path/to/xsa执行petalinux-config后会自动打开配置界面这里需要确认三个关键点U-Boot版本、根文件系统类型和启动介质。第一版调试我建议选initramfs方式启动把根文件系统直接加载进内存省去SD卡分区的麻烦。等到驱动调稳定了再切回SD卡或eMMC启动通过petalinux-config里Subsystem AUTO Hardware Settings路径下的设置改启动介质。3.2 内核配置和根文件系统定制Petalinux默认内核配置是基于Xilinx官方defconfig微调而来的对ZynqMP的常用驱动覆盖已经很全但自研板卡的外设驱动不一定会被自动包含。比如我板上用的USB转串口芯片是CP2102默认内核配置不一定开启这个驱动需要在petalinux-config -c kernel里进入Device Drivers - USB串口支持勾选对应的驱动选项。内核配置界面是基于Linux menuconfig的操作习惯和编译内核一样。配置完保存后会自动增量编译不需要手动清理整个内核源码目录。但有一点要注意如果你修改了设备树文件需要单独编译设备树命令是petalinux-build -c device-tree。如果修改了内核配置则要petalinux-build -c kernel。很多人直接把两个都改了然后只跑一次petalinux-build看起来没问题实际上有时不会触发生成新的设备树二进制文件上板后还是旧设备树。根文件系统方面Petalinux默认提供的是一个精简的BusyBox用户空间加少量工具。调试阶段建议手动加入网络工具和编辑工具比如iperf3、tcpdump、vim这些可以在petalinux-config -c rootfs里勾选。不要一开始就想着把整个Ubuntu用户空间搬上去又大又慢调试网络性能的时候iperf3一个工具就够用了。3.3 设备树深度解析如何在Petalinux中修改板级配置设备树是Petalinux里最需要花时间理解的部分也是ZynqMP板卡定制最核心的环节。整个设备树生成机制是Petalinux从XSA文件自动提取硬件配置生成一组默认的dtsi文件存放在工程目录下components/plnx_workspace/device-tree/device-tree里。这些dtsi包含zynqmp.dtsiSoC通用定义、pl.dtsiPL侧IP信息、以及pcw.dtsiPS外设配置。你真正要改的是工程根目录下的project-spec/meta-user/recipes-bsp/device-tree/files/system-user.dtsi它会被自动包含进最终设备树专门用来做用户层覆盖。举个例子我板上的以太网PHY芯片地址不是默认的0需要在system-user.dtsi里覆盖。默认设备树里gem0节点的phy-handle指向一个PHY地址0但我用的PHY挂在地址7上那么就要这样写gem0 { status okay; phy-mode rgmii-id; phy-handle phy7; phy7: phy7 { reg 7; device_type ethernet-phy; }; };这里还有两个常见的坑。第一个是phy-modeZynqMP的GEM接口支持多种PHY接口模式如果板子是RGMII就要明确写rgmii-id一般要让PHY自己产生延迟而不是在FPGA逻辑里手动加延迟。第二个是PHY的reset引脚如果有GPIO控制PHY复位需要在设备树里使用reset-gpios字段否则内核驱动在PHY上电后访问寄存器会超时。另一个高频场景是PL侧自定义IP的中断号和地址空间。Petalinux从XSA自动生成的pl.dtsi已经包含了地址映射但中断号有时不对。ZynqMP的中断控制器是GICPL侧的AXI中断通过IRQ_F2P引脚接入PS映射关系和你在Vivado里配置的中断ID要能对上。检查方法是启动系统后在/proc/interrupts里确认设备有没有拿到正确中断号如果IRQ没有触发就要回头检查Vivado IP的中断连接和Petalinux设备树里的interrupts属性。3.4 打包镜像与烧写启动设备树改好、内核配置完成之后构建最终镜像petalinux-build完成后在images/linux目录下会生成BOOT.BIN、image.ub、system.dtb等文件。如果你改过设备树要确认一下system.dtb是不是最新的对比一下生成时间戳最保险。BOOT.BIN包含了ZynqMP的启动引导程序FSBL和U-BootPetalinux默认把FSBL、PMU固件和ARM Trusted Firmware都集成进去了不需要手动单独打包。生成BOOT.BIN的命令是petalinux-package --boot --fsbl --fpga --u-boot如果要更新设备树到已有镜像里可以直接用petalinux-package --dtb命令不用重新构建整个系统。把BOOT.BIN和image.ub拷到SD卡第一个分区FAT32第二个分区放根文件系统插入板卡上电就能进入Linux系统。JFFS2/SD卡/eMMC等不同启动介质对应的镜像打包参数会有差异。SD卡启动最简单eMMC启动需要在U-Boot里烧写镜像NAND/NOR Flash启动需要额外生成对应镜像格式。第一次做ZynqMP板卡的工程师我强烈建议先用SD卡启动跑通整个流程再考虑其他介质。4. 上板调试、问题排查与量产经验4.1 第一轮启动失败U-Boot阶段的那些坑新板卡第一次上电能跑到U-Boot命令提示符就算成功了一大半。我遇到过最气人的一种情况是SD卡里镜像都正确但U-Boot只打印几行就卡死了。用JTAG连上去看最后卡在DDR初始化或者PMU固件加载的位置。DDR初始化在U-Boot里是通过FSBL完成的如果DDR配置和实际颗粒不匹配训练就会失败。排查方法是在Vivado里重新检查DDR颗粒型号、位宽和地址映射导出XSA时选择Include bitstream确保Petalinux拿到的是最新的配置。还有一种情况是U-Boot能进命令行但boot命令执行到一半卡住。最常见的原因是环境变量里的bootcmd和bootargs不对。在U-Boot命令行里执行printenv确认bootcmd是不是指向正确的分区和文件名。Petalinux默认的U-Boot环境变量一般是去FAT分区找image.ub如果你的SD卡分区格式不对或者文件名不匹配系统就会卡住。另外一个容易忽略的坑是PMU固件。ZynqMP的电源管理单元需要独立的固件运行Petalinux构建时自动集成了PMU固件。如果你在Petalinux工程里手动修改过PMU相关配置或者用旧版本固件配新内核就可能出现系统起来后R5核不工作、电源域切换失败等奇怪问题。遇到诡异问题先检查固件版本把PMU固件恢复为默认再试。4.2 网络和PHY适配实战ZynqMP板卡的千兆以太网是调试阶段最重要的通信手段。内核起来后首先确认网络接口能不能link up。如果ip link看不到网卡多半是设备树里PHY节点写错或者内核缺失对应PHY驱动。如果link up了但ping不通先查PHY模式RGMII接口模式下rgmii-id与rgmii的区别就是延迟是否由PHY内部处理这个搞错会导致物理层包收发异常。调试网络还有一个技巧在U-Boot阶段就测试网口。U-Boot自带网络命令比如可以ping 192.168.1.100如果能通说明硬件链路和PHY没问题问题出在内核设备树或者驱动配置。如果U-Boot阶段就不通那问题大概率在硬件或者PHY芯片配置上内核都不用等。如果PHY芯片有掉电问题网口会出现“link up后马上link down”的现象这种基本是PHY的供电纹波或者复位时序异常用示波器量PHY的复位引脚和供电电压就能定位。4.3 常见错误速查表现象可能原因排查方法U-Boot卡在DDR初始化DDR颗粒参数不对检查Vivado DDR配置、颗粒型号、总线位宽系统启动后无网卡PHY节点设备树错误检查gem节点phy-handle、PHY地址、phy-mode挂在Waiting for root device启动参数或根文件系统问题检查bootargs里的root参数、SD卡分区内核崩溃打印Kernel panic - not syncing设备树与内核不匹配重新编译设备树、检查内核版本PL侧IP无中断中断号映射错误检查Vivado中断连接、pl.dtsi的interrupts字段串口无输出MIO配置错误或波特率不对检查MIO映射、U-Boot/内核波特率配置这张表大多数问题我都踩过一遍。耗时最久的是PHY地址问题因为我原理图里PHY地址引脚设计错了导致PHY实际地址和预期不一致当时还怀疑是内核驱动问题最后用U-Boot的mii命令读PHY寄存器才定位到。4.4 从开发板到量产的额外提醒如果你的板卡最终要走向量产有几个提前就要想清楚的事。第一电源时序。ZynqMP对电源要求很苛刻多路电源的上电顺序必须符合PS和PL的要求。Vivado里可以配置电源管理功能但硬件上还是要靠PMIC或者分立电源电路保证时序。量产板请务必做电源时序测试不能只在实验室用程控电源手动上电。第二启动介质选择。开发阶段用SD卡方便但量产板要考虑eMMC或者QSPI Flash。eMMC启动的镜像封装方式与SD卡不同还要在U-Boot环境变量里配置好root设备。Petalinux对eMMC的支持很成熟但你要提前在工程里配置好分区表不然批量烧录时会头疼。第三量产烧录方案。几十块板子手动插SD卡拷镜像效率太低建议用JTAG烧写工具配合Vivado和PetaLinux的烧写脚本把BOOT.BIN和image.ub直接烧进eMMC。Xilinx官方有对应的量产烧录方案简单说就是通过U-Boot的ums命令或者JTAG工具把镜像写到eMMC指定分区。第四温度适应性。ZynqMP的DDR控制器在温度变化剧烈时会出现初始化失败如果你的产品在户外环境使用务必做高低温测试。在Linux系统起来后可以读取PS内部温度传感器ZynqMP自带温度监控功能/sys/class/thermal下能看到温度节点跑压力测试时多留意温度变化。5. 最后再分享一个实用小技巧如果你要维护多块不同配置的板卡建议在Petalinux工程里用不同的system-user.dtsi分支来管理设备树差异。不要每个板卡单独建一个Petalinux工程那样既占磁盘空间又难维护。我的做法是建立三个设备树配置文件base板、video扩展板和industrial版三个文件通过#include机制共享公共配置只覆盖差异部分。具体步骤是在meta-user的recipes-bsp/device-tree/files目录下创建多个dtsi在system-user.dtsi里用条件编译或者直接注释切换。实测下来多板卡管理成本能降低一半以上。还有一个小细节Petalinux的缓存问题。如果你在同一台机器上反复切换不同的XPU配置可能会遇到内核编译缓存没有正确清理的情况。遇到莫名其妙的内核编译错误时直接删除build/linux/kernel目录下的临时文件重来一次往往能解决。做ZynqMP自定义板卡这件事前期硬件的坑最多中期设备树和U-Boot的坑最耗时间后期反倒平稳。只要把Vivado和Petalinux的版本组合锁定好每次改动都留好记录整个流程是完全可控的。希望这篇记录能帮你少走点弯路。
返回列表