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