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

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

5小時(shí)前
278
加入交流群
掃碼加入
獲取工程師必備禮包
參與熱點(diǎn)資訊討論

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

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

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

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

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

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

那就讓我們開始吧!

項(xiàng)目工具清單

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

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

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

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

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

基本流程如下:

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

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

3. 緩存存儲(chǔ)(VDMA + DDR

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

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

1. 攝像頭正常采集

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

3. 顯示輸出無錯(cuò)幀

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

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

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

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

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

調(diào)試方法論

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

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

2. 控制變量:減少變量與干擾項(xiàng)

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

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

ILA 插樁策略

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

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

1. 優(yōu)先監(jiān)控控制信號(hào)、復(fù)位線、狀態(tài)/錯(cuò)誤標(biāo)志等關(guān)鍵位置。這些信號(hào)通常可以第一時(shí)間反映系統(tǒng)行為,幫助我們?cè)谡{(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)試初期,我們可以從一組合理的控制信號(hào)、復(fù)位、狀態(tài)/錯(cuò)誤信息以及關(guān)鍵 AXI 接口信號(hào)入手,采用中等采樣深度。

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

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

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

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

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

ILA 模塊

ILA_LCD_LVDS

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

Video ILA

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

Memory ILA

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

Output ILA

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

IP 模塊

CIPS

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

NoC

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

SmartConnect

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

MIPI CSI-2 RX

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

Demosaic(去馬賽克)

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

AXI Subset Converter

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

VDMA

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

AXI4-Stream to Video Out

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

VTC

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

LCD LVDS 接口

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

Advanced IO Wizard

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

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

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

在生成比特流時(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)一軟件平臺(tái)進(jìn)行開發(fā),負(fù)責(zé)執(zhí)行以下關(guān)鍵任務(wù):

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

完整軟件項(xiàng)目已上傳至我的 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 驗(yàn)證

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

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

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

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

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

該 IP 會(huì)輸出多個(gè)指示信號(hào),用于表征 AXI 視頻流與視頻時(shí)序信號(hào)是否同步。

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

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

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

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

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

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

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

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

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

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

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

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

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

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

總結(jié)

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

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

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

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

相關(guān)推薦