來源:數字站
前面在講解HDMI接口之前,講解過IDDR、ODDR、OSERDESE2、IBUF等原語,之后一直有讀者在問什么時候更新ISERDESE2這個原語。前文講解過這些原語都在HDMI或者RGMII中使用過,但是ISERDESE2這個原語目前我的板子除了HDMI輸入,其余并不會使用到,所以當時就沒有出。
最近在網上看并沒有用戶對ISERDESE2的使用講解的很清晰,所以本文就通過手冊、仿真和ILA去講解一下這個原語的使用方式,希望對大家的使用有所幫助。
01ISERDESE2的功能
ISERDESE2就是一個串并轉換的模塊,支持單沿或者雙沿傳輸數據,其實ISERDESE2和IDDR使用的是同一個器件,所以均有雙沿轉單沿的功能,這可以在vivado綜合后的布局布線中查看,也是同一管腳輸入的信號不能同時使用IDDR和ISERDESE2的原因。
理想情況如下圖所示,并行輸出的數據就剛好被ISERDESE2采集,進而完成串并轉換,然而真實情況是這樣嗎?
圖1 理想情況串并轉換
由于器件上電和初始化等等原因,實際的情況更可能如下圖所示,并串轉換模塊工作時,串并轉換模塊還沒有工作,導致并串轉換模塊輸出的前幾個數據丟失,下圖中前面黑框中三個串行數據丟失。
此時串并轉換模塊就只能從后面黃色框中依次取八個數據進行轉換,由此轉換出的數據會是正常的數據?
顯然不是,因此在串并轉換模塊正常工作的初期,往往需要對轉換后的數據進行判斷,如果轉換后的數據不對,則需要將ISERDESE2轉換的起始位置更改,直到轉換后的數據正確為止,之后數據的數據才是有效的。
這個校準的過程需要用戶通過ISERDESE2的BITSLIP引腳去完成,在校準的過程中,輸入端必須一直循環輸入一個校準序列,就像下圖中一直輸入8’h5c和8’h82組成的序列一樣,這是相對于其他原語會難一點的地方。
圖2 真實情況串并轉換
通過上面知道了ISERDESE2原語需要解決的問題后,下面就通過手冊講解原語的各個端口以及參數,后面通過仿真驗證前面所說的原因。
02 ISERDESE2原語端口及參數
PART2.1
ISERDESE2端口信號
下圖是ISERDESE2的框圖。
圖3 ISERDESE2框圖
Q1~Q8:ISERDESE2模塊的并行輸出數據,其中Q8是最先輸入的串行數據位。一個ISERDESE2塊最多輸出8位并行數據,在DDR雙沿采樣模式下,兩個ISERDESE2塊級聯可以輸出10位和14位并行數據。
Q8是接收到的最低位數據,如下圖所示,OSERDESE2將8位從高到低為HGFEDCBA的并行數據轉換為串行數據輸出,最先輸出最低位D1的值A。當ISERDESE2塊接收串行數據時,Q1出現最高位,Q8出現最低位。
圖4 ISERDESE2接收數據
端口O:由圖3知,該端口直接連接到串行輸入的幾個端口,并沒有經過ISERDESE2核心邏輯,可以把D或DDLY的數據直接輸出。
SHIFTIN1、SHIFTIN2、SHIFTOUT1和SHIFTOUT2與OSERDESE2中該信號的原理一致,都是在兩個OSERDESE2級聯的時候,把從OSERDESE2的SHIFTOUT與主OSERDESE2的SHIFTIN連接。
ISERDESE2的輸入可以來自FPGA的管腳,即D端輸入信號。也可以來自IDELAYE2的輸出,即DDLY端口作為輸入。還可以來自OSERDESE2的輸出,即OFB作為輸入,與OSERDESE2連接方式如下所示,兩個器件的OFB信號相連即可。
圖5 ISERDESE2與OSERDESE2連接
ISERDESE2與OSERDESE2連接時需要添加“OFB_USED = TRUE ”屬性,并且ISERDESE2和OSERDESE2的DATA_RATE、DATA_WIDTH參數必須設置一致。
高速時鐘輸入CLK,與串行數據流對齊。
輔助時鐘輸入CLKB,在MEMORY_QDR模式下,CLKB應連接到唯一的相移時鐘,其余模式下,CLKB連接到CLK取反信號。
分頻時鐘CLKDIV,用于驅動串并轉換器、Bitslip子模塊和CE模塊的輸出,與輸出的并行數據對齊。
在SDR模式下,如果輸出的X位并行數據,那么CLKDIV的頻率是CLK頻率的1/X,如果是DDR模式,則CLKDIV的頻率是CLK頻率的2/X。
手冊要求CLK和CLKDIV的相位必須對齊,一般推薦兩種連接方式,一種如下所示,時鐘輸入管腳通過BUFIO之后直接作為串行輸入數據的時鐘信號,BUFIO優點就是路徑短,延時小,缺點就是只能驅動當前時鐘區域的IDDR和ISERDESE2的時鐘管腳。而并行時鐘需要通過BUFR進行分頻,分頻系數根據并行數據位寬和工作模式確定。
關于BUFIO和BUFR的相關使用,可以查看前文關于時鐘資源相關原語的講解,清晰講解過BUFG、BUFIO、BUFR、BUFH、BUFMR的使用。
圖6 時鐘推薦
另一種就是通過同一個MMCM產生CLK和CLKDIV兩路時鐘信號,這種方式更常用。原因是BUFIO和BUFR需要用戶提供高頻串行時鐘,如果需要幾百M的串行時鐘,顯然用戶的外部晶振一般是無法提供的。
時鐘使能CE1和CE2,與參數NUM_CE的值有關。當NUM_CE為1時,使用CE1作為時鐘使能信號。當NUM_CE為2時,當CLK_DIV為低電平時,CE2作為時鐘使能信號,當CLK_DIV為高電平時,CE1作為時鐘使能信號,對應真值表如下圖所示。
圖7 輸入時鐘使能模塊
BITSLIP引腳在高電平時執行與CLKDIV同步的移位操作,后文詳解。
RST復位信號,高電平有效,推薦退出復位時間與CLKDIV同步。
過采樣模式時鐘OCLK,僅當INTERFACE_TYPE設置不為NETWORKING,才會使用OCLK時鐘。
PART2.2
ISERDESE2原語參數
上述就是ISERDESE2原語相關的端口信號,下面講解ISERDESE2原語的參數。
DATA_RATE用于設置ISERDESE2工作模式,可選擇單沿工作模式(SDR)和雙沿工作模式(DDR),默認DDR模式。
DATA_WIDTH用于設置輸出并行數據位寬,取決于DATA_RATE和INTERFACE_TYPE的設置。如下圖所示,SDR模式下可以設置為2、3、4、5、6、7、8。DDR模式下單個ISERDESE2塊只能設置為4、6、8,兩個ISERDESE2塊級聯可以設置為10、14。
圖8 支持的數據寬度
INTERFACE_TYPE參數決定ISERDESE2是配置為內存模式還是網絡模式??蛇x的值有MEMORY、MEMORY_DDR3、MEMORY_QDR、OVERSAMPLE、NETWORKING,默認模式是MEMORY,常用NETWORKING模式。
NUM_CE參數定義使用的時鐘使能(CE1和CE2)數量,可設為1和2(默認值為2)。
OFB_USED參數使能從OSERDESE2的OFB引腳到ISERDESE2 OFB引腳的路徑,禁用外部管腳輸入D和IDELAYE2的輸入DLY。
當使用DDR模式進行10位或者14位并行數據轉換時,需要將兩個模塊級聯,此時需要通過參數SERDES_MODE確定哪個是主ISERDESE2,哪個是從ISERDESE2。
INIT_Qn用于設置第n個采樣寄存器的初始值,而SRVAL_Qn用于設置復位第n個采樣寄存器后的值。
由圖3知D和DDLY都是ISERDESE2的專用輸入,D直接連接到IOB(直接與管腳相連),DDLY直接連接到IDELAYE2(在ISERDESE2和管腳之間有IDELAYE2加入延遲)。
允許用戶把延遲或非延遲的外部管腳輸入信號作為ISERDESE2輸入,通過參數IOBDELAY確定D和DDLY哪個作為ISERDESE2的輸入,下圖是IOBDELAY參數與輸入信號的關系,經常設置位NONE,將外部管腳信號作為ISERDESE2串行數據輸入。
圖9 IOBDELAY參數值
03位滑塊(BITSLIP)
這個信號就是進行校準的關鍵信號,如果沒有這個信號,那么ISERDESE2的輸出數據其實沒有意義,很大可能是錯誤的。
通過拉高ISERDESE2模塊的Bitslip信號,輸入的串行數據流在并行端重新排序,Bitslip與CLKDIV同步。
下圖說明了SDR和DDR模式下位滑移操作對數據采樣的影響,ISERDESE2的數據寬度是八。在SDR模式下,每次Bitslip拉高都會導致輸出數據左移一位。在DDR模式下,每次Bitslip拉高都會導致輸出數據在右移1位和左移3位之間交替變化。
圖10 位滑移操作示例
上述操作其實可以看成下圖所示的操作,上電后因為初始化結束比較晚等原因,ISERDESE2錯過了下圖黑框中前三位數據的采集時刻,從紅框處開始取數據進行轉換。
圖11 采集數據
轉換結果為8’he4,并不是8’h5c或者8’h82,此時將Bitslip拉高一個CLKDIV時鐘周期,則ISERDESE2會將下次采集數據的位置向后移動一位,如下圖所示。
本來第二次轉換應該從下圖中天藍色方框開始,因為Bitslip拉高一個時鐘,就會將開始位置向后移動一位,從紅框處開始轉換,轉換結果繼續與目標結果對比,如果不是,則繼續拉高Bitslip,直到ISERDESE2的輸出是8’h5c或者8’h82為止。
圖12 采集數據
其實用戶并不需要關心Bitslip為高電平后,SDR和DDR模式下,輸出數據怎么移動,只需要在這段校準的時間內保證輸入串行數據一直都是8’h5c或者8’h82即可,然后去檢測ISERDESE2的輸出是不是8’h5c或者8’h82,不是則拉高Bitslip將轉換開始的位置移動,直到找到開始轉換的位置為止。
只有當ISERDESE2處于網絡模式(NETWORKING)下,位滑塊(BITSLIP)才可用。Bitslip每次只能拉高一個CLKDIV周期,不能在兩個CLKDIV周期內連續拉高Bitslip信號。
在SDR和DDR模式下,從ISERDESE2檢測到Bitslip的高電平開始,到ISERDESE2把Bitslip移動后的數據輸出到Q1–Q8引腳為止,延遲時間為兩個CLKDIV周期。
在分析接收到的數據模式并可能發出下一個Bitslip命令之前,用戶邏輯應在SDR模式下等待至少兩個CLKDIV周期,在DDR模式下等待至少三個CLKDIV周期。
綜上Bitslip拉高后,需要等待至少三個時鐘周期,才能檢測并行輸出結果是否與預期一致,進而確定是否通過拉高Bitslip信號繼續調整輸出。
下圖是4位并行數據的DDR模式下Bitslip的時序圖,數據(D)重復的4位串行數據ABCD。ABCD可能以四種方式出現在ISERDESE2的Q1–Q4并行輸出端:ABCD、BCDA、CDAB和DABC,只有ABCD才是正確的輸出。
拉高Bitslip信號選擇所需的對齊方式(ABCD),下圖顯示了Bitslip的時序以及ISERDESE2并行輸出Q1–Q4的校準時序。
圖13 DDR Bitslip功能圖
注意上圖在Bitslip拉高后的第三個時鐘,Q4-Q1才輸出移位后的轉換結果,與前文的延時一致。
04代碼設計
本文利用OSERDESE2和ISERDESE2回環,來驗證前文所講ISERDESE2和Bitslip的功能。ISERDESE2采用網絡模式(NETWORKING),選擇DDR的串行采樣方式,并行數據位寬為8位。
OSERDESE2相關模塊如下圖所示,用于產生測試的并行數據,然后轉換為串行數據,對應代碼如下所示。
通過一個計數器cnt,上電后前64個時鐘周期用于產生用于校準的序列,為8’h5c和8’h82交替發送的串行序列。當校準序列發送完畢后,通過m序列生成偽隨機數據用于測試。
//--############################################################################################### //--# //--# File Name : oserdese2_ctrl //--# Designer : 數字站 //--# Tool : Vivado 2021.1 //--# Design Date : 2024.4.4 //--# Description : 并串轉換數據生成模塊; //--# Version : 0.0 //--# Coding scheme : GBK(If the Chinese comment of the file is garbled, please do not save it and check whether the file is opened in GBK encoding mode) //--# //--############################################################################################### module oserdese2_ctrl( input clk ,//系統時鐘信號; input clk_div , input rst ,//系統復位信號,高電平有效; output ofb //直連iserdese2的OFB管腳。 ); reg flag ;// reg [7:0] cnt ;// reg [7:0] din ;// //輔助生成測試信號; always@(posedge clk_div)begin if(rst)begin//初始值為0; flag<=?1'b0; ? ? ? ? end ? ? ? ??else?begin ? ? ? ? ? ? flag?<=?~flag; ? ? ? ? end ? ? end ? ?? ? ??//用于對校準序列個數進行計數。 ? ? always@(posedge clk_div)begin ? ? ? ??if(rst)begin//初始值為0; ? ? ? ? ? ? cnt?<=?'d0; ? ? ? ? end ? ? ? ??else?if(&cnt)begin ? ? ? ? ? ? cnt?<=?cnt; ? ? ? ? end ? ? ? ??else?begin ? ? ? ? ? ? cnt?<=?cnt?+?1; ? ? ? ? end ? ? end ? ??//生成用于校準的循環數據; ? ? always@(posedge clk_div)begin ? ? ? ??if(rst)begin//初始值為0; ? ? ? ? ? ? din?<=?8'h82; ? ? ? ? end ? ? ? ??else?if(&cnt)begin//如果校準序列發送完畢,則發送偽隨機信號用于測試。 ? ? ? ? ? ? din?<=?{(din[0]?^?din[4]?^?din[5]?^?din[6]),din[7:1]};//M序列公式為x^8+x^4+x^3+x^2+1。 ? ? ? ? end ? ? ? ??else?if(flag)begin//發送校準序列8'h5c; ? ? ? ? ? ? din?<=?8'h5c; ? ? ? ? end ? ? ? ??else?begin//發送校準序列8'h82. ? ? ? ? ? ? din?<=?8'h82; ? ? ? ? end ? ? end ? ??//例化主OSERDESE2原語 ? ??OSERDESE2?#( ? ? ? ? .DATA_RATE_OQ? ?(?"DDR"? ? ?),// DDR, SDR ? ? ? ? .DATA_RATE_TQ? ?(?"DDR"? ? ?),// DDR, BUF, SDR ? ? ? ? .DATA_WIDTH? ? ?(?8? ? ? ? ?),// Parallel data width (2-8,10,14) ? ? ? ? .INIT_OQ? ? ? ? (?1'b0 ? ? ?),// Initial value of OQ output (1'b0,1'b1) ? ? ? ? .INIT_TQ? ? ? ? (?1'b0 ? ? ?),// Initial value of TQ output (1'b0,1'b1) ? ? ? ? .SERDES_MODE? ? (?"MASTER"? ),// MASTER, SLAVE ? ? ? ? .SRVAL_OQ? ? ? ?(?1'b0 ? ? ?),// OQ output value when SR is used (1'b0,1'b1) ? ? ? ? .SRVAL_TQ? ? ? ?(?1'b0 ? ? ?),// TQ output value when SR is used (1'b0,1'b1) ? ? ? ? .TBYTE_CTL? ? ? (?"FALSE"? ?),// Enable tristate byte operation (FALSE, TRUE) ? ? ? ? .TBYTE_SRC? ? ? (?"FALSE"? ?),// Tristate byte source (FALSE, TRUE) ? ? ? ? .TRISTATE_WIDTH?(?1? ? ? ? ?)?// 3-state converter width (1,4) ? ? ) ? ??OSERDESE2_inst?( ? ? ? ? .OFB? ? ? ? ( ofb ? ? ? ? ? ),// 1-bit output: Feedback path for data ? ? ? ? .OQ? ? ? ? ?( ? ? ? ? ? ? ? ),// 1-bit output: Data path output ? ? ? ??// SHIFTOUT1 / SHIFTOUT2: 1-bit (each) output: Data output expansion (1-bit each) ? ? ? ? .SHIFTOUT1? ( ? ? ? ? ? ? ? ), ? ? ? ? .SHIFTOUT2? ( ? ? ? ? ? ? ? ), ? ? ? ? .TBYTEOUT? ?( ? ? ? ? ? ? ? ),// 1-bit output: Byte group tristate ? ? ? ? .TFB? ? ? ? ( ? ? ? ? ? ? ? ),// 1-bit output: 3-state control ? ? ? ? .TQ? ? ? ? ?( ? ? ? ? ? ? ? ),// 1-bit output: 3-state control ? ? ? ? .CLK? ? ? ? ( clk ? ? ? ? ? ),// 1-bit input: High speed clock ? ? ? ? .CLKDIV? ? ?( clk_div ? ? ? ),// 1-bit input: Divided clock ? ? ? ??// D1 - D8: 1-bit (each) input: Parallel data inputs (1-bit each) ? ? ? ? .D1? ? ? ? ?( din[0] ? ? ? ?), ? ? ? ? .D2? ? ? ? ?( din[1] ? ? ? ?), ? ? ? ? .D3? ? ? ? ?( din[2] ? ? ? ?), ? ? ? ? .D4? ? ? ? ?( din[3] ? ? ? ?), ? ? ? ? .D5? ? ? ? ?( din[4] ? ? ? ?), ? ? ? ? .D6? ? ? ? ?( din[5] ? ? ? ?), ? ? ? ? .D7? ? ? ? ?( din[6] ? ? ? ?), ? ? ? ? .D8? ? ? ? ?( din[7] ? ? ? ?), ? ? ? ? .OCE? ? ? ? (?1'b1 ? ? ? ? ?),// 1-bit input: Output data clock enable ? ? ? ? .RST? ? ? ? ( rst ? ? ? ? ? ),// 1-bit input: Reset ? ? ? ??// SHIFTIN1 / SHIFTIN2: 1-bit (each) input: Data input expansion (1-bit each) ? ? ? ? .SHIFTIN1? ?( ? ? ? ? ? ? ? ), ? ? ? ? .SHIFTIN2? ?( ? ? ? ? ? ? ? ), ? ? ? ??// T1 - T4: 1-bit (each) input: Parallel 3-state inputs ? ? ? ? .T1? ? ? ? ?(?1'b0 ? ? ? ? ?), ? ? ? ? .T2? ? ? ? ?(?1'b0 ? ? ? ? ?), ? ? ? ? .T3? ? ? ? ?(?1'b0 ? ? ? ? ?), ? ? ? ? .T4? ? ? ? ?(?1'b0 ? ? ? ? ?), ? ? ? ? .TBYTEIN? ? (?1'b0 ? ? ? ? ?),// 1-bit input: Byte group tristate ? ? ? ? .TCE? ? ? ? (?1'b0 ? ? ? ? ?) ?// 1-bit input: 3-state clock enable ? ? ); endmodule
為了方便后續上板測試,OSERDESE2的串行輸出信號和ISERDESE2串行輸入信號采用OFB直連,不需要經過IOB,直接在芯片內部進行回環。
之后是ISERDESE2模塊,對應的原語調用如下所示,采用DDR雙沿采集數據模式,啟用OFB作為串行輸入,將輸出Q8-Q1順序調換,使得ISERDESE2輸出并行數據與OSERDESE2并行輸入數據保持一致。
//例化主ISERDESE2原語 ISERDESE2#( .DATA_RATE ("DDR" ),//DDR, SDR .DATA_WIDTH (8 ),//Parallel data width (2-8,10,14) .DYN_CLKDIV_INV_EN ("FALSE" ),//Enable DYNCLKDIVINVSEL inversion (FALSE, TRUE) .DYN_CLK_INV_EN ("FALSE" ),//Enable DYNCLKINVSEL inversion (FALSE, TRUE) .INIT_Q1 (1'b0 ),// INIT_Q1 : Initial value on the Q outputs (0/1) .INIT_Q2 ( 1'b0 ),//INIT_Q2 : Initial value on the Q outputs (0/1) .INIT_Q3 (1'b0 ),// INIT_Q3 : Initial value on the Q outputs (0/1) .INIT_Q4 ( 1'b0 ),//INIT_Q4 : Initial value on the Q outputs (0/1) .INTERFACE_TYPE ("NETWORKING" ),//MEMORY, MEMORY_DDR3, MEMORY_QDR, NETWORKING, OVERSAMPLE .IOBDELAY ("NONE" ),//NONE, BOTH, IBUF, IFD .NUM_CE (2 ),//Number of clock enables (1,2) .OFB_USED ("TRUE" ),//Select OFB path (FALSE, TRUE) .SERDES_MODE ("MASTER" ),//MASTER, SLAVE .SRVAL_Q1 (1'b0 ),// SRVAL_Q1 : Q output values when SR is used (0/1) .SRVAL_Q2 ( 1'b0 ),//SRVAL_Q2 : Q outputvalueswhenSR is used (0/1) .SRVAL_Q3 (1'b0 ),// SRVAL_Q3 : Q output values when SR is used (0/1) .SRVAL_Q4 ( 1'b0 ) // SRVAL_Q4 : Q outputvalueswhenSR is used (0/1) ) ISERDESE2_inst ( .O ( ),//1-bit output: Combinatorial output .Q1 (q[7] ),//Q1 - Q8:1-bit (each) output: Registered data outputs .Q2 (q[6] ), .Q3 (q[5] ), .Q4 (q[4] ), .Q5 (q[3] ), .Q6 (q[2] ), .Q7 (q[1] ), .Q8 (q[0] ), .SHIFTOUT1 ( ),//SHIFTOUT1 :1-bit (each) output: Data width expansion output ports .SHIFTOUT2 ( ),//SHIFTOUT2 :1-bit (each) output: Data width expansion output ports .BITSLIP ( bitslip ),//1-bit input: The BITSLIP pin performs a Bitslip operation synchronous to // CLKDIVwhenasserted (active High). Subsequently, the data seen on the Q1 // to Q8 output ports willshift, as in a barrel-shifter operation, one // position everytimeBitslip is invoked (DDR operation is different from SDR). .CE1 (1'b1 ),// CE1: 1-bit (each) input: Data register clock enable inputs .CE2 ( 1'b1 ),//CE2:1-bit (each) input: Data register clock enable inputs .CLKDIVP (1'b0 ),// 1-bit input: TBD // Clocks: 1-bit (each) input: ISERDESE2 clock input ports .CLK ( clk ),// 1-bit input: High-speed clock .CLKB ( ~clk ),// 1-bit input: High-speed secondary clock .CLKDIV ( clk_div ),// 1-bit input: Divided clock .OCLK ( 1'b0 ),//1-bit input: High speed output clock usedwhenINTERFACE_TYPE="MEMORY" // Dynamic Clock Inversions:1-bit (each) input: Dynamic clock inversion pins to switch clock polarity .DYNCLKDIVSEL(1'b0 ),// 1-bit input: Dynamic CLKDIV inversion .DYNCLKSEL ( 1'b0 ),//1-bit input: Dynamic CLK/CLKB inversion // Input Data:1-bit (each) input: ISERDESE2 data input ports .D (1'b0 ),// 1-bit input: Data input .DDLY ( 1'b0 ),//1-bit input: Serial data from IDELAYE2 .OFB ( ofb ),//1-bit input: Data feedback from OSERDESE2 .OCLKB (1'b0 ),// 1-bit input: High speed negative edge output clock .RST ( rst ),// 1-bit input: Active high asynchronous reset // SHIFTIN1, SHIFTIN2: 1-bit (each) input: Data width expansion input ports .SHIFTIN1 ( ), .SHIFTIN2 ( ) );之后需要對ISERDESE2并行輸出進行校準,OSERDESE2產生的校準序列是8’h5c和8’h82交替串行序列,因此ISERDESE2轉換結果也應該是8’h5c或者8’h82。如果轉換結果不是這兩個數據,那么將bitslip拉高一個時鐘周期,對應代碼如下所示。
//當沒有完成校準時,如果檢測到轉換結果與要求不一致,則把該信號拉高。 always@(posedge clk_div)begin if(rst)begin//初始值為0; bitslip<=?1'b0; ? ? ? ? end//當沒有校準,且沒有處于校準階段時檢測到串并轉換結果不為8'h5c或者8'h82時拉高; ? ? ? ? else if(((q != 8'h5c)?&&?(q?!=?8'h82)) && (~slip_flag) && (~bitslip) && (~dout_vld))begin ? ? ? ? ? ? bitslip <= 1'b1; ? ? ? ??end ? ? ? ??else?begin//其余時間拉低; ? ? ? ? ? ? bitslip?<=?1'b0; ? ? ? ? end ? ? end
Bitslip拉高之后,ISERDESE2輸出數據不是立即有效的,需要經過幾個時鐘的轉換時鐘,手冊中說SDR模式需要消耗2個時鐘,而DDR模式需要消耗三個時鐘。
為了方便設計,此處直接使用一個位寬為2的計數器,每次bitslip拉高之后,等待4個時鐘,之后才對ISERDESE2的并行數據進行檢測,確定是否滿足要求,bitslip還是否需要拉高。
//滑塊計數器,因為bitslip拉高后,輸出需要經過一段時間才會有效,因此這段時間不能對輸出數據進行讀取判斷。 always@(posedge clk_div)begin if(rst)begin//初始值為0; slip_cnt<=?'d0; ? ? ? ? end ? ? ? ? else if(slip_flag)begin//對bitslip拉高后的時鐘計數。 ? ? ? ? ? ? slip_cnt <= slip_cnt + 'd1; ? ? ? ??end ? ??end ? ?? ? ??//bitslip拉高后的標志信號,初始值為0,當bitslip拉高時拉高,當slip_cnt計數器計數到最大值時清零。 ? ? always@(posedge clk_div)begin ? ? ? ? if(rst)begin//初始值為0; ? ? ? ? ? ? slip_flag?<=?1'b0; ? ? ? ? end ? ? ? ? else if(&slip_cnt)begin ? ? ? ? ? ? slip_flag <= 1'b0; ? ? ? ??end ? ? ? ??else?if(bitslip)begin ? ? ? ? ? ? slip_flag?<=?1'b1; ? ? ? ? end ? ? end
在校準階段ISERDESE2輸出可能會出現偶然結果,導致沒有校準情況下,輸出的部分并行數據與校準序列一致。為了避免這種情況,應該多次檢測連續輸出數據均與校驗數據一致時,才認為校準完成。
因此需要一個計數器,對ISERDESE2輸出的正確數據進行計數,當bitslip拉高或者處于拉高后的一段時間時,證明前面檢測到的數據錯誤,將計數器清零。
當連續檢測CNT_NUM個數據均正確時,認為校準完成,將計數器置為最大值,之后一直保持不變。
//轉換成功計數器,用于記錄校準階段,當校準階段檢測到固定個連續有效數據時,認為校準成功。 always@(posedge clk_div)begin if(rst)begin// cnt<=?0; ? ? ? ??end//當在校準階段時,當bitslip有效時拉高; ? ? ? ??else?if((slip_flag?||?bitslip)?&&?(~dout_vld))begin ? ? ? ? ? ? cnt?<=?0; ? ? ? ??end ? ? ? ??else?if(cnt?==?CNT_NUM?-?1)begin//當檢測到固定校準數據時,計數器保持該數值。 ? ? ? ? ? ? cnt?<=?CNT_NUM?-?1; ? ? ? ??end ? ? ? ??else?if(add_cnt)begin ? ? ? ? ? ? cnt?<=?cnt?+?1; ? ? ? ??end ? ??end ? ?? ? ??//當不處于移動滑塊狀態且檢測到輸出數據為規定數據時加1. ? ? assign add_cnt?=?((q?==?8'h5c) || (q == 8'h82))?&&?(~slip_flag)?&&?(~bitslip); ? ?? ? ??//將轉換后的數據輸出,只有當校準完成后,輸出有效指示信號磁能拉高,表示輸出的數據有效。 ? ? always@(posedge clk_div)begin ? ? ? ? dout?<=?q; ? ? ? ? dout_vld?<=?(cnt?==?CNT_NUM?-?1); ? ??end
之后是頂層模塊的處理,對于串行時鐘和并行時鐘的處理方式有如下兩種,第一種是本時鐘區域的外部時鐘管腳輸入串行時鐘信號,之后通過BUFIO作為ISERDESE2和OSERDESE2的串行時鐘信號。通過BUFR分頻輸出的時鐘作為ISERDESE2和OSERDESE2的并行數據時鐘信號,對應代碼如下所示。
但是這種方式仿真會出現錯誤,OSERDESE2輸出的數據始終是不定態,不知道為什么。另外要求輸入串行時鐘,然而串行時鐘一般頻率很高,用戶的晶振一般是提供不了的,因此這種方式不太常用。
//調用BUFIO; /*BUFIO u_BUFIO ( .O ( o_clk ),//1-bit output: Clock output (connectto I/O clock loads). .I ( clk ) //1-bit input: Clock input (connectto an IBUForBUFMR). ); //調用BUFR對時鐘進行分頻; BUFR#( .BUFR_DIVIDE ("4" ),//Values:"BYPASS, 1, 2, 3, 4, 5, 6, 7, 8" .SIM_DEVICE ("7SERIES" ) //Must be set to"7SERIES" ) u_BUFR ( .O ( clk_div ),//1-bit output: Clock output port .CE (1'b1 ),//1-bit input: Active high, clock enable (Divided modes only) .CLR ( 1'b0 ),//1-bit input: Active high, asynchronous clear (Divided modes only) .I ( clk ) );*/另一種時鐘處理方式是使用同一個MMCM,生成串行時鐘和并行時鐘,對于輸入時鐘頻率沒有太大要求。本文外部輸入100MHz時鐘信號作為ISERDESE2和OSERDESE2的并行時鐘信號,通過MMCM生成400MHz作為串行時鐘信號。對應代碼如下所示:
clk_wiz_0u_clk_wiz_0( .clk_out1 ( clk_div_o ),//output clk_out1 .clk_out2 (clk ),//output clk_out2 .reset (rst ),//input reset .clk_in1 (clk_div )//input clk_in1 );
MMCM的輸出配置如下所示:
圖14 MMCM輸出配置
之后頂層模塊需要例化前面兩個模塊,對應的完整代碼如下所示。
//例化并串轉換原語; oserdese2_ctrlu_oserdese2_ctrl( .clk ( clk ),//系統時鐘信號; .clk_div (clk_div_o ), .rst (rst ),//系統復位信號,高電平有效; .ofb (oserdese_ofb ) ); //例化串并轉換原語; iserdese2_ctrlu_iserdese2_ctrl( .clk ( clk ),//系統時鐘信號; .clk_div (clk_div_o ), .rst (rst ),//系統復位信號,高電平有效; .ofb (oserdese_ofb ), .dout (o_iserdese2 ),//輸出數據 .dout_vld (o_iserdese2_vld )//輸出數據有效指示信號; ); //例化ILA ila_0u_ila_0( .clk ( clk_div_o ),//input wire clk; .probe0(u_oserdese2_ctrl.din ),//input wire [7:0] probe0; .probe1(u_iserdese2_ctrl.q ),//input wire [7:0] probe1; .probe2(u_iserdese2_ctrl.dout ),//input wire [7:0] probe2; .probe3(u_iserdese2_ctrl.cnt ),//input wire [3:0] probe3; .probe4(u_iserdese2_ctrl.slip_cnt),//input wire [1:0] probe4; .probe5(u_iserdese2_ctrl.bitslip ),//input wire [0:0] probe5; .probe6(u_iserdese2_ctrl.slip_flag),//input wire [0:0] probe6; .probe7(u_iserdese2_ctrl.add_cnt ),//input wire [0:0] probe7; .probe8(u_iserdese2_ctrl.dout_vld)//input wire [0:0] probe8; );
頂層模塊對應的RTL視圖如下所示:
圖15 頂層模塊RTL
05工程仿真
對應的TestBench很簡單,只需要提供時鐘和復位信號即可,如下所示:
//--############################################################################################### //--# //--# File Name : testBench //--# Designer : 數字站 //--# Tool : Vivado 2021.1 //--# Design Date : 2024.4.4 //--# Description : 測試串并轉換原語 //--# Version : 0.0 //--# Coding scheme : GBK(If the Chinese comment of the file is garbled, please do not save it and check whether the file is opened in GBK encoding mode) //--# //--############################################################################################### `timescale1ns /1ps moduletest(); localparam CYCLE = 10 ;//系統時鐘周期,單位ns,默認10ns; localparam RST_TIME = 10 ;//系統復位持續時間,默認10個系統時鐘周期; reg clk ;//系統時鐘,默認100MHz; reg rst_n ;//系統復位,默認低電平有效; wire [7:0] o_iserdese2 ; wire o_iserdese2_vld ; topu_top( .clk_div ( clk ),//系統時鐘信號; .rst_n (rst_n ),//系統復位信號,低電平有效; .o_iserdese2 (o_iserdese2 ), .o_iserdese2_vld (o_iserdese2_vld ) ); //生成周期為CYCLE數值的系統時鐘; initial begin clk =0; forever#(CYCLE/2) clk = ~clk; end //生成復位信號; initial begin rst_n =1; #2; rst_n =0;//開始時復位10個時鐘; #(RST_TIME*CYCLE); rst_n =1; @(posedge o_iserdese2_vld);//校準完成; repeat(400)@(posedge clk); $stop;//停止仿真; end endmodule
之后運行vivado仿真,下圖是OSERDESE2的時序圖,將并行數據轉換為串行數據輸出,串行數據與時鐘clk的雙沿對齊。
圖16 OSERDESE2時序
之后查看ISERDESE2時序,如下圖所示,在校準開始階段,ISERDESE2輸出數據Q為8’h20,并不是校準序列8’h5c或者8’h82,所以將bitslip拉高一個clk_div時鐘寬度。
等待四個clk_div時鐘周期后,再次檢測ISERDESE2輸出并行數據,依舊不是規定數值,繼續拉高bitslip進行調整。
圖17 OSERDESE2時序
直到某次調整之后,ISERDESE2輸出的并行數據序列均為8’h5c或8’h82,如下圖所示,此時就可以拉高bitslip了。
圖18 OSERDESE2時序
之后檢測連續16個ISERDESE2并行輸出數據,如果均為規定序列,沒有問題,則將dout_vld拉高,表示輸出數據已經對齊,是有效數據。
如果檢測過程中出現錯誤,則計數器清零,bitslip拉高繼續調整,直到滿足要求即可。
圖19 計數器對校準序列計數下面是截取當轉換完成后,發送端校驗數據發送完成之后,發送偽隨機的測試數據,ISERDESE2的輸出依舊是正確的,證明前文的校準方式沒有問題。
圖20 接收偽隨機序列
上述仿真就沒有問題了,之后上板通過ila抓取相關信號,查看結果是否正確。
06上板測試
至于在使用OFB回環時,為什么不能使用D管腳,如下圖所示,ISERDESE2和OSERDESE2會使用掉一個管腳的ILOGIC和OLOGIC資源,導致這個IOB管腳不能使用,ISERDESE2的D管腳就不能使用了。
下圖中白色走線就是ISERDESE2和OSERDESE2的OFB回環走線。
圖21 IO資源分布
工程綜合完畢之后,將代碼下載到開發板中,之后把dout_vld的上升沿作為ILA的觸發條件。由于該條件在復位之后只會觸發一次,因此在ILA啟動之后,需要按一下開發板的復位引腳,才能夠觸發條件,對應截圖如下所示。
圖22 ILA的觸發條件設置
如下圖所示,開始校準時,ISERDESE2輸出并行數據并不是校準序列的8’h5c或者8’h82。之后把bitslip拉高一個時鐘,調整串并轉換的起始位置,下圖只調整了兩次,ISERDESE2就輸出了正確數據。
圖23 校準時序
計數器cnt對ISERDESE2輸出的正確數據進行計數,當ISERDESE2連續輸出16個正確數據時,認為校準成功,如果覺得16個太少,在校準的時候可以設置更大的數據。
圖24 校準計數器
最后就是對比校準后偽隨機序列的轉換了,din是OSERDESE2并串轉換的輸入數據,而dout是ISERDESE2串并轉換的輸出結果,下圖中兩圖的數據相等,證明校準電路和串并轉換均沒有問題。
din和dout有延時是正常現象,因為兩者中間有很多電路和觸發器嘛,延時是正常的。
圖25 轉換數據
關于ISERDESE2的講解到此結束了,本文雖然只是講解了DDR模式的使用,但SDR原理也是類似的,只不過是單沿轉換數據,兩個時鐘頻率的比值不一樣罷了。
主要理解bitslip的使用,才能夠真正的了解該模塊,不必在意bitslip拉高后,數據該怎么移動,只需要關注ISERDESE2輸出是不是需要的輸出,不是就繼續通過bitslip調整ISERDESE2輸出。這個校準的過程需要輸入一直連續輸入固定序列,不然無法校準。
需要本工程的在公眾號后臺回復“ISERDESE2”(不包括引號)即可,工程使用vivado2021.1,平臺是zynq-7030。
-
接口
+關注
關注
33文章
8783瀏覽量
152467 -
Xilinx
+關注
關注
72文章
2174瀏覽量
122969 -
仿真
+關注
關注
50文章
4163瀏覽量
134552
原文標題:xilinx原語詳解及仿真—ISERDESE2
文章出處:【微信號:HXSLH1010101010,微信公眾號:FPGA技術江湖】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
如何使用其gearbox功能來實現不同的比率的串并轉換功能

FPGA | Xilinx ISE14.7 LVDS應用
ADC3583怎么用Xilinx的ISERDESE2采集信號?
請問是否必須總是有一個訓練模式來使用ISERDESE2?
請問ISERDESE2原語支持多少位輸入?
如何正確配置ISERDESE2?
使用ISERDESE2 INTERFACE_TYPE設置為NETWORKING時收到警告的原因?
應用程序中是否需要外部LVDS終端才能進行此配置?
使用帶有XC7K160T的ISE 14.7在布局布線步驟中出現錯誤的解決辦法?
Xilinx FPGA常用原語介紹

Xilinx原語使用方法有哪些

Xilinx原語使用方法

評論