采用 Vitis 技术的 Ultra96 (v1):DPU 集成与 MIPI 平台教程

作者:Parker Holloway,来源:赛灵思中文社区论坛

Parker Holloway 在赛灵思工作仅有一年多的时间,他专注于边缘平台和加速设计工作。他对这些主题的关注来自于对 FPGA 和 ACAP 器件上以软件为中心的算法设计方法的兴趣,尤其是在计算机视觉和机器人领域。Parker 毕业于南卫理公会大学,居住在得克萨斯州达拉斯 。

导读

Ultra 96™ 是构建边缘用例机器学习应用的绝佳平台。Zynq® MPSoC ZU3 器件采用的 96 电路板的外形尺寸以及可编程逻辑,使其能够灵活地添加用于此类终端应用视频输入的通用 MIPI CSI2 RX 标准接口。同时为了驱动高性能、低功耗机器学习边缘应用,也可以将赛灵思深度学习处理单元 ( DPU ) 集成到设计中。由于众多首次采用赛灵思 Vitis™ 统一软件平台的用户将从现有的Vivado 设计入手,因此我们会从如何将 Vivado IPI 中实现的传统设计转换为可加速的 Vitis 目标平台来开始我们的教程。

本设计中的 MIPI 流水线利用 Ultra96 常见的 96Boards 外形尺寸,在 MIPI 成像夹层卡上使用 OV5640 成像传感器,并使用 YUYV 输出类型从 MIPI RX IP 直接输入帧缓冲写入 DMA 内核,然后输入到 PS DDR。接下来,我们将演示更新 PetaLinux 项目的步骤,以包含必要的库和驱动程序,从而创建能够支持硬件加速工作流的 Vitis 软件平台,其中包括基于 DPU 的机器学习应用。一旦完成软硬件平台组件,我们将使用 Vitis 开发套件将它们组合成 Vitis 加速平台,然后我们就可以借助该平台构建硬件加速的软件应用。最后,我们将介绍赛灵思DPU 在机器学习加速应用中的集成。在添加 DPU 之后,我们可以使用所提供的 DPU 运行时来评估高性能人脸检测应用,该应用使用来自生成平台的流式 MIPI 输入。

设计要求

本节列出了使用赛灵思深度学习处理单元 ( DPU ) IP 加速机器学习算法所需的软硬件工具。

  • 赛灵思设计工具 2019.2
  • Ultra96 v1 板文件
  • Ultra96 电路板 (v1)
  • Ultra96 12V 电源
  • MicroUSB 转 USB-A 线缆
  • AES-ACC-USB-JTAG 电路板
  • 一张使用 FAT32 文件系统格式化的空白 microSD 卡
  • 赛灵思 CSI2 RX MIPI IP 许可证
  • D3 Engineering Designcore 摄像头夹层电路板 OV5640(MIPI 输入源)
  • 可选项

  • DisplayPort 监控器
  • 适用于所选监控器的微型显示端口线缆
  • USB 网络摄像头
  • 准备工作空间

    将该数据库复制到您的本地计算机上,并下载参考文件目录。在下载完参考文件之后,将它们解压缩到刚才复制的数据库的参考文件目录中。该层级中的其余文件夹将在下载完成后变成空白,并将在整个教程中进行补充。

    生成 MIPI 基础项目

    首先,我们将在 Vivado® 和 Petalinux 工具中创建原始的非加速 MIPI 项目。在完成这一步骤之后,您将得到可启动软硬件镜像,用来启动流水线,从而查看来自 Ultra96 的输入 MIPI 视频。

    Vivado

    1. 将“脚本”文件夹从[reference_files/base_project/vivado]目录复制到顶层 vivado 目录
    2. 启动 Vivado,并在顶层“vivado”目录中创建一个名为“u96v1_mipi”的新项目,确保选择“创建项目子目录”选项,然后单击“下一步”
    3. 选择创建“RTL 项目”,然后单击“下一步”
    4. 选择“添加文件”,从[reference_files/base_project/vivado/sources]目录中选择“U96v1_mipi_wrapper.v”文件,单击“下一步”
    5. 选择“添加文件”,从[reference_files/base_project/vivado/sources]目录中选择“cnst.xdc”文件,然后单击“下一步”
    6. 选择“电路板”选项卡并选择项目的 Ultra96 V1 电路板,然后选择“下一步”和“完成”创建项目
    7. 在屏幕底部的“TCL 控制台”选项卡中,将目录更改为顶层“vivado”目录
    8. 使用 TCL 控制台调用资源./scripts/u96v1_mipi_static.tcl
    9. 在“流导航器”窗口中选择“生成Block设计”并允许完成此操作
    10. 将项目构建为比特流
    11. 选择“文件 > 导出 > 导出硬件”并将硬件导出到 hw_platform 顶层目录,包括比特流

    PetaLinux

    1. 获取 Petalinux 工具
    2. 将目录更改为顶层目录,并使用以下命令创建一个新的 petalinux 项目: petalinux-create –t project –n petalinux –sreference_files/base_project/bsps/u96v1_mipi_static.bsp
    3. 将目录更改为新目录
    4. 运行 petalinux-config --get-hw-description ../hw_platform --silentconfig 导入生成的硬件
    5. 阅读petalinux-config -c rootfs and petalinux-config -c kernel 菜单,查看为了在 Ultra96 上包含 MIPI 进行了哪些定制
    6. 运行 petalinux-build to build the system
    7. 运行 petalinux-package --boot --force --fsbl --pmufw --u-boot --fpga 创建 BOOT.bin
    8. 将 BOOT.bin 和 image.ub 从[petalinux/images/linux]目录复制到 SD 卡,并使用它来启动系统
    9. [在此处输入 GStreamer 命令测试视频输入]

    创建 Vitis 硬件平台

    现在,我们将对硬件设计进行必要的添加和修改,以便为软件定义加速设计做好准备:打开 Vivado 基础项目开始。

    配置 MPSoC Block

    当我们在硬件设计中添加其他组件以满足加速要求时,需要对处理子系统进行定制。在这里,我们将修改配置以创建附加时钟、打开额外的中断端口,并创建 AXI 主端口,以便在设计中添加其他外设。

    1. 双击 Zynq IP Block,打开处理器配置向导 (PCW)
    2. 转到“时钟配置”选项卡,选择“输出时钟”选项卡,展开低功耗域时钟 > PL 架构时钟
    3. 启用 PL1,并将两个时钟的请求频率更改为 100MHz,选择 IOPLL 作为源时钟
    4. 进入“PS-PL 配置”选项卡,展开通用 > 架构重置,然后启用第二次架构重置
    5. 添加另一个 AXI 主端口,稍后我们将使用它来连接中断控制器 - 单击 PS-PL 接口 > 主接口,并启用 AXI HPM0 LPD
    6. 展开通用 > 中断 > PS-PL
    7. 启用 IRQ1[0-7]
    8. 单击“确定”离开 PCW

    配置平台接口

    为了让 Vitis 工具将硬件加速Block插入到设计中,我们需要保持打开状态,并为它指定可以用来连接Block的接口。在本设计中,我们需要一些存储器映射接口,以便 DPU 可以连接到 PS DDR。在这个平台上我们将打开三个 HP 从端口,因为在 DPU Block上有三个存储器映射的主端口。此外,这部分流程还支持我们“命名”端口,给它起一个更短的昵称,以便以后指定连接。

    1. 在“窗口”菜单中,选择“平台接口”
    2. 在“平台接口”选项卡中,单击“启用平台接口”
    3. 右键单击接口并选择“启用”(HP 0、1、2),添加三个尚未使用的 PS HPx_FPD 从设备
    4. 同时,启用 HPM0 主设备接口 - 确保在 Zynq PS Block上禁用此接口。工具将使用这一主设备连接到加速器
    5. 对于每个已启用的从设备接口,在“选项”选项卡中添加一个“sptag”值,该值将在稍后的流中引用该端口:分别为 HP0、HP1 和 HP2

    指定“平台”时钟

    类似于为平台指定接口的方式,现在我们必须向工具指示它应该为平台中的加速器使用哪些时钟。在这种情况下,DPU 使用两个时钟(1x 和 2x 时钟)。因此,我们将向平台指示 250MHz 和 500MHz 时钟。DPU 时钟频率可以快于或慢于该速率,选择该速率是为了平衡应用中的功耗和帧速率性能。

    1. 右键单击Block设计,选择“添加 IP”,然后添加时钟向导 IP
    2. 将实例名称更改为 clk_wiz_dynamic
    3. 双击 clk_wiz_dynamic IP,并在“输出时钟”选项卡中进行以下更改:[clk_out1=250MHz],[clk_out2=500MHz],[两者路由匹配],[重置类型 = 低电平有效]
    4. 将原始时钟向导 (clk_wiz_static) 从 pl clk0 移动到 pl clk1
    5. 在“平台接口”选项卡中,启用 clk_wiz_dynamic 实例的 clk_out1 和 clk_out2
    6. 将较慢的时钟(本例中为 clk_out1)设置为默认值
    7. clk_out1 的 id 应设置为 0、clk_out2 的 id 应设置为 1
    8. 确保将每个窗口中列出的 proc_sys_reset Block均设置为连接到该时钟的实例

    分离原始组件

    在本设计中,我们选择将原始组件(MIPI 子系统)放置在来自 PS 的独立时钟上。将加速器的时钟向导和处理器系统重置连接到 PL0 时钟,MIPI 子系统连接到 PL1 时钟。这有助于我们确保原始组件或加速组件时钟频率(或时钟门控)的任何更改都不会影响其他组件的运行。

    1. 右键单击 pl_clk0 并在菜单中选择“断开引脚连接”
    2. 将 pl_clk0 连接到 clk_wiz_dynamic clk_in1,并将 pl_clk1 连接到 clk_wiz_static 的 clk_in1
    3. 删除连接到 pl_reset0 的网络
    4. 右键单击Block设计,选择“添加 IP”,并为每个新时钟添加处理器系统重置 IP。
    5. 将它们命名为 proc_sys_reset_dynamic_1 和 proc_sys_reset_dynamic_2
    6. 将 clk_wizard_dynamic Block的 clk_out1 和 clk_out2 输出分别连接到 proc_sys_reset_dynamic_1 和 proc_sys_reset_dynamic_2 slowest_sync_clk 输入
    7. 将 PS pl_reset0 连接到两个新处理器系统重置Block的 ext_reset_in 输入
    8. 将 pl_reset0 连接到 clk_wiz_dynamic 的重置端口
    9. 将 pl_reset1 连接到 clk_wiz_static 的重置端口和 proc_sys_reset_200 的 ext_reset_in 引脚
    10. 将 clk_wiz_dynamic 锁定输出连接到两个新处理器系统重置Block的 dcm_locked 输入

    启用基于中断的内核

    加速内核的默认调度模式为轮询模式。为了在平台中启用基于中断的处理,我们需要添加中断控制器。在当前设计中,我们需要将常量 “gnd”连接到中断控制器,此时不连接任何有效的中断源。与 AXI 中断控制器配对的是 Vivado 源代码中的“dynamic_postlink”tcl 脚本,它将选择中断常数网络,将其与连接Block断开,然后通过 Vitis 工具添加加速内核后自动连接。

    1. 右键单击Block设计,选择“添加 IP”,添加 AXI 中断控制器
    2. 在中断控制器的Block属性中,将名称设置为 axi_intc_dynamic
    3. 添加“连接”IP,将输入连接到中断控制器中
    4. 在“连接”Block的Block属性中,将名称设置为 int_concat_dynamic
    5. 双击“连接”Block,将端口数修改为 8
    6. 添加“常量”IP,为中断控制器提供一个常量“0”- 这个常量会在编译时由工具断开连接并被加速中断连接所取代
    7. 双击“常量”IP,并将常量值修改为 0
    8. 单击设计辅助栏中的“运行连接自动化”链接,连接 AXI 中断控制器的从 AXI 接口 - 选择 HPM0_LPD,因为 HPM1_FPD 用于视频子系统。
    9. 将中断控制器的所有输入连接到“连接”Block输出
    10. 将“连接”Block的输出连接到中断控制器的 intr 输入
    11. 将中断控制器的输出连接到 PS Block上的 pl_ps_irq1
    12. 选择常量Block的输出网络,并将其命名为 int_const_net

    生成设计和 XSA

    目前,我们已经对该设计进行了定制,可以通过赛灵思支持存档 (XSA) 将其导出到 Vitis 工具中。请注意:我们不会将这个项目构建为比特流。Vitis 工具将利用这一存档来导入设计,在硬件加速器中进行合成,然后,它将构建比特流。使用 dsa.tcl 脚本自动化这部分流程 - 在将赛灵思支持存档 (XSA) 文件导出到 hw_platform 目录之前,会自动化命名和平台详细信息。此外,该脚本还链接了前面提到的 dynamic_postlink.tcl 脚本,以便将特定于该平台的脚本包含在存档文件中。

    生成Block设计
    1. 通过运行 source ./scripts/dsa.tcl 导出硬件平台
    2. 创建软件平台

    软件平台要求对 Petalinux 项目进行一些更改,需要将必要的赛灵思运行时 (XRT)组件添加到设计中。此时,提供两个选项:按照以下所有步骤复制必要的文件并在 Petalinux 中启用这些组件,或者跳过 1-8,用[reference_files/platform_project/bsps/u96v1_mipi_dynamic.bsp] 处的 u96v1_mipi_dynamic.bsp 中的新项目替换 Petalinux 项目。

    添加赛灵思运行时程序

    创建加速平台的第一步是添加上面提到的库组件:赛灵思运行时和 DPU 运行时 (dnndk)。它们以程序的形式出现,我们将把它们添加到 Petalinux 构建中的用户层中。首先,复制文件并构建程序,然后通过 Petalinux 根文件系统配置菜单启用它们。

    1. 将目录更改为 Petalinux 目录
    2. 添加程序,从而将 DPU 实用工具、库和头文件添加到根文件系统中
    cp -rp ../reference_files/platform_project/plnx/recipes-apps/dnndk project-spec/meta-user/recipes-apps

    3. 添加程序以添加赛灵思运行时 (XRT) 驱动程序
    cp -rp ../reference_files/platform_project/plnx/recipes-xrt project-spec/meta-user

    4. 添加程序创建插件,用于添加在 Linux 启动期间自动运行的“自动启动”脚本
    cp -rp ../reference_files/platform_project/plnx/recipes-apps/autostart project-spec/meta-user/recipes-apps

    5. 将上面的程序添加到 Petalinux 映像配置
    vi

    project-spec/meta-user/recipes-core/images/petalinux-image-full.bbap

    pend

    并将其添加到文档的末尾:

    IMAGE_INSTALL_append = " dnndk"
    IMAGE_INSTALL_append = " autostart"
    IMAGE_INSTALL_append = " opencl-headers"
    IMAGE_INSTALL_append = " ocl-icd"
    IMAGE_INSTALL_append = " xrt"
    IMAGE_INSTALL_append = " xrt-dev"
    IMAGE_INSTALL_append = " zocl"

    使用从 Vivado 导出的新 XSA 更新 Petalinux 项目
    petalinux-config --get-hw-description=../hw_platform --silentconfig

    打开 Petalinux 根文件系统配置 GUI 以启用上面的程序
    petalinux-config -c rootfs

    然后在“用户包”子菜单中启用上面的所有程序

    修改 Linux 器件树

    需要修改 Linux 器件树,以便正确探测赛灵思运行时内核驱动程序。修改[project-spec/meta-user/recipes-bsp/device-tree/files/system-user.dtsi],将 Zynq OpenCL 节点添加到器件树。

    在 project-spec/meta-user/recipes-bsp/device-tree/files/system-user.dtsi 的底部,添加以下文本:
    &amba {
    ​ zyxclmm_drm: zyxclmm_drm@0xA0000000 {
    ​ reg = ;
    ​ compatible = "xlnx,zocl";
    ​ status = "okay";
    ​ interrupt-parent = ;
    ​ interrupts = , , , 1>,
    ​ , , , ;
    ​ };
    };\

    构建 Petalinux 并打包软件组件

    目前,我们已经为 Petalinux 构建完成了所有必要的配置更改,可以开始构建。这可能需要相当长的时间,但考虑到计算机的处理能力,也可能需要很短的时间。Linux 构建完成后,我们需要将所有构建的软件组件移动到一个公共目录中。通过将所有启动组件放在一个目录中,在硬件和软件侧打包到结果平台中时,会变得很容易。此外,我们还将使用 Petalinux 构建 sysroot,以便为该软件平台提供完整的交叉编译环境。这个 sysroot 也将包含在平台的软件部分中,因为在为平台编译时,需要它来提供正确版本的头文件/包含文件。

    构建 Petalinux
    petalinux-build\

    1. 将所有 .elf 文件从[petalinux/images/linux]目录复制到[SW_Platform/boot],此操作应复制以下文件:

  • ARM可信固件 - b131.elf
  • PMU 固件 – pmufw.elf
  • U-Boot – u-boot.elf
  • Zynq FSBL – zynqmp_fsbl.elf
  • 2. 将 image.ub 文件从[petalinux/images/linux]目录复制到[SW_Platform/image]
    3. 将 linux.bif 文件从[reference_files/platform_project/plnx]目录复制到[sw_platform/boot]
    4. 从项目 petalinux-build --sdk 构建 Yocto SDK(提供 sysroot)
    5. 将[images/linux/sdk.sh]移动到[SW_Platform/sysroot],然后提取 SDK cd sw_platform/sysroot ./sdk.sh -d ./-y

    生成 Vitis 软件平台

    Vitis 软件平台是一套组件,包括启动和开发特定电路板/电路板配置所需的所有内容,且包含硬件和软件组件。目前,我们已经为平台构建了硬件 (XSA) 和软件(Linux 镜像和启动 elf 文件)组件,我们可以使用这些组件来生成和导出用户定义的定制平台。我们将在赛灵思 Vitis 开发套件中介绍这些步骤。

    1. 打开 Vitis IDE,选择顶层工作空间目录作为工作空间
    2. 选择“文件”、“新建”和“平台项目”
    3. 将平台命名为“u96v1_mipi”
    4. 选择从硬件规格创建,然后在[hw_platform]中选择 XSA
    5. 选择 Linux 操作系统和 psu_cortexa53
    6. 双击文件导航器中的 platform.spr 打开项目
    7. 自定义“linux on psu_cortexa53”域以指向[sw_platform/boot]中的启动组件和 bif
    8. 自定义“linux on psu_cortexa53”域以指向[sw_platform/image]中的镜像目录
    9. 点击“锤子”图标或“生成平台”按钮,从平台项目生成输出产品

    目前,平台已经生成,请注意,这里有一个“导出”目录。这个导出目录是完整的生成平台,可以压缩和共享 - 提供组件,使新的开发者能够在自定义平台上进行操作。

    创建人脸检测应用项目

    对于最终应用,我们可以将 MIPI 平台定位于机器学习应用。使用预先生成的赛灵思深度学习处理器单元 (DPU) 作为加速内核,并使用赛灵思 Vitis IDE 将该内核编译到平台中,然后构建调用该硬件的用户空间应用来运行自定义人脸检测应用。

    创建新的应用项目

    从创建新的应用项目开始。在 Vitis 工具中,应用项目保存在系统项目容器中,以便在平台中跨各个启用域(例如:A53 和 R5)为内聚系统开发提供方法。由于我们在与之前相同的工作空间内开展工作,所以可以轻松地将目标锁定在之前生成的平台上 - 但是您也可以通过单击“+”按钮并指向“平台选择”对话框中包含 xpfm 的目录来添加其他平台数据库。

    1. 打开 Vitis IDE,选择顶层工作空间目录作为工作空间
    2. 选择“文件”、“新建”和“应用项目”
    3. 将项目命名为“face_detection”,并使用自动生成的系统项目名称
    4. 选择刚刚创建的“u96v1_mipi”平台
    5. 确认在下一个界面中选择了 Linux 域,然后指向在 sw_platform 中生成的 sysroot
    6. 选择“空应用”作为模板,然后单击“完成”

    编辑生成设置

    1. 右键单击文件导航器中的[face_detection/src],选择“导入”
    2. 选择“通用”和“文件系统”
    3. 使用[reference_files/application]作为目标位置,并导入所有这些文件
    4. 右键单击文件导航器中的“face_detection”并选择“C/C++ 生成设置”
    5. 如果您不在 C/C++ 生成设置菜单中,请导航到该菜单
    6. 对于配置,选择“所有配置”
    7. 在下面的“GCC 主机链接器、库”子菜单中,单击绿色“+”添加以下库:
    - n2cube
    - dputils
    - opencv_core
    - opencv_imgcodecs
    - opencv_highgui
    - opencv_imgproc
    - opencv_videoio\

    1. 在“主机链接器”、“其他项”、“其他对象”子菜单中,从 workspace./src 位置添加 dpu_densebox.elf
    2. 在主机编译器的“包含”部分,选择 XILINX_VIVADO_HLS 的包含路径,然后单击红色“X”进行删除
    3. 单击“应用”和“关闭”

    添加 DPU 作为硬件加速器

    最后,我们将 DPU 添加进来作为硬件加速内核,并使用 Vitis 进行连接和编译设计。

    1. 双击 face_detection 项目下的 project.sdx 打开项目视图
    2. 在硬件功能下,单击“闪电”标志添加新加速器
    3. 选择我们在之前添加的 dpu.xo 文件中包含的“dpu_xrt_top
    4. 单击 binary_container_1 将名称更改为 dpu
    5. 右键单击“dpu”,选择“编辑 V++”选项
    6. 添加 --config ../src/connections.ini 指定将 DPU 的哪个端口连接到前面所创建的平台接口
    7. 在右上角,将活动构建更改为“系统”
    8. 单击“锤子”图标构建项目

    这可能需要大约 30 分钟或更长时间,具体取决于您用来完成构建的计算机。您可能已经注意到,我们从未将设计的硬件部分用于比特流生成。在运行时,该工具在硬件设计中使用“开放”接口,将 DPU 导入到设计中,然后连接这些接口以匹配“connections.ini”中调用的内容。在完成设计和新组件之后,将运行综合和实现来生成二进制文件并加载到架构中。

    在 Ultra96 上运行应用

    在完成构建流程之后,您将在项目的系统目录下找到补充的 sd_card 文件夹。将 sd_card 镜像复制到格式化的 SD 卡以启动电路板。电路板成功启动后,您可以遵循几个快速步骤来运行设计。

    1. 在电路板上,将目录更改为[/run/media/mmcblktab/]
    2. 将 dpu.xclbin 文件复制到 /usr/lib
    3. 运行 face_detection.elf

    不带参数运行时,face_detection 应用会提供辅助对话框,其中包含通过应用的示例流水线(mipi、网络摄像头、UDP 流)。这些都是在类似 gstreamer 的散热器中提供给应用的,以提供对人脸检测应用的轻松定制。

    示例流水线:

    "./face_detection -i /dev/video0 -o autovideosink" will display over x11 forwarding or on local monitor
    "./face_detection -i /dev/video0 -o udpsink host=192.168.1.50 port=8080" will stream over UDP\

    推荐阅读