ARTICLE DETAIL

资讯详情

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

赛灵思SDK到Vitis工程迁移实战指南

赛灵思SDK到Vitis工程迁移实战指南 这几年用赛灵思家工具链做嵌入式开发的朋友应该都有一个很明显的体感SDK 这个老伙计正在被 Vitis 逐步取代。很多老项目、线上产品、毕设课题代码还躺在 SDK 工程里一打开 Vitis 就不知道怎么下手。我最近刚把一个基于 Zynq 的视觉采集板卡工程从 SDK 迁到 Vitis过程比想象中复杂但也比想象中可控。这篇就把移植思路、操作步骤、踩过的坑一次性捋清楚给正准备做赛灵思 SDK 到 Vitis 工程移植的朋友一份可以直接照着干的地图。老规矩先说明白一件事SDK 和 Vitis 在本质上并不是两个完全不同的世界Vitis 的嵌入式开发流程实际上是 SDK 的进化版它把硬件平台、板级支持包、应用工程、Linux 系统、加速内核全部揉进了一个叫“平台Platform”的概念里。理解了这一点后面所有操作都能对上号。这篇文章适合手里有旧 SDK 工程、想升级到新版工具链的嵌入式工程师也适合刚接触 Vitis、想打开已有工程却一脸懵的新手。1. 为什么要把 SDK 工程迁到 Vitis1.1 不是喜新厌旧是生态真的在往前走很多人第一反应是“能用就行干嘛迁移”。我理解这种心态但现实是赛灵思从 2019 年推出 Vitis 统一软件平台之后SDK 的维护节奏明显放慢新器件、新驱动、新库的支持几乎都优先在 Vitis 上落地。你如果继续用老 SDK很可能遇到几个非常现实的问题新买的 Versal、Zynq UltraScale 型号在旧版 SDK 里压根不被识别或者识别了也生成不了完整的 BSP。新版 Vivado 导出的硬件描述文件.hdf / .xsa老 SDK 打不开两边版本对不上。官方技术支持的默认回复已经是“请在 Vitis 中复现”老工程一旦出问题排查路径天然比别人长。很多第三方 IP、开源库、板卡厂商的参考设计提供的示例工程默认就是 Vitis 格式你拿着 SDK 去打开只能干瞪眼。这就像你手里还有一台运行 Windows 7 的老电脑不是不能用但新驱动、新软件、安全补丁都不再优先照顾你最终只能被迫升级。对于嵌入式项目来说工具链晚升级一年后面积累的技术债就多一年。1.2 迁移能带来什么实际收益抛开“被迫”的成分Vitis 本身确实有一些值得迁移的硬优势这也是我做完这次移植后感触比较深的地方。首先是工程结构更清晰。SDK 时代是一个 workspace 底下散落一堆应用工程和 BSP每次换电脑都要重新导入路径稍微不对就是一片红色报错。Vitis 引入了 Platform 的概念把硬件描述文件.xsa、操作系统、处理器、驱动库、BSP 打包成一个独立的平台组件应用工程只依赖平台不再直接和底层硬件配置纠缠。这样在多项目复用、团队协作、版本管理上都要顺手很多。其次是开发流程更完整。Vitis 不只是嵌入式软件 IDE它还能开发 FPGA 加速内核、DPU、AI 推理、数据中心应用。哪怕你暂时用不到这些功能单单把嵌入式开发、Linux 应用、启动镜像生成统一到一个界面里就比 SDK 时代的分散工具要省心。再一个是对 Linux 开发更友好。SDK 里做 Petalinux 和传统嵌入式 Linux 应用需要来回切换工具Vitis 里可以直接创建 Linux 平台sysroot、根文件系统、设备树都能在平台工程里配置。对于跑 Linux 的 Zynq 项目迁移的收益尤其明显。2. 动手前的评估先搞清楚家底再搬家2.1 盘点你的旧工程哪些能直接搬哪些要重写我在真正动手之前先把旧工程从上到下过了一遍这个步骤非常建议照着做。你要知道自己手里有哪些东西才能判断迁移的工作量。一个典型的 SDK 工程通常包含这几类内容硬件描述文件老版本是 .hdfVitis 用 .xsa这是整个移植的地基。应用源码C/C 代码包括 main.c、驱动封装、算法实现、网络协议栈、文件系统逻辑等。BSP 配置在 SDK 里通过 .mss 文件和 GUI 配置生成的板级支持包包含 xparameters.h、驱动库、链接脚本。第三方静态库/动态库比如算法库、编解码库以 .a、.so 形式存在。启动镜像配置BIF 文件boot image format用于生成 BOOT.BIN。设备树源文件如果是 Linux 工程还涉及设备树 dts/dtsi。按我的经验应用源码基本可以原封不动搬过去顶多改改头文件路径和编译选项。BSP 配置不能直接复制因为 Vitis 的 BSP 是基于新的平台工程重新生成的你只能参考旧配置手动重建。硬件描述文件建议用当前版本的 Vivado 重新导出一份 .xsa而不是直接把老 .hdf 转格式这样最稳妥。2.2 版本与工具链匹配确定 Vitis 版本这一步是很多人忽略但最容易出坑的地方。Vitis 和 Vivado 的版本必须严格对应而且 .xsa 文件的生成版本最好和 Vitis 版本一致或接近否则会遇到各种奇奇怪怪的兼容性报错。我的建议是先看你原来的 Vivado 工程是什么版本。如果你现在用的是 2023.2那就安装对应的 Vitis 2023.2 作为统一 IDE。如果旧工程是 2020.1 或更早生成的 .hdf不要直接用新版 Vitis 去打开建议用新版 Vivado 打开硬件工程重新综合、实现、导出 .xsa。版本对应关系大致可以参考这个规律以常见版本为例工具版本硬件描述文件支持的典型器件Vivado/SDK 2019.1.hdfZynq-7000, Zynq UltraScaleVitis 2019.2 ~ 2021.2.xsaZynq-7000, Zynq UltraScale, Versal 初期Vitis 2022.1 ~ 2023.2.xsa新增 Versal 系列完善支持实际操作里我不建议跨大版本升级比如从 2019.1 直接跳到 2023.2中间涉及的 IP 版本、约束语法、器件定义差异会放大很多。稳妥的做法是Vivado 和 Vitis 装同一个版本旧工程先在新版 Vivado 里跑通硬件导出再去做软件移植。2.3 评估硬件规格与依赖库这一步听起来像废话但我真的遇到过有人连处理器内核和操作系统都没搞清楚就开始建工程。你需要先确认几个关键信息处理器内核Zynq-7000 通常是 arm Cortex-A9 双核Zynq UltraScale 是 Cortex-A53 四核MicroBlaze 软核也支持。操作系统standalone裸机还是 Linux。外设依赖UART、IIC、SPI、QSPI Flash、DDR、以太网、DMA 等。特殊库依赖lwIP 网络协议栈、xilffs 文件系统、OpenAMP 异构多核通信库、Freertos 等。我这次迁移的目标平台是 Zynq UltraScale 跑 standalone 裸机外加一个自定义 DMA 驱动和一个 TCP 网络功能。提前把外设清单列出来之后后面生成的 BSP 就能按需勾选省去很多排除问题的时间。3. 分步实操从 SDK 工程到 Vitis 平台工程3.1 生成/导出现有硬件 XSA整个移植流程的第一步是在 Vivado 里把硬件工程导出为 .xsa 文件。这一步看着简单但有几个细节如果硬件工程里包含 bitstream记得在导出时勾选 “Include bitstream”否则后面启动镜像和调试下载会缺少 PL 配置。导出的路径不要放在带空格或者中文的目录下Vitis 对某些路径字符敏感越简单越好。如果你手头只有旧的 .hdf 文件没有完整 Vivado 工程那就只能先重建硬件工程或者找同事要最新的 .xsa硬转格式不可取。在 Vivado 里操作路径是File - Export Hardware。勾选包含 bitstream输出格式选择 XSA。导出完成之后会生成一个类似system_wrapper.xsa的文件后面所有步骤都以这个文件为核心。3.2 创建 Vitis 平台工程并导入 XSA打开 Vitis IDE先指定一个全新的 workspace 目录这里我特别建议不要用 SDK 时期的老 workspace避免.project、.cproject等旧配置干扰新工程的加载。然后在菜单栏选择 File - New - Platform Project填写工程名称点击 Next。在 Hardware Specification 那一栏选择刚才导出的 .xsa 文件。接下来的界面会让你选择操作系统standalone 或 linux、处理器比如 psu_cortexa53、运行时库standalone 对应的是 libc 等基础库。创建平台工程后Vitis 会自动读取 XSA 中的硬件信息生成对应的 BSP。这个过程需要一点时间但不需要你手动做什么。等生成完毕你会看到平台工程下面挂着一个 BSP 子工程里面包含xparameters.h、platform.h、platform.c、驱动库、链接脚本等。这里有一个非常关键的概念Vitis 里的 Platform 是独立可复用的。你可以把同一个平台供多个应用工程使用也可以把一个平台导出给其他项目。如果你后续要维护多个固件版本平台工程会帮上大忙。3.3 在平台工程上创建应用工程平台工程搞定之后下一步就是创建应用工程也就是你真正的业务代码所在的地方。在 Vitis 里操作路径是 File - New - Application Project。这一步有几个选择需要注意选择刚才创建的平台工程作为 Target Platform。选择处理器和域Domain如果平台里有多个域要选对。选择系统工程类型你可以选 Hello World 模板先跑通流程也可以直接选 Empty Application 再手动添加源码。我个人的习惯是先创建一个空的 Application 工程把旧的源码文件拖进去编译一把。为什么不用模板因为模板生成的 main.c 和旧逻辑差异很大容易让人产生“工程是不是坏了”的错觉。空工程更干净问题更容易定位。创建完应用工程后右键工程名选择 Properties在 C/C Build 设置里重点检查编译选项里的 include 路径是否包含了 BSP 生成的目录。宏定义是否有XPAR_...系列这些通常是硬件平台相关的。优化等级和调试信息格式建议开始迁移时用-O0 -g方便定位问题。3.4 配置构建选项与 Sysroot如果你原来的 SDK 工程里自己加过编译宏、链接库或者额外的头文件路径这些都要在 Vitis 里重新配置一遍。不要指望 Vitis 能自动识别旧工程的所有设置。打开应用工程的 Properties依次检查C/C General - Paths and Symbols添加旧工程用到的外部头文件目录。C/C Build - Settings - ARM GCC linker - Libraries添加静态库名称和库搜索路径。C/C Build - Settings - ARM GCC compiler - Symbols添加自定义宏。对于 Linux 工程还要在平台工程里配置 sysroot 路径否则交叉编译时找不到 libc 和头文件。Vitis 里通常会在创建 Linux 平台时自动指定 sysroot但如果你用的是自定义根文件系统需要手动指向正确的路径。这里有个经验如果你在 SDK 里使用了自定义链接脚本lscript.ld建议把里面的内存分配信息抄下来和 Vitis 生成的新链接脚本对照一遍。Vitis 默认的链接脚本往往和旧版不同尤其当你对 DDR 地址做过特殊划分时照抄默认配置很容易出现程序跑飞或者内存越界。3.5 把旧代码真正“搬”进来这一步反而是整个迁移中最需要耐心的环节。把源码文件从旧工程的 src 目录下复制到新应用工程的 src 目录下可以通过文件管理器直接拖拽也可以在 Vitis 里右键 import。导入后我最常做的一件事是全局搜索以下几类东西#include xparameters.h和#include platform.h确认路径是否被正确解析。XPAR_宏定义的引用这些宏在 BSP 重新生成后可能会变化例如设备 ID、基地址、中断号。自定义驱动中直接访问寄存器的地址常量比如某个 IP 的基地址新硬件导出后可能因为地址分配调整而变化。与硬件版本强相关的代码比如固定写死的时钟频率、DDR 大小、DMA 描述符数量。我当时就遇到一个很典型的坑旧代码里对某个自定义 IP 的基地址宏是XPAR_MY_AXI_IP_0_BASEADDR重新生成 BSP 之后这个宏居然变成了新的名字因为 IP 在 Vivado 工程中被重新编排了地址段。这种问题只有通过编译报错才能发现所以不要幻想一次编译通过报错才是正常的。4. 编译、运行与调试的实操要点4.1 构建流程与常见构建错误迁移之后第一件要做的事就是让新工程在 Vitis 里编译通过。编不过太正常了关键是学会从报错里快速定位问题。常见的编译错误和对应的排查思路错误现象可能原因处理办法找不到 xparameters.hBSP 未生成或 include 路径没配先 Build 平台工程再检查应用工程 include 路径未定义的引用xil_printf等缺少 BSP 库或工程类型错误确认是否链接了 xilstandalone 库找不到自定义头文件include 路径没加在 Properties 里添加头文件目录宏定义冲突旧代码里定义了和 BSP 重名的宏优先使用 BSP 里的宏删掉重复定义链接时地址越界链接脚本内存区域不匹配检查 lscript.ld必要时恢复旧自定义脚本如果你在编译时看到大量来自 BSP 内部的头文件报错大概率是工程类型选错了。比如你把一个 standalone 工程建成了 Linux 工程或者反过来。删掉应用工程重新创建一次比硬调编译选项快得多。4.2 运行方式从 JTAG 启动到 SD 卡启动编译通过只是第一步你的程序最终要能在板子上跑起来。在 Vitis 里运行的方式其实和 SDK 很像开发调试阶段用 JTAG 下载。右键应用工程选择 Run As - Launch Hardware。Vitis 会通过 JTAG 把 bitstream、FSBL、应用 elf 加载到板子上运行。生产启动阶段生成 BOOT.BIN 放到 SD 卡或烧写到 QSPI Flash。如果你只是调试裸机程序直接用 JTAG 最方便因为 Vitis 会自动处理硬件初始化不需要你先去烧写 Flash。但要注意如果你的工程包含自定义 PL 逻辑必须先确保 bitstream 和硬件配置一致。Vitis 启动硬件时会自动下载 bitstream但有时候需要你在 Run Configuration 里勾选对应的选项。如果想生成 SD 卡启动的 BOOT.BIN需要用到 Vitis 的 Create Boot Image 功能。菜单路径大约是 Xilinx - Create Boot Image。你需要指定Bootloader一般是平台 BSP 生成的 FSBL路径在platform/zynqmp_fsbl/Debug/下面。PMUFW如果是 Zynq UltraScale需要添加 PMU Firmware 的 elf。Bitstream 文件就是硬件工程导出的 .bit 文件。应用 elf你的应用工程编译产物。把这些文件按正确的顺序排好生成 BOOT.BIN放到 SD 卡 BOOT 分区里开发板设置为 SD 启动模式上电就能跑。4.3 Debug 配置中的几个关键细节Vitis 的调试器底层也是 GDB用起来和 SDK 类似但有几个细节在迁移时特别容易踩调试时如果发现程序卡在某个外设初始化函数里出不来先检查 BSP 里该外设的时钟配置。很多时候不是软件逻辑问题而是新 BSP 里的时钟频率和设备树里写的对不上。单步调试时出现“Cannot access target memory”之类的错误大概率是链接脚本里某个段的地址没有映射到实际的 DDR 空间或者 DDR 根本没有初始化。这时要看板子是否已经正确加载了 FSBL。Vitis 的 Debug 配置里可以设置 initialization script但默认情况下不需要。如果你的板子有特殊的上电时序可能需要在调试启动前手动初始化一些 GPIO。我的建议是第一次调试裸机程序时先在 main 函数第一行打断点。如果断点能停住说明启动流程没有问题后面逐步排查业务逻辑即可。如果连断点都停不住那就是 FSBL、DDR 初始化或链接脚本的问题先把这部分解决再说。5. 常见问题与排查技巧速查5.1 BSP 与外设驱动错乱这个问题在移植时太常见了。SDK 里你可能手动改过 BSP 的配置比如把某个串口的波特率从 9600 改成 115200或者在 .mss 外部添加过自定义驱动。Vitis 生成的新 BSP 不会继承这些手动修改一切以 XSA 硬件描述为准。遇到外设行为异常时第一件事不是翻代码而是打开 BSP 的system.mss或者xparameters.h确认外设的基地址、中断号、时钟频率是否和原来一致。尤其要注意中断号很多外设驱动在 SDK 时期和 Vitis 时期的中断 ID 会发生变化因为硬件工程里 IP 的连接关系可能已经动了。我这次迁移就遇到一个坑原来的 DMA 中断号是 0x27重新生成平台工程之后Vitis 自动分配的中断向量表把 DMA 中断号排到了 0x24。我一开始没注意程序跑到 DMA 传输完成后一直卡在中断等待里。后来查到是中断号对不上改成新的宏定义才恢复正常。5.2 第三方库和链接错误嵌入式工程很少只依赖 BSP多少会用到一些第三方库。比如通用的加密库、压缩库、TCP/IP 协议栈、图像处理库。这些库在 SDK 时代编译出来的 .a 文件能不能直接用到 Vitis 里我的经验是最好重新编译不要偷懒。因为第三方库的编译参数、宏定义、依赖的头文件路径都可能和旧版 BSP 不一致。你用旧库硬链到新工程里轻则警告一堆重则直接出现神秘的运行时崩溃。如果你用的第三方库有源码建议把源码加入工程一起编译。如果只有预编译的 .a 文件至少确认这个库是否独立于平台。例如纯数学库、纯 C 标准库实现问题不大。凡是和硬件外设、中断、DMA、缓存相关的库必须重新编译。链接时报undefined reference时可以用这个顺序排查库名称是否正确有没有少了lib前缀。库搜索路径是否指向了正确目录。库的依赖顺序是否正确静态库依赖的顺序是从左到右。所有依赖的交叉编译架构是否一致比如 arm64 的库不能用在 arm32 工程里。5.3 设备树和启动镜像问题如果你做的是 Linux 工程设备树是迁移里绕不开的一环。SDK 时代的设备树可能需要手动维护Vitis 里可以通过 XSA 自动生成基础设备树但自动生成的未必完全满足你的应用需求。常见的设备树问题包括某个外设节点不存在导致驱动无法 probe。中断号传递错误和 BSP 里的编号不一致。引脚配置pinmux不匹配外设初始化失败。内存节点和实际 DDR 大小不一致。我的建议是优先让 Vitis 生成一份新的设备树然后拿旧设备树做对照把你自定义修改的节点例如设备名称、reg 属性、自定义 API 节点逐个移植过去。不要直接拿旧的整套 dts 给新内核用否则大概率会挂。5.4 源码版本管理这个虽然不是编译错误但我必须单独提一下。迁移历史工程时最容易发生的问题就是“改到一半发现回不去了”。开始迁移之前先用 Git 给旧的 SDK 工程打一个 tag或者至少备份一份完整目录。迁移过程中的每一步创建平台工程、生成 BSP、导入源码、修改链接脚本都应该有对应的提交记录。Vitis 工作区里的.metadata、.analytics这类目录不需要提交但.project、.cproject、platform.hdf这些工程描述文件建议保留。我见过太多团队迁移到一半代码改得乱七八糟想回退又发现旧工程文件被覆盖了只能靠记忆恢复。这种痛经历过一次就再也不想经历第二次。6. 几点移植心得6.1 先跑通最小系统再搬业务逻辑无论你多着急都别一上来就把所有源代码一次性导入 Vitis。我的习惯是分三步走第一步创建一个空应用工程用 Vivado 导出的 XSA 生成平台和 BSP跑一个 Hello World确认工具链和硬件链路都是通的。第二步导入板级初始化和外设驱动相关代码比如 UART、GPIO、DMA 的初始化编译并验证基础外设能正常工作。第三步再把核心业务逻辑、算法、网络协议栈等移植进来逐步编译、运行、测试。这样做的好处是任何一个环节出了问题你都能快速判断是工具链的问题、BSP 的问题还是业务代码的问题而不是几百个编译错误混在一起无从下手。6.2 保留一份 SDK 工程做对照移植期间不建议急着删除旧的 SDK 工程。新旧两个环境同时保留出了诡异问题的时候把两边生成的xparameters.h、lscript.ld、platform.c做一次 diff往往能很快定位差异。例如有次我遇到一个问题新工程里定时器中断始终不触发对比了两边的xparameters.h发现是 Vitis 新 BSP 里定时器设备 ID 改变了。这种差异光靠肉眼阅读是看不出来的但 diff 一下立刻清楚。等新工程稳定运行一两周确认所有功能都验证过之后再把旧 SDK 工程归档压缩。不要删放在存档目录里万一哪天客户要求回退或者要查历史问题它还有价值。6.3 把脚本化和版本化做在前面最后一条心得算是给长期维护提个醒。Vitis 工程本身比较庞大GUI 操作虽然直观但很难做到完全可重复。建议把关键流程脚本化比如用 Tcl 脚本重建平台工程以后换电脑或者 CI 构建时可以直接跑脚本。用 Makefile 封装应用工程的编译命令避免每次都打开 IDE。把 XSA、BSP 配置、设备树源文件、链接脚本、BIF 文件都纳入版本库。我这次迁移之后就把平台创建和应用编译写成了脚本后续同事接手时不用再打开 Vitis 一步步点菜单省了不少沟通成本。说到底从赛灵思 SDK 迁移到 Vitis本质上是一次工具链和开发范式的升级。平台工程的概念让硬件和软件之间的边界更清晰也让工程复用和团队协作更顺畅。虽然中间有不少细节要处理但只要按照“评估现状、重建平台、移植代码、逐个验证”的节奏走绝大多数坑都是可以提前避开的。最后分享一个小技巧在 Vitis 里迁移老工程时如果遇到某个诡异问题排查很久不妨先把 workspace 换到一个全新的空目录试试。Vitis 对 workspace 的缓存状态非常敏感旧 workspace 里残留的元数据经常会导致一些看起来毫无逻辑的构建错误。新 workspace 配合重新导入的 XSA往往能让问题药到病除。这个办法我用了很多次每次都管用。
返回列表