戰(zhàn):基于SMPTE-SDI IP核的HD-SDI視頻流解析)
SDISerial Digital Interface這個(gè)接口在廣電、醫(yī)療、工業(yè)視覺這些領(lǐng)域里幾乎是無處不在的存在。做FPGA圖像處理的工程師只要一碰到SDI大概率第一時(shí)間就去翻SMPTE 292M協(xié)議文檔從幾百頁的英文規(guī)范里找“3FF 000 000 XYZ”這幾個(gè)時(shí)序基準(zhǔn)碼到底怎么對齊結(jié)果折騰三天項(xiàng)目進(jìn)度還是原地踏步。說實(shí)話這個(gè)坑我自己也踩過而且踩得相當(dāng)深。這篇文章不打算帶你一個(gè)字一個(gè)字去啃協(xié)議而是換個(gè)思路直接用Xilinx FPGA的SMPTE-SDI IP核把HD-SDI視頻流的解析過程變成一次“搭積木”式的工程實(shí)踐??赐昴憔椭酪曨l數(shù)據(jù)是怎么從串行差分線上被收下來、做完時(shí)鐘恢復(fù)、排列成并行像素流最后通過AXI4-Stream接口交給FPGA內(nèi)部邏輯處理的。文章里會(huì)配關(guān)鍵時(shí)序圖和數(shù)據(jù)對齊關(guān)系適合剛接手SDI相關(guān)項(xiàng)目、或者做視頻采集卡/圖像處理板卡的同學(xué)參考。1. 方案選型為什么直接上SMPTE-SDI IP核1.1 SDI協(xié)議解析的真正難點(diǎn)在哪先聊一個(gè)現(xiàn)實(shí)問題HD-SDI的物理層速率是1.485Gbps雖然這個(gè)速率在今天看起來不高但它背后的工程問題一點(diǎn)不少。SDI是單向串行接口信號經(jīng)過線纜傳輸后會(huì)有衰減、抖動(dòng)和碼間干擾接收端必須先做均衡Equalization、時(shí)鐘恢復(fù)CDR和解串才能拿到干凈的并行數(shù)據(jù)。這一塊涉及高速模擬前端和鎖相環(huán)光靠用戶邏輯里的狀態(tài)機(jī)是玩不轉(zhuǎn)的。再往上一層SDI不是簡單地把像素?cái)?shù)據(jù)串行發(fā)出去就完了。它要按照SMPTE 292M的格式把視頻數(shù)據(jù)劃分成行Line每行又分成有效視頻區(qū)Active Video和水平消隱區(qū)Horizontal Blanking消隱區(qū)里還嵌入了時(shí)序基準(zhǔn)碼TRSTiming Reference Signal也就是大家經(jīng)常聽說的EAV和SAV。除此之外還有一個(gè)標(biāo)準(zhǔn)叫SMPTE 299M規(guī)定了輔助數(shù)據(jù)ANC Data的格式——音頻、時(shí)間碼、HDR元數(shù)據(jù)這些都藏在消隱期的ANC包里。所以自己寫SDI接收邏輯等于要同時(shí)搞定三個(gè)層面的問題物理層的CDR和均衡、鏈路層的8B/10B解碼和字對齊、還有協(xié)議層的TRS檢測和行場解析。任何一個(gè)環(huán)節(jié)出錯(cuò)畫面不是黑屏就是花屏而且排查起來極其痛苦。1.2 SMPTE-SDI IP核到底幫你干了哪些活Xilinx的SMPTE-SDI IP核本質(zhì)上是把上面那三層工作打包成了一個(gè)可配置的模塊。使用時(shí)只需要把它掛在GT TransceiverGTP/GTX上IP核內(nèi)部會(huì)自動(dòng)完成串行數(shù)據(jù)流的解串、解碼、對齊和TRS檢測最后輸出一路AXI4-Stream格式的視頻數(shù)據(jù)流。這里說的AXI4-Stream接口經(jīng)常用FPGA的工程師應(yīng)該不陌生它不像AXI4-Full那樣需要地址讀寫而是純粹的流式數(shù)據(jù)傳輸由tdata、tvalid、tready、tuser、tlast這幾個(gè)信號組成。SDI核把解析好的YUV 4:2:2 10bit像素?cái)?shù)據(jù)按行打包好一幀一幀地往這個(gè)接口上送用戶邏輯只需要在tvalid有效時(shí)把數(shù)據(jù)接住就行。值得說明的是IP核同時(shí)提供了接收RX和發(fā)送TX兩條通路。接收方向負(fù)責(zé)解串和解析發(fā)送方向則是把并行視頻數(shù)據(jù)編碼成SDI串行流發(fā)出去。做采集或者輸入處理的項(xiàng)目用RX通路就夠做發(fā)送卡或者視頻輸出再考慮TX。很多開發(fā)板上的SDI參考設(shè)計(jì)都是TX/RX同時(shí)使能方便做回環(huán)測試。1.3 一個(gè)誤區(qū)IP核不是黑盒接口才是核心我見到過不少新人拿到IP核配置向?qū)е箅S便點(diǎn)了幾下生成完IP就往工程里一放然后對著沒有輸出的tdata發(fā)呆。這里有個(gè)很重要的認(rèn)知SDI IP核交付的是“已經(jīng)解好串、對齊好字的視頻流”但它并不會(huì)替你做后續(xù)的視頻處理比如色彩空間轉(zhuǎn)換、縮放、幀緩存、顯示時(shí)序生成這些統(tǒng)統(tǒng)要自己寫。換句話說IP核幫你把“獲得干凈視頻數(shù)據(jù)”這個(gè)最臟最累的活干完了但你要真正把畫面顯示出來還需要理解它輸出的數(shù)據(jù)結(jié)構(gòu)——也就是每個(gè)時(shí)鐘周期里tdata上那幾十個(gè)bit分別代表什么tuser的哪個(gè)位是幀同步信號tlast在什么位置拉高。這部分工作沒有捷徑但好消息是它比啃協(xié)議文檔輕松得多抓住幾個(gè)關(guān)鍵信號就行。2. 硬件層面的關(guān)鍵決策引腳、時(shí)鐘與參考設(shè)計(jì)2.1 GT Bank、參考時(shí)鐘怎么選用SMPTE-SDI IP核第一步不是在Vivado里點(diǎn)IP配置而是先把硬件底子搞清楚。SDI的高速串行信號從連接器進(jìn)來之后一般先過一顆SDI專用電纜均衡器比如LMH0384、GS2974這類芯片把單端信號轉(zhuǎn)換成CML差分對然后送進(jìn)FPGA的GT Bank。選擇GT Bank時(shí)要看FPGA芯片的封裝和可用資源。Artix-7系列里如果選到合適的封裝GTX Bank數(shù)量有限而SDI信號最好分配在專用的高速Bank上避免與PCIe、SFP等其他高速接口搶位置。我自己的經(jīng)驗(yàn)是畫原理圖之前就要先確認(rèn)SDI的TX/RX差分對接到了哪個(gè)Bank參考時(shí)鐘引腳是不是和這個(gè)Bank匹配不然后期布線換Bank簡直是災(zāi)難。參考時(shí)鐘的選擇也很關(guān)鍵。SMPTE-SDI核的線速率在1.485GbpsHD-SDI或2.97Gbps3G-SDI對應(yīng)的GT參考時(shí)鐘通常是148.5MHz或者148.35MHz59.94Hz幀率對應(yīng)也有些配置會(huì)用125MHz。這個(gè)頻率必須和你的視頻源幀率嚴(yán)格對應(yīng)否則會(huì)出現(xiàn)間歇性的畫面跳動(dòng)。配置IP時(shí)界面里允許設(shè)置的參考時(shí)鐘范圍會(huì)根據(jù)目標(biāo)線速率自動(dòng)算出來你只需要根據(jù)板卡實(shí)際晶振頻率選擇即可。2.2 時(shí)鐘架構(gòu)恢復(fù)時(shí)鐘與線路鎖定SDI信號接收過程中最容易被忽略但也最重要的是時(shí)鐘架構(gòu)。FPGA內(nèi)部存在好幾套時(shí)鐘它們之間有嚴(yán)格的頻率關(guān)系。第一套是GT的參考時(shí)鐘GT_REFCLK它只作為GT收發(fā)器的基準(zhǔn)不直接參與像素?cái)?shù)據(jù)處理。第二套是恢復(fù)時(shí)鐘Recovered ClockSDI接收端通過CDR從串行數(shù)據(jù)流中提取出和發(fā)送端同步的時(shí)鐘這個(gè)時(shí)鐘就是視頻數(shù)據(jù)的“節(jié)奏”。第三套是用戶邏輯工作時(shí)鐘通常是恢復(fù)時(shí)鐘分頻或者直接使用恢復(fù)時(shí)鐘。這里要特別提一下“線路鎖定”Line-Locked的概念。SDI視頻流的像素時(shí)鐘必須鎖定在行頻上這樣處理音頻和視頻同步時(shí)才能保證樣本數(shù)一致。Xilinx的SDI IP核會(huì)輸出恢復(fù)時(shí)鐘相關(guān)的信號用戶邏輯如果需要做音頻嵌入或者解嵌必須基于這個(gè)恢復(fù)時(shí)鐘域來操作不能隨便用板上的自由振蕩時(shí)鐘否則音頻會(huì)慢慢漂移。做視頻采集卡的人應(yīng)該對這個(gè)坑深有體會(huì)。2.3 功耗、復(fù)位順序和可靠性設(shè)計(jì)SDI項(xiàng)目的功耗估算要留足余量。GT收發(fā)器本身就是功耗大戶1.485Gbps鏈路加上TX/RX同時(shí)工作電流輕松上到幾百毫安。再加上FPGA內(nèi)部邏輯、DDR顆粒、HDMI/SDI驅(qū)動(dòng)芯片電源設(shè)計(jì)不能摳門。我建議至少在電源裕量上留出30%以上同時(shí)每個(gè)電源軌的紋波控制在30mV以內(nèi)這對GT的抖動(dòng)性能至關(guān)重要。復(fù)位設(shè)計(jì)同樣不能馬虎。SDI IP核的復(fù)位輸入一般叫作sdi_rst它控制著核內(nèi)部的全部狀態(tài)機(jī)。上電后必須先等待GT的復(fù)位完成信號比如gt_rxresetdone拉高再釋放sdi_rst順序反了的話IP核可能永遠(yuǎn)鎖不定信號。不少工程師遇到“為什么SDI收不到視頻”的問題最后查出來就是復(fù)位時(shí)序不對。3. 核心節(jié)點(diǎn)解析配置步驟與時(shí)序圖深度拆解3.1 Vivado中的IP配置以Vivado/Vitis版本為例打開Vivado的IP Catalog在搜索框里輸入“SDI”一般能找到“SMPTE SDI LogiCORE IP”或者類似名稱的IP。雙擊創(chuàng)建一個(gè)IP實(shí)例配置界面主要需要關(guān)注幾個(gè)選項(xiàng)線速率Line Rate選擇HD-SDI/3G-SDI等參考時(shí)鐘頻率以及數(shù)據(jù)接口的位寬。數(shù)據(jù)位寬的選項(xiàng)很有意思IP核允許你選擇AXI4-Stream接口為20位、32位或者40位等不同寬度這些位寬對應(yīng)不同的數(shù)據(jù)打包方式。如果是1080i/720p這類HD視頻20位模式下tdata上每個(gè)周期正好是一個(gè)像素的YCbCr數(shù)據(jù)Y占10bitCb/Cr各占10bit交替出現(xiàn)32位模式下則是一次打包兩個(gè)像素。選32位的好處是tdata寬度對后續(xù)DDR緩存比較友好因?yàn)镈DR的位寬通常做32位或64位選20位則邏輯更直觀??错?xiàng)目需求定。配置完成后IP核會(huì)生成例化模板。在頂層模塊里你需要在IP核周圍加上GT的例化和時(shí)鐘資源連接。Vivado的IP生成目錄下會(huì)附帶一個(gè)參考設(shè)計(jì)Example Design強(qiáng)烈建議直接參考它里面有完整的GT例化、復(fù)位邏輯、時(shí)鐘緩沖器連接比自己從頭接線省太多事。3.2 關(guān)鍵時(shí)序從K28.5到EAV/SAV的全鏈路對齊接下來是這篇文章最有價(jià)值的部分——HD-SDI的數(shù)據(jù)時(shí)序到底是怎么組織的。理解了這一節(jié)你以后看到任何SDI相關(guān)代碼都會(huì)覺得親切。SDI串行數(shù)據(jù)流在物理層是經(jīng)過8B/10B編碼的比特流接收端先要找到K28.5特殊字符來建立字對齊。對齊之后數(shù)據(jù)被組織成一個(gè)個(gè)10bit的碼字。這些碼字在IP核內(nèi)部被轉(zhuǎn)換為20bit并行數(shù)據(jù)然后經(jīng)過ESCRAMBLING解擾操作恢復(fù)出真正的視頻數(shù)據(jù)。視頻數(shù)據(jù)按照行來組織。每一行都以一個(gè)時(shí)序基準(zhǔn)碼TRS開頭整個(gè)TRS由4個(gè)碼字組成3FF、000、000、XYZ。前三個(gè)是固定的XYZ則攜帶了場、消隱和行標(biāo)識信息。TRS分為兩類EAVEnd of Active Video出現(xiàn)在有效視頻結(jié)束的位置SAVStart of Active Video出現(xiàn)在有效視頻開始的位置。如圖示意一行HD-SDI數(shù)據(jù)流 |- EAV -|- 水平消隱區(qū) -|- SAV -|- 有效視頻區(qū) -| | 3FF | 000 | 000 | XYZ | ANC輔助數(shù)據(jù)/填充 | 3FF | 000 | 000 | XYZ | Cb Y Cr Y ... |從EAV的XYZ到SAV的XYZ之間的區(qū)域就是水平消隱期長度跟視頻格式有關(guān)。比如1080i格式一行總共1920個(gè)有效像素加上消隱區(qū)一行總樣本數(shù)通常是2200不同制式有差異。有效視頻區(qū)就是實(shí)實(shí)在在的圖像數(shù)據(jù)按Cb Y Cr Y的4:2:2采樣結(jié)構(gòu)排列每個(gè)分量10bit。XYZ這個(gè)碼字里最有意思的是它的bit5、bit6、bit7三位它們分別表示H、V、F標(biāo)志H位區(qū)分當(dāng)前是EAV還是SAVH1表示EAVH0表示SAVV位表示當(dāng)前是否處于垂直消隱期F位表示當(dāng)前是奇數(shù)場還是偶數(shù)場。這三個(gè)標(biāo)志位組合起來就能精確確定當(dāng)前處在畫面的哪個(gè)位置。3.3 拿到AXI4-Stream后的數(shù)據(jù)還原方法IP核完成所有協(xié)議解析之后通過AXI4-Stream接口把數(shù)據(jù)吐出來。先看一個(gè)典型的接收數(shù)據(jù)時(shí)序文字描述版m_axis_video_tdata : | Cb0 Y0 Cr0 Y1 | Cb2 Y2 Cr2 Y3 | ... | 行尾填充 | m_axis_video_tvalid: |_______高電平持續(xù)整個(gè)有效行_______| m_axis_video_tlast : | |____最后一個(gè)數(shù)據(jù)時(shí)拉高| m_axis_video_tuser : |第一個(gè)有效數(shù)據(jù)時(shí)拉高幀/場起始標(biāo)記| |這里有個(gè)關(guān)鍵點(diǎn)tvalid不是只在有效視頻區(qū)拉高。在消隱期SDI數(shù)據(jù)流中依然有數(shù)據(jù)不斷輸出只是這些數(shù)據(jù)不是圖像像素而是ANC輔助數(shù)據(jù)或者無效填充。所以如果你想提取真正的圖像數(shù)據(jù)不能只看tvalid還要通過IP核輸出的行場同步信號或者EAV/SAV信息來判斷當(dāng)前是否處于有效視頻區(qū)。我自己常用的做法是在FPGA內(nèi)部維護(hù)一個(gè)行計(jì)數(shù)器和一個(gè)幀計(jì)數(shù)器收到tuser的幀起始脈沖后清零然后統(tǒng)計(jì)tdata上有效像素的數(shù)量。等到有效像素?cái)?shù)量達(dá)到1920對1080i或者1280對720p時(shí)就認(rèn)為這一行收滿了可以做行緩存或者直接寫入DDR。這種做法不依賴IP核內(nèi)部的具體實(shí)現(xiàn)即使以后換IP版本也基本不用改邏輯。另一個(gè)實(shí)用技巧是把32位tdata拆成兩個(gè)像素來處理。如果tdata的布局是{Cb_n, Y_n, Cr_n, Y_{n1}}這么交錯(cuò)排列的那么一個(gè)時(shí)鐘周期內(nèi)其實(shí)拿到了兩個(gè)像素的Y分量和一個(gè)Cb一個(gè)Cr。你可以把每個(gè)像素補(bǔ)齊成YUV 4:2:2格式后存入FIFO也可以通過簡單換算轉(zhuǎn)成RGB。總之了解數(shù)據(jù)打包格式是后續(xù)所有圖像處理的第一步這塊一旦概念清晰后面的代碼寫起來就非常順。4. 常見問題與排查技巧實(shí)錄4.1 常見故障速查表這部分記錄一下我調(diào)試SDI接收項(xiàng)目時(shí)碰到過的高頻問題按經(jīng)驗(yàn)整理成表方便直接對照排查。故障現(xiàn)象可能原因排查方法IP核完全無輸出tvalid一直為低GT參考時(shí)鐘未配置或晶振頻率不對用ILA抓gt_rxresetdone是否拉高測量參考時(shí)鐘引腳有輸出但畫面整體偏移/花屏SAV/EAV對齊位置理解錯(cuò)誤像素坐標(biāo)偏移檢查tuser信號和tlast位置確認(rèn)行數(shù)據(jù)是否移位畫面偶爾黑一下信號源不穩(wěn)定或CDR鎖定丟失檢查線纜和連接器查看rx_aligned/rx_locked信號是否出現(xiàn)毛刺輸出幀率只有標(biāo)稱的一半場同步/幀同步提取邏輯錯(cuò)誤重點(diǎn)觀察F位和V位標(biāo)志確認(rèn)奇偶場判斷條件是否正確音頻數(shù)據(jù)取不到ANC輔助數(shù)據(jù)沒被正確解析確認(rèn)消隱期數(shù)據(jù)是否被丟棄檢查ANC包的用戶數(shù)據(jù)字UDW位置熱插拔后需要重新復(fù)位才能恢復(fù)復(fù)位狀態(tài)機(jī)不夠健壯增加持續(xù)監(jiān)測功能檢測到鎖定丟失后自動(dòng)執(zhí)行軟復(fù)位流程這張表里最常出問題的就是第二行“畫面整體偏移/花屏”。這種問題通常不是SDI鏈路本身出錯(cuò)而是你在提取像素時(shí)沒有根據(jù)SAV的位置開始計(jì)數(shù)。如果你把消隱期的前幾個(gè)數(shù)據(jù)誤當(dāng)成有效像素那整行數(shù)據(jù)都會(huì)向右偏移圖像看起來就像被水平“撕裂”了一樣。處理方法很簡單在接收邏輯里檢測到SAV的XYZ碼字后再開始正式的有效像素計(jì)數(shù)。4.2 從行業(yè)社區(qū)學(xué)到的幾個(gè)典型排查思路Xilinx官方論壇和各大FPGA技術(shù)社區(qū)里SDI相關(guān)的求助帖常年居高不下。久而久之我也總結(jié)出了一些通用的排查套路在這里分享給你們。第一招先測物理層再談協(xié)議層。如果SDI輸入信號不正常后面所有邏輯都白搭。可以用Vivado的IBERT IP核直接對GT鏈路做誤碼率測試根據(jù)眼圖結(jié)果判斷信號質(zhì)量。實(shí)測下來如果誤碼率在1e-12以下物理層基本沒問題可以放心去查協(xié)議層。不會(huì)用IBERT也沒關(guān)系先用示波器探一下GT的差分接收引腳看有沒有明顯的信號幅度和眼圖張開度至少能排除線纜和連接器的問題。第二招巧用環(huán)回模式。SMPTE-SDI IP核參考設(shè)計(jì)里一般會(huì)帶一個(gè)近端PMA環(huán)回Near-End PMA Loopback或者遠(yuǎn)端環(huán)回選項(xiàng)。在SDI發(fā)送端發(fā)一個(gè)測試圖樣然后把串行數(shù)據(jù)直接環(huán)回到接收端就能在不依賴外部信號源的情況下驗(yàn)證整條鏈路。如果環(huán)回模式下能正常收到圖像說明FPGA和IP核配置沒問題問題一定出在外部輸入鏈路上。第三招不要忽略AXI4-Stream的握手信號。FPGA用戶邏輯如果沒拉高treadySDI IP核會(huì)進(jìn)入等待狀態(tài)數(shù)據(jù)就會(huì)積壓在核內(nèi)部出不來看起來就像是“沒有數(shù)據(jù)”。這種問題極其隱蔽因?yàn)閠valid和tdata看起來可能是正常的但tready一直為低導(dǎo)致數(shù)據(jù)流卡住。排查方法很簡單在ILA波形里同時(shí)抓tvalid、tready、tdata三個(gè)信號看握手狀態(tài)。接收端如果暫時(shí)不需要處理數(shù)據(jù)也要保證tready信號邏輯正確不要出現(xiàn)死鎖。4.3 測試驗(yàn)證的實(shí)用技巧最后聊聊怎么把SDI接收鏈路完整地測起來。畢竟光看波形只能確認(rèn)數(shù)據(jù)通路上有東西在跑是否真的是正確的視頻畫面還必須結(jié)合圖像內(nèi)容來判斷。最省心的方式是利用SDI信號發(fā)生器。市面上的SDI測試信號源能輸出彩條、灰階、活動(dòng)圖像等標(biāo)準(zhǔn)測試圖形配合IP核接收和緩存邏輯在HDMI顯示器上或者通過JTAG讀回幀緩存一眼就能看出接收是否正常。如果預(yù)算緊張也可以用支持HDMI轉(zhuǎn)SDI的轉(zhuǎn)換器雖然畫質(zhì)不是專業(yè)級別但做功能驗(yàn)證足夠了。我自己做驗(yàn)證時(shí)有幾個(gè)固定動(dòng)作先在FPGA里寫一個(gè)簡單的視頻幀存模塊把SDI核輸出的YUV數(shù)據(jù)寫入DDR3然后通過Vivado的ILA抓取寫入DDR前的最后一級數(shù)據(jù)檢查每一行的像素?cái)?shù)量是否和預(yù)期一致。對于1080i30這種隔行格式還要特別注意場標(biāo)志F位的切換規(guī)律奇數(shù)場和偶數(shù)場的數(shù)據(jù)順序不能搞混。另外一個(gè)小技巧是打印錯(cuò)誤計(jì)數(shù)。在SDI接收邏輯里加一個(gè)CRC校驗(yàn)或者簡單的行計(jì)數(shù)值比對如果連續(xù)檢測到不正常的行長度就累加一個(gè)錯(cuò)誤計(jì)數(shù)。實(shí)測中這種錯(cuò)誤統(tǒng)計(jì)比單純看畫面更敏感很多間歇性故障在畫面上可能只是偶爾閃幾幀但錯(cuò)誤計(jì)數(shù)早就悄悄漲上去了。有了這個(gè)統(tǒng)計(jì)值排查“偶發(fā)黑屏”“偶發(fā)花屏”這類神出鬼沒的故障時(shí)就多了一雙眼睛。對于剛接觸SDI的朋友我特別想說一開始就打算“先熟讀協(xié)議再動(dòng)手”的思路在SDI這種復(fù)雜接口上真的效率太低。更務(wù)實(shí)的路徑是先跑通IP核參考設(shè)計(jì)用ILA把EAV/SAV和XYZ這幾個(gè)關(guān)鍵點(diǎn)抓到親眼看一遍數(shù)據(jù)流的組織方式然后再回頭翻協(xié)議文檔去驗(yàn)證理解。這時(shí)候原來覺得晦澀的那些章節(jié)往往會(huì)變得豁然開朗。