1. 项目概述:在KV260上实现裸金属4K流媒体

如果你手头有一块Xilinx Kria KV260视觉AI入门套件,并且一直在琢磨如何榨干它的性能,实现超低延迟、高稳定性的4K视频流处理,那么你很可能已经对基于Linux的解决方案感到厌倦了。系统调度、内存管理、中断延迟……这些在通用操作系统里无法避免的开销,在追求极致性能的实时流媒体场景下,就成了难以逾越的障碍。这正是“裸金属”(Bare-metal)编程的用武之地。所谓裸金属,就是让我们的应用程序直接运行在硬件之上,没有操作系统的中间层,从而实现对处理器、FPGA可编程逻辑(PL)和外设的绝对控制。

这个项目,就是一份针对2025.2版本Vitis/Vitis AI工具链的实战指南,目标是在KV260上,从零开始构建一个纯粹的裸金属4K视频流处理与传输系统。我们不会使用Petalinux,也不会启动Linux内核,而是直接操作ARM Cortex-A53处理器和FPGA逻辑,完成从MIPI摄像头采集、通过PL进行图像处理(如缩放、色彩空间转换),最终通过千兆以太网以极低延迟流式输出的完整链路。这对于工业视觉检测、高端监控、专业直播推流等场景具有极高的价值。整个系列的第一部分,我们将聚焦于最基础也最关键的环节:搭建2025.2版本的裸金属开发环境,并构建一个能够运行在KV260上的“Hello World”级硬件-软件协同工程。

2. 核心思路与平台选型解析

2.1 为什么选择KV260进行裸金属4K开发?

KV260并不是一块传统的FPGA开发板,它是Xilinx推出的面向视觉AI的“自适应系统模块”(SOM)套件。其核心优势在于高度集成和明确的定位。板载的Zynq UltraScale+ MPSoC器件(XCZU3EG)集成了四核ARM Cortex-A53处理器(处理系统,PS)和一片规模可观的FPGA(可编程逻辑,PL),并且出厂就配备了MIPI CSI-2摄像头接口和千兆以太网PHY。这意味着,要实现4K流媒体,我们所需的主要物理接口都已就绪,无需额外的转换板或适配器。

选择裸金属而非Linux,主要基于以下几点考量:

  1. 确定性延迟 :在Linux中,视频采集、处理、网络发送等任务由内核调度,其执行时机受系统负载影响,会产生不可预测的抖动。裸金属应用由开发者完全掌控时序,可以实现从传感器到网络包的微秒级确定性流水线。
  2. 资源独占与高效利用 :没有操作系统内核、驱动、服务进程的内存和CPU占用,所有资源都可服务于我们的流媒体应用。这对于处理4K@60fps(约12 Gbps的原始数据)的数据洪流至关重要。
  3. 简化与固化 :对于最终产品,移除复杂的操作系统也意味着减少了安全漏洞、不必要的维护和启动时间。系统上电即运行特定功能,非常可靠。

2.2 2025.2工具链的新特性与挑战

Xilinx Vitis/Vitis AI 2025.2版本带来了一些对裸金属开发至关重要的更新。首先是 Vitis HLS(高层次综合)的增强 ,对视频处理库( xfOpenCV )和AXI流( hls::stream )的支持更加成熟,使得在PL部分实现复杂的4K视频流水线(如去马赛克、伽马校正、2D噪声滤波)变得更加高效和直观。其次, Vitis裸金属库(BSP) 得到了更新,对Zynq UltraScale+ MPSoC的外设驱动(如GEM千兆以太网控制器、SD/eMMC控制器)支持更完善,特别是对DMA(直接内存访问)控制器的底层操作进行了优化,这对于实现高带宽、零拷贝的数据搬运是核心。

然而,挑战也随之而来。2025.2版本的环境配置与早期版本(如2021.1或2022.1)有显著差异。Vivado、Vitis、PetaLinux的集成方式发生了变化,裸金属工程模板的创建流程也更为“Vitis-centric”。最大的一个变化是,传统的通过 xsct (Xilinx Software Command-Line Tool)手动创建FSBL(First Stage Boot Loader)和裸金属应用的方式,在Vitis IDE中有了更图形化但步骤更复杂的替代方案。本指南将采用一种结合Vitis IDE图形界面和脚本的混合方法,以确保流程清晰且可复现。

3. 开发环境搭建与工程创建

3.1 软件工具链安装与配置

首先,你需要一台性能足够的Linux开发主机(推荐Ubuntu 20.04 LTS或22.04 LTS)。从Xilinx官网下载 Vitis 2025.2 Unified Installer 。这个安装包非常大(超过100GB),因为它包含了Vivado、Vitis HLS、Vitis AI、文档和所有器件支持文件。在安装时,务必勾选以下组件:

  • Vivado Design Suite :用于硬件逻辑设计和生成比特流。
  • Vitis :用于嵌入式软件(包括裸金属)开发。
  • Vitis HLS :用于将C/C++算法综合成RTL。
  • Kria KV260 相关的器件支持文件。

安装完成后,需要设置环境变量。通常安装脚本会在 ~/.Xilinx 目录下生成初始化脚本。最可靠的方法是使用Xilinx提供的 settings64.sh (或 .csh )脚本。

# 假设安装目录为 /tools/Xilinx
source /tools/Xilinx/Vitis/2025.2/settings64.sh
source /tools/Xilinx/Vivado/2025.2/settings64.sh

注意 :2025.2版本对License的要求更为严格。确保你拥有有效的Vivado License,并且支持 Zynq UltraScale+ 器件。如果使用Web版License,请确保网络通畅。

3.2 创建硬件平台项目(Vivado)

裸金属应用需要一个定义好的硬件平台,这包括PS的配置(时钟、DDR内存、外设)和PL的接口(如用于视频流的AXI-Stream)。我们首先在Vivado中创建一个项目。

  1. 启动Vivado 2025.2 ,选择“Create Project”。
  2. 项目类型选择“RTL Project”,并勾选“Do not specify sources at this time”。
  3. 在“Default Part”页面,在搜索框中输入 xck26 ,选择 xck26-sfvc784-2LV-c 。这就是KV260上MPSoC的具体型号。
  4. 进入Vivado主界面后,点击左侧Flow Navigator中的“Create Block Design”。在Diagram窗口中,点击“+”按钮,添加Zynq UltraScale+ MPSoC IP核。
  5. 运行“Block Automation”和“Connection Automation”,让Vivado自动完成基本的时钟、复位和互联配置。
  6. 双击Zynq IP核,进行关键配置:
    • PS-PL Configuration > PS-PL Interfaces > Master Interface :确保 M_AXI_HPM0_FPD 和 M_AXI_HPM1_FPD 使能,用于PS控制PL。
    • PS-PL Configuration > PS-PL Interfaces > Slave Interface :使能 S_AXI_HPC0_FPD 和 S_AXI_HPC1_FPD ,用于PL通过高性能端口访问DDR。
    • I/O Configuration :根据KV260原理图,使能所需外设。对于基础测试,我们需要:
      • UART 0 用于串口调试输出。
      • SD 0 用于从SD卡启动。
      • GEM 3 用于千兆以太网(KV260的ETH接口连接在GEM3上)。
      • I2C 0 和 I2C 1 可能用于未来连接摄像头传感器。
    • Clock Configuration :确保为以太网(GEM3)提供正确的时钟(通常为125 MHz)。
  7. 在Block Design中,你可能还需要添加一个 AXI Direct Memory Access (AXI DMA) IP核。这个IP将是未来实现PS和PL之间高速视频数据传输的桥梁。将其配置为“Scatter Gather”模式,数据宽度设为 128-bit 以匹配高性能端口带宽。将它的 S_AXI_LITE 接口连接到Zynq的 M_AXI_HPM0_FPD (用于PS控制),将它的 M_AXI_MM2S 和 S_AXI_S2MM 连接到Zynq的 S_AXI_HPC0_FPD (用于数据搬运)。其流接口( M_AXIS_MM2S 和 S_AXIS_S2MM )暂时悬空,留给后续的视频处理IP。
  8. 保存Block Design,在Source窗口中右键点击该设计文件( .bd ),选择“Generate Output Products”和“Create HDL Wrapper”。
  9. 在左侧Flow Navigator中,点击“Generate Bitstream”。这个过程会综合、实现并生成最终的比特流文件( .bit )和硬件描述文件( .xsa )。首次运行可能耗时较长。

3.3 在Vitis中创建裸金属应用项目

硬件平台( .xsa 文件)准备好后,我们转向Vitis进行软件开发。

  1. 启动Vitis 2025.2 ,并指定一个工作空间(Workspace)。
  2. 选择 File > New > Application Project 。
  3. 在“Platform”页面,点击“Create a new platform from hardware (XSA)”,选择刚才Vivado导出的 .xsa 文件。Vitis会基于此创建一个软件平台,其中包含了所有外设的驱动和底层库。
  4. 输入应用项目名称,例如 kv260_baremetal_hello 。
  5. 在“Templates”页面,选择“Empty Application”。 不要 选择“Hello World”,因为那个模板可能包含不必要的依赖。我们从最干净的状态开始。
  6. 项目创建完成后,在Explorer视图中,右键点击你的应用项目下的 src 文件夹,选择 New > File ,创建一个名为 helloworld.c 的文件。

现在,你将拥有一个最基本的Vitis工程结构,包含一个硬件平台项目( platform_0 )和一个空的裸金属应用项目。

4. 编写首个裸金属应用:串口打印

4.1 理解裸金属的启动流程与内存映射

在编写代码前,必须理解Zynq UltraScale+的启动过程。对于裸金属应用:

  1. BootROM :芯片上电后,固化在ROM中的代码会根据启动模式(如SD卡)加载FSBL。
  2. FSBL (First Stage Boot Loader) :这是我们工程的一部分。它初始化关键的PS部件(如时钟、DDR内存控制器),然后将PL的比特流(如果有)配置到FPGA中,最后加载并跳转到我们的应用程序( .elf 文件)。
  3. 应用程序 :我们的 helloworld.c 中的 main() 函数就在这里开始执行。

在Vitis 2025.2中,FSBL是作为“Board Support Package (BSP)”的一部分自动生成的,我们通常不需要手动修改它。我们的应用需要知道硬件平台的内存布局,例如DDR的起始地址。这些信息在 platform_0 生成的 platform.h 或链接脚本( lscript.ld )中定义。

4.2 实现串口输出功能

裸金属下没有 printf ,我们需要直接操作UART外设。幸运的是,Vitis BSP提供了驱动库。首先,我们需要在应用项目中设置正确的BSP属性。右键点击应用项目的BSP(例如 kv260_baremetal_hello_bsp ),选择“Board Support Package Settings”。

  • 在“Overview”中,确保“stdout”和“stdin”被设置为 psu_uart_0 或 psu_uart_1 (根据你在Vivado中的配置,KV260通常使用UART0连接到底板上的USB-UART桥接器)。
  • 在“drivers”中,确保 psu_uart 驱动被包含。

现在,编写 helloworld.c :

#include <stdio.h> // 注意:这个stdio是BSP提供的简化版,最终会映射到UART驱动
#include “platform.h”
#include “xil_printf.h” // Vitis提供的轻量级打印函数,比printf开销小

int main()
{
    // 1. 初始化硬件平台
    init_platform();

    // 2. 使用xil_printf打印信息
    xil_printf(“\r\n—————————————\r\n”);
    xil_printf(“Bare-metal 4K Streaming on KV260\r\n”);
    xil_printf(“Boot Successful from SD Card.\r\n”);
    xil_printf(“System Clock: %d MHz\r\n”, XPAR_PSU_CRL_APB_CPU_1X_AXI_CLK_FREQ_HZ / 1000000);
    xil_printf(“DDR Memory Start: 0x%08x\r\n”, XPAR_PSU_DDR_0_S_AXI_BASEADDR);
    xil_printf(“—————————————\r\n\r\n”);

    // 3. 主循环(对于这个Hello World,我们可以什么都不做,或者闪烁一个LED)
    // 注意:KV260用户LED在PS端通过GPIO控制,需要先查找并初始化GPIO驱动。
    // 此处省略LED闪烁代码,专注于串口通信。

    while (1) {
        // 空循环,或在此处添加心跳指示
    }

    // 4. 清理(对于裸金属,通常不会返回)
    cleanup_platform();
    return 0;
}

init_platform() 和 cleanup_platform() 是BSP提供的函数,用于初始化和清理底层硬件,包括UART。 xil_printf 是定向到你所选UART设备的打印函数。

4.3 编译、链接与生成启动文件

代码写好后,在Vitis中直接点击“Build Project”(锤子图标)。Vitis会完成以下工作:

  1. 编译应用代码,生成对象文件( .o )。
  2. 使用链接脚本(由BSP根据硬件平台自动生成或修改)将对象文件、BSP库链接成可执行文件( .elf )。
  3. 自动调用 bootgen 工具,将FSBL的 .elf 、硬件比特流( .bit )和应用的 .elf 打包成一个可启动的 BOOT.BIN 文件。

这个过程在2025.2中基本是自动化的。编译成功后,你可以在应用项目的 Debug 或 Release 目录下找到 BOOT.BIN 文件。

5. 系统部署与上电测试

5.1 准备SD卡并部署镜像

  1. 准备一张microSD卡(建议16GB或以上),使用 fdisk 或图形化工具将其格式化为FAT32文件系统。
  2. 将Vitis生成的 BOOT.BIN 文件复制到SD卡的根目录。
  3. 关键一步 :你还需要一个 boot.scr 或 uEnv.txt 文件吗?对于纯裸金属启动, 不需要 。 BOOT.BIN 包含了所有必要的代码。Linux启动才需要那些文件。确保SD卡上只有 BOOT.BIN ,避免混淆。
  4. 安全弹出SD卡,将其插入KV260底板的SD卡槽。

5.2 硬件连接与上电

  1. 串口调试 :使用USB Type-C数据线连接KV260底板的 J10 (USB-UART)接口到你的开发主机。在主机上使用串口终端工具(如 minicom , screen , 或Putty)。
    • 端口:通常是 /dev/ttyUSB0 或 /dev/ttyUSB1 。
    • 波特率: 115200 。
    • 数据位:8。
    • 停止位:1。
    • 无奇偶校验,无流控。
  2. 以太网连接 :用网线连接KV260的千兆以太网口到你的路由器或开发主机直连。未来测试网络流媒体时会用到。
  3. 电源 :使用KV260配套的12V DC电源适配器供电。
  4. 启动模式 :确保KV260底板上的启动模式开关 SW1 设置为 SD 模式(具体开关位置请参考KV260用户手册,通常是所有开关拨到 OFF 位置)。

5.3 上电观察与结果验证

给KV260上电,立即观察串口终端。你应该看到类似以下的输出:

—————————————
Bare-metal 4K Streaming on KV260
Boot Successful from SD Card.
System Clock: 1333 MHz
DDR Memory Start: 0x00000000
—————————————

如果你看到了这些信息,那么恭喜你!你已经成功地在KV260上运行了第一个裸金属程序。这证明了:

  • 硬件平台设计正确。
  • FSBL工作正常,能初始化DDR并加载应用。
  • 串口驱动和BSP配置正确。
  • 整个从SD卡启动裸金属应用的流程是通的。

如果没有输出,请按以下步骤排查:

  1. 检查串口连接和终端设置(波特率115200最关键)。
  2. 确认SD卡中的 BOOT.BIN 文件是最新生成的。
  3. 在Vivado中确认UART0是否被正确使能并映射到MIO管脚。
  4. 检查KV260启动模式开关设置。
  5. 在Vitis中检查应用BSP设置,确认stdout指向了正确的UART实例。

6. 常见问题与深度排查指南

6.1 编译与链接阶段问题

  • 错误:未找到 platform.h 或 xil_printf.h

    • 原因 :BSP没有正确生成,或者编译包含路径未设置。
    • 解决 :右键点击应用项目,选择“C/C++ Build Settings”。在“GCC ARM Cross Compiler > Includes”中,确保包含了 “${BSPDIR}/include” 等路径。最根本的方法是确保创建应用时正确选择了从XSA创建的硬件平台。
  • 错误:链接失败,提示内存区域溢出

    • 原因 :应用程序(或数据)太大,超过了链接脚本中定义的内存区域(如DDR的特定范围)。
    • 解决 :检查Vitis生成的 lscript.ld 文件。确保 psu_ddr_0 区域有足够的空间。在Vivado硬件设计中,确认分配给PS的DDR容量和地址是正确的。对于Zynq UltraScale+,通常DDR起始于 0x00000000 ,容量为1GB或2GB。
  • 警告: bootgen 生成 BOOT.BIN 失败

    • 原因 : .bit 文件缺失,或FSBL .elf 文件路径错误。
    • 解决 :在Vitis中,右键点击应用项目,选择“Create Boot Image”。在打开的界面中,检查三个镜像组件是否齐全: fsbl.elf , system.bit , app.elf 。确保 system.bit 来自正确的硬件平台输出。

6.2 运行时问题

  • 无任何串口输出

    • 排查顺序 :
      1. 硬件连接 :换一根USB线,尝试主机上不同的USB口。使用 ls /dev/ttyUSB* 查看设备是否出现。
      2. 启动顺序 :确认上电瞬间串口终端是否已打开并准备接收。有时FSBL的早期信息一闪而过。
      3. 比特流 :确认 BOOT.BIN 中包含了比特流( .bit )。如果没有配置PL,UART的MIO引脚可能未被正确配置为UART功能,导致无输出。一个简单的测试是,在Vivado中生成一个 不包含任何PL逻辑(仅Zynq PS) 的比特流,用它来打包 BOOT.BIN ,排除PL配置的影响。
      4. 代码问题 :在 main() 函数最开始,尝试用最简单的循环操作某个GPIO(如果连接了LED)来指示程序是否运行,以此判断是卡在启动还是卡在应用。
  • 输出乱码

    • 原因 :几乎可以肯定是波特率不匹配。Zynq UltraScale+ PS端的UART默认时钟频率下,115200是标准配置。请 严格检查 终端软件的波特率设置是否为115200。
  • 程序运行一次后挂起或复位

    • 原因 :可能是 main() 函数返回了。在裸金属环境中, main() 返回后没有操作系统接管,行为是未定义的,通常会导致处理器异常或复位。
    • 解决 :确保 main() 函数末尾是一个无限循环( while(1); )。

6.3 高级调试技巧

  • 使用Vitis Debugger :通过JTAG接口(KV260底板上的 J301 接口)连接板卡与开发主机。在Vitis中配置调试连接,可以设置断点、单步执行、查看内存和寄存器。这对于调试复杂的硬件-软件交互问题(如DMA传输失败)至关重要。
  • 查看FSBL调试信息 :在Vitis中编译FSBL时,可以修改其BSP设置,增加调试信息输出级别。这有助于了解在加载你的应用之前,硬件初始化是否成功。
  • 内存布局检查 :熟练使用 arm-none-eabi-objdump 工具(包含在Vitis工具链中)来分析生成的 .elf 文件,查看各段(.text, .data, .bss)的地址和大小,确保它们落在有效的DDR地址范围内。

至此,我们已经完成了在KV260上搭建2025.2裸金属开发环境,并成功运行了第一个测试程序。这为后续真正的4K流媒体开发奠定了坚实的基础。在接下来的部分中,我们将深入探讨如何配置MIPI CSI-2接口接收摄像头数据,在PL中构建视频处理流水线,以及如何通过千兆以太网实现高效的裸金属网络流输出。每一个环节都将面临独特的挑战,但遵循这种从基础到复杂、从硬件到软件的拆解方法,我们能够一步步构建起一个高性能、确定性的4K流媒体系统。

Logo

火山引擎视频云技术社区,是面向 AI 音视频开发者的技术交流平台。这里汇聚源自抖音、豆包等亿级 DAU 产品的 RTC、直播、点播、AI 媒体处理、音视频互动技术,提供接入指南、最佳实践、性能调优、场景案例、Demo 代码、开源项目、白皮书和 API 文档。社区汇聚官方工程师与一线开发者,为 AI 视频通话、数字人、AI 视频处理等应用的开发与落地提供技术支持。

更多推荐