赞
踩
LVDS(Low-Voltage Differential Signaling ,低电压差分信号)是美国国家半导体(National Semiconductor, NS,现TI)于1994年提出的一种信号传输模式的电平标准,它采用极低的电压摆幅高速差动传输数据,可以实现点对点或一点对多点的连接,具有低功耗、低误码率、低串扰和低辐射等优点,已经被广泛应用于串行高速数据通讯场合当,如高速背板、电缆和板到板数据传输与时钟分配,以及单个PCB内的通信链路。
每对LVDS信号是一个差分信号对,一个信号用两个相反的p,n信号线表示,通过差值 [公式] 传输数据,这样可以有效减小共模噪声的干扰,信号线传输如下图:
Xilinx 7系列fpga包含ISERDES和OSERDES原语,这些原语使得serdes电路的设计非常简单,并且当使用逐位deskew时,根据使用的系列和速度等级,允许以415 Mb/s到1200 Mb/s的速度进行更高的操作。较低的操作速度使用静态数据对齐。
以下图为例子
在XAPP585里有这么一张图,我觉得很好用,received clock是输入得时钟,从图上可以看到,他的占空比为3:4,一个时钟周期每条线传7个bit得数据,对比正常得信号传输,一个clock 只能传一个bit得数据,所以又称lvds为高速串行接口。
lvds有两种传输模式,一种是SDR(Single Data Rate),一种是DDR(Double Data Rate),通过一组图片就可以看到SDR和DDR的区别:
上图中,FB_CLK是在第一章里得Received CLK倍频之后得到得时钟,虽然说一个时钟传输7个bit数据,但实际上还是需要将大时钟经过倍频之后得时钟沿去传输,每个小时钟传一个或者两个得数据。
上图一是SDR模式,每个clk传输1个bit数据。
上图二是DDR模式,每个clk传输2个bit数据,上升沿和下降沿触发。
SDR和DDR模式选择是有条件的:
使用SDR技术的优点是所需的一般互连逻辑少得多,并且与时钟的占空比失真无关。
然而使用DDR技术,在对数据采样的时候就有可能发生时钟偏移,采样到错的数据。
在第一章节有提到,lvds的信号线都是差分信号,需要使用FPGA的buffer原语将其转换成需要使用的单信号线。
IBUFGDS_DIFF_OUT #(
.DIFF_TERM (DIFF_TERM),
.IBUF_LOW_PWR ("FALSE"))
iob_clk_in (
.I (clkin_p),
.IB (clkin_n),
.O (rx_clk_in_p),
.OB (rx_clk_in_n));
经过BUF之后的时钟才是我们可以使用的时钟,当然转换之后有一步是必须要做的,就是delay一下
用这个时钟做被频,生成三个时钟,rxpllmmcm_x1,rxpllmmcm_xs,rxpllmmcm_d4
MMCME2_ADV #( .BANDWIDTH ("OPTIMIZED"), .CLKFBOUT_MULT_F (7*MMCM_MODE), .CLKFBOUT_PHASE (0.0), .CLKIN1_PERIOD (CLKIN_PERIOD), .CLKIN2_PERIOD (CLKIN_PERIOD), .CLKOUT0_DIVIDE_F (2*MMCM_MODE), .CLKOUT0_DUTY_CYCLE (0.5), .CLKOUT0_PHASE (0.0), .CLKOUT0_USE_FINE_PS ("FALSE"), .CLKOUT1_PHASE (11.25), .CLKOUT1_DIVIDE (4*MMCM_MODE), .CLKOUT1_DUTY_CYCLE (0.5), .CLKOUT1_USE_FINE_PS ("FALSE"), .COMPENSATION ("ZHOLD"), .DIVCLK_DIVIDE (1), .REF_JITTER1 (0.100)) rx_mmcm_adv_inst ( .CLKFBOUT (rxpllmmcm_x1), .CLKFBOUTB (), .CLKFBSTOPPED (), .CLKINSTOPPED (), .CLKOUT0 (rxpllmmcm_xs), .CLKOUT0B (), .CLKOUT1 (rxpllmmcm_d4), .PSCLK (1'b0), .PSEN (1'b0), .PSINCDEC (1'b0), .PWRDWN (1'b0), .LOCKED (mmcm_locked), .CLKFBIN (pixel_clk), .CLKIN1 (rx_clkin_p_d), .CLKIN2 (1'b0), .CLKINSEL (1'b1), .DADDR (7'h00), .DCLK (1'b0), .DEN (1'b0), .DI (16'h0000), .DWE (1'b0), .RST (reset)) ;
其中时钟的传输是有限制的,在xilinx xapp585 中提出SDR时钟需要两个时钟缓冲区,DDR时钟需要三个。其他没有列出的方案要么是不支持,要么是不推荐。
这里采用DDR模式,上面生成的3个时钟分别经过时clock buffer,生成pixel_clk,rx_clk,rx_clk_d4.
parameter SAMPL_CLOCK = "BUFIO" ; // Parameter to set sampling clock buffer type, BUFIO, BUF_H, BUF_G parameter INTER_CLOCK = "BUF_R" ; // Parameter to set intermediate clock buffer type, BUFR, BUF_H, BUF_G parameter PIXEL_CLOCK = "BUF_G" ; // Parameter to set final pixel buffer type, BUF_R, BUF_H, BUF_G if (PIXEL_CLOCK == "BUF_G") begin // Final clock selection BUFG bufg_mmcm_x1 (.I(rxpllmmcm_x1), .O(pixel_clk)) ; assign status[1:0] = 2'b00 ; end else if (PIXEL_CLOCK == "BUF_R") begin BUFR #(.BUFR_DIVIDE("1"),.SIM_DEVICE("7SERIES"))bufr_mmcm_x1 (.I(rxpllmmcm_x1),.CE(1'b1),.O(pixel_clk),.CLR(1'b0)) ; assign status[1:0] = 2'b01 ; end else begin BUFH bufh_mmcm_x1 (.I(rxpllmmcm_x1), .O(pixel_clk)) ; assign status[1:0] = 2'b10 ; end if (INTER_CLOCK == "BUF_G") begin // Intermediate clock selection BUFG bufg_mmcm_d4 (.I(rxpllmmcm_d4), .O(rxclk_d4)) ; assign status[3:2] = 2'b00 ; end else if (INTER_CLOCK == "BUF_R") begin BUFR #(.BUFR_DIVIDE("2"),.SIM_DEVICE("7SERIES"))bufr_mmcm_d4 (.I(rxpllmmcm_xs),.CE(1'b1),.O(rxclk_d4),.CLR(1'b0)) ; assign status[3:2] = 2'b01 ; end else begin BUFH bufh_mmcm_d4 (.I(rxpllmmcm_d4), .O(rxclk_d4)) ; assign status[3:2] = 2'b10 ; end if (SAMPL_CLOCK == "BUF_G") begin // Sample clock selection BUFG bufg_mmcm_xn (.I(rxpllmmcm_xs), .O(rxclk)) ; assign status[5:4] = 2'b00 ; end else if (SAMPL_CLOCK == "BUFIO") begin BUFIO bufio_mmcm_xn (.I (rxpllmmcm_xs), .O(rxclk)) ; assign status[5:4] = 2'b11 ; end else begin BUFH bufh_mmcm_xn (.I(rxpllmmcm_xs), .O(rxclk)) ; assign status[5:4] = 2'b10 ; end
可以实现的方案如下:
时钟的仿真如下:
原来的rxclk是一个占空比为3:4的波形,因为他们都要经过idelay,所以rx_clk_in_p_d延迟了一点时间,经MMCM调频之后,输出一个7倍频的时钟,一个4倍频的时钟,还有一个原来的时钟。
官方给出了两种设计方案,其中当以相同像素时钟速率运行的多个通道被接收时,它们可以被放置在相同的I/O bank中,并且所有的时钟选项都是可用的,或者它们可以被放置在不同的bank中,并且只有BUFG时钟可以被使用。
使用SDR采样时钟时,ISERDES直接以1:7模式使用。ISERDES支持的唯一时钟元素组合是两个BUFGs、两个BUFHs或一个BUFIO和一个BUFR。使用BUFG的优点是并行数据可以在覆盖整个设备的时钟上使用。使用BUFR或BUFH,数据在只覆盖当前时钟区域的时钟上可用。
当使用DDR采样时钟时,ISERDES以1:4模式使用,然后1:7模式使用基于分布式RAM的gear box进行。这种方法需要三个时钟域。采样时钟,采样时钟除以4,采样时钟除以7,等于原始输入像素时钟。
其中gear box的作用就是取两次4bit数据,然后拼接成7bit的数据。
参考ISERDES的参数,可以看到,在SDR模式下,可以取7位数据,但是在DDR模式下,他只能取偶数位,不能直接取七位,所以官方给出的方案就是取4位数据,然后经过gear box将4位数据转成7位。
当然还有一种方案就是将ISERDES串联,然后取14位数据,就是相当于取了2个像素点的数据。
// // Copyright (c) 2012-2015 Xilinx, Inc. // This design is confidential and proprietary of Xilinx, All Rights Reserved. // // ____ ____ // / /\/ / // /___/ \ / Vendor: Xilinx // \ \ \/ Version: 1.2 // \ \ Filename: gearbox_4_to_7.v // / / Date Last Modified: 21JAN2015 // /___/ /\ Date Created: 5MAR2010 // \ \ / \ // \___\/\___\ // //Device: 7 Series //Purpose: multiple 4 to 7 bit gearbox // //Reference: XAPP585 // //Revision History: // Rev 1.0 - First created (nicks) // Rev 1.1 - reset outputs added // Rev 1.2 - Updated format (brandond) // // // // Disclaimer: // // This disclaimer is not a license and does not grant any rights to the materials // distributed herewith. Except as otherwise provided in a valid license issued to you // by Xilinx, and to the maximum extent permitted by applicable law: // (1) THESE MATERIALS ARE MADE AVAILABLE "AS IS" AND WITH ALL FAULTS, // AND XILINX HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, EXPRESS, IMPLIED, OR STATUTORY, // INCLUDING BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY, NON-INFRINGEMENT, OR // FITNESS FOR ANY PARTICULAR PURPOSE; and (2) Xilinx shall not be liable (whether in contract // or tort, including negligence, or under any other theory of liability) for any loss or damage // of any kind or nature related to, arising under or in connection with these materials, // including for any direct, or any indirect, special, incidental, or consequential loss // or damage (including loss of data, profits, goodwill, or any type of loss or damage suffered // as a result of any action brought by a third party) even if such damage or loss was // reasonably foreseeable or Xilinx had been advised of the possibility of the same. // // Critical Applications: // // Xilinx products are not designed or intended to be fail-safe, or for use in any application // requiring fail-safe performance, such as life-support or safety devices or systems, // Class III medical devices, nuclear facilities, applications related to the deployment of airbags, // or any other applications that could lead to death, personal injury, or severe property or // environmental damage (individually and collectively, "Critical Applications"). Customer assumes // the sole risk and liability of any use of Xilinx products in Critical Applications, subject only // to applicable laws and regulations governing limitations on product liability. // // THIS COPYRIGHT NOTICE AND DISCLAIMER MUST BE RETAINED AS PART OF THIS FILE AT ALL TIMES. // // `timescale 1ps/1ps module gearbox_4_to_7 (input_clock, output_clock, datain, reset, jog, reset_out, dataout) ; parameter integer D = 8 ; // Parameter to set the number of data lines input input_clock ; // high speed clock input input output_clock ; // low speed clock input input [D*4-1:0] datain ; // data inputs input reset ; // Reset line input jog ; // jog input, slips by 4 bits output reg [1:0] reset_out ; // reset out signal output reg [D*7-1:0] dataout ; // data outputs reg [3:0] read_addra ; reg [3:0] read_addrb ; reg [3:0] read_addrc ; reg [3:0] write_addr ; reg read_enable ; reg read_enable_dom_ch ; wire [D*4-1:0] ramouta ; wire [D*4-1:0] ramoutb ; wire [D*4-1:0] ramoutc ; reg local_reset ; reg local_reset_dom_ch ; reg [1:0] mux ; wire [D*4-1:0] dummy ; reg jog_int ; reg rst_int ; genvar i ; always @ (posedge input_clock) begin // generate local sync reset if (reset == 1'b1) begin local_reset <= 1'b1 ; reset_out[0] <= 1'b1 ; end else begin local_reset <= 1'b0 ; reset_out[0] <= 1'b0 ; end end always @ (posedge input_clock) begin // Gearbox input - 4 bit data at input clock frequency if (local_reset == 1'b1) begin write_addr <= 4'h0 ; read_enable <= 1'b0 ; end else begin if (write_addr == 4'hD) begin write_addr <= 4'h0 ; end else begin write_addr <= write_addr + 4'h1 ; end if (write_addr == 4'h3) begin read_enable <= 1'b1 ; end end end always @ (posedge output_clock) begin read_enable_dom_ch <= read_enable ; local_reset_dom_ch <= local_reset ; end always @ (posedge output_clock) begin // Gearbox output - 10 bit data at output clock frequency reset_out[1] <= rst_int ; if (local_reset_dom_ch == 1'b1 || read_enable_dom_ch == 1'b0) begin rst_int <= 1'b1 ; end else begin rst_int <= 1'b0 ; end if (reset_out[1] == 1'b1) begin read_addra <= 4'h0 ; read_addrb <= 4'h1 ; read_addrc <= 4'h2 ; jog_int <= 1'b0 ; end else begin case (jog_int) 1'b0 : begin case (read_addra) 4'h0 : begin read_addra <= 4'h1 ; read_addrb <= 4'h2 ; read_addrc <= 4'h3 ; mux <= 2'h1 ; end 4'h1 : begin read_addra <= 4'h3 ; read_addrb <= 4'h4 ; read_addrc <= 4'h5 ; mux <= 2'h2 ; end 4'h3 : begin read_addra <= 4'h5 ; read_addrb <= 4'h6 ; read_addrc <= 4'h7 ; mux <= 2'h3 ; end 4'h5 : begin read_addra <= 4'h7 ; read_addrb <= 4'h8 ; read_addrc <= 4'h9 ; mux <= 2'h0 ; end 4'h7 : begin read_addra <= 4'h8 ; read_addrb <= 4'h9 ; read_addrc <= 4'hA ; mux <= 2'h1 ; end 4'h8 : begin read_addra <= 4'hA ; read_addrb <= 4'hB ; read_addrc <= 4'hC ; mux <= 2'h2 ; end 4'hA : begin read_addra <= 4'hC ; read_addrb <= 4'hD ; read_addrc <= 4'hD ; mux <= 2'h3 ; jog_int <= jog ; end default : begin read_addra <= 4'h0 ; read_addrb <= 4'h1 ; read_addrc <= 4'h2 ; mux <= 2'h0 ; end endcase end 1'b1 : begin case (read_addra) 4'h1 : begin read_addra <= 4'h2 ; read_addrb <= 4'h3 ; read_addrc <= 4'h4 ; mux <= 2'h1 ; end 4'h2 : begin read_addra <= 4'h4 ; read_addrb <= 4'h5 ; read_addrc <= 4'h6 ; mux <= 2'h2 ; end 4'h4 : begin read_addra <= 4'h6 ; read_addrb <= 4'h7 ; read_addrc <= 4'h8 ; mux <= 2'h3 ; end 4'h6 : begin read_addra <= 4'h8 ; read_addrb <= 4'h9 ; read_addrc <= 4'hA ; mux <= 2'h0 ; end 4'h8 : begin read_addra <= 4'h9 ; read_addrb <= 4'hA ; read_addrc <= 4'hB ; mux <= 2'h1 ; end 4'h9 : begin read_addra <= 4'hB ; read_addrb <= 4'hC ; read_addrc <= 4'hD ; mux <= 2'h2 ; end 4'hB : begin read_addra <= 4'hD ; read_addrb <= 4'h0 ; read_addrc <= 4'h1 ; mux <= 2'h3 ; jog_int <= jog ; end default : begin read_addra <= 4'h1 ; read_addrb <= 4'h2 ; read_addrc <= 4'h3 ; mux <= 2'h0 ; end endcase end endcase end end generate for (i = 0 ; i <= D-1 ; i = i+1) begin : loop0 always @ (posedge output_clock) begin case (mux) 2'h0 : dataout[7*i+6:7*i] <= { ramoutb[4*i+2:4*i+0], ramouta[4*i+3:4*i+0]} ; 2'h1 : dataout[7*i+6:7*i] <= {ramoutc[4*i+1:4*i+0], ramoutb[4*i+3:4*i+0], ramouta[4*i+3]} ; 2'h2 : dataout[7*i+6:7*i] <= {ramoutc[4*i+0], ramoutb[4*i+3:4*i+0], ramouta[4*i+3:4*i+2]} ; default : dataout[7*i+6:7*i] <= { ramoutb[4*i+3:4*i+0], ramouta[4*i+3:4*i+1]} ; endcase end end endgenerate // Data gearboxes generate for (i = 0 ; i <= D*2-1 ; i = i+1) begin : loop2 RAM32M ram_inst ( .DOA (ramouta[2*i+1:2*i]), .DOB (ramoutb[2*i+1:2*i]), .DOC (ramoutc[2*i+1:2*i]), .DOD (dummy[2*i+1:2*i]), .ADDRA ({1'b0, read_addra}), .ADDRB ({1'b0, read_addrb}), .ADDRC ({1'b0, read_addrc}), .ADDRD ({1'b0, write_addr}), .DIA (datain[2*i+1:2*i]), .DIB (datain[2*i+1:2*i]), .DIC (datain[2*i+1:2*i]), .DID (dummy[2*i+1:2*i]), .WE (1'b1), .WCLK (input_clock)); end endgenerate endmodule
xilinx 7系列的原语之一,作用就是将串行信号转化为并行信号,
// ISERDESE2: Input SERial/DESerializer with Bitslip // 7 Series // Xilinx HDL Libraries Guide, version 14.7 ISERDESE2 #( .DATA_RATE("DDR"), // DDR, SDR .DATA_WIDTH(4), // 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 - INIT_Q4: Initial value on the Q outputs (0/1) .INIT_Q1(1'b0), .INIT_Q2(1'b0), .INIT_Q3(1'b0), .INIT_Q4(1'b0), .INTERFACE_TYPE("MEMORY"), // MEMORY, MEMORY_DDR3, MEMORY_QDR, NETWORKING, OVERSAMPLE .IOBDELAY("NONE"), // NONE, BOTH, IBUF, IFD .NUM_CE(2), // Number of clock enables (1,2) .OFB_USED("FALSE"), // Select OFB path (FALSE, TRUE) .SERDES_MODE("MASTER"), // MASTER, SLAVE // SRVAL_Q1 - SRVAL_Q4: Q output values when SR is used (0/1) .SRVAL_Q1(1'b0), .SRVAL_Q2(1'b0), .SRVAL_Q3(1'b0), .SRVAL_Q4(1'b0) ) ISERDESE2_inst ( .O(O), // 1-bit output: Combinatorial output // Q1 - Q8: 1-bit (each) output: Registered data outputs .Q1(Q1), .Q2(Q2), .Q3(Q3), .Q4(Q4), .Q5(Q5), .Q6(Q6), .Q7(Q7), .Q8(Q8), // SHIFTOUT1, SHIFTOUT2: 1-bit (each) output: Data width expansion output ports .SHIFTOUT1(SHIFTOUT1), .SHIFTOUT2(SHIFTOUT2), .BITSLIP(BITSLIP), // 1-bit input: The BITSLIP pin performs a Bitslip operation synchronous to // CLKDIV when asserted (active High). Subsequently, the data seen on the Q1 // to Q8 output ports will shift, as in a barrel-shifter operation, one // position every time Bitslip is invoked (DDR operation is different from // SDR). // CE1, CE2: 1-bit (each) input: Data register clock enable inputs .CE1(CE1), .CE2(CE2), .CLKDIVP(CLKDIVP), // 1-bit input: TBD // Clocks: 1-bit (each) input: ISERDESE2 clock input ports .CLK(CLK), // 1-bit input: High-speed clock .CLKB(CLKB), // 1-bit input: High-speed secondary clock .CLKDIV(CLKDIV), // 1-bit input: Divided clock .OCLK(OCLK), // 1-bit input: High speed output clock used when INTERFACE_TYPE="MEMORY" // Dynamic Clock Inversions: 1-bit (each) input: Dynamic clock inversion pins to switch clock polarity .DYNCLKDIVSEL(DYNCLKDIVSEL), // 1-bit input: Dynamic CLKDIV inversion .DYNCLKSEL(DYNCLKSEL), // 1-bit input: Dynamic CLK/CLKB inversion // Input Data: 1-bit (each) input: ISERDESE2 data input ports .D(D), // 1-bit input: Data input .DDLY(DDLY), // 1-bit input: Serial data from IDELAYE2 .OFB(OFB), // 1-bit input: Data feedback from OSERDESE2 .OCLKB(OCLKB), // 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(SHIFTIN1), .SHIFTIN2(SHIFTIN2) ); // End of ISERDESE2_inst instantiation
比较重要的参数设置:
因为在LVDS里只用这个选项,其他选项就不多赘述,可以参考ug471了解。
端口说明
使用这个端口可以更好的找到数据的边界。
其他的端口注释讲的很明白,对于DDR模式,建议使用2个Iserdes级联使用
对于DDR模式,还有一个可选的方案就是使用IDDR原语,这也是一个串行转并行的器件,与ISERDES不同的是,IDDR只有两个输出端口,q1,q2,,也没有bilislip,无法进行数据对齐,想比较之下,使用IDDR没有使用Iserdes方便。
波形图整上:
数据在发送端送出的时候,可能是对齐的,但是在传输的过程中,可能会有各种乱七八糟的因素导致数据和时钟不对齐,偏差一二三四等等位,这时候怎么办,刚刚的bitslip就是用来做这个的,通过调整BITSLIP,找到数据的边界,然后解出正确的值。
如何确定bitslip,在本章的开头里,有给出一个方案,因为一个时钟周期是传送7个bit数据,所以他要么是4:3,要么是3:4,往往在发送端,会给出时钟的pattern,一般是7‘b1100011或者7’b1100001,基本除了这两种也不会有其他的,所以可以把时钟信号delay一下,然后给他解串,如果解串的数据是7‘b1100011或者7’b1100001,就说明数据对齐,如果没有,那就发送一个脉冲,直到对齐为止。
时钟方面,和接收端的时钟配置是一样的,一个大时钟,一个小时钟。
/// // Copyright (c) 2012-2015 Xilinx, Inc. // This design is confidential and proprietary of Xilinx, All Rights Reserved. /// // ____ ____ // / /\/ / // /___/ \ / Vendor: Xilinx // \ \ \/ Version: 1.2 // \ \ Filename: clock_generator_pll_7_to_1_diff_ddr.v // / / Date Last Modified: 21JAN2015 // /___/ /\ Date Created: 5JAN2010 // \ \ / \ // \___\/\___\ // //Device: 7 Series //Purpose: DDR MMCM or PLL based clock generator. Takes in a differential clock and multiplies it // appropriately //Reference: XAPP585 // //Revision History: // Rev 1.0 - First created (nicks) // Rev 1.1 - Some net names changed to make more sense in Vivado // Rev 1.2 - Updated format (brandond) // /// // // Disclaimer: // // This disclaimer is not a license and does not grant any rights to the materials // distributed herewith. Except as otherwise provided in a valid license issued to you // by Xilinx, and to the maximum extent permitted by applicable law: // (1) THESE MATERIALS ARE MADE AVAILABLE "AS IS" AND WITH ALL FAULTS, // AND XILINX HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, EXPRESS, IMPLIED, OR STATUTORY, // INCLUDING BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY, NON-INFRINGEMENT, OR // FITNESS FOR ANY PARTICULAR PURPOSE; and (2) Xilinx shall not be liable (whether in contract // or tort, including negligence, or under any other theory of liability) for any loss or damage // of any kind or nature related to, arising under or in connection with these materials, // including for any direct, or any indirect, special, incidental, or consequential loss // or damage (including loss of data, profits, goodwill, or any type of loss or damage suffered // as a result of any action brought by a third party) even if such damage or loss was // reasonably foreseeable or Xilinx had been advised of the possibility of the same. // // Critical Applications: // // Xilinx products are not designed or intended to be fail-safe, or for use in any application // requiring fail-safe performance, such as life-support or safety devices or systems, // Class III medical devices, nuclear facilities, applications related to the deployment of airbags, // or any other applications that could lead to death, personal injury, or severe property or // environmental damage (individually and collectively, "Critical Applications"). Customer assumes // the sole risk and liability of any use of Xilinx products in Critical Applications, subject only // to applicable laws and regulations governing limitations on product liability. // // THIS COPYRIGHT NOTICE AND DISCLAIMER MUST BE RETAINED AS PART OF THIS FILE AT ALL TIMES. // // `timescale 1ps/1ps module clock_generator_pll_7_to_1_diff_ddr (clkin_p, clkin_n, txclk, reset, pixel_clk, txclk_div, mmcm_lckd, status) ; parameter real CLKIN_PERIOD = 6.000 ; // clock period (ns) of input clock on clkin_p parameter DIFF_TERM = "FALSE" ; // Parameter to enable internal differential termination parameter integer MMCM_MODE = 1 ; // Parameter to set multiplier for MMCM to get VCO in correct operating range. 1 multiplies input clock by 7, 2 multiplies clock by 14, etc parameter TX_CLOCK = "BUFIO" ; // Parameter to set transmission clock buffer type, BUFIO, BUF_H, BUF_G parameter INTER_CLOCK = "BUF_R" ; // Parameter to set intermediate clock buffer type, BUFR, BUF_H, BUF_G parameter PIXEL_CLOCK = "BUF_G" ; // Parameter to set final clock buffer type, BUF_R, BUF_H, BUF_G parameter USE_PLL = "FALSE" ; // Parameter to enable PLL use rather than MMCM use, note, PLL does not support BUFIO and BUFR input reset ; // reset (active high) input clkin_p, clkin_n ; // differential clock inputs output txclk ; // CLK for serdes output pixel_clk ; // Pixel clock output output txclk_div ; // CLKDIV for serdes, and gearbox output = pixel clock / 2 output mmcm_lckd ; // Locked output from BUFPLL output [6:0] status ; // clock status wire clkint ; // clock input from pin wire txpllmmcm_x1 ; // pll generated x1 clock wire txpllmmcm_xn ; // pll generated xn clock IBUFGDS #( .DIFF_TERM (DIFF_TERM)) clk_iob_in ( .I (clkin_p), .IB (clkin_n), .O (clkint)); generate if (USE_PLL == "FALSE") begin : loop8 // use an MMCM assign status[6] = 1'b1 ; MMCME2_ADV #( .BANDWIDTH ("OPTIMIZED"), .CLKFBOUT_MULT_F (7*MMCM_MODE), .CLKFBOUT_PHASE (0.0), .CLKIN1_PERIOD (CLKIN_PERIOD), .CLKIN2_PERIOD (CLKIN_PERIOD), .CLKOUT0_DIVIDE_F (2*MMCM_MODE), .CLKOUT0_DUTY_CYCLE (0.5), .CLKOUT0_PHASE (0.0), .CLKOUT1_DIVIDE (14*MMCM_MODE), .CLKOUT1_DUTY_CYCLE (0.5), .CLKOUT1_PHASE (0.0), .CLKOUT2_DIVIDE (7*MMCM_MODE), .CLKOUT2_DUTY_CYCLE (0.5), .CLKOUT2_PHASE (0.0), .CLKOUT3_DIVIDE (8), .CLKOUT3_DUTY_CYCLE (0.5), .CLKOUT3_PHASE (0.0), .CLKOUT4_DIVIDE (8), .CLKOUT4_DUTY_CYCLE (0.5), .CLKOUT4_PHASE (0.0), .CLKOUT5_DIVIDE (8), .CLKOUT5_DUTY_CYCLE (0.5), .CLKOUT5_PHASE (0.0), .COMPENSATION ("ZHOLD"), .DIVCLK_DIVIDE (1), .REF_JITTER1 (0.100)) tx_mmcme2_adv_inst ( .CLKFBOUT (txpllmmcm_x1), .CLKFBOUTB (), .CLKFBSTOPPED (), .CLKINSTOPPED (), .CLKOUT0 (txpllmmcm_xn), .CLKOUT0B (), .CLKOUT1 (txpllmmcm_d2), .CLKOUT1B (), .CLKOUT2 (), .CLKOUT2B (), .CLKOUT3 (), .CLKOUT3B (), .CLKOUT4 (), .CLKOUT5 (), .CLKOUT6 (), .DO (), .DRDY (), .PSDONE (), .PSCLK (1'b0), .PSEN (1'b0), .PSINCDEC (1'b0), .PWRDWN (1'b0), .LOCKED (mmcm_lckd), .CLKFBIN (pixel_clk), .CLKIN1 (clkint), .CLKIN2 (1'b0), .CLKINSEL (1'b1), .DADDR (7'h00), .DCLK (1'b0), .DEN (1'b0), .DI (16'h0000), .DWE (1'b0), .RST (reset)) ; if (PIXEL_CLOCK == "BUF_G") begin // Final clock selection BUFG bufg_mmcm_x1 (.I(txpllmmcm_x1), .O(pixel_clk)) ; assign status[1:0] = 2'b00 ; end else if (PIXEL_CLOCK == "BUF_R") begin BUFR #(.BUFR_DIVIDE("1"),.SIM_DEVICE("7SERIES"))bufr_mmcm_x1 (.I(txpllmmcm_x1),.CE(1'b1),.O(pixel_clk),.CLR(1'b0)) ; assign status[1:0] = 2'b01 ; end else begin BUFH bufh_mmcm_x1 (.I(txpllmmcm_x1), .O(pixel_clk)) ; assign status[1:0] = 2'b10 ; end if (INTER_CLOCK == "BUF_G") begin // Intermediate clock selection BUFG bufg_mmcm_d2 (.I(txpllmmcm_d2), .O(txclk_div)) ; assign status[3:2] = 2'b00 ; end else if (INTER_CLOCK == "BUF_R") begin BUFR #(.BUFR_DIVIDE("1"),.SIM_DEVICE("7SERIES"))bufr_mmcm_d2 (.I(txpllmmcm_d2),.CE(1'b1),.O(txclk_div),.CLR(1'b0)) ; assign status[3:2] = 2'b01 ; end else begin BUFH bufh_mmcm_d2 (.I(txpllmmcm_d2), .O(txclk_div)) ; assign status[3:2] = 2'b10 ; end if (TX_CLOCK == "BUF_G") begin // Sample clock selection BUFG bufg_mmcm_xn (.I(txpllmmcm_xn), .O(txclk)) ; assign status[5:4] = 2'b00 ; end else if (TX_CLOCK == "BUFIO") begin BUFIO bufio_mmcm_xn (.I (txpllmmcm_xn), .O(txclk)) ; assign status[5:4] = 2'b11 ; end else begin BUFH bufh_mmcm_xn (.I(txpllmmcm_xn), .O(txclk)) ; assign status[5:4] = 2'b10 ; end end else begin assign status[6] = 1'b0 ; // Use a PLL PLLE2_ADV #( .BANDWIDTH ("OPTIMIZED"), .CLKFBOUT_MULT (7*MMCM_MODE), .CLKFBOUT_PHASE (0.0), .CLKIN1_PERIOD (CLKIN_PERIOD), .CLKIN2_PERIOD (CLKIN_PERIOD), .CLKOUT0_DIVIDE (2*MMCM_MODE), .CLKOUT0_DUTY_CYCLE (0.5), .CLKOUT0_PHASE (0.0), .CLKOUT1_DIVIDE (14*MMCM_MODE), .CLKOUT1_DUTY_CYCLE (0.5), .CLKOUT1_PHASE (0.0), .CLKOUT2_DIVIDE (7*MMCM_MODE), .CLKOUT2_DUTY_CYCLE (0.5), .CLKOUT2_PHASE (0.0), .CLKOUT3_DIVIDE (8), .CLKOUT3_DUTY_CYCLE (0.5), .CLKOUT3_PHASE (0.0), .CLKOUT4_DIVIDE (8), .CLKOUT4_DUTY_CYCLE (0.5), .CLKOUT4_PHASE (0.0), .CLKOUT5_DIVIDE (8), .CLKOUT5_DUTY_CYCLE (0.5), .CLKOUT5_PHASE (0.0), .COMPENSATION ("ZHOLD"), .DIVCLK_DIVIDE (1), .REF_JITTER1 (0.100)) tx_mmcme2_adv_inst ( .CLKFBOUT (txpllmmcm_x1), .CLKOUT0 (txpllmmcm_xn), .CLKOUT1 (txpllmmcm_d2), .CLKOUT2 (), .CLKOUT3 (), .CLKOUT4 (), .CLKOUT5 (), .DO (), .DRDY (), .PWRDWN (1'b0), .LOCKED (mmcm_lckd), .CLKFBIN (pixel_clk), .CLKIN1 (clkint), .CLKIN2 (1'b0), .CLKINSEL (1'b1), .DADDR (7'h00), .DCLK (1'b0), .DEN (1'b0), .DI (16'h0000), .DWE (1'b0), .RST (reset)) ; if (PIXEL_CLOCK == "BUF_G") begin // Final clock selection BUFG bufg_mmcm_x1 (.I(txpllmmcm_x1), .O(pixel_clk)) ; assign status[1:0] = 2'b00 ; end else if (PIXEL_CLOCK == "BUF_R") begin BUFR #(.BUFR_DIVIDE("1"),.SIM_DEVICE("7SERIES"))bufr_mmcm_x1 (.I(txpllmmcm_x1),.CE(1'b1),.O(pixel_clk),.CLR(1'b0)) ; assign status[1:0] = 2'b01 ; end else begin BUFH bufh_mmcm_x1 (.I(txpllmmcm_x1), .O(pixel_clk)) ; assign status[1:0] = 2'b10 ; end if (INTER_CLOCK == "BUF_G") begin // Intermediate clock selection BUFG bufg_mmcm_d2 (.I(txpllmmcm_d2), .O(txclk_div)) ; assign status[3:2] = 2'b00 ; end else if (INTER_CLOCK == "BUF_R") begin BUFR #(.BUFR_DIVIDE("1"),.SIM_DEVICE("7SERIES"))bufr_mmcm_d2 (.I(txpllmmcm_d2),.CE(1'b1),.O(txclk_div),.CLR(1'b0)) ; assign status[3:2] = 2'b01 ; end else begin BUFH bufh_mmcm_d2 (.I(txpllmmcm_d2), .O(txclk_div)) ; assign status[3:2] = 2'b10 ; end if (TX_CLOCK == "BUF_G") begin // Sample clock selection BUFG bufg_mmcm_xn (.I(txpllmmcm_xn), .O(txclk)) ; assign status[5:4] = 2'b00 ; end else if (TX_CLOCK == "BUFIO") begin BUFIO bufio_mmcm_xn (.I (txpllmmcm_xn), .O(txclk)) ; assign status[5:4] = 2'b11 ; end else begin BUFH bufh_mmcm_xn (.I(txpllmmcm_xn), .O(txclk)) ; assign status[5:4] = 2'b10 ; end end endgenerate endmodule
两个时钟输出被用于高速和低速时钟从锁相环或MMCM。这两个时钟是相位对齐的,以确保在所有OSERDES都同步并在SR输入上同步复位后,OSERDES中的串行化是正确的。应用的并行数据然后被串行化输出使用高速传输时钟。通过向与时钟线相关的OSERDES发送一个常量值,转发的时钟输出以类似的方式生成。视频7:1应用的转发时钟需要1100001或1100011,以确保转发的时钟和数据关系符合广泛使用的标准。
每个channel配合一个clock,当然也可以配合一个总的clock,这几个clock都是一样的。
// OSERDESE2: Output SERial/DESerializer with bitslip // 7 Series // Xilinx HDL Libraries Guide, version 14.7 OSERDESE2 #( .DATA_RATE_OQ("DDR"), // DDR, SDR .DATA_RATE_TQ("DDR"), // DDR, BUF, SDR .DATA_WIDTH(4), // 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(4) // 3-state converter width (1,4) ) OSERDESE2_inst ( .OFB(OFB), // 1-bit output: Feedback path for data .OQ(OQ), // 1-bit output: Data path output // SHIFTOUT1 / SHIFTOUT2: 1-bit (each) output: Data output expansion (1-bit each) .SHIFTOUT1(SHIFTOUT1), .SHIFTOUT2(SHIFTOUT2), .TBYTEOUT(TBYTEOUT), // 1-bit output: Byte group tristate .TFB(TFB), // 1-bit output: 3-state control .TQ(TQ), // 1-bit output: 3-state control .CLK(CLK), // 1-bit input: High speed clock .CLKDIV(CLKDIV), // 1-bit input: Divided clock // D1 - D8: 1-bit (each) input: Parallel data inputs (1-bit each) .D1(D1), .D2(D2), .D3(D3), .D4(D4), .D5(D5), .D6(D6), .D7(D7), .D8(D8), .OCE(OCE), // 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(SHIFTIN1), .SHIFTIN2(SHIFTIN2), // T1 - T4: 1-bit (each) input: Parallel 3-state inputs .T1(T1), .T2(T2), .T3(T3), .T4(T4), .TBYTEIN(TBYTEIN), // 1-bit input: Byte group tristate .TCE(TCE) // 1-bit input: 3-state clock enable ); // End of OSERDESE2_inst instantiation
首先关注OSEDES2的属性内容,它的重要属性决定的因素如下:
DATA_RATE_OQ:决定OQ端口输出的数据速率,可选SDR或DDR;
DATA_RATE_TQ:决定TQ端口输出的数据速率,可选BUF, SDR或DDR;
DATA_WIDTH: 根据"DATA_RATE_OQ"确定具体数值;SDR Rate:可设为2,3,4,5,6,7,8;DDR Rate:可设为4,6,8,10,14;
SERDES_MODE:确定OSERDES是主模块还是从模块,这跟OSERDES级联使用有关,具体内容请看下面的内容;
TRISTATE_WIDTH:这跟"DATA_RATE_TQ"有关,大多情况都设为1,它的具体设置关系如下:
OSERDES原语的端口定义如上图所示,其中重要的端口设置如下:
OQ:串行数据输出,直接到IOB,也就是直接连接到IOBUF,ODELAY等特殊结构
SHIFTOUT1/2:级联时使用,详见下文
CLK:高速时钟,串行数据时钟输入
CLKDIV:慢速时钟,并行数据时钟输入
D1 to D8:并行数据输入,当并行数据多于8bit不超过14bit,可以使用OSERDES级联,级联的使用方法详见下文
OCE: 串行数据时钟使能信号输出
RST: 高复位信号输入
SHIFTIN1/2: 级联时使用,详见下文
OSERDES的波形如下图:
OSERDES级联使用:
当并行数据多于8bit不超过14bit时,可以采用两个OSERDES2级联的使用方法,示意图如下,
还有一种实现lvds传输的方法就是使用ODDR这个原语,按照惯例,先看端口和波形:
根据波形可以看出,ODDR是把两个数据转换成一个周期的双边沿触发的数据,和IDDR的做法类似,ODDR只适用于DDR模式,不适合SDR模式,同样需要两个数据传一下:
这里可以使用一个counter和buffer来解决。
begin
case (outcount)
0: shiftdata <= { buffer[0][0], buffer[0][1] };
1: shiftdata <= { buffer[0][2], buffer[0][3] };
2: shiftdata <= { buffer[0][4], buffer[0][5] };
3: shiftdata <= { buffer[0][6], buffer[1][0] };
4: shiftdata <= { buffer[1][1], buffer[1][2] };
5: shiftdata <= { buffer[1][3], buffer[1][4] };
6: shiftdata <= { buffer[1][5], buffer[1][6] };
endcase
LVDS数据格式有2种:JEIDA标准和VESA标准。
LVDS的每个clock周期内有7bit数据
JEIDA标准,如下图,第一张图是24bit的RGB数据,其中XX表示未定义,一般是0,第二张是18bit的RGB数据,
24bit:
18bit:
VESA标准,同样,如果使用18bit的RGB数据,TxOUT3不使用。
24bit:
《xapp585-lvds-source-synch-serdes-clock-multiplication》
《UG768 Xilinx 7 Series FPGA Libraries Guide for HDL Designs 》
《UG471 7 Series FPGAs SelectIO Resources》
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。