入門:HDMI環(huán)路輸出從硬件到調(diào)試全解析)
FPGA視頻開發(fā)的門檻往往不是Verilog語法而是你面前那條什么信號(hào)都好的HDMI線纜一旦接上開發(fā)板就黑屏。做視頻方向的朋友應(yīng)該都有體會(huì)調(diào)接口比調(diào)算法痛苦得多。所以黑金云課堂這套FPGA基礎(chǔ)教程里把“HDMI視頻輸入與環(huán)路輸出”放在比較靠前的位置我是很贊同的——這個(gè)實(shí)驗(yàn)看著簡(jiǎn)單實(shí)際上把FPGA視頻開發(fā)里最難啃的接口鏈路整個(gè)串了一遍。這篇博文就圍繞這個(gè)實(shí)驗(yàn)把我自己做環(huán)路輸出時(shí)的思路、硬件要點(diǎn)、代碼結(jié)構(gòu)和調(diào)試方法完整梳理一遍給準(zhǔn)備動(dòng)手或者正在被黑屏折磨的朋友一份可直接參考的筆記。先說清楚這篇內(nèi)容適合誰。如果你剛?cè)腴TFPGA、板子上有HDMI輸入輸出接口但不知道從哪里開始如果你拿到黑金或其他Artix-7開發(fā)板跑通LED流水燈之后想進(jìn)入視頻方向又或者你已經(jīng)在做視頻接口相關(guān)項(xiàng)目但對(duì)TMDS、EDID、HPD這些概念還停留在“聽過”的階段——這篇文章就是為你準(zhǔn)備的。1. 環(huán)路輸出是什么憑什么當(dāng)FPGA視頻第一課1.1 真實(shí)設(shè)備中的Loop Out環(huán)路輸出這個(gè)功能在視頻行業(yè)里其實(shí)很常見。你去看看拼接處理器、視頻矩陣、廣播級(jí)監(jiān)視器背面除了HDMI輸入口往往還有一個(gè)標(biāo)著“LOOP OUT”或者“環(huán)路輸出”的口。這個(gè)口做的事情很簡(jiǎn)單把輸入信號(hào)原封不動(dòng)地再復(fù)制一份出去不經(jīng)過任何圖像處理、縮放、疊加。為什么需要它因?yàn)楝F(xiàn)場(chǎng)設(shè)備經(jīng)常要級(jí)聯(lián)。比如一個(gè)信號(hào)源要同時(shí)送到三臺(tái)顯示器手頭又沒有分配器那就可以把三臺(tái)顯示器用HDMI線串起來信號(hào)源接第一臺(tái)第一臺(tái)的LOOP OUT接第二臺(tái)第二臺(tái)的LOOP OUT再接第三臺(tái)。環(huán)路輸出就是讓信號(hào)能“穿透”這臺(tái)設(shè)備繼續(xù)往后走。在FPGA里做環(huán)路輸出本質(zhì)上也是同一件事把HDMI RX接收端恢復(fù)出來的視頻流原樣交給TX發(fā)送端發(fā)出去。代碼量可能不到幾十行但這條鏈路一旦跑通說明你已經(jīng)把視頻信號(hào)從物理層到協(xié)議層完整打通了。1.2 為什么第一個(gè)視頻實(shí)驗(yàn)選它很多新手拿到帶HDMI接口的FPGA板子第一反應(yīng)是直接去調(diào)圖像處理算法比如灰度轉(zhuǎn)換、邊緣檢測(cè)、卡爾曼濾波。這個(gè)想法我能理解但實(shí)操中會(huì)陷入一個(gè)非常痛苦的境地顯示器是黑的你根本不知道是HDMI接收沒通、時(shí)序沒對(duì)齊、還是算法寫錯(cuò)了。接口問題和算法問題攪在一起排查起來一層疊一層。環(huán)路輸出的價(jià)值就在于它把算法變量全部去掉只做一件事——驗(yàn)證視頻通路能不能穩(wěn)定工作。你不需要寫復(fù)雜的圖像處理只需要把RX的數(shù)據(jù)搬到TX。如果出圖了說明整條鏈路是通的后面掛什么算法都行如果不出圖問題一定出在鏈路本身排查范圍非常明確。這也是黑金教程把環(huán)路輸出放在視頻實(shí)驗(yàn)靠前位置的原因。它不是一個(gè)“炫技”的實(shí)驗(yàn)而是一個(gè)“打地基”的實(shí)驗(yàn)。1.3 做之前先明確驗(yàn)收標(biāo)準(zhǔn)動(dòng)手之前先定一個(gè)清晰目標(biāo)避免做著做著失去方向。我給自己定的驗(yàn)收標(biāo)準(zhǔn)是這樣的信號(hào)源電腦、機(jī)頂盒、手機(jī)轉(zhuǎn)接器輸出720p或1080p開發(fā)板接上后顯示器能穩(wěn)定出圖。拔掉HDMI線再插回去重復(fù)幾次系統(tǒng)不宕機(jī)、畫面能恢復(fù)。換一個(gè)不同的分辨率比如從720p切到1080p在正確配置下也能出圖。最后一個(gè)不一定在基礎(chǔ)實(shí)驗(yàn)里做但如果能支持說明你對(duì)時(shí)序的理解已經(jīng)很扎實(shí)了。這個(gè)實(shí)驗(yàn)?zāi)懿荒苓^直接決定了你后面做幀緩沖、圖像縮放、OSD疊加時(shí)有沒有一個(gè)可靠的調(diào)試底座。2. 動(dòng)手前必須吃透的HDMI物理層與像素時(shí)鐘2.1 4對(duì)差分線怎么把像素裝進(jìn)去HDMI的物理層走的是TMDSTransition Minimized Differential Signaling差分串行協(xié)議一共有4對(duì)差分線3對(duì)數(shù)據(jù)線1對(duì)時(shí)鐘線。源端把并行的像素?cái)?shù)據(jù)串行化后從這3對(duì)數(shù)據(jù)線送出去每一對(duì)線專門負(fù)責(zé)一個(gè)顏色分量——你可以理解成一條線管紅色、一條管綠色、一條管藍(lán)色。但這里有個(gè)關(guān)鍵點(diǎn)并行像素?cái)?shù)據(jù)是8bit一個(gè)分量HDMI發(fā)送端會(huì)把它編碼成10bit再串行發(fā)送。所以每一條數(shù)據(jù)通道上的實(shí)際串行速率等于像素時(shí)鐘乘以10。舉個(gè)例子1080p60的像素時(shí)鐘是148.5MHz那么每一條通道的串行速率就是1485Mbps換算過來就是1.485Gbps三條通道加起來總帶寬約4.455Gbps。新手聽到1.485Gbps這種數(shù)字容易慌覺得很高端。其實(shí)在FPGA里處理它并沒有想象中那么恐怖因?yàn)槟悴皇怯眠壿嬋ァ白汾s”這個(gè)速率而是用專門的硬件原語——輸入端用ISERDESE2把高速串行信號(hào)解成并行輸出端用OSERDESE2把并行信號(hào)串行化。你的FPGA邏輯始終跑在像素時(shí)鐘148.5MHz或74.25MHz這個(gè)頻率上真正的高速部分被原語消化了。2.2 DE信號(hào)和高低電平周期的意義TMDS協(xié)議里沒有像網(wǎng)絡(luò)數(shù)據(jù)包那樣的包頭包尾它是靠一個(gè)叫DEData Enable數(shù)據(jù)使能的信號(hào)來區(qū)分當(dāng)前傳輸?shù)氖鞘裁磧?nèi)容。DE為高電平時(shí)三通道傳輸?shù)氖窍袼財(cái)?shù)據(jù)一個(gè)時(shí)鐘周期發(fā)一個(gè)像素的24bitRGB各8bit。DE為低電平時(shí)傳輸?shù)氖强刂菩盘?hào)主要是行同步HSYNC和場(chǎng)同步VSYNC。這兩個(gè)同步信號(hào)各自只有1bit合起來2bit通過TMDS編碼后也在數(shù)據(jù)通道里傳。你可以把DE理解成一把刀把連續(xù)的數(shù)據(jù)流切成了兩段有效圖像區(qū)域和消隱區(qū)域。接收端拿到DE、HSYNC、VSYNC這三個(gè)信號(hào)再配合像素時(shí)鐘就能準(zhǔn)確地還原出一幀一幀的圖像。這就是為什么HDMI對(duì)時(shí)序參數(shù)極其敏感——它沒有額外的幀標(biāo)記全靠這些同步信號(hào)來對(duì)齊。你在配置TX輸出時(shí)序時(shí)如果行消隱前肩、同步脈沖寬度、后肩這些參數(shù)和源端不匹配顯示器立刻就會(huì)表現(xiàn)異常。2.3 像素時(shí)鐘的算法和幾個(gè)常用數(shù)值像素時(shí)鐘的計(jì)算公式很簡(jiǎn)單像素時(shí)鐘 ≈ 水平總周期 × 垂直總周期 × 幀率其中水平總周期包括有效像素、前肩、同步脈沖、后肩垂直總周期包括有效行數(shù)、前肩、同步脈沖、后肩。拿最常見的兩個(gè)分辨率來說參數(shù)720p601080p60有效分辨率1280×7201920×1080水平總周期16502200垂直總周期7501125像素時(shí)鐘74.25MHz148.5MHzTMDS時(shí)鐘74.25MHz148.5MHz單通道串行速率742.5Mbps1485Mbps總帶寬約2.23Gbps約4.455Gbps對(duì)入門級(jí)FPGA開發(fā)板來說720p60是比較舒服的工作點(diǎn)74.25MHz像素時(shí)鐘不高不低布局布線壓力小IO帶寬也寬裕。1080p60就接近很多入門級(jí)板卡IO能力的上限了所以如果你用的板子比較基礎(chǔ)我建議先跑720p跑穩(wěn)了再挑戰(zhàn)1080p。在調(diào)試中如果發(fā)現(xiàn)1080p偶爾出花屏或者信號(hào)質(zhì)量差降分辨率排查是一個(gè)很實(shí)用的手段。2.4 有獨(dú)立時(shí)鐘線意味著什么注意看上面表格里有一行叫“TMDS時(shí)鐘”。HDMI和PCIe、以太網(wǎng)這些接口有一個(gè)非常大的區(qū)別它專門用了一對(duì)差分線來傳像素時(shí)鐘接收端不用從數(shù)據(jù)流里做時(shí)鐘恢復(fù)CDR。這一點(diǎn)幫了FPGA開發(fā)者大忙。沒有CDR意味著什么意味著你不需要在FPGA里去寫復(fù)雜的時(shí)鐘數(shù)據(jù)恢復(fù)邏輯只需要把TMDS時(shí)鐘直接當(dāng)成像素時(shí)鐘來用或者送進(jìn)PLL/MMCM做倍頻和相位調(diào)整。數(shù)據(jù)通道上要做的工作相對(duì)簡(jiǎn)單一些只需要做“比特對(duì)齊”——也就是找到每個(gè)10bit編碼字的邊界把串行數(shù)據(jù)正確切成并行數(shù)據(jù)。當(dāng)然簡(jiǎn)單是相對(duì)的。比特對(duì)齊這個(gè)操作在調(diào)試時(shí)依然是翻車重災(zāi)區(qū)后面第五節(jié)我會(huì)詳細(xì)講怎么排查。3. 硬件連接與供電HDMI座子不是插上就行3.1 先分清你的板子是直連還是帶PHY芯片開始寫邏輯之前一定要先翻開你手里板子的原理圖看清楚HDMI輸入接口是直接用差分線連到FPGA的IO還是中間經(jīng)過了一顆HDMI PHY接收芯片比如ADI的ADV7611這類。這兩種方案在FPGA里的設(shè)計(jì)路徑完全不同。直連方案下FPGA要自己處理TMDS解串、比特對(duì)齊、編碼解碼靈活度高但難度也高黑金云課堂這類基礎(chǔ)實(shí)驗(yàn)一般走的是這個(gè)路線因?yàn)樗钅苤v清楚底層原理。帶PHY芯片的方案則簡(jiǎn)單得多PHY芯片已經(jīng)把TMDS信號(hào)解成了并行視頻總線比如BT.1120格式FPGA只需要讀并行數(shù)據(jù)和時(shí)鐘就行但這種方案你能學(xué)到的東西也少。如果你手上是不帶PHY的直連板子恭喜你這個(gè)實(shí)驗(yàn)做完你對(duì)HDMI的理解會(huì)比用PHY芯片的人深一個(gè)層次。另外說一句如果你用Vivado打開工程卻發(fā)現(xiàn)自己板子型號(hào)不在器件列表里不用懷疑工程文件壞了多半是安裝Vivado時(shí)沒有勾選對(duì)應(yīng)的FPGA系列比如7系列或UltraScale系列。該補(bǔ)裝補(bǔ)裝該重裝重裝這不是代碼問題。3.2 端接、ESD和I/O電平直連方案下硬件上有幾個(gè)點(diǎn)會(huì)影響信號(hào)質(zhì)量尤其是掉以輕心就全黑屏。第一是差分端接。HDMI接收端的差分對(duì)之間必須有100Ω的跨接電阻這組電阻一般畫在HDMI座子附近。如果板子設(shè)計(jì)省掉了這個(gè)電阻高速信號(hào)沒有阻抗匹配波形反射嚴(yán)重常見表現(xiàn)就是畫面閃爍、花屏嚴(yán)重的直接沒有信號(hào)。第二是IO電平標(biāo)準(zhǔn)。在Xilinx 7系列里HDMI輸入輸出通常用TMDS_33或者LVDS電平標(biāo)準(zhǔn)具體用哪個(gè)要看你的板卡設(shè)計(jì)不能上來就隨便選個(gè)LVCMOS——電平標(biāo)準(zhǔn)選錯(cuò)了IO端口的電壓閾值不對(duì)信號(hào)進(jìn)來就是一堆亂碼。第三是ESD保護(hù)。HDMI是熱插拔接口靜電放電是家常便飯。正規(guī)板子在座子后面都會(huì)放ESD防護(hù)芯片。這里給個(gè)小提醒調(diào)試時(shí)不要用示波器探頭直接在座子引腳上亂戳一方面容易短路另一方面可能會(huì)把靜電引到器件上搞壞一片。3.3 電源、HPD和EDID三個(gè)“假裝沒看見就會(huì)死”的細(xì)節(jié)新手在這個(gè)實(shí)驗(yàn)上翻車一半以上不是栽在代碼上而是栽在下面這三個(gè)硬件細(xì)節(jié)上。第一個(gè)是電源。HDMI座子上有一個(gè)5V引腳但這個(gè)5V是信號(hào)源設(shè)備比如電腦輸出的“檢測(cè)電壓”用來告訴接收端“線插好了”電流很小毫安級(jí)。網(wǎng)上經(jīng)常看到有人問“HDMI供電電流需要多大”其實(shí)這是個(gè)誤解——HDMI座子上的5V不是用來給設(shè)備供電的FPGA開發(fā)板必須用自己的USB口、電源適配器或者板載電源來供電。如果你以為插上HDMI線板子就能通電那肯定開不了機(jī)。第二個(gè)是HPDHot Plug Detect熱插拔檢測(cè)。接收端通過HPD引腳告訴源端“我準(zhǔn)備好了你可以輸出信號(hào)了”。HPD沒有拉高電腦會(huì)認(rèn)為顯示器沒連接HDMI口不會(huì)輸出任何信號(hào)。開發(fā)板上HPD一般通過電阻上拉到3.3V或者由FPGA引腳控制。如果你發(fā)現(xiàn)電腦能識(shí)別到顯示器但就是沒有畫面先拿萬用表量一下HPD電平。第三個(gè)是EDIDExtended Display Identification Data。源端怎么知道該輸出什么分辨率、什么刷新率靠讀取接收端的EDID數(shù)據(jù)。這個(gè)數(shù)據(jù)一般存在一個(gè)EEPROM里或者由FPGA通過I2C接口動(dòng)態(tài)回放。如果EDID是空的或者內(nèi)容不對(duì)源端要么不輸出要么輸出一個(gè)奇怪的分辨率顯示器自然沒圖或者異常。這三個(gè)細(xì)節(jié)每一個(gè)都能讓你的實(shí)驗(yàn)“看起來莫名其妙失敗”。所以硬件階段不要急著寫代碼先把這三個(gè)點(diǎn)摸清楚。4. 環(huán)路通路的邏輯設(shè)計(jì)RX解串、時(shí)鐘直通與TX回放4.1 RX側(cè)解串鏈路的四個(gè)環(huán)節(jié)假設(shè)你的板子是FPGA直連HDMI座子RX側(cè)的數(shù)據(jù)通路大致分成四個(gè)環(huán)節(jié)。第一個(gè)環(huán)節(jié)是差分緩沖。TMDS差分對(duì)信號(hào)進(jìn)入FPGA后先用IBUFDS把差分信號(hào)轉(zhuǎn)成單端信號(hào)數(shù)據(jù)通道和時(shí)鐘通道都要這么做。第二個(gè)環(huán)節(jié)是輸入延遲調(diào)節(jié)。HDMI的差分對(duì)在PCB上走線、經(jīng)過連接器會(huì)有細(xì)微的時(shí)序偏差。FPGA里用IDELAYE2原語給數(shù)據(jù)通道加可調(diào)的延遲單位大概在幾十皮秒量級(jí)用來補(bǔ)償這些偏差。第三個(gè)環(huán)節(jié)是解串器。ISERDESE2把高速串行信號(hào)轉(zhuǎn)成并行信號(hào)。因?yàn)門MDS是10bit編碼實(shí)際工程中可能先用1:8解串再用其他邏輯補(bǔ)成10bit或者直接按1:10來設(shè)計(jì)取決于你選用的具體方案。第四個(gè)環(huán)節(jié)是比特對(duì)齊。串行數(shù)據(jù)只有一串比特流你要找到每個(gè)10bit編碼字從哪里開始。一般做法是利用TMDS控制字符的固定碼型來掃描邊界然后通過“滑動(dòng)比特位”讓解串結(jié)果對(duì)齊。做完這四個(gè)環(huán)節(jié)你就能在FPGA里恢復(fù)出像素?cái)?shù)據(jù)和DE、HSYNC、VSYNC了。這四步看起來簡(jiǎn)單但每步都對(duì)應(yīng)著不同的故障現(xiàn)象調(diào)試時(shí)一定要有耐心。4.2 環(huán)路輸出最核心的決策用誰家的時(shí)鐘這是環(huán)路輸出實(shí)驗(yàn)里最關(guān)鍵的一個(gè)決定也是很多教程一筆帶過但實(shí)際工程里必須想清楚的地方TX發(fā)送端的像素時(shí)鐘從哪里來有兩條路可以走。方案A是時(shí)鐘直通直接用RX恢復(fù)出來的TMDS時(shí)鐘作為TX的像素時(shí)鐘。這樣做的好處是輸入和輸出完全同源不需要任何幀緩沖理論上整個(gè)環(huán)路只有幾十納秒的延遲。代碼最簡(jiǎn)單符合“環(huán)路輸出”的原始定義——信號(hào)進(jìn)來什么樣出去就什么樣。壞處是如果上游信號(hào)源有抖動(dòng)輸出也會(huì)跟著抖。方案B是時(shí)鐘隔離RX把數(shù)據(jù)寫成異步FIFO或DDR幀緩沖TX用本地晶振產(chǎn)生的時(shí)鐘從緩沖里讀數(shù)據(jù)。好處是輸入輸出解耦可以改變分辨率、刷新率還能在不打斷上游的情況下疊加OSD。但代價(jià)是需要額外管理跨時(shí)鐘域和幀同步問題。基礎(chǔ)實(shí)驗(yàn)應(yīng)該選方案A。原因很簡(jiǎn)單這個(gè)實(shí)驗(yàn)的目的是驗(yàn)證鏈路不是練習(xí)跨時(shí)鐘域。你把方案A跑通了再去做方案B心里會(huì)對(duì)“為什么要幀緩沖”有更直觀的認(rèn)識(shí)。順便說一句方案A里RX恢復(fù)的TMDS時(shí)鐘雖然能直接用但為了保證TX側(cè)的信號(hào)質(zhì)量建議讓這個(gè)時(shí)鐘先過BUFG或者M(jìn)MCM再驅(qū)動(dòng)TX邏輯不要拿原始時(shí)鐘到處亂驅(qū)動(dòng)。這在布局布線階段能減少很多時(shí)序收斂的麻煩。4.3 直通邏輯的Verilog最小骨架下面這段代碼就是環(huán)路輸出的核心在基礎(chǔ)實(shí)驗(yàn)里你甚至可以把它寫到模塊的頂層幾乎沒有多余的東西。// 簡(jiǎn)化示意HDMI環(huán)路直通 // rx_clk為從TMDS時(shí)鐘恢復(fù)出的像素時(shí)鐘 // module hdmi_loop_through ( input wire rx_clk, input wire rx_de, input wire rx_hsync, input wire rx_vsync, input wire [23:0] rx_pixel, output wire tx_de, output wire tx_hsync, output wire tx_vsync, output wire [23:0] tx_pixel ); // 環(huán)路輸出數(shù)據(jù)原樣回放 assign tx_de rx_de; assign tx_hsync rx_hsync; assign tx_vsync rx_vsync; assign tx_pixel rx_pixel; endmodule注意這段代碼是高度簡(jiǎn)化的示意真實(shí)工程里你還要在前面加RX解串鏈路在后面加TMDS編碼和OSERDESE2輸出中間可能還需要加幾級(jí)寄存器流水線來滿足時(shí)序收斂。但這個(gè)骨架想表達(dá)的意思很明確環(huán)路輸出在邏輯層面就是“搬數(shù)據(jù)”沒有任何算法。你要花心思的地方全在接口的物理層和解串對(duì)齊上。4.4 EDID回放和HPD的落地方案EDID在環(huán)路輸出實(shí)驗(yàn)里有兩類做法。最省事的是板載EEPROM。很多HDMI開發(fā)板上已經(jīng)有一顆EEPROM出廠就寫好了EDID數(shù)據(jù)。這種情況下FPGA不需要參與DDCDisplay Data Channel通信插上電腦就能識(shí)別到屏幕。前提是EEPROM內(nèi)容是對(duì)的如果識(shí)別出來的分辨率不對(duì)或者根本沒有識(shí)別可能要自己用I2C編程器重新燒寫EDID。另一種做法是用FPGA實(shí)現(xiàn)一個(gè)I2C從機(jī)當(dāng)源端通過HDMI的SDA/SCL引腳來讀EDID時(shí)FPGA把事先存在ROM里的EDID數(shù)據(jù)回放回去。這個(gè)方案靈活度高以后想支持動(dòng)態(tài)分辨率切換、模擬不同顯示器EDID都可以改代碼實(shí)現(xiàn)適合想深入練習(xí)I2C狀態(tài)機(jī)的朋友。但在基礎(chǔ)實(shí)驗(yàn)里我不建議一上來就在FPGA里寫I2C從機(jī)先把主鏈路跑通EDID用EEPROM解決。不管用哪種方案都要記得檢查HPD是否正常拉高。有些開發(fā)板的HPD引腳是和FPGA相連的如果FPGA沒有配置這個(gè)引腳的輸出默認(rèn)可能是低電平電腦端就會(huì)認(rèn)為“沒有顯示器”自然不輸出。這是硬件配置問題不是邏輯問題但在邏輯代碼里也得有對(duì)應(yīng)處理。4.5 TX輸出的最后幾級(jí)TX側(cè)的鏈路和RX相反并行像素?cái)?shù)據(jù)先經(jīng)過TMDS編碼器把8bit像素?cái)?shù)據(jù)編碼成10bit同時(shí)把HSYNC/VSYNC編碼成控制字符然后送進(jìn)OSERDESE2做并轉(zhuǎn)串最后通過OBUFDS轉(zhuǎn)成差分信號(hào)輸出到HDMI座子。TX側(cè)相對(duì)RX側(cè)少了一個(gè)大麻煩——不需要做比特對(duì)齊。因?yàn)槟阕约菏前l(fā)送端比特邊界完全由你決定編碼器在哪個(gè)bit邊界發(fā)數(shù)據(jù)接收端就必須在那個(gè)邊界去對(duì)齊。這也是為什么很多HDMI發(fā)送端的調(diào)試比接收端輕松。如果你用的是Xilinx的官方HDMI IP這些原語都被封裝好了配置一下就能跑。但如果你是為了學(xué)習(xí)我強(qiáng)烈建議至少手寫一次TX鏈路和RX解串別直接上IP。用IP跑通只能算會(huì)用工具手寫一次你才知道TMDS編碼里那些控制字符是怎么回事DE信號(hào)是怎么和像素?cái)?shù)據(jù)交替發(fā)送的。5. 上板調(diào)試從全黑到穩(wěn)定出圖的完整排查鏈路5.1 把“黑屏”拆成三個(gè)層面環(huán)路輸出實(shí)驗(yàn)里你遇到的所有問題都可以拆到三個(gè)層面里去看這個(gè)思維方法非常重要。第一個(gè)層面是電信號(hào)層。HDMI線插上后TMDS時(shí)鐘對(duì)有沒有差分信號(hào)HPD是不是高電平5V檢測(cè)電壓是否正常這些問題從原理圖就能找到測(cè)量點(diǎn)用萬用表就能排查一大半。沒有示波器也能做很多判斷比如用萬用表量HPD電平、量5V電壓。第二個(gè)層面是數(shù)字鏈路層。FPGA內(nèi)部有沒有解出DE、HSYNC、VSYNC像素?cái)?shù)據(jù)是不是周期性變化這一層主要靠Vivado的ILA邏輯分析儀來抓信號(hào)。第三個(gè)層面是協(xié)議層。EDID內(nèi)容是否正確輸出的時(shí)序參數(shù)是否符合VESA/CEA標(biāo)準(zhǔn)顯示器支不支持你當(dāng)前的分辨率排查的時(shí)候一定要自下而上先確認(rèn)電信號(hào)層沒問題再查數(shù)字鏈路層最后才去懷疑協(xié)議層。很多人一黑屏就懷疑EDID、懷疑代碼里的時(shí)序參數(shù)結(jié)果量了一下HPD是低電平白折騰半小時(shí)。5.2 用ILA定位問題的一個(gè)具體思路Vivado里的ILAIntegrated Logic Analyzer是FPGA調(diào)試最常用的工具。環(huán)路輸出實(shí)驗(yàn)里我建議你先把下面這幾個(gè)信號(hào)加到ILA探針里rx_clk恢復(fù)出的像素時(shí)鐘rx_hsync、rx_vsync行場(chǎng)同步rx_de數(shù)據(jù)使能rx_pixel[23:0]像素?cái)?shù)據(jù)抓這些信號(hào)的時(shí)候時(shí)鐘域選rx_clk。如果你的恢復(fù)時(shí)鐘本身有問題ILA壓根跑不起來這也是一個(gè)有效的檢查手段。抓完波形之后怎么判斷按優(yōu)先級(jí)看三件事。第一rx_clk到底有沒有在跑。如果ILA觸發(fā)不了或者抓到是全0大概率是TMDS時(shí)鐘就沒有正確恢復(fù)出來?;厝ゲ殡娦盘?hào)層查差分時(shí)鐘有沒有進(jìn)FPGA、時(shí)鐘引腳有沒有約束對(duì)。第二rx_hsync和rx_vsync有沒有周期性的脈沖。這兩個(gè)信號(hào)是判斷“數(shù)字鏈路層是否解通”的關(guān)鍵。如果解串和比特對(duì)齊做對(duì)了HSYNC和VSYNC一定是規(guī)律翻轉(zhuǎn)的。如果這兩個(gè)信號(hào)都不動(dòng)問題基本出在ISERDESE2或比特對(duì)齊邏輯上。第三rx_de為高時(shí)rx_pixel是不是在變化。哪怕你輸入的是靜態(tài)畫面HDMI發(fā)送端也會(huì)以一定頻率刷新數(shù)據(jù)所以DE高電平期間像素值不可能是完全靜止的。如果DE正常但像素值恒定不變說明解串出來的數(shù)據(jù)有問題或者IDELAY的延遲配置不對(duì)。這一套排查下來至少能定位到八成以上的問題。5.3 常見現(xiàn)象、可能原因和排查手段速查表把我在做這個(gè)實(shí)驗(yàn)以及幫別人看問題時(shí)遇到的現(xiàn)象整理成一張表遇到問題可以直接對(duì)號(hào)入座現(xiàn)象可能原因排查手段電腦識(shí)別不到顯示器HPD未拉高、EDID為空萬用表量HPD電平檢查EEPROM或I2C回放邏輯顯示器全黑但電腦顯示已連接TMDS時(shí)鐘未恢復(fù)、解串鏈路沒通用ILA看rx_clk和rx_de檢查IBUFDS/IDELAYE2花屏、雪花點(diǎn)比特對(duì)齊錯(cuò)誤、IDELAY延遲不對(duì)掃描IDELAY的tap值檢查比特對(duì)齊邏輯顏色通道互換紅藍(lán)對(duì)調(diào)R/G/B通道映射接反對(duì)照原理圖檢查數(shù)據(jù)通道和RGB的對(duì)應(yīng)關(guān)系畫面有滾動(dòng)條紋時(shí)序參數(shù)和源端不匹配、行場(chǎng)同步位置不對(duì)檢查HFP/HSW/HBP和VFP/VSW/VBP參數(shù)熱插拔后不恢復(fù)HPD處理不完善、ESD導(dǎo)致器件異常檢查熱插拔流程圖重新插拔并觀察HPD電平變化1080p出圖不穩(wěn)定720p正常信號(hào)質(zhì)量余量不足、IO速率逼近上限嘗試降低分辨率驗(yàn)證檢查端接電阻和線材這張表不一定覆蓋所有情況但它能幫你把排查方向確認(rèn)下來。如果你碰到的問題不在表里也先按“電信號(hào)層到數(shù)字鏈路層到協(xié)議層”的順序查一遍基本都能縮小范圍。5.4 別急著怪代碼先懷疑線和屏這是個(gè)老生常談但必須強(qiáng)調(diào)的點(diǎn)。我見過太多人花一整天調(diào)代碼最后發(fā)現(xiàn)是HDMI線的問題。HDMI線纜質(zhì)量參差不齊尤其是在跑1080p60的時(shí)候劣質(zhì)線纜的衰減很嚴(yán)重表現(xiàn)出來就是畫面閃爍、花屏甚至完全無信號(hào)。另一個(gè)容易被忽略的是顯示器本身。不同顯示器對(duì)輸入信號(hào)的容錯(cuò)能力差別非常大有的顯示器對(duì)同步信號(hào)的偏差很敏感稍微不對(duì)就黑屏有的顯示器則很寬容花屏也硬顯示。做環(huán)路輸出實(shí)驗(yàn)時(shí)如果條件允許準(zhǔn)備一臺(tái)已知工作正常的監(jiān)視器和一根已知好用的線交叉驗(yàn)證一下。這個(gè)習(xí)慣能幫你省掉大量無意義的調(diào)試時(shí)間。我自己就踩過這個(gè)坑。有一次調(diào)TX時(shí)序怎么調(diào)都覺得參數(shù)沒問題但顯示器就是偶爾閃一下黑屏。后來換了一根短線、質(zhì)量好的HDMI線問題立刻消失。從此我在調(diào)試這類高速接口時(shí)永遠(yuǎn)默認(rèn)“線材可能有問題”直到用替換法排除為止。6. 環(huán)路直通跑通后的三條擴(kuò)展路線6.1 加幀緩沖讓輸入輸出真正解耦環(huán)路直通跑通之后你可能很快會(huì)發(fā)現(xiàn)它的限制輸入是什么分辨率輸出就必須是什么分辨率輸入一旦閃斷輸出也跟著閃斷。要解決這個(gè)問題就要加幀緩沖。做法是在RX和TX之間插入一個(gè)異步FIFO或者DDR3/DDR4幀緩沖。RX側(cè)把恢復(fù)的視頻數(shù)據(jù)寫入緩沖TX側(cè)用本地晶振產(chǎn)生的時(shí)鐘從緩沖里讀數(shù)據(jù)。這樣輸入和輸出被緩沖隔開輸入抖動(dòng)不會(huì)直接傳到輸出甚至可以做到輸入1080p、輸出720p這種跨分辨率轉(zhuǎn)換。做幀緩沖是個(gè)絕佳的進(jìn)階練習(xí)它會(huì)把異步FIFO讀寫字長(zhǎng)、幀同步、緩存管理這些知識(shí)點(diǎn)一次性練到位。比直接去學(xué)那些復(fù)雜算法實(shí)在得多。6.2 在通路上掛圖像處理環(huán)路直通和幀緩沖做好了你的視頻數(shù)據(jù)通路就是一個(gè)標(biāo)準(zhǔn)的“輸入—流水線—輸出”架構(gòu)。這時(shí)候你想在中間掛任何圖像處理都很方便灰度轉(zhuǎn)換、色彩空間轉(zhuǎn)換、邊緣檢測(cè)、OSD疊加、縮放全都只是在這條通路上插入一個(gè)模塊的事。很多人在網(wǎng)上問“FPGA圖像處理怎么入門”其實(shí)入門的重點(diǎn)不在算法本身而在于你能不能穩(wěn)定地拿到一幀一幀的視頻數(shù)據(jù)。環(huán)路輸出實(shí)驗(yàn)就是幫你去掉這個(gè)最大的障礙。通路都不通再好的算法也出不來效果。6.3 我建議的后續(xù)學(xué)習(xí)順序以黑金這套教程的進(jìn)度為參考我給新手朋友建議的順序是這樣的先搞定HDMI環(huán)路輸出再做一塊“行緩沖或幀緩沖”然后是簡(jiǎn)單的像素級(jí)圖像處理灰度、二值化、邊緣檢測(cè)最后再上OSD疊加、縮放、多分辨率適配這些綜合功能。每走一步都以“畫面穩(wěn)定不出錯(cuò)”為驗(yàn)收標(biāo)準(zhǔn)。別急著追求花哨效果先把每一步的鏈路底層吃透。如果你正在做這個(gè)實(shí)驗(yàn)卡在某一個(gè)現(xiàn)象出不來對(duì)照第五節(jié)那張表一層一層查大概率能解決問題。等這條直通鏈路穩(wěn)定出圖之后你會(huì)明顯感覺到FPGA視頻開發(fā)里最難的那道坎已經(jīng)過去了。后面再遇到問題你至少知道該往哪個(gè)方向看而不是對(duì)著黑屏發(fā)呆。