【ALINX 实战笔记】FPGA 大神 Adam Taylor 使用 ChipScope 调试 AMD Versal 设计

本篇文章来自 FPGA 大神、Ardiuvo & Hackster.IO 知名博主 Adam Taylor。在这里感谢 Adam Taylor 对 ALINX 产品的关注与使用。为了让文章更易阅读,我们在原文的基础上作了一些灵活的调整。原文链接已贴在文章底部,欢迎大家在评论区友好互动。

在上篇文章中,我们已经通过测试图案生成器,成功验证了 ALINX VD100 的图像显示链路。

这次终于要接入 MIPI 摄像头,进行真正的图像处理了!

在这个过程中,**集成逻辑分析仪(ILA)**将作为我们的调试"透视眼",帮助我们逐步验证每一阶段的运行效果。

本项目规模不小,从图像采集到处理再到输出,每一环都可能出现问题------做好调试准备了吗?

那就让我们开始吧!

项目工具清单

本次开发平台基于 AMD Versal AI Edge 芯片,开发板采用 ALINX 的 VD100。

Versal AI Edge 系列是 AMD 推出的系统级异构芯片(SoC),专为边缘端 AI 应用优化,集成了 Arm Cortex-A72 应用处理器、Cortex-R5F 实时处理器、可编程逻辑(PL)以及 AI 引擎专用加速模块等多种处理单元。这些模块通过片上网络(NoC)实现高效互联,形成强大灵活的计算平台,非常适合本地化部署卷积神经网络(CNN)等 AI 推理任务。

ALINX VD100 开发板配备了 2 个 4 通道的 MIPI 摄像头输入接口,以及一个 LVDS LCD 显示输出,并且支持 Vivado免费版开发环境,对原型验证和早期开发者极其友好。

在进入 AI 阶段前,我们需要打好基础------构建一条稳定的图像处理通路。基本流程如下:

  1. 图像采集(MIPI 摄像头)

  2. 预处理(去马赛克、颜色空间转换、图像增强)

  3. 缓存存储(VDMA + DDR)

  4. 图像显示(LVDS LCD 输出)

一个可靠的图像通路必须满足三个条件:

  1. 摄像头正常采集

  2. 数据通路不丢包

  3. 显示输出无错帧

通过早期验证这些关键环节,可确保 I/O 分配、时钟策略和图像处理流程的正确性,降低在集成上层 AI 逻辑或应用功能时的开发风险。只有基础打牢,后续的开发迭代才能更高效,项目推进也更有把握。

Versal 调试机制

虽然 Versal 器件的应用调试与 7 系列、UltraScale 及 UltraScale+ 系列大体相似(均可使用 ChipScope 工具),但在使用方式上也发生了一些变化:

|-------------------|---------------------------------------|-------------------------------|
| _ | 旧平台(7/US/US+等) | Versal 平台 |
| Debug hub 连接方式 | 通过 JTAG 接口 | 通过 CIPS 中的 AXI4 接口 |
| Debug hub 插入方式 | 自动插入 | 自动/手动 (涉及 DFX 必须手动) |
| Debug Core 接口协议 | 专有接口 | 标准 AXI4-Stream |
| AXI-Stream ILA 特性 | 集成标准ILA+System ILA 支持 BRAM/URAM存储介质选择 | 标准 ILA 与 System ILA 分立 存储介质固定 |

Versal 的调试架构更加现代化,也更加灵活,但也意味着你在设计之初就必须考虑调试资源的布局,尤其是CIPS 模块和 AXI 调试路径 的预留。

调试方法论

FPGA 开发是一个需要多次迭代的过程,只有遵循逻辑推理的方法,才能更高效地解决问题,不至于造成资源浪费。我在调试时遵循以下原则帮助我更快速地排查问题:

  1. 问题拆解:将复杂问题拆解为更小的部分

  2. 控制变量:减少变量与干扰项

  3. 假设验证:做出合理预测,并验证预测结果

  4. 前瞻规划:在设计初期就规划好调试方案与观测点位置

ILA 插桩策略

集成逻辑分析仪(ILA)使用起来非常占用逻辑和 BRAM 资源,且采样深度、监控信号的宽度也会直接影响 BRAM 的使用量------探针越宽、采样窗口越长,占用的内存越多,资源也越快耗尽。

在真实项目中使用 ILA 进行调试时,必须合理选择插桩位置,以平衡调试可视性与 FPGA 资源的使用。我的建议是,在遵循前述调试方法论的条件下:

  1. 优先监控控制信号、复位线、状态/错误标志等关键位置。这些信号通常可以第一时间反映系统行为,帮助我们在调试早期就定位问题。

  2. 逐步拓展至一些关键的 AXI 总线 ,尤其是连接 Versal 的**片上网络(NoC)与处理系统(PS)**的部分,这些接口是可编程逻辑(PL)、NoC 与 PS 之间的数据主通道,能揭示系统集成与数据传输过程中的一些微妙问题。

因此,在调试初期,我们可以从一组合理的控制信号、复位、状态/错误信息以及关键 AXI 接口信号入手,采用中等采样深度

这样既能获得系统层面的良好可视性,又能为后续迭代调试保留资源空间。

Vivado 设计架构

基于 Versal AI Edge 的图像处理流水线,核心架构通过 CIPS 模块实现全局控制;图像帧通过一系列 IP 模块被采集与处理;应用程序、DDR 内存访问以及 CIPS 与可编程逻辑(PL)之间的通信,通过片上网络(NoC)实现高速互联。

系统的整体结构如下图所示:

具体使用的 IP 核取决于应用需求,但核心流水线一般包括:传感器接口、去马赛克(Demosaic)、颜色空间转换、图像增强、视频时序控制模块,以及 AXI Stream 的互联与控制逻辑。

ILA 模块

ILA_LCD_LVDS

→ 监控 LCD / LVDS 接口,观察状态与错误信号。

Video ILA

→ 使用四个通道,监控图像处理流程中的 AXI-Stream 视频信号,包括 MIPI 原始输出、去马赛克后的 RGB 流、24 位像素转换输出与 VDMA 输出流。

Memory ILA

→ 监控通过 NoC 访问 DDR 的 AXI4 总线,确保 DDR 的读写操作正常进行。

Output ILA

→ 监控 AXI-Stream 到视频输出的状态信息,如视频输出同步信号诊断(HSync/VSync 相位对齐监测)

IP 模块

CIPS

→ 配置处理系统(PS)、平台初始化,提供外设访问。

NoC

→ 提供高带宽的数据流通通道,连接多个互联节点,并集成 DDR 控制器用于外部内存访问。

SmartConnect

→ 连接各 IP 模块的 AXI-Lite 寄存器接口,使处理系统可以对其进行控制与配置。

MIPI CSI-2 RX

→ 支持 4 通道,每通道 1000 Mbps 的高速图像采集。

Demosaic(去马赛克)

→ 将图像传感器输出的 Bayer 模式像素数据转换为完整 RGB 图像,重建每个像素的颜色信息。

AXI Subset Converter

→ 将 40 位像素数据(每个 RGB 通道 10 位)转换为 24 位格式(每通道 8 位),每时钟周期保持 4 像素吞吐。

VDMA

→ 桥接 AXI4-Stream 与 AXI4 存储接口,在 NoC 上实现 DDR 帧存的存取,同时为处理阶段提供高效的缓存机制。

AXI4-Stream to Video Out

→ 将 AXI4-Stream 视频流转换为标准视频输出格式,生成 HSync、VSync 等同步信号以驱动显示设备。

VTC

→ 生成 HSync、VSync、有效视频等信号,并与AXI4-Stream to Video Out模块同步,确保显示时序正确。

LCD LVDS 接口

→ 将标准并行视频输出信号转换为串行 VESA LVDS 格式,适配基于 LVDS 的 LCD 显示屏。

Advanced IO Wizard

→ 配置 Versal 设备中的 XPIO,将 LVDS 输出数据串行化,满足 VESA LVDS 显示标准。

通过这些 ILA,我们能够同时观察静态的状态信号与动态的高带宽数据流,全面掌控图像处理系统的运行状态。

完整设计如图所示,可通过本项目所附的 TCL 脚本复现该设计。

在生成比特流时,必须定义 XDC I/O 约束文件,明确所有外部接口的物理引脚位置与电气标准。

关键接口的引脚配置如下:

cpp 复制代码
set_property BITSTREAM.GENERAL.COMPRESS TRUE [current_design]
set_property DIFF_TERM_ADV TERM_100 [get_ports sys_clk_p]
set_property PACKAGE_PIN A23 [get_ports {clkout1_p[0]}]
set_property IOSTANDARD LVDS15 [get_ports {clkout1_p[0]}]
set_property PACKAGE_PIN F22 [get_ports {dataout1_p_0[0]}]
set_property PACKAGE_PIN A20 [get_ports {dataout1_p_1[0]}]
set_property PACKAGE_PIN C22 [get_ports {dataout1_p_2[0]}]
set_property PACKAGE_PIN A25 [get_ports {dataout1_p_3[0]}]
set_property IOSTANDARD LVDS15 [get_ports {dataout1_p_*[0]}]
set_property PACKAGE_PIN E24 [get_ports {lcd_en}]
set_property IOSTANDARD LVCMOS15 [get_ports {lcd_en}]
set_property PACKAGE_PIN D24 [get_ports {lcd_sync}]
set_property IOSTANDARD LVCMOS15 [get_ports {lcd_sync}]
set_property PACKAGE_PIN AC11 [get_ports {DDR4_act_n[0]}]
set_property PACKAGE_PIN AB12 [get_ports {DDR4_adr[0]}]
set_property PACKAGE_PIN AB17 [get_ports {DDR4_adr[10]}]
set_property PACKAGE_PIN AE13 [get_ports {DDR4_adr[11]}]
set_property PACKAGE_PIN AH12 [get_ports {DDR4_adr[12]}]
set_property PACKAGE_PIN AD15 [get_ports {DDR4_adr[13]}]
set_property PACKAGE_PIN AD21 [get_ports {DDR4_adr[14]}]
set_property PACKAGE_PIN AD17 [get_ports {DDR4_adr[15]}]
set_property PACKAGE_PIN AC13 [get_ports {DDR4_adr[16]}]
set_property PACKAGE_PIN AE22 [get_ports {DDR4_adr[1]}]
set_property PACKAGE_PIN AD22 [get_ports {DDR4_adr[2]}]
set_property PACKAGE_PIN AB15 [get_ports {DDR4_adr[3]}]
set_property PACKAGE_PIN AD12 [get_ports {DDR4_adr[4]}]
set_property PACKAGE_PIN AE17 [get_ports {DDR4_adr[5]}]
set_property PACKAGE_PIN AD16 [get_ports {DDR4_adr[6]}]
set_property PACKAGE_PIN AG11 [get_ports {DDR4_adr[7]}]
set_property PACKAGE_PIN AE14 [get_ports {DDR4_adr[8]}]
set_property PACKAGE_PIN AB14 [get_ports {DDR4_adr[9]}]
set_property PACKAGE_PIN AC16 [get_ports {DDR4_ba[0]}]
set_property PACKAGE_PIN AD11 [get_ports {DDR4_ba[1]}]
set_property PACKAGE_PIN AB18 [get_ports {DDR4_bg[0]}]
set_property PACKAGE_PIN AC19 [get_ports {DDR4_ck_t[0]}]
set_property PACKAGE_PIN AD19 [get_ports {DDR4_ck_c[0]}]
set_property PACKAGE_PIN AB21 [get_ports {DDR4_cke[0]}]
set_property PACKAGE_PIN AC17 [get_ports {DDR4_cs_n[0]}]
set_property PACKAGE_PIN AG12 [get_ports {DDR4_dm_n[0]}]
set_property PACKAGE_PIN AH13 [get_ports {DDR4_dm_n[1]}]
set_property PACKAGE_PIN AE28 [get_ports {DDR4_dm_n[2]}]
set_property PACKAGE_PIN AD24 [get_ports {DDR4_dm_n[3]}]
set_property PACKAGE_PIN V22 [get_ports {DDR4_dm_n[4]}]
set_property PACKAGE_PIN V28 [get_ports {DDR4_dm_n[5]}]
set_property PACKAGE_PIN N28 [get_ports {DDR4_dm_n[6]}]
set_property PACKAGE_PIN U25 [get_ports {DDR4_dm_n[7]}]
set_property PACKAGE_PIN AF14 [get_ports {DDR4_dq[0]}]
set_property PACKAGE_PIN AH18 [get_ports {DDR4_dq[10]}]
set_property PACKAGE_PIN AH20 [get_ports {DDR4_dq[11]}]
set_property PACKAGE_PIN AH14 [get_ports {DDR4_dq[12]}]
set_property PACKAGE_PIN AH22 [get_ports {DDR4_dq[13]}]
set_property PACKAGE_PIN AH15 [get_ports {DDR4_dq[14]}]
set_property PACKAGE_PIN AG22 [get_ports {DDR4_dq[15]}]
set_property PACKAGE_PIN AF26 [get_ports {DDR4_dq[16]}]
set_property PACKAGE_PIN AE26 [get_ports {DDR4_dq[17]}]
set_property PACKAGE_PIN AH27 [get_ports {DDR4_dq[18]}]
set_property PACKAGE_PIN AE27 [get_ports {DDR4_dq[19]}]
set_property PACKAGE_PIN AG18 [get_ports {DDR4_dq[1]}]
set_property PACKAGE_PIN AG27 [get_ports {DDR4_dq[20]}]
set_property PACKAGE_PIN AD26 [get_ports {DDR4_dq[21]}]
set_property PACKAGE_PIN AG26 [get_ports {DDR4_dq[22]}]
set_property PACKAGE_PIN AG28 [get_ports {DDR4_dq[23]}]
set_property PACKAGE_PIN AE24 [get_ports {DDR4_dq[24]}]
set_property PACKAGE_PIN AD25 [get_ports {DDR4_dq[25]}]
set_property PACKAGE_PIN AH24 [get_ports {DDR4_dq[26]}]
set_property PACKAGE_PIN AF25 [get_ports {DDR4_dq[27]}]
set_property PACKAGE_PIN AG23 [get_ports {DDR4_dq[28]}]
set_property PACKAGE_PIN AG25 [get_ports {DDR4_dq[29]}]
set_property PACKAGE_PIN AG15 [get_ports {DDR4_dq[2]}]
set_property PACKAGE_PIN AH23 [get_ports {DDR4_dq[30]}]
set_property PACKAGE_PIN AH25 [get_ports {DDR4_dq[31]}]
set_property PACKAGE_PIN Y22 [get_ports {DDR4_dq[32]}]
set_property PACKAGE_PIN V23 [get_ports {DDR4_dq[33]}]
set_property PACKAGE_PIN Y23 [get_ports {DDR4_dq[34]}]
set_property PACKAGE_PIN W24 [get_ports {DDR4_dq[35]}]
set_property PACKAGE_PIN AA22 [get_ports {DDR4_dq[36]}]
set_property PACKAGE_PIN V24 [get_ports {DDR4_dq[37]}]
set_property PACKAGE_PIN AA21 [get_ports {DDR4_dq[38]}]
set_property PACKAGE_PIN W25 [get_ports {DDR4_dq[39]}]
set_property PACKAGE_PIN AF18 [get_ports {DDR4_dq[3]}]
set_property PACKAGE_PIN V25 [get_ports {DDR4_dq[40]}]
set_property PACKAGE_PIN W27 [get_ports {DDR4_dq[41]}]
set_property PACKAGE_PIN AA28 [get_ports {DDR4_dq[42]}]
set_property PACKAGE_PIN W26 [get_ports {DDR4_dq[43]}]
set_property PACKAGE_PIN Y26 [get_ports {DDR4_dq[44]}]
set_property PACKAGE_PIN AA26 [get_ports {DDR4_dq[45]}]
set_property PACKAGE_PIN AB28 [get_ports {DDR4_dq[46]}]
set_property PACKAGE_PIN AB26 [get_ports {DDR4_dq[47]}]
set_property PACKAGE_PIN P27 [get_ports {DDR4_dq[48]}]
set_property PACKAGE_PIN K27 [get_ports {DDR4_dq[49]}]
set_property PACKAGE_PIN AF13 [get_ports {DDR4_dq[4]}]
set_property PACKAGE_PIN R28 [get_ports {DDR4_dq[50]}]
set_property PACKAGE_PIN L28 [get_ports {DDR4_dq[51]}]
set_property PACKAGE_PIN R27 [get_ports {DDR4_dq[52]}]
set_property PACKAGE_PIN K28 [get_ports {DDR4_dq[53]}]
set_property PACKAGE_PIN T28 [get_ports {DDR4_dq[54]}]
set_property PACKAGE_PIN M27 [get_ports {DDR4_dq[55]}]
set_property PACKAGE_PIN P25 [get_ports {DDR4_dq[56]}]
set_property PACKAGE_PIN L26 [get_ports {DDR4_dq[57]}]
set_property PACKAGE_PIN R26 [get_ports {DDR4_dq[58]}]
set_property PACKAGE_PIN M26 [get_ports {DDR4_dq[59]}]
set_property PACKAGE_PIN AF19 [get_ports {DDR4_dq[5]}]
set_property PACKAGE_PIN T25 [get_ports {DDR4_dq[60]}]
set_property PACKAGE_PIN K26 [get_ports {DDR4_dq[61]}]
set_property PACKAGE_PIN T26 [get_ports {DDR4_dq[62]}]
set_property PACKAGE_PIN J25 [get_ports {DDR4_dq[63]}]
set_property PACKAGE_PIN AG13 [get_ports {DDR4_dq[6]}]
set_property PACKAGE_PIN AE19 [get_ports {DDR4_dq[7]}]
set_property PACKAGE_PIN AH17 [get_ports {DDR4_dq[8]}]
set_property PACKAGE_PIN AG21 [get_ports {DDR4_dq[9]}]
set_property PACKAGE_PIN AG17 [get_ports {DDR4_dqs_t[0]}]
set_property PACKAGE_PIN AG16 [get_ports {DDR4_dqs_c[0]}]
set_property PACKAGE_PIN AG20 [get_ports {DDR4_dqs_t[1]}]
set_property PACKAGE_PIN AH19 [get_ports {DDR4_dqs_c[1]}]
set_property PACKAGE_PIN AC28 [get_ports {DDR4_dqs_t[2]}]
set_property PACKAGE_PIN AD27 [get_ports {DDR4_dqs_c[2]}]
set_property PACKAGE_PIN AF24 [get_ports {DDR4_dqs_t[3]}]
set_property PACKAGE_PIN AF23 [get_ports {DDR4_dqs_c[3]}]
set_property PACKAGE_PIN Y24 [get_ports {DDR4_dqs_t[4]}]
set_property PACKAGE_PIN AA23 [get_ports {DDR4_dqs_c[4]}]
set_property PACKAGE_PIN Y28 [get_ports {DDR4_dqs_t[5]}]
set_property PACKAGE_PIN Y27 [get_ports {DDR4_dqs_c[5]}]
set_property PACKAGE_PIN U27 [get_ports {DDR4_dqs_t[6]}]
set_property PACKAGE_PIN U28 [get_ports {DDR4_dqs_c[6]}]
set_property PACKAGE_PIN P26 [get_ports {DDR4_dqs_t[7]}]
set_property PACKAGE_PIN N27 [get_ports {DDR4_dqs_c[7]}]
set_property PACKAGE_PIN AC22 [get_ports {DDR4_odt[0]}]
set_property PACKAGE_PIN AC24 [get_ports {DDR4_reset_n[0]}]
set_property PACKAGE_PIN AB23 [get_ports {sys_clk_clk_p[0]}]
set_property PACKAGE_PIN AC23 [get_ports {sys_clk_clk_n[0]}]
set_property IOSTANDARD LVDS15 [get_ports {sys_clk_clk_n[0]}]
set_property IOSTANDARD LVDS15 [get_ports {sys_clk_clk_p[0]}]
create_clock -period 5.000 -name sys_clk -waveform {0.000 2.500} [get_ports {sys_clk_clk_p[0]}]
set_property PACKAGE_PIN G26 [get_ports {cam1_gpio[0]}]
set_property IOSTANDARD LVCMOS15 [get_ports {cam1_gpio[0]}]
set_property PULLUP true [get_ports {cam1_gpio[0]}]
set_property PACKAGE_PIN G27  [get_ports cam1_i2c_scl_io]
set_property PACKAGE_PIN F28 [get_ports cam1_i2c_sda_io]
set_property IOSTANDARD LVCMOS15 [get_ports cam1_i2c_scl_io]
set_property IOSTANDARD LVCMOS15 [get_ports cam1_i2c_sda_io]
set_property PULLUP true [get_ports cam1_i2c_scl_io]
set_property PULLUP true [get_ports cam1_i2c_sda_io]
set_property PACKAGE_PIN U23 [get_ports mipi_phy_if_0_clk_p]
set_property PACKAGE_PIN T23 [get_ports mipi_phy_if_0_data_p[0]]
set_property PACKAGE_PIN R23 [get_ports mipi_phy_if_0_data_p[1]]
set_property PACKAGE_PIN L23 [get_ports mipi_phy_if_0_data_p[2]]
set_property PACKAGE_PIN M22 [get_ports mipi_phy_if_0_data_p[3]]
set_property IOSTANDARD MIPI_DPHY [get_ports mipi_phy_if_0_clk_p]
set_property IOSTANDARD MIPI_DPHY [get_ports mipi_phy_if_0_clk_n]
set_property IOSTANDARD MIPI_DPHY [get_ports mipi_phy_if_0_data_p[0]]
set_property IOSTANDARD MIPI_DPHY [get_ports mipi_phy_if_0_data_n[0]]
set_property IOSTANDARD MIPI_DPHY [get_ports mipi_phy_if_0_data_p[1]]
set_property IOSTANDARD MIPI_DPHY [get_ports mipi_phy_if_0_data_n[1]]
set_property IOSTANDARD MIPI_DPHY [get_ports mipi_phy_if_0_data_p[2]]
set_property IOSTANDARD MIPI_DPHY [get_ports mipi_phy_if_0_data_n[2]]
set_property IOSTANDARD MIPI_DPHY [get_ports mipi_phy_if_0_data_p[3]]
set_property IOSTANDARD MIPI_DPHY [get_ports mipi_phy_if_0_data_n[3]]
set_property CLOCK_REGION X3Y0 [get_cells -hier -filter {name =~ *mipi_csi2_rx_subsyst_1/inst/phy/inst/inst/rxbyteclkhs_buf}]
set_property CLOCK_DEDICATED_ROUTE FALSE [get_nets -hier -filter {name =~ *mipi_csi2_rx_subsyst_0/inst/phy/inst/inst/*/inst/BANK_WRAPPER_INST0/fifo_wr_clk[0]}]

应用软件配置

应用软件将基于 Vitis 统一软件平台进行开发,负责执行以下关键任务:

  • 配置摄像头(借助 ALINX 提供的初始化文件)。

  • 配置视频时序控制器(VTC),输出 720p 所需的同步信号。

  • 配置 Demosaic IP,实现正确的颜色重建。

  • 通过 GPIO 控制信号启动摄像头。

  • 配置 VDMA 与 DDR 进行高效读写。

完整软件项目已上传至我的 GitHub,可供参考与复用。

cpp 复制代码
#include <stdio.h>
#include "math.h"
#include <ctype.h>
#include <stdlib.h>
#include "xil_types.h"
#include "xil_cache.h"
#include "xparameters.h"
#include "xiicps.h"
#include "i2c/PS_i2c.h"
#include "demosaic/demosaic.h"
#include "cam_config.h"
#include "config.h"
#include "sleep.h"

#include "xil_cache.h"

#include "xgpiops.h"
#include "xscugic.h"
#include "vtc.h"
#include "xaxivdma.h"
#include "xaxivdma_i.h"

//#include "ff.h"
/* ------------------------------------------------------------ */
/*				Global Variables								*/
/* ------------------------------------------------------------ */

#define LED_MIO	25
#define CAM1_EMIO	26
#define CAM2_EMIO	27

XAxiVdma vdma;
XAxiVdma_DmaSetup vdmaDMA;
XAxiVdma_Config *vdmaConfig;

XVtc Vtc_inst;

//static int WriteError;

int wr_index=0;
int rd_index=0;


XIicPs ps_i2c0;
XIicPs ps_i2c1;
XGpioPs GPIO_PTR ;


int PsGpioSetup() ;

/*
 * Framebuffers for video data
 */

u8 frameBuf0[1][DEMO_MAX_FRAME] __attribute__ ((aligned(4096)));
u8 *pFrames0; 


void InitVideoFmt(XIicPs *IicInstance,int w, int h)
{

	i2c_reg16_write(IicInstance, 0x36, 0x3808, (w>>8)&0xff);
	i2c_reg16_write(IicInstance, 0x36, 0x3809, (w>>0)&0xff);
	i2c_reg16_write(IicInstance, 0x36, 0x380a, (h>>8)&0xff);
	i2c_reg16_write(IicInstance, 0x36, 0x380b, (h>>0)&0xff);

}

void InitDisplay()
{
    Vtc_init(&Vtc_inst,VMODE_1280x720);
    
}

int main(void)
{

	int i;
    int Status;

	PsGpioSetup() ;

    for (i = 0; i < 1; i++) 
	{
		pFrames0 = frameBuf0[i];
	}
	
	demosaic_init(XPAR_V_DEMOSAIC_0_BASEADDR,VIDEO_COLUMNS,VIDEO_ROWS);

	i2c_init(&ps_i2c0,100000);

    XGpioPs_WritePin(&GPIO_PTR, CAM1_EMIO, 1) ;
	usleep(500000);
	XGpioPs_WritePin(&GPIO_PTR, CAM1_EMIO, 0) ;
	usleep(500000);
	XGpioPs_WritePin(&GPIO_PTR, CAM1_EMIO, 1) ;
	usleep(500000);

	sensor_init(&ps_i2c0);
    InitVideoFmt(&ps_i2c0,VIDEO_COLUMNS,VIDEO_ROWS);



	InitDisplay();

	xil_printf("config done!\r\n");

    vdmaConfig = XAxiVdma_LookupConfig(XPAR_AXI_VDMA_0_BASEADDR);
	XAxiVdma_CfgInitialize(&vdma, vdmaConfig, vdmaConfig->BaseAddress);
	//video = VMODE_1280x720;
	vdmaDMA.FrameDelay = 0;
	vdmaDMA.EnableCircularBuf = 1;
	vdmaDMA.EnableSync = 0;
	vdmaDMA.PointNum = 0;
	vdmaDMA.EnableFrameCounter = 0;

	vdmaDMA.VertSizeInput = 720;
	vdmaDMA.HoriSizeInput = (1280)*3;
	vdmaDMA.FixedFrameStoreAddr = 0;
	vdmaDMA.FrameStoreStartAddr[0] = (u32)  pFrames0[0];
	vdmaDMA.Stride = (1280)*3;

	XAxiVdma_DmaConfig(&vdma, XAXIVDMA_WRITE, &(vdmaDMA));
    XAxiVdma_DmaSetBufferAddr(&vdma, XAXIVDMA_WRITE,vdmaDMA.FrameStoreStartAddr);

	XAxiVdma_DmaConfig(&vdma, XAXIVDMA_READ, &(vdmaDMA));
	XAxiVdma_DmaSetBufferAddr(&vdma, XAXIVDMA_READ,vdmaDMA.FrameStoreStartAddr);


	XAxiVdma_DmaStart(&vdma, XAXIVDMA_WRITE);
	//Status = XAxiVdma_StartParking(&vdma, 0, XAXIVDMA_WRITE);
	XAxiVdma_DmaStart(&vdma, XAXIVDMA_READ);
	//XAxiVdma_StartParking(&vdma, 0, XAXIVDMA_READ);

	while(1){
		XGpioPs_WritePin(&GPIO_PTR, LED_MIO, 0) ;
		usleep(500000);
		XGpioPs_WritePin(&GPIO_PTR, LED_MIO, 1) ;
		usleep(500000);
	}


	return 0;
}


int PsGpioSetup()
{
	XGpioPs_Config *GPIO_CONFIG ;
	int Status ;


	GPIO_CONFIG = XGpioPs_LookupConfig(XPAR_XGPIOPS_0_DEVICE_ID) ;

	Status = XGpioPs_CfgInitialize(&GPIO_PTR, GPIO_CONFIG, GPIO_CONFIG->BaseAddr) ;
	if (Status != XST_SUCCESS)
	{
		return XST_FAILURE ;
	}

	XGpioPs_SetDirectionPin(&GPIO_PTR, LED_MIO, 1) ;
	XGpioPs_SetOutputEnablePin(&GPIO_PTR, LED_MIO, 1) ;

	return XST_SUCCESS ;
}

ILA 验证

当系统软件运行时,我们可以借助 ILA 来验证图像处理流水线是否按预期工作。

这些 ILA 在系统优化与调试过程中也发挥着关键作用。

在 Vivado 硬件管理器中,每个 ILA 会被映射为一个数字编号,映射关系如下:

  • ILA1:Memory ILA

  • ILA2:Output ILA

  • ILA3:LCD LVDS ILA

  • ILA4:Video ILA

验证的第一步是监控 AXI4-Stream to Video Out 模块的状态信号

该 IP 会输出多个指示信号,用于表征 AXI 视频流与视频时序信号是否同步。

如果输入的视频时序存在不匹配或不稳定的情况,该模块将无法锁定,导致视频无法输出。

由于该模块内部包含FIFO 存储器,我们可以通过 ILA 观察其上溢和下溢状态信号。这些信号对于诊断流水线中的数据不足(data starvation)或背压(backpressure)等性能问题尤为重要,能够指导我们改进存储带宽或缓冲策略。

在 **ILA1(即 Output ILA)**上观察这些信号,可以看到包含视频数据的 AXI Stream 信号与视频时序控制器生成的时序信号已经保持同步。如果 AXI Stream 信号格式不匹配(例如视频格式不符),AXI4 Stream to Video Out 模块将无法完成同步锁定。

验证过程的下一步是检查 LCD LVDS 输出接口。该阶段的关键状态指示可以确认内部时钟是否锁定,以及接口是否成功启用向显示屏传输数据。监控这些信号,有助于确保序列化视频流被正确生成并传输至 LCD 面板,若出现时钟错误或链路未启用等问题,也能迅速定位。

在验证图像处理通路本身时,首先要检查的是MIPI CSI-2 RX 子系统的视频输出

在此阶段,我们应该观察到每个时钟周期输出 4 像素的 10 bit 原始数据。如果相机配置或 MIPI 接口存在问题,通常会在此处显现为无视频输出或格式异常。验证此输出有助于确认相机初始化是否正确以及 MIPI 链路是否正常建立。

MIPI CSI-2 RX 子系统的输出会送入Demosaic 去马赛克模块,它会将 Bayer 格式的 10 位原始像素转换为 30 位 RGB 格式(每个颜色通道 10 位)。由于流水线保持每个时钟处理 4 像素的吞吐量,去马赛克模块输出的 AXI4-Stream 数据总宽度为 120 位(4 像素×30 位),在维持高吞吐量的同时提供完整重构的色彩数据。

LCD 显示屏需要24 位 RGB 像素(每个颜色通道 8 位)。为满足这一要求,AXI 子集转换器将每像素深度从 30 位压缩至 24 位。系统继续保持每个时钟处理 4 像素的速率,因此转换器输出总线宽度为 96 位(4 像素×24 位),与下游视频输出路径的格式要求完全匹配。

在写入路径上,我们可以观察到 AXI4 总线将处理后的视频帧写入 DDR 存储器的过程。这些传输由 VDMA 发起,它作为 AXI4-Stream 视频流水线与 AXI4 存储器映射接口的桥梁,通过片上网络(NoC)实现帧数据的高效存储。监控这一过程可确保帧缓冲正确写入存储器,供后续读取显示。

读取路径始于 VDMA 通过 NoC 发起 AXI4 读操作,从 DDR 存储器中获取视频帧。这些操作将存储的帧数据重新送回 AXI4-Stream 域,使其能在流水线中继续流向显示端。观察这些 AXI4 读操作可以确认存储器访问功能正常,且帧数据的获取与视频输出时序保持同步。

图像处理流水线的最后环节是 VDMA 输出的 AXI4-Stream 信号,该接口每个时钟周期传输 1 个像素。该数据流输入 AXI4-Stream to Video Out 模块,与时序信号同步后输出至显示端。这一环节标志着系统从基于内存的缓冲机制向实时视频输出的转换,至此,整个图像处理流程闭环完成。

通过观测上述所有 ILA 信号,我们能够深入了解图像处理流水线的内部运行状态,有效排查和定位可能出现的各类问题。

通常这些问题可追溯至软件配置错误或单个 IP 核模块参数设置不当------在早期系统搭建和集成阶段尤为常见。

当然,判断系统是否正常工作的最直观方式仍然是------屏幕上成功显示出图像。但当遇到异常情况时,ILA 提供的深层信号可见性将成为故障诊断的关键工具。

总结

在本项目中,我们探讨了如何在 Versal AI Edge 器件上构建基础的图像处理流水线并验证其功能。

无论是图像识别、智能驾驶,还是工业检测,只要有图像数据的地方,就离不开这条看不见的流水线。而我们今天所做的,就是让它"可见"。

通过利用ChipScope 及 ILA ,我们能够观察并验证设计中的关键点,确保每个阶段都按预期运行。这种实时可视化功能使我们能够快速有效地识别在集成或应用阶段系统可能出现的问题及其根本原因,使后续的开发过程变得更加顺畅、可靠。


芯驿电子自 2012 年成立以来,旗下 AUMO 与 ALINX 两大品牌,在智能车载与 FPGA 行业解决方案领域持续深耕。

ALINX 提供完整的用户开发手册和工具链与全备的技术支持,帮助您缩短从原型到量产的周期。欢迎访问 ALINX 官网了解更多详情。

原文:Using ChipScope to Debug AMD Versal Designs - Hackster.io

相关推荐
珊瑚里的鱼16 分钟前
第九讲 | 模板进阶
开发语言·c++·笔记·visualstudio·学习方法·visual studio
shlR1 小时前
Figma 新手教程学习笔记
笔记·学习·figma
陵易居士2 小时前
JVM-类加载子系统
jvm·笔记·学习
千歌叹尽执夏2 小时前
FPGA: UltraScale+ bitslip实现(ISERDESE3)
fpga开发·training·ultrascale+·bitslip
狮智先生3 小时前
【学习笔记】点云自动化聚类简要总结
笔记·学习·自动化
zly88653723 小时前
MLX5 Linux 驱动代码分析
linux·运维·fpga开发
愚润求学4 小时前
【Linux】动静态库的使用
linux·运维·服务器·开发语言·c++·笔记
weixin_448119944 小时前
Datawhale 5月llm-universe 第2次笔记
笔记
Dovis(誓平步青云)4 小时前
基于面向对象设计的C++日期推算引擎:精准高效的时间运算实现与运算重载工程化实践
开发语言·c++·经验分享·笔记
寂空_4 小时前
【算法笔记】ACM数论基础模板
c++·笔记·算法