• 正文
    • 項目工具清單
    • Versal 調(diào)試機(jī)制
    • 調(diào)試方法論
    • ILA 插樁策略
    • Vivado 設(shè)計架構(gòu)
    • ILA 模塊
    • IP 模塊
    • 應(yīng)用軟件配置
    • ILA 驗證
    • 總結(jié)
  • 相關(guān)推薦
申請入駐 產(chǎn)業(yè)圖譜

FPGA 大神 Adam Taylor 使用 ChipScope 調(diào)試 AMD Versal 設(shè)計

05/16 11:34
340
加入交流群
掃碼加入
獲取工程師必備禮包
參與熱點資訊討論

本篇文章來自 FPGA 大神、Ardiuvo &?Hackster.IO?知名博主 Adam Taylor。在這里感謝 Adam Taylor 對 ALINX 產(chǎn)品的關(guān)注與使用。為了讓文章更易閱讀,我們在原文的基礎(chǔ)上作了一些靈活的調(diào)整。原文鏈接已貼在文章底部。歡迎大家在評論區(qū)友好互動。

在上篇文章中,我們已經(jīng)通過測試圖案生成器,成功驗證了 ALINX VD100 的圖像顯示鏈路。

→ 傳送門:【實戰(zhàn)筆記】FPGA 大神 Adam Taylor 使用 ALINX VD100(AMD Versal系列)開發(fā)平臺實現(xiàn)圖像處理

這次終于要接入 MIPI 攝像頭,進(jìn)行真正的圖像處理了!

在這個過程中,集成邏輯分析儀(ILA)將作為我們的調(diào)試“透視眼”,幫助我們逐步驗證每一階段的運行效果。

本項目規(guī)模不小,從圖像采集到處理再到輸出,每一環(huán)都可能出現(xiàn)問題——做好調(diào)試準(zhǔn)備了嗎?

那就讓我們開始吧!

項目工具清單

本次開發(fā)平臺基于 AMD Versal AI Edge 芯片,開發(fā)板采用 ALINX 的 VD100。

VD100,VD100S/N:000017 , ALINX, www.alinx.com (二維碼自動識別)?

Versal AI Edge 系列是 AMD 推出的系統(tǒng)級異構(gòu)芯片(SoC),專為邊緣端 AI 應(yīng)用優(yōu)化,集成了 Arm Cortex-A72 應(yīng)用處理器、Cortex-R5F 實時處理器、可編程邏輯(PL)以及 AI 引擎專用加速模塊等多種處理單元。這些模塊通過片上網(wǎng)絡(luò)(NoC)實現(xiàn)高效互聯(lián),形成強(qiáng)大靈活的計算平臺,非常適合本地化部署卷積神經(jīng)網(wǎng)絡(luò)(CNN)等 AI 推理任務(wù)。

ALINX VD100 開發(fā)板配備了 2 個 4 通道的 MIPI 攝像頭輸入接口,以及一個 LVDS LCD 顯示輸出,并且支持 Vivado免費版開發(fā)環(huán)境,對原型驗證和早期開發(fā)者極其友好。

在進(jìn)入 AI 階段前,我們需要打好基礎(chǔ)——構(gòu)建一條穩(wěn)定的圖像處理通路。

基本流程如下:

1. 圖像采集(MIPI 攝像頭)

2. 預(yù)處理(去馬賽克、顏色空間轉(zhuǎn)換、圖像增強(qiáng))

3. 緩存存儲(VDMA + DDR

4. 圖像顯示(LVDS LCD 輸出)

一個可靠的圖像通路必須滿足三個條件:

1. 攝像頭正常采集

2. 數(shù)據(jù)通路不丟包

3. 顯示輸出無錯幀

通過早期驗證這些關(guān)鍵環(huán)節(jié),可確保 I/O 分配、時鐘策略和圖像處理流程的正確性,降低在集成上層 AI 邏輯或應(yīng)用功能時的開發(fā)風(fēng)險。只有基礎(chǔ)打牢,后續(xù)的開發(fā)迭代才能更高效,項目推進(jìn)也更有把握。

Versal 調(diào)試機(jī)制

雖然 Versal 器件的應(yīng)用調(diào)試與 7 系列、UltraScale 及 UltraScale+ 系列大體相似(均可使用 ChipScope 工具),但在使用方式上也發(fā)生了一些變化:

_ 舊平臺(7/US/US+等) Versal 平臺
Debug hub連接方式 通過 JTAG 接口 通過 CIPS 中的 AXI4 接口
Debug hub插入方式 自動插入 自動/手動 (涉及 DFX 必須手動)
Debug Core接口協(xié)議 專有接口 標(biāo)準(zhǔn) AXI4-Stream
AXI-Stream ILA 特性 集成標(biāo)準(zhǔn)ILA+System ILA支持 BRAM/URAM存儲介質(zhì)選擇 標(biāo)準(zhǔn) ILA 與System ILA 分立存儲介質(zhì)固定

Versal 的調(diào)試架構(gòu)更加現(xiàn)代化,也更加靈活,但也意味著你在設(shè)計之初就必須考慮調(diào)試資源的布局,尤其是?CIPS 模塊和 AXI 調(diào)試路徑?的預(yù)留。

調(diào)試方法論

FPGA 開發(fā)是一個需要多次迭代的過程,只有遵循邏輯推理的方法,才能更高效地解決問題,不至于造成資源浪費。我在調(diào)試時遵循以下原則幫助我更快速地排查問題:

1. 問題拆解:將復(fù)雜問題拆解為更小的部分

2. 控制變量:減少變量與干擾項

3. 假設(shè)驗證:做出合理預(yù)測,并驗證預(yù)測結(jié)果

4. 前瞻規(guī)劃:在設(shè)計初期就規(guī)劃好調(diào)試方案與觀測點位置

ILA 插樁策略

集成邏輯分析儀(ILA)使用起來非常占用邏輯和 BRAM 資源,且采樣深度、監(jiān)控信號的寬度也會直接影響 BRAM 的使用量——探針越寬、采樣窗口越長,占用的內(nèi)存越多,資源也越快耗盡。

在真實項目中使用 ILA 進(jìn)行調(diào)試時,必須合理選擇插樁位置,以平衡調(diào)試可視性與 FPGA 資源的使用。我的建議是,在遵循前述調(diào)試方法論的條件下:

1. 優(yōu)先監(jiān)控控制信號、復(fù)位線、狀態(tài)/錯誤標(biāo)志等關(guān)鍵位置。這些信號通??梢缘谝粫r間反映系統(tǒng)行為,幫助我們在調(diào)試早期就定位問題。

2. 逐步拓展至一些關(guān)鍵的 AXI 總線,尤其是連接 Versal 的片上網(wǎng)絡(luò)(NoC)與處理系統(tǒng)(PS)的部分,這些接口是可編程邏輯(PL)、NoC 與 PS 之間的數(shù)據(jù)主通道,能揭示系統(tǒng)集成與數(shù)據(jù)傳輸過程中的一些微妙問題。

因此,在調(diào)試初期,我們可以從一組合理的控制信號、復(fù)位、狀態(tài)/錯誤信息以及關(guān)鍵 AXI 接口信號入手,采用中等采樣深度。

這樣既能獲得系統(tǒng)層面的良好可視性,又能為后續(xù)迭代調(diào)試保留資源空間。

Vivado 設(shè)計架構(gòu)

基于 Versal AI Edge 的圖像處理流水線,核心架構(gòu)通過 CIPS 模塊實現(xiàn)全局控制;圖像幀通過一系列 IP 模塊被采集與處理;應(yīng)用程序、DDR 內(nèi)存訪問以及 CIPS 與可編程邏輯(PL)之間的通信,通過片上網(wǎng)絡(luò)(NoC)實現(xiàn)高速互聯(lián)。

系統(tǒng)的整體結(jié)構(gòu)如下圖所示:

具體使用的 IP 核取決于應(yīng)用需求,但核心流水線一般包括:傳感器接口、去馬賽克(Demosaic)、顏色空間轉(zhuǎn)換、圖像增強(qiáng)、視頻時序控制模塊,以及 AXI Stream 的互聯(lián)與控制邏輯。

ILA 模塊

ILA_LCD_LVDS

→ 監(jiān)控 LCD / LVDS 接口,觀察狀態(tài)與錯誤信號。

Video ILA

→ 使用四個通道,監(jiān)控圖像處理流程中的 AXI-Stream 視頻信號,包括 MIPI 原始輸出、去馬賽克后的 RGB 流、24 位像素轉(zhuǎn)換輸出與 VDMA 輸出流。

Memory ILA

→ 監(jiān)控通過 NoC 訪問 DDR 的 AXI4 總線,確保 DDR 的讀寫操作正常進(jìn)行。

Output ILA

→ 監(jiān)控 AXI-Stream 到視頻輸出的狀態(tài)信息,如視頻輸出同步信號診斷(HSync/VSync 相位對齊監(jiān)測)

IP 模塊

CIPS

→ 配置處理系統(tǒng)(PS)、平臺初始化,提供外設(shè)訪問。

NoC

→ 提供高帶寬的數(shù)據(jù)流通通道,連接多個互聯(lián)節(jié)點,并集成 DDR 控制器用于外部內(nèi)存訪問。

SmartConnect

→ 連接各 IP 模塊的 AXI-Lite 寄存器接口,使處理系統(tǒng)可以對其進(jìn)行控制與配置。

MIPI CSI-2 RX

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

Demosaic(去馬賽克)

→ 將圖像傳感器輸出的 Bayer 模式像素數(shù)據(jù)轉(zhuǎn)換為完整 RGB 圖像,重建每個像素的顏色信息。

AXI Subset Converter

→ 將 40 位像素數(shù)據(jù)(每個 RGB 通道 10 位)轉(zhuǎn)換為 24 位格式(每通道 8 位),每時鐘周期保持 4 像素吞吐。

VDMA

→ 橋接 AXI4-Stream 與 AXI4 存儲接口,在 NoC 上實現(xiàn) DDR 幀存的存取,同時為處理階段提供高效的緩存機(jī)制。

AXI4-Stream to Video Out

→ 將 AXI4-Stream 視頻流轉(zhuǎn)換為標(biāo)準(zhǔn)視頻輸出格式,生成 HSync、VSync 等同步信號以驅(qū)動顯示設(shè)備。

VTC

→ 生成 HSync、VSync、有效視頻等信號,并與AXI4-Stream to Video Out模塊同步,確保顯示時序正確。

LCD LVDS 接口

→ 將標(biāo)準(zhǔn)并行視頻輸出信號轉(zhuǎn)換為串行 VESA LVDS 格式,適配基于 LVDS 的 LCD 顯示屏。

Advanced IO Wizard

→ 配置 Versal 設(shè)備中的 XPIO,將 LVDS 輸出數(shù)據(jù)串行化,滿足 VESA LVDS 顯示標(biāo)準(zhǔn)。

通過這些 ILA,我們能夠同時觀察靜態(tài)的狀態(tài)信號與動態(tài)的高帶寬數(shù)據(jù)流,全面掌控圖像處理系統(tǒng)的運行狀態(tài)。

完整設(shè)計如圖所示,可通過本項目所附的 TCL 腳本復(fù)現(xiàn)該設(shè)計。

在生成比特流時,必須定義 XDC I/O 約束文件,明確所有外部接口的物理引腳位置與電氣標(biāo)準(zhǔn)。

關(guān)鍵接口的引腳配置如下:

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]}]

應(yīng)用軟件配置

應(yīng)用軟件將基于 Vitis 統(tǒng)一軟件平臺進(jìn)行開發(fā),負(fù)責(zé)執(zhí)行以下關(guān)鍵任務(wù):

  • 配置攝像頭(借助 ALINX 提供的初始化文件)。
  • 配置視頻時序控制器(VTC),輸出 720p 所需的同步信號。
  • 配置 Demosaic IP,實現(xiàn)正確的顏色重建。
  • 通過 GPIO 控制信號啟動攝像頭。
  • 配置 VDMA 與 DDR 進(jìn)行高效讀寫。

完整軟件項目已上傳至我的 GitHub,可供參考與復(fù)用。

#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!rn");

    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 驗證

當(dāng)系統(tǒng)軟件運行時,我們可以借助 ILA 來驗證圖像處理流水線是否按預(yù)期工作。

這些 ILA 在系統(tǒng)優(yōu)化與調(diào)試過程中也發(fā)揮著關(guān)鍵作用。

在 Vivado 硬件管理器中,每個 ILA 會被映射為一個數(shù)字編號,映射關(guān)系如下:

  • ILA1:Memory ILA
  • ILA2:Output ILA
  • ILA3:LCD LVDS ILA
  • ILA4:Video ILA

驗證的第一步是監(jiān)控 AXI4-Stream to Video Out 模塊的狀態(tài)信號。

該 IP 會輸出多個指示信號,用于表征 AXI 視頻流與視頻時序信號是否同步。

如果輸入的視頻時序存在不匹配或不穩(wěn)定的情況,該模塊將無法鎖定,導(dǎo)致視頻無法輸出。

由于該模塊內(nèi)部包含?FIFO 存儲器,我們可以通過 ILA 觀察其上溢和下溢狀態(tài)信號。這些信號對于診斷流水線中的數(shù)據(jù)不足(data starvation)或背壓(backpressure)等性能問題尤為重要,能夠指導(dǎo)我們改進(jìn)存儲帶寬或緩沖策略。

在?ILA1(即 Output ILA)上觀察這些信號,可以看到包含視頻數(shù)據(jù)的 AXI Stream 信號與視頻時序控制器生成的時序信號已經(jīng)保持同步。如果 AXI Stream 信號格式不匹配(例如視頻格式不符),AXI4 Stream to Video Out 模塊將無法完成同步鎖定。

驗證過程的下一步是檢查 LCD LVDS 輸出接口。該階段的關(guān)鍵狀態(tài)指示可以確認(rèn)內(nèi)部時鐘是否鎖定,以及接口是否成功啟用向顯示屏傳輸數(shù)據(jù)。監(jiān)控這些信號,有助于確保序列化視頻流被正確生成并傳輸至 LCD 面板,若出現(xiàn)時鐘錯誤或鏈路未啟用等問題,也能迅速定位。

在驗證圖像處理通路本身時,首先要檢查的是MIPI CSI-2 RX 子系統(tǒng)的視頻輸出。

在此階段,我們應(yīng)該觀察到每個時鐘周期輸出 4 像素的 10 bit 原始數(shù)據(jù)。如果相機(jī)配置或 MIPI 接口存在問題,通常會在此處顯現(xiàn)為無視頻輸出或格式異常。驗證此輸出有助于確認(rèn)相機(jī)初始化是否正確以及 MIPI 鏈路是否正常建立。

MIPI CSI-2 RX 子系統(tǒng)的輸出會送入Demosaic去馬賽克模塊,它會將 Bayer 格式的 10 位原始像素轉(zhuǎn)換為 30 位 RGB 格式(每個顏色通道 10 位)。由于流水線保持每個時鐘處理 4 像素的吞吐量,去馬賽克模塊輸出的 AXI4-Stream 數(shù)據(jù)總寬度為 120 位(4 像素×30 位),在維持高吞吐量的同時提供完整重構(gòu)的色彩數(shù)據(jù)。

LCD 顯示屏需要?24 位 RGB 像素(每個顏色通道 8 位)。為滿足這一要求,AXI 子集轉(zhuǎn)換器將每像素深度從 30 位壓縮至 24 位。系統(tǒng)繼續(xù)保持每個時鐘處理 4 像素的速率,因此轉(zhuǎn)換器輸出總線寬度為 96 位(4 像素×24 位),與下游視頻輸出路徑的格式要求完全匹配。

在寫入路徑上,我們可以觀察到 AXI4 總線將處理后的視頻幀寫入 DDR 存儲器的過程。這些傳輸由 VDMA 發(fā)起,它作為 AXI4-Stream 視頻流水線與 AXI4 存儲器映射接口的橋梁,通過片上網(wǎng)絡(luò)(NoC)實現(xiàn)幀數(shù)據(jù)的高效存儲。監(jiān)控這一過程可確保幀緩沖正確寫入存儲器,供后續(xù)讀取顯示。

讀取路徑始于 VDMA 通過 NoC 發(fā)起 AXI4 讀操作,從 DDR 存儲器中獲取視頻幀。這些操作將存儲的幀數(shù)據(jù)重新送回 AXI4-Stream 域,使其能在流水線中繼續(xù)流向顯示端。觀察這些 AXI4 讀操作可以確認(rèn)存儲器訪問功能正常,且?guī)瑪?shù)據(jù)的獲取與視頻輸出時序保持同步。

圖像處理流水線的最后環(huán)節(jié)是?VDMA 輸出的 AXI4-Stream 信號,該接口每個時鐘周期傳輸 1 個像素。該數(shù)據(jù)流輸入 AXI4-Stream to Video Out 模塊,與時序信號同步后輸出至顯示端。這一環(huán)節(jié)標(biāo)志著系統(tǒng)從基于內(nèi)存的緩沖機(jī)制向?qū)崟r視頻輸出的轉(zhuǎn)換,至此,整個圖像處理流程閉環(huán)完成。

通過觀測上述所有 ILA 信號,我們能夠深入了解圖像處理流水線的內(nèi)部運行狀態(tài),有效排查和定位可能出現(xiàn)的各類問題。

通常這些問題可追溯至軟件配置錯誤或單個 IP 核模塊參數(shù)設(shè)置不當(dāng)——在早期系統(tǒng)搭建和集成階段尤為常見。

當(dāng)然,判斷系統(tǒng)是否正常工作的最直觀方式仍然是——屏幕上成功顯示出圖像。但當(dāng)遇到異常情況時,ILA 提供的深層信號可見性將成為故障診斷的關(guān)鍵工具。

總結(jié)

在本項目中,我們探討了如何在 Versal AI Edge 器件上構(gòu)建基礎(chǔ)的圖像處理流水線并驗證其功能。

無論是圖像識別、智能駕駛,還是工業(yè)檢測,只要有圖像數(shù)據(jù)的地方,就離不開這條看不見的流水線。而我們今天所做的,就是讓它“可見”。

通過利用?ChipScope 及 ILA,我們能夠觀察并驗證設(shè)計中的關(guān)鍵點,確保每個階段都按預(yù)期運行。這種實時可視化功能使我們能夠快速有效地識別在集成或應(yīng)用階段系統(tǒng)可能出現(xiàn)的問題及其根本原因,使后續(xù)的開發(fā)過程變得更加順暢、可靠。

芯驛電子自 2012 年成立以來,旗下 AUMO 與 ALINX 兩大品牌,在智能車載與 FPGA 行業(yè)解決方案領(lǐng)域持續(xù)深耕。

相關(guān)推薦