ARTICLE DETAIL

资讯详情

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

ZynqMP自研板卡Bring-Up:Vivado与PetaLinux协同实战指南

ZynqMP自研板卡Bring-Up:Vivado与PetaLinux协同实战指南 做zynqMP的自研板卡Bring-Up最花时间的不是写Verilog也不是配内核而是把Vivado工程里的硬件描述和PetaLinux里的软件配置调成一致。我最近刚把一块完全自研的基于Zynq UltraScale MPSoC的PCB开发板从空板带到能跑Linux整个过程中PetaLinux的镜像构建、Vivado的硬件生成、设备树的调试每一步都有不少值得记录的坑。这篇东西写给正在做类似事情的工程师尤其是第一次拿自定义板卡搭配zynqMP平台的朋友希望大家少走几周弯路。这套流程核心就三件事第一在Vivado里把ZynqMP的PS端和PL端按实际电路配置好生成带比特流的硬件描述文件XSA第二用PetaLinux基于这份XSA创建BSP并进行定制产出可启动的Linux系统镜像第三处理设备树、启动加载、外设驱动等细节让系统在自己设计的板卡上真正转起来。适合的读者包括嵌入式软件工程师、FPGA工程师也适合那些需要从零搭建硬件验证平台的团队。1. 项目全景与方案设计思路1.1 这块板子在做什么为什么要做这个工程标题里写的custom pcb dev-board指的就是自己画的、非Xilinx官方评估板的硬件平台。官方开发板的好处是Xilinx已经把硬件配置、设备树、参考设计都准备好拿到就能跑但代价是引脚资源、接口类型、板级尺寸往往不符合实际产品需求。自研板卡的优势在于外设接口完全可控代价是“所有硬件细节都要自己告诉工具链”。zynqMP平台和普通单芯片方案不太一样它是典型的异构SoC集成了四核Cortex-A53APU、双核Cortex-R5FRPU、Mali-400 GPU以及一块UltraScale架构的可编程逻辑PL。PS端跑LinuxPL端可以放自定义逻辑和高速接口。这样一块芯片既要配置DDR、MIO、时钟这些PS硬核资源还要配置PL端的逻辑和引脚约束两边的描述必须精确匹配实际电路否则后面每一步都会有连锁问题。这个Vivado PetaLinux工程就是整个系统的“硬件底账”和“软件基座”。Vivado工程产出的比特流描述PL逻辑导出的XSA则成为PetaLinux了解板卡硬件细节的唯一天然输入。没有这个底账PetaLinux不知道DDR容量多大、UART在哪个MIO上、有没有以太网自然没法生成能用的系统。1.2 为什么选 Vivado PetaLinux 而不是硬刚 Yocto构建嵌入式Linux不是只有PetaLinux一条路你也可以直接用Yocto、Buildroot甚至手工交叉编译。但在这个项目里我坚持用Vivado PetaLinux组合核心原因是“软硬件协同的一致性”。Xilinx官方对zynqMP的BSP支持是围绕PetaLinux展开的内核补丁、U-Boot配置、PMU固件、ATF、设备树生成脚本这些都已经集成在PetaLinux工具链里。自己用Yocto从零配一套BSP光是适配U-Boot启动参数和DDR训练代码就够写一本手册。用生活类比解释一下PetaLinux相当于一套“自动装配车间”它根据Vivado导出的XSA自动生成设备树、U-Boot配置、内核默认配置把硬件工程师的设计意图翻译成软件工程师能直接使用的系统镜像。我只需要在关键节点上做定制而不是从每一颗螺丝开始拧。如果项目是量产级产品、需要长期维护整个软件栈那Yocto是值得投入的但如果目标是快速Bring-Up、验证自定义PCB、迭代外设驱动PetaLinux就是投入产出比最高的方案。2. 硬件工程Vivado 工程搭建与比特流生成2.1 ZynqMP 的 PS 配置从 DDR 到 MIO打开Vivado新建工程后第一件事是加入“Zynq UltraScale MPSoC”这个IP然后进入其配置界面。这里的每一项配置都直接对应板卡硬件设计出错就是在给后面埋雷。首先是DDR配置。zynqMP的PS内建DDR控制器必须在Vivado里精确指定DDR类型DDR4、DDR3、LPDDR4等、位宽通常64bit、总线频率、颗粒型号和地址映射。我这次用的是DDR4 64bit两片DIE组成的Rank配置时发现一个容易忽略的点必须按实际颗粒的地址结构选择正确的Bank Group和Row/Column配置否则U-Boot阶段能读DDR一旦跑大量数据就随机崩溃。DDR控制器还涉及地址映射Cortex-A53的地址空间里DDR通常映射在0x00000000起始这块配置错的话内核一启动就panic。然后是MIO配置。zynqMP的MIO总共78个引脚UART、SD卡、以太网PS-GEM、USB、I2C、SPI等都可能复用到这里。我板子上UART接的是MIO18/19所以要在PS配置里把UART1映射过去并设置正确的电压域。一个教训MIO的电平标准必须和PCB的Bank电压一致比如Bank500工作在1.8V那你映射到这里的SD信号就不能按3.3V电平来配否则电气特性不匹配信号不稳定还不好排查。PS-PL接口的配置同样影响巨大。如果PL端有AXI外设比如AXI GPIO、AXI BRAM、自定义加速器需要通过PS的AXI接口连接。zynqMP提供通用AXI GP接口适合低速控制类、高性能AXI HP接口适合大数据吞吐和ACP缓存一致性端口。我这次在PL端放了一组AXI GPIO用来控制板上的LED和拨码开关就挂在GP接口上如果后续要跑PL端的高速数据通路建议务必留出HP接口的带宽规划。2.2 PL 外设、地址空间与 XDC 约束PL端的逻辑工程相对标准但自研板卡有个额外负担所有引脚约束都得自己写XDC。开发板一般附带现成约束文件自研板卡则必须从原理图里逐个核对每个信号的FPGA引脚位置和电平标准。在Vivado里添加AXI GPIO等IP后地址空间一般从0xA0000000这类区域分配。多个PL外设的地址要避免冲突Vivado的Address Editor会显示当前分配情况一定要养成习惯每加一个IP就检查地址分配是否有重叠或未分配。实际项目中我就碰到过AXI BRAM和AXI GPIO的地址区间重叠导致读外设返回的数据完全错乱折腾好久才发现是地址问题。XDC约束我重点提醒三点第一引脚的物理管脚号必须和PCB布线一致差一个bank都不行第二电平标准必须匹配IO Bank的VCCO电压例如某些Bank是1.8V供电你就不能把常开极高电平标准的引脚放在那里第三不要遗漏时钟约束。PL端如果有时钟信号进来必须创建对应的create_clock约束否则综合实现会报时序未收敛生成比特流直接失败。另外XDC文件里如果写了某些引脚被PS端MIO占用的复用关系Vivado会给出警告先不要忽略逐条确认是属于正常的PS-PL共享还是真的冲突。这些警告往往是不稳定现象的根源。2.3 综合实现与导出 XSA常见翻车点综合、实现、生成比特流这套流程理论上是自动化操作的但自研板卡的工程里几乎每一步都可能因为约束不完整、IP版本不一致或者时序没收敛而中断。“生成比特流失败”是出现频率最高的报错。我记得有一次卡在Implementation布局布线阶段的时序违例打开Implementation Timing Summary发现关键路径是PL端AXI接口跨时钟域的路径原因是PS端给的AXI时钟频率和PL端逻辑工作时钟没有对齐。解决办法要么提高逻辑工作频率、要么降低PS端AXI时钟配置或者给跨时钟域路径添加异步FIFO处理。对很多第一次做zynqMP的人来说看到时序违例会心慌其实只要定位到违例路径来源于哪个时钟域问题就解决一半了。在Vivado导出的文件上老用户可能还记得以前的HDF现在新版本导出的是XSAeXport System Acceleration。导出时务必勾选“Include bitstream”否则PetaLinux那边加载硬件工程时没有比特流信息分区启动和FPGA重配置都会出问题。导出的动作很简单File → Export Hardware → 选择目标目录但导出的XSA文件必须和最终下载到板卡上的比特流一致否则就是不同步的硬件描述这个一定要自己把控。3. 软件工程PetaLinux 环境准备与系统构建3.1 环境版本对齐这一步吃亏最多PetaLinux最大的坑在于版本匹配。Vivado 2020.2就一定要配PetaLinux 2020.2Vivado 2019.2就配PetaLinux 2019.2版本不对加载XSA时可能直接报解析失败或者生成的U-Boot完全无法启动。我亲眼见过同事拿PetaLinux 2020.1配Vivado 2019.2折腾了一周最后发现是版本不匹配。安装时还需要注意宿主机的Linux版本支持范围。PetaLinux官方支持Ubuntu 18.04/20.04/22.04等但每个小版本支持范围不同。比如PetaLinux 2020.2官方推荐Ubuntu 18.04和20.04如果你非要在Ubuntu 22.04上跑则会撞上一堆库不兼容的问题。老版本PetaLinux在Ubuntu 22.04上经常需要手动安装libncurses5、tcl之类的兼容包否则配置界面启动就崩掉。安装完成后可以先跑一下petalinux-util --version确认安装成功。另外建议用一个独立的磁盘分区或较大的home目录因为一个PetaLinux工程动辄占用几十GB磁盘空间加上各种临时文件空间不够会在构建中途失败而且报错信息不一定直接提示“磁盘满”。3.2 从 XSA 到 PetaLinux 工程的快速创建拿到Vivado导出的XSA后PetaLinux的创建命令非常固定但每一步都要理解用途。创建工程用petalinux-create --type project --template zynqMP --name my_zynqmp_dev注意模板必选zynqMP不要选成zynq那是老款Zynq-7000。然后在工程目录里导入硬件描述cd my_zynqmp_dev petalinux-config --get-hw-description/path/to/your.xsa执行后会自动弹出一个配置菜单这是定制系统的总入口。里面比较重要的是“Subsystem AUTO Hardware Settings”这里能看到从XSA解析出的DDR配置、MIO配置、外设配置。如果你发现这里读到的硬件信息和原理图不一致说明XSA导出不对或者Vivado里配置错了先回头改硬件工程。同一级配置菜单里还有其他重要项启动模式SD启动、QSPI启动、eMMC启动等、U-Boot配置、内核配置、Rootfs配置。做自定义PCB开发板验证时我强烈建议先把启动模式设为SD因为SD启动最灵活、最容易调后续量产烧写再改QSPI/eMMC。硬件配置导入后可以先用默认配置编译一次完整系统。这个过程会下载大量开源软件包耗时较长。建议在网络稳定的环境下操作并且把PetaLinux的下载镜像源配置好否则下载源码包的环节会非常煎熬。3.3 启动镜像的组成拆解与 SD 卡制作编译完成后生成的关键镜像包括BOOT.BIN、image.ub和boot.scr。这三个东西很多新手分不清。BOOT.BIN是启动链路上的第一阶段组合体里面按顺序包含PMU固件、ATFArm Trusted Firmware、FSBLFirst Stage Boot Loader通常是U-Boot SPL或Xilinx FSBL、U-Boot本身以及可选的FPGA比特流。你可以把它理解为一张“多层饼”启动流程是BootROM先读BOOT.BIN把PMU固件和ATF加载起来再由ATF拉起U-Boot最后U-Boot做硬件初始化和镜像加载。PetaLinux构建BOOT.BIN用petalinux-package --boot --fsbl --fpga --pmufw --u-boot --force其中--fsbl指定FSBL的elf文件--fpga指定比特流文件--pmufw指定PMU固件。实际参数在不同版本略有差异建议先petalinux-package --help查看当前版本支持的选项。image.ub是一个FIT镜像里面包着Linux内核、设备树和可选的ramdisk。U-Boot启动时会从启动介质读取image.ub然后将其加载到DDR中执行。SD卡制作相对简单第一个分区格式化为FAT32放BOOT.BIN、image.ub和boot.scr第二个分区用ext4存放rootfs根文件系统。注意不是直接把rootfs镜像dd到卡上而是把根文件系统解压到ext4分区里这样调试时修改文件也方便。4. 设备树与引导过程从 BootROM 到 U-Boot、内核4.1 设备树硬件的“户口簿”设备树对zynqMP不是可选项而是整个Linux系统的“硬件户口簿”。PetaLinux会根据XSA自动生成一整套设备树源文件路径一般在工程目录的components/plnx_workspace/device-tree/device-tree-generation/下。打开这些文件你会发现里面已经帮你把psu_uart_1、psu_ddr、psu_ethernet等节点定义好了这些就是PS端硬件资源的内核视图。我自己在做自定义板卡时几乎总要改设备树因为PetaLinux自动生成的节点只是基于XSA的通用描述并不完全等于板级功能。例如我板上的某个I2C设备地址和默认配置不同或者某个GPIO扩展芯片挂在特定I2C总线上就需要在device-tree的system-user.dtsi里追加节点而不是直接改自动生成的文件。PetaLinux提供了一个用户设备树补丁目录project-spec/meta-user/recipes-bsp/device-tree/files/system-user.dtsi。所有自定义硬件描述写在这里重新构建时会被合并进最终设备树。设备树调试有个技巧内核启动后查看/proc/device-tree目录可以检查实际加载的设备树节点是否完整。如果某个外设没工作先看这个节点在不在再看属性值是否正确往往比乱改驱动代码高效得多。4.2 启动流程各环节的日志怎么看zynqMP完整启动链路是BootROM读取启动介质 → 加载并执行PMU固件 → ATF运行 → 进入U-Boot → U-Boot加载设备树和内核 → Linux启动并挂载rootfs。这条链路里几乎每一段失败现象都不一样排查方法也不一样。板子通电后如果串口完全没有输出先不要怀疑软件回看硬件电源、时钟、复位、MIO配置里UART引脚是否正确。如果串口能看到BootROM阶段打印的字符但U-Boot没有输出大概率是FSBL或ATF阶段DDR初始化失败。这时候优先确认Vivado里DDR参数是否与实际颗粒一致包括位宽、密度、时序。如果U-Boot起来了但内核启动到一半卡住常见原因是设备树里的DDR地址或者内存大小与U-Boot传给内核的参数不一致。可以按任意键进入U-Boot命令行用printenv查看bootargs确认mem参数是否与硬件匹配。如果内核启动到“Waiting for root device”卡住那是rootfs没挂上检查SD卡的分区格式、bootargs里root参数以及ext4分区是否真的有文件。搞清楚每个阶段的日志在哪一段出现实际上就把启动问题拆成了三段独立的排查工作BootROM阶段看硬件最小系统U-Boot阶段看DDR与存储介质内核阶段看设备树与rootfs。这种做法能帮你快速缩小问题范围而不是对着整段启动日志一头雾水。5. 实际问题大合集安装、许可、时序、工程清理5.1 Vivado 安装和 License 的经典报错Vivado安装过程里最常见的报错是“a fatal error has been detected by the Java Runtime Environment”很多人在Windows和Linux上都遇过。这个报错一般不是Vivado本身坏了而是安装器的运行环境出了问题。我遇到的情况是安装路径带有中文目录导致JVM解析路径异常。解决办法很简单安装目录全用英文路径不要有空格有空格时加引号处理。另一个高频问题是系统内存不足。Vivado WebPACK安装器在选择安装内容时会产生大量临时文件特别是你同时勾选了SoC、HLS、Vitis等多个组件却只给安装器2GB内存很容易触发JVM崩溃。安装Vivado的机器建议至少16GB内存而且要让/tmp目录所在分区有足够空间。License方面要正规渠道获取。zynqMP确实需要完整的Vivado授权WebPACK免费许可覆盖不了部分高级功能比如某些高速串行收发器IP或者100G级Ethernet核就要求额外的License。用公司邮箱注册时要注意License节点锁定是根据MAC地址生成的换了网卡或换了机器就要重新申请。5.2 工程清理与版本管理Vivado工程会越来越大一个综合实现完的工程有时十几个GB大部分是中间生成文件。这些文件不仅占空间还容易在版本管理时制造混乱。我见过有人把整个工程目录直接丢进Git提交速度慢不说.runs目录下的中间文件随便改一下就导致几十MB的diff。正确做法是在工程目录里建立.gitignore把以下内容排除.runs综合实现结果目录、.cache缓存、.hw硬件管理数据、.ip_user_filesIP用户文件、.jou、.log、*.str。只保留.xpr工程文件和源码、约束文件、脚本。这样Git管理的工程体积小、合并冲突少。工程清理本身也有讲究。Vivado菜单里有“Reset Implementation”和“Reset Synthesis”用来清掉实现和综合结果以便重新跑流程。命令行也可以用reset_project命令。真正要达到“干净工程”状态直接删除.runs和.cache目录就好下次重新综合实现时Vivado会自动重新生成。需要注意别手滑删掉.srcs目录那是你的源码和约束所在。关于版本降级有些网友会问能不能把Vivado 2021.2的工程降级到2019.2打开。官方机制上Vivado工程格式是向前兼容但不可向后兼容的即新版本可以打开旧版本工程旧版本打不开新版本工程。真遇到临时需要降级比较现实的路子是用Tcl脚本重建工程在新版本里用write_project_tcl导出脚本然后把脚本拿到旧版本环境中重新source。即便如此IP版本和某些约束写法在新旧版本间仍可能有差异降级后要专门检查IP版本和XDC兼容性。与其折腾降级不如在项目开始就冻结工具版本。5.3 生成比特流失败和时序收敛问题“生成比特流失败”属于老演员了。我在调试自研板时统计了一下大部分失败发生在Implementation阶段最后报时序失败或者DRC错误。DRC错误通常与引脚约束有关比如两个信号被约束到同一个引脚、某个Bank的VCCO电压与电平标准冲突、或者PL的某个时钟输入引脚被误用为普通IO。这些DRC错误在报告中都有明确提示一条条解决就行。时序不收敛则要分两类看。如果只是建立时间违例先检查时钟约束是否完整再看代码里是否有跨时钟域的路径没有打拍或FIFO同步。zynqMP的PL端支持的时钟频率很高但跨时钟域处理不好照样翻车。如果系统时钟本身没问题还要看看组合逻辑路径上有没高扇出信号。很多“默认配置综合不过”的情况其实是某个IP没有配置正确的时钟周期导致布局布线工具无法按时序要求收敛。这个时候回过头修改Vivado中IP的输入时钟频率或修改XDC中create_clock的周期值往往比继续调整约束更有效。另外一种情况是访问外部存储器接口的时序比如PL端接了DDR或者MIPI PHY。自研板卡的PCB走线长度、阻抗控制都会影响时序Vivado报出的setup/hold违例如果实在无法消除就要回到PCB层面评估是不是走线等长没做好、参考地是否完整。把问题归到硬件层面之后可以临时放宽约束先让工程跑通但量产前必须解决。5.4 PetaLinux 与设备树相关的排查速查表最后整理一个我这次项目里反复用到的排查思路按现象直接对照操作。现象可能原因优先排查动作板子上电串口完全无输出MIO配置错误、UART引脚错误、电源未初始化回Vivado检查PS MIO配置和UART映射BootROM打印后无U-Boot日志DDR初始化失败、BOOT.BIN组件缺失检查DDR参数、确认petalinux-package包含PMU和ATFU-Boot有日志但内核不起设备树不匹配、DDR大小不一致U-Boot命令行printenv检查bootargs对比设备树memory节点内核启动卡在Waiting for root devicerootfs未挂载、SD分区格式错误确认bootargs的root参数检查ext4分区是否可读某个I2C外设无响应设备树节点缺失或地址错误检查/system-user.dtsi中的节点定义和地址核对原理图PL端外设读写异常地址空间冲突、时钟域不一致回Vivado检查Address Editor和时钟约束单独强调一下设备树的增量修改。很多新手喜欢直接编辑PetaLinux自动生成的完整设备树源文件然后跑petalinux-build结果发现重新构建后修改被人覆盖。这是因为自动生成文件是不可持续持有的每次解析XSA都会重新生成。应该把所有自定义节点放在system-user.dtsi里它会被自动include进最终的设备树。我吃了一次这个亏之后就再也不碰自动生成目录了。写在最后这套Vivado PetaLinux zynqMP的组合在自研PCB开发板上完整跑通并不难难的是过程中每一个细节都做对。我个人在实际操作中体会到软硬件团队的信息同步比技术本身更重要。Vivado工程里改了DDR配置或者MIO映射一定要第一时间同步给PetaLinux侧重新导出XSA、重新导入PetaLinux而不是只改一个比特流就完事否则设备树与硬件描述脱节后面出现的故障会非常隐蔽。最后再分享一个小技巧拿到一块新做好的板子别急着烧完整Linux系统。先用Vivado的硬件管理器把PS端初始化起来确认DDR能读写、UART能回显、SD卡能枚举再进到PetaLinux构建阶段。把Bring-Up分层进行每一层都验证扎实整体推进速度反而最快。
返回列表