指南)
你打開Vivado的IP Catalog在搜索框里敲下“SelectIO”雙擊那個藍綠色圖標時屏幕前的新手和踩過坑的老工程師往往是兩種完全不同的心情。這個IP核的本質并不復雜就是把FPGA物理層的差分收發(fā)邏輯、延遲調節(jié)、串并轉換打包成一個圖形化配置工具尤其是做LVDS接口采集或者高速ADC數據接收的時候它幾乎就是繞不開的一站。我在多個7系列項目里用過這個IP核包括Artix-7和Kintex-7從最初照著別人的示例改端口到后來自己手寫約束、排查數據錯位中間翻過不少文檔也踩過不少硬件坑。這篇東西不打算做成PG182的翻譯而是從一個實際工程的角度把SelectIO IP核的配置流程、7系列LVDS的硬件要點、時序約束和調試技巧串起來講給你一條可以直接上板驗證的路。1. SelectIO IP核到底解決什么問題從手寫原語到IP核的關鍵差異1.1 為什么7系列上LVDS強烈建議走SelectIO IP核很多剛從Verilog語法學完就開始做FPGA的同學第一次接觸LVDS時想的都是“差分信號嘛IBUFDS和OBUFDS兩個原語一包不就完事了”。這個說法在低速、點對點、單向傳輸的場景下確實成立比如把一對差分信號引入內部邏輯用個IBUFDS實例化1-bit數據就出來了。但一旦數據位寬變大、速率上去問題就完全不同了。以7系列內部結構為例每個IO Bank相當于是由一系列IO Tile構成的而每個IO Tile里除了最原始的輸入輸出緩沖器之外還有ISERDES和OSERDES這種專門做串并轉換的硬核資源再加上IDELAY、ODELAY這種可以精確調節(jié)數據延遲的模擬電路。直接寫原語意味著這些資源都得自己實例化、自己接時鐘、自己管理FIFO位寬變換還要自己處理bitslip對齊邏輯工作量很容易翻倍。而SelectIO IP核做的事情就是把這一套東西在圖形界面里暴露出來你在選項里勾選一下數據位寬、時鐘模式、差分標準它自動幫你生成對應的ISERDES/OSERDES/IDELAY邏輯和約束。統(tǒng)一用IP核還有一個很重要的原因Vivado在實現階段會對IP核內部做特定優(yōu)化和約束傳遞。如果你自己手寫IBUFDSISERDES很可能漏掉IO delay相關約束或者參考時鐘連接不對結果就是時序報告看起來沒有問題硬件上抓出來的數據卻錯位、亂碼這種問題極難排查。所以我的建議是7系列做LVDS接口除非你是想寫一篇講底層原語的博客否則一律走SelectIO IP核把時間花在調試和驗證上。1.2 SelectIO和IBUFDS/OBUFDS/ISERDES/OSERDES的分工關系明白了為什么用IP核還得理解一下IP核內部到底生成了什么不然碰到自定義需求時依然無從下手。SelectIO IP核本質上是自動生成了一段RTL和XDC的封裝它的底層調用的還是Xilinx的底層原語。以接收方向為例IP核內部通常會實例化如下資源IBUFDS把外部差分P/N信號轉成內部單端信號同時也負責DIFF_TERM終端電阻的控制IDELAY對輸入數據做延遲調整延遲顆粒度由IDELAYCTRL提供的參考時鐘決定ISERDESE2把高速串行數據按照設定的串并轉換比變成并行總線BUFIO/BUFR為ISERDES提供專用的時鐘網絡BUFIO負責高速時鐘BUFR負責分頻后的并行時鐘。輸出方向則是反過來的OBUFDS、ODELAY、OSERDESE2那一套。如果你勾選了雙向接口IP核還會自動管理IO方向的使能邏輯。了解這一層之后再看到IP核配置界面里那些選項就不會懵了——你其實就是在替這些底層原語選參數只不過不用自己寫實例化代碼而已。這個認知在調試階段也特別重要。比如你發(fā)現輸入數據在某個延遲值附近能采對換到另一塊板卡上就不行了其實就是IDELAY的延遲鏈在不同溫度和電壓下發(fā)生了變化。這時候你得知道去調整IP核的延遲參數或者直接通過動態(tài)延遲接口如果開了動態(tài)延遲功能在運行時微調而不是去懷疑數據邏輯寫錯了。2. 7系列LVDS硬件基礎電壓域、終端電阻與引腳約束2.1 HP bank和HR bank第一步就要確認VCCO配置IP核之前先看一眼原理圖上這個FPGA引腳落在了哪個Bank這是很多初學者最容易忽略的一步。7系列里的Bank分成兩類HPHigh Performancebank和HRHigh Rangebank。HP bank的IO電壓最高支持到1.8V適合高速接口LVDS這種低壓差分信號天生就是為HP bank準備的HR bank則可以支持到3.3V低電壓支持到1.2V左右。SelectIO IP核里選擇LVDS標準時一般會看到LVDS和LVDS_25兩個選項對應的VCCO要求分別是1.8V和2.5V。如果你在VCCO為1.8V的HP bank上做LVDS就選LVDS標準如果在2.5V的bank上做就選LVDS_25。還有一種叫LVDSEXT的擴展擺幅模式適合更長距離的傳輸但普通板級差分互連基本用不上。我遇到過不止一次這種情況原理圖明明畫的是LVDS接口結果對應Bank的VCCO因為同時接了別的電平信號被設計成了3.3V。這種時候LVDS根本沒法正常工作因為LVDS的共模電壓在1.2V左右擺幅才350mV上下3.3V的輸入緩沖器根本沒法正確判斷這種電平。所以拿到一塊新板子第一件事永遠是打開原理圖逐個Bank核對VCCO和接口標準是否匹配這個習慣能省下后面一整周的調試時間。2.2 LVDS終端電阻內部DIFF_TERM和外置100歐的取舍LVDS是電流驅動的差分信號接收端必須有一個100歐姆的差分終端電阻把電流轉成電壓否則信號反射會造成嚴重損傷。這個終端電阻可以放在片外也可以直接用FPGA內部的DIFF_TERM選項。SelectIO IP核配置界面上有一個很顯眼的選項叫DIFF_TERM勾上之后IP核會在約束文件里自動加上set_property DIFF_TERM TRUE。對于普通的板內LVDS傳輸內部終端電阻足夠好用好處是省掉兩顆電阻布局面積也小。需要注意內部這個電阻是弱終端嗎并不是實際上7系列內部大約就是100歐姆左右的差分阻抗和規(guī)范要求一致。但我個人習慣是如果這個LVDS接口要跨板連接比如經連接器連接到另一個單板或者鏈路長度比較長我會在接收端靠近FPGA引腳的地方放一對物理電阻用作終端。原因很簡單檢測和替換都方便。內部DIFF_TERM在高低溫下可能有微小波動而且它消耗的功耗也比預期要高一點。究竟是內部還是外部歸根結底是SI信號完整性設計和成本之間的權衡。如果你只是調試一個短距離ADC采樣板開內部終端就夠了如果你是做背板互聯建議老老實實把外部100歐焊上。2.3 引腳約束差分Pin和Pin assignment的實操細節(jié)在Vivado里約束差分引腳有個很容易踩的坑就是有些新手會試圖在XDC里分別給P端和N端寫兩行PACKAGE_PIN約束Vivado并不會直接報錯但實現后你會發(fā)現N端方向有時變得不對或者差分標準被警告覆蓋。正確的做法是只對P端指定封裝引腳并給整個端口對port pair設置IO標準。舉個例子如果項目里有LVDS輸入信號adc_d_p和adc_d_n、adc_clk_p和adc_clk_nXDC可以這樣寫set_property PACKAGE_PIN K20 [get_ports adc_d_p] set_property PACKAGE_PIN K21 [get_ports adc_d_n] set_property IOSTANDARD LVDS_25 [get_ports adc_d_p] set_property DIFF_TERM TRUE [get_ports adc_d_p]如果你用了SelectIO IP核IP核生成的端口名一般是data_in_from_pins_p和data_in_from_pins_n這種格式依次類推還要約束clk_in_p/form_clk_n。差分對需要保證P/N連到物理上相鄰的引腳對通常叫P與N是互補的。Vivado在做引腳規(guī)劃時會在Device視圖里把你選中的兩個引腳用顏色標注出來如果N端和P端不在同一個差分對里實現會直接報錯。把引腳約束搞定之后下一步才能真正進入IP核的圖形化配置。3. Vivado中SelectIO IP核的完整配置步驟與參數詳解3.1 打開IP Catalog并創(chuàng)建SelectIO IP核實例在Vivado的Flow Navigator里點IP Catalog搜索SelectIO能看到一個叫“SelectIO Interface”的IP核直接雙擊。在彈出的對話框中先給IP核起一個名字比如lvds_rx_1to8然后會進入它的配置界面。版本方面7系列用Vivado 2019.1到2022.2都遇到過不同小版本的界面排布略有區(qū)別但核心選項基本沒有變化。值得注意的是Vivado對7系列支持一直保持得很好即使比較新的版本也能直接生成7系列IP核不需要像某些專用IP那樣擔心授權問題。SelectIO IP核在Vivado里是直接可用的不需要額外license。打開的配置界面里首先要選擇接口方向。如果你要接ADC的LVDS輸出選Input如果要把并行數據發(fā)送給后級DAC或SerDes芯片選Output如果是類似并口轉LVDS再加上回讀信號這種場景可以選Bidirectional不過雙向模式下集成電路引腳復用會變得復雜建議按需選擇。3.2 配置頁關鍵選項逐項拆解第一個要決定的是串行化系數也就是Serialization Factor。這個系數代表每個物理LVDS引腳對應內部并行數據的位寬。7系列的ISERDESE2天然支持1:2的SDR、1:4的DDR以及1:6、1:8等模式。選系數時要考慮你的數據速率和FPGA內部邏輯時鐘能否匹配上。舉個例子LVDS時鐘是100MHz DDR模式數據速率是200Mbps如果你選1:4串并轉換那么內部并行總線時鐘就是50MHz這個頻率對于普通邏輯處理很舒服。如果你選1:8內部時鐘降到25MHz但每個引腳數據位寬變成8bit總線面積也翻倍。我一般會優(yōu)先選1:4或1:8因為這兩個數值對外部數據對齊和內部FIFO拼接都比較友好1:10、1:14這些系數雖然IP核也支持但意味著內部需要額外的級聯邏輯時序收斂難度會上升。接下來是Data Rate的選擇。一般如果外部接口是DDR上升沿和下降沿都采樣就選DDR如果是SDR就選SDR。實際做ADC采集時絕大部分LVDS接口都是DDR因為DDR可以在相同時鐘頻率下把吞吐翻倍這也是LVDS接口常見用法。時鐘模式里還有個選項是“Use Clock Forwarding”之類的意思是是否將接收到的源同步時鐘轉發(fā)輸出如果后級還接了別的FPGA或者芯片需要同一個參考時鐘可以考慮勾選但一般用不到。關鍵選項里還有Delay Control類比如Reference Clock頻率。IP核內部IDELAY/ODELAY需要IDELAYCTRL提供一個參考時鐘這個參考時鐘的頻率直接決定了延遲鏈的單步精度。7系列的IDELAYCTRL要求參考時鐘范圍是190MHz~210MHz常見的就是200MHz可以在IP核的Delay Reference Clock里填200。這里有個重要細節(jié)這路參考時鐘必須是真實、穩(wěn)定、無毛刺的時鐘很多工程把這路時鐘和普通邏輯時鐘共用結果因為毛刺導致延遲鏈完全不工作排查起來非常頭痛。建議單獨用一個全局時鐘資源或者從差分引腳直接接一個干凈的200M晶振進去。另一個值得說明的選項是TEACH Pattern。SelectIO IP核支持一個“TEACH”功能大致意思是你可以提供一個已知的輸入訓練序列IP核會在硬件上自動搜索最佳的延遲設置。這個功能對8B/10B類接口或者有前導碼的ADC鏈路非常實用但如果是普通無訓練序列的數據流就只能在配置里先設置初始延遲值再通過硬件調試去手動調整。我自己的項目里通常先把TEACH關掉用固定延遲把鏈路打通之后再看是否需要開TEACH提高魯棒性。開啟TEACH后需要在配置里額外指定參考Pattern和通道數量IP核會生成對應的控制邏輯。3.3 生成IP后的工程集成與端口連接所有參數配置完成后點擊Generate生成IP核之后在工程里就能看到生成的示例例化模板。有一個習慣值得養(yǎng)成把生成的示例文件打開看一眼尤其是頂層端口注釋里對每個信號的說明。IP核生成后可以在Sources面板里點開IP核的Instantiation TemplateVivado會自動生成一個HDL例化模板。直接把模板端口復制到自己的模塊里例化不容易漏信號。如果是Input方向端口一般類似下面這種寫法不同配置下端口名可能略有差異lvds_rx_1to8 u_lvds_rx ( .data_in_from_pins_p (adc_d_p), .data_in_from_pins_n (adc_d_n), .data_in_to_device (adc_data_parallel), .clk_in_p (adc_clk_p), .clk_in_n (adc_clk_n), .clk_out (clk_parallel), .bitslip (bitslip_ctrl), .io_reset (io_reset), .delay_refclk (clk_200m), .delay_locked (delay_locked) );注意io_reset要接一個高有效的復位信號建議在系統(tǒng)時鐘穩(wěn)定之后至少再等幾百微秒釋放不要直接和全局復位綁在一起。delay_locked信號是延遲鏈鎖定指示上板調試時一定要接到ILA里監(jiān)控如果這個信號一直拉低那大概率是delay_refclk沒進來或者頻率不對排查方向就有了。bitslip這個信號在非對齊場景下極為關鍵后面時序約束那一章會專門說。Output方向的端口則是data_out_to_pins_p/n、data_out_from_device、clk_out這類整體思路一致。4. LVDS接口的時序約束與數據對齊方法4.1 時鐘約束input clock和data clock的關系SelectIO IP核能自動生成一部分約束但并不會自動幫你約束外部引腳到FPGA引腳的時序關系這部分需要自己在XDC里用set_input_delay和set_output_delay補全。否則Vivado雖然能跑通但時序報告里input delay默認是0測出來結果對不上現實情況。以源同步LVDS輸入為例假設ADC輸出的LVDS數據時鐘頻率是200MHz數據在DDR模式下相對于時鐘邊沿的關系是上升沿對應奇數位下降沿對應偶數位數據在時鐘邊沿上變化。也就是所謂中心對齊或邊沿對齊需要根據ADC數據手冊里的時序參數來算。一般ADC數據手冊會給tcoclock to output delay范圍?;谶@個范圍可以計算create_clock -name adc_clk -period 5.000 [get_ports adc_clk_p] # 假設tco_min -1.5ns, tco_max 1.5ns 相對于的是時鐘的某個邊沿 set_input_delay -clock adc_clk -max 1.5 [get_ports adc_d_p] set_input_delay -clock adc_clk -min -1.5 [get_ports adc_d_p]DDR模式下還要用-clock_fall補充下降沿的約束這里要分兩條分別寫。如果偷懶只約束上升沿時序分析的結果就不完整硬件上偶爾采錯位就很正常了。我第一次做這類約束時不理解為什么要把min設成負數后來才明白這是用來描述數據在時鐘邊沿之前就發(fā)生變化的時間窗口負值對應的是數據提前翻轉的情況。更省事的辦法是直接用IP核內部的輸入延遲接口比如在配置里開了動態(tài)延遲功能然后在硬件里以固定步長掃描延遲值看哪個區(qū)間出數穩(wěn)定。這種方式對信號完整性好但約束依然不可少因為時序工具需要知道延遲鏈之外的外部路徑時間。4.2 數據對齊Bitslip、TEACH與延遲調整LVDS接收里最令人頭疼的往往不是時序約束而是數據在串并轉換之后錯位。你可以想象一下發(fā)送端按1:8把并行數據變成串行流送過來接收端的ISERDES從任意一個比特位置開始拼并第一次拼出來的8bit大概率不是原來發(fā)送端那個字節(jié)邊界里的8bit。你的并行數據和鏈路建立的初始相位之間差了一個偏移這個偏移可能是0到7個bit之間的任意值。解決這個問題的機制就是bitslip。SelectIO IP核的Input方向幾乎一定會生成一個bitslip端口每拉高一拍ISERDES的并行輸出數據就被移位一個bit。基于這個原理我常用的對齊方法是發(fā)送端先發(fā)送一個已知的8bit或16bit訓練碼比如常見的0x5A或者0x3C然后接收端用狀態(tài)機檢測并行數據是否等于期望值不相等就拉一次bitslip直到相等為止。筆者的一個項目中曾用這種方式在1ms內完成了8路LVDS通道的自動對齊原理就是每個通道獨立檢測訓練碼收到后再實時Insight整個邏輯代碼量也不大。如果不想自己寫狀態(tài)機也可以利用IP核的TEACH功能它本質上也是在硬件上實現類似掃描只是自定義程度不如自己寫控制邏輯高。個人經驗是訓練碼方式更透明可控TEACH適合那種鏈路特別多、自己寫狀態(tài)機容易出錯的場景。對齊完成后如果發(fā)現某個通道偶爾誤碼可以考慮延遲值的動態(tài)微調。開了動態(tài)延遲功能后RTL里可以通過一個總線把延遲值設置寫入IP核也可以用ILA在線調試時直接改輸入直到眼圖中央落在采樣點上。7系列的IDELAY單步分辨率大約是幾十皮秒實際調節(jié)的時候每步效果可能并不明顯但多調幾步就能看到邊界這個過程本質上就是板級“找眼圖中央”的數字化實現。5. 工程調試實錄常見報錯、信號質量與排錯速查表5.1 最典型的DRC/實現報錯DRC RTSTAT-2這個報錯在搜索熱詞里都出現了含義是某個信號的邏輯連接不是最優(yōu)。Vivado對IP核接口如果連接了不合適的邏輯比如IO輸出直接進了普通LUT而不是IO資源就會報這種錯誤。排查時回到原理圖和約束文件確認IP核的引腳連接肯定是對應的物理引腳并且沒有經過額外的組合邏輯。Bank VCCO mismatch如果你在VCCO3.3V的bank上選了LVDS_25或者反過來在VCCO1.8V的bank上選了LVDS_25Vivado會在實現時給出警告甚至直接報錯說IOSTANDARD和bank電壓不匹配。這時候不是改約束就完事而是要從原理圖層面確認這個bank的供電到底是多少曾經有人把XDC里的IOSTANDARD改成IBUF_NOT_DIFF去繞過檢查結果硬件啥反應都沒有。Bitslip/FIFO Overflow一定概率上板后ILA里看到數據顯示其實正確但內部FIFO或者狀態(tài)機偶爾報溢出。這不是IP核的問題而是你的內部邏輯時鐘和并行數據時鐘不是同一個時鐘域跨時鐘域處理沒做對。建議把ILA的采樣時鐘直接接在IP核輸出的clk_out上先排除跨時鐘域因素。5.2 信號完整性問題和硬件排查實錄LVDS調試還有個特點邏輯上全對物理上全錯。所謂物理上全錯主要是信號質量相關最典型的場景就是用內部DIFF_TERM時人眼看到ILA數據偶爾會跳變但示波器探針能測到振鈴和過沖。這種問題在短距離幾厘米到幾十厘米通常不嚴重但線纜稍長或者PCB層疊走線有問題就麻煩了。判斷到底是FPGA內部問題還是外部信號問題最直接的辦法是寫一個loopback測試把FPGA的LVDS輸出引腳用短跳線或板上走線直接連回輸入引腳然后發(fā)送PRBS數據統(tǒng)計誤碼率。如果loopback沒問題說明問題在外部器件或鏈路如果loopback都有錯那優(yōu)先檢查FPGA側的信號完整性和終端電阻。另外7系列里你可以用IBERT這個工具對一些高速收發(fā)器做眼圖掃描但普通LVDS引腳沒有專門的硬件眼圖掃描功能所以很多時候只能靠ILA抓數據和示波器看波形來交叉判斷。有一回我調試一塊ADC板ILA里看到數據低位偶爾翻轉檢查所有配置都沒發(fā)現問題最后用示波器在引腳上量到時鐘信號邊沿有很明顯的振鈴原因是PCB走線跨了一個分割的地平面。后來把地平面補完整問題就消失了。這類問題用XDC去修是修不出來的必須回到硬件設計本身。5.3 常見問題速查表現象可能原因排查建議delay_locked一直為低delay_refclk未注入或頻率不對用ILA或chipscope看參考時鐘頻率確認穩(wěn)定且為200MHz附近輸入數據全是0或全1LVDS電平標準選錯或P/N接反檢查VCCO、IOSTANDARD用示波器看P/N是否有差分波形數據能出但錯位未做bitslip對齊發(fā)送訓練碼用狀態(tài)機掃描bitslip某個通道偶爾翻轉延遲踩在數據邊沿上微調IDELAY步數或用TEACH重新訓練Vivado報DRC RTSTAT-2IP核接口連接了非預期邏輯/引腳檢查引腳約束和RTL連接高低溫下誤碼率變化延遲鏈隨溫度漂移改用動態(tài)延遲用訓練碼定期校準內部DIFF_TERM打開后功耗偏高終端電阻在傳輸時持續(xù)消耗評估鏈路長度必要時改為外部100歐電阻6. 寫在實際項目后的一些建議我這幾年用SelectIO IP核做LVDS接口總體的心得是這個IP核只是把底層原語封裝得很好但它不能替代硬件設計層面的思考。VCCO匹配、差分對引腳成對、終端電阻位置、參考時鐘干凈、訓練碼對齊這些才是決定一個LVDS鏈路能不能穩(wěn)定工作的基本盤。配置界面上點幾下鼠標永遠是最快的部分真正花時間的是后面的約束和調試驗證。最后分享一個實際操作上的小訣竅頭一次調LVDS時BITSLIP狀態(tài)機不要做太復雜先手動在ILA的VIO里逐個拉高bitslip觀察并行數據的變化規(guī)律確認每個通道對bitslip的響應和預期一致再寫自動對齊邏輯。這樣既能把訓練碼邏輯錯誤和物理連接問題分開定位也能讓你更快理解bitslip的影響機制。7系列的老架構雖然不像UltraScale那么花哨但勝在資料多、夠穩(wěn)定好好理解了這套LVDS實現路徑后面切任何平臺都會輕松很多。