zoukankan      html  css  js  c++  java
  • Xilinx FPGA LVDS应用

    最近项目需要用到差分信号传输,于是看了一下FPGA上差分信号的使用。Xilinx FPGA中,主要通过原语实现差分信号的收发:OBUFDS(差分输出BUF),IBUFDS(差分输入BUF)。

    注意在分配引脚时,只需要分配SIGNAL_P的引脚,SIGNAL_N会自动连接到相应差分对引脚上;若没有使用差分信号原语,则在引脚电平上没有LVDS的选项(IO Planning PlanAhead)。

    测试代码:

    //////////////////////////////////////////////////////////////////////////////////
    module lvds_test(    sys_clk,
                            sys_rst,
                            
                            signal_in_p,
                            signal_in_n,
                            signal_out_p,
                            signal_out_n,
                            
                            led_signal
                         );
    
    input sys_clk,sys_rst;
    input signal_in_p,signal_in_n;
    output signal_out_p,signal_out_n;
    output led_signal;
    
    wire signal_out_temp;
    reg[31:0] clk_cnt;
    
    always @ (posedge sys_clk) begin
        if(!sys_rst) clk_cnt <= 32'd0;
        else begin
            if(clk_cnt == 32'd10_000_000) clk_cnt <= 32'd0;
            else clk_cnt <= clk_cnt+1'b1;
        end
    end
    
    assign signal_out=(clk_cnt >= 32'd5_000_000) ? 1 : 0;
    
    OBUFDS signal_out_diff(    .O(signal_out_p),
                                    .OB(signal_out_n),
                                    .I(signal_out)
                                );
    
    IBUFDS signal_in_diff(    .O(led_signal),
                                    .I(signal_in_p),
                                    .IB(signal_in_n)
                                );
    
    endmodule

    约束文件:

    NET "signal_out_p" IOSTANDARD = LVDS_33;
    
    NET "signal_out_p" LOC = U16;
    
    NET "sys_clk" IOSTANDARD = LVCMOS33;
    NET "sys_rst" IOSTANDARD = LVCMOS33;
    
    NET "led_signal" LOC = D18;
    
    NET "led_signal" IOSTANDARD = LVCMOS33;
    #Created by Constraints Editor (xc6slx45t-csg324-3) - 2016/06/06
    NET "sys_clk" TNM_NET = "sys_clk";
    TIMESPEC TS_sys_clk = PERIOD "sys_clk" 50 MHz HIGH 50 %;
    
    
    NET "signal_in_p" LOC = T12;
    NET "signal_in_n" LOC = V12;
    NET "sys_clk" LOC = G8;
    NET "sys_rst" LOC = U3;
    
    # PlanAhead Generated IO constraints 
    
    NET "signal_in_p" IOSTANDARD = LVDS_33;

    约束文件IO Planning PlanAhead产生,原语的使用可参考:E:XilinxISE14.7ISE_DSISEdocusenglishisehelpspartan6里面提供了所用器件的原语。同时,Xilinx器件内部信号内部还提供了100欧姆电阻匹配,可参考Spartan-6 FPGA SelectIO Resources(UG381)
    补充:

    若要实现高速通信的场合,可以利用FPGA内部自带的SelectIO资源,利用ISERDESE2、 OSERDESE2,实现串-并,并-串的转换,理论速度可达到750Mbs,参考资料:Spartan-6 FPGA Data Sheet: DC and Switching Characteristics(UG162)

    通信框图:

    因为串行转成并行的时候,输出的数据无法判断哪个 Bit 是高位,哪个 bit 是低位,因此,对于 ISERDESE2 可以利用bitslip 信号来重新对齐串行数据以获得正确的字节数据;代码实现时,也需要先进行数据对齐,才能进行数据的正常接收。

    `timescale 1ns / 1ps
    //////////////////////////////////////////////////////////////////////////////////
    //////////////////////////////////////////////////////////////////////////////////
    module lvds_test(
      input clk_50m,//全局时钟
      input rstn, //复位
      
      input clk_in_from_pin_p,         //lvds时钟输出P
      input clk_in_from_pin_n,         //lvds时钟输入N
      input data_in_from_pin_p,        //lvds输入数据P
      input data_in_from_pin_n,        //lvds输入数据N
      
      output clk_out_to_pin_p,         //lvds时钟输出P
      output clk_out_to_pin_n,         //lvds时钟输出N
      output data_out_to_pin_p,        //lvds输出数据P
      output data_out_to_pin_n         //lvds输出数据N  
        );
    
    
    wire clk_div_out_1;      //低速时钟1,串行发送时钟的8分频
    wire clk_div_out_2;      //低速时钟2,串行接收时钟的8分频
    
    wire [7:0] datain;       //LVDS输入的8位并行数据
    
    //产生LVDS发送的测试数据,0~FF
    reg [7:0] dataout;
    always @(posedge clk_div_out_1) begin
       if (~rstn) 
         dataout <= 0;
       else if (dataout == 8'hff)
         dataout <= 0;
        else 
         dataout <= dataout + 1'b1;    
     end
    
    //产生BITSLIP信号,用于修改串转并的Bit的起始位置
    wire [7:0] data_delay;
    reg BITSLIP=1'b0;
    reg slip_check;
    reg equal=1'b0;
    assign data_delay=datain;
    
    always @(posedge clk_div_out_2)
    begin
            if (~rstn) 
                 slip_check <= 1'b0;
            else if(data_delay==8'h80)      //当串转并的输入的数据为0x80的时候,检测开始
                  slip_check <= 1'b1;      
            else
                  slip_check <= 1'b0;        
    end
    
    always @(posedge clk_div_out_2)
    begin
            if (~rstn) begin
                  BITSLIP <= 1'b0;
               equal<=1'b0;        
            end      
            else if((slip_check==1'b1) && (equal==1'b0))
              if (data_delay ==8'h81) begin  //如果检测到数据0x80后面的下一个时钟的数据为0x81时
                 BITSLIP <= 1'b0;            //BITSLIP不为高
               equal<=1'b1;                   //数据正确信号为高          
            end
              else begin
                 BITSLIP <= 1'b1;           //BITSLIP产生一个高脉冲,改变串转并的数据排列
               equal<=1'b0;                  //数据正确信号为低
            end     
            else begin
                 BITSLIP <= 1'b0;
               equal<=equal;    
          end              
    end
              
    //并转串,8位数据dataout转换成串行数据,并通过lvds差分信号输出
    p_to_s p_to_s_inst
       (
      // From the device out to the system
        .DATA_OUT_FROM_DEVICE(dataout), //Input pins
        .DATA_OUT_TO_PINS_P(data_out_to_pin_p), //Output pins
        .DATA_OUT_TO_PINS_N(data_out_to_pin_n), //Output pins
        .CLK_TO_PINS_P(clk_out_to_pin_p), //Output pins
        .CLK_TO_PINS_N(clk_out_to_pin_n), //Output pins
    
        .CLK_IN(clk_50m),        // Single ended clock from IOB
        .CLK_DIV_OUT(clk_div_out_1),   // Slow clock output
        .IO_RESET(~rstn)  //system reset
    );
    
    //串转并,LVDS差分信号转换成单端信号再通过串转并,转换为8位数据datain
    s_to_p s_to_p_inst
       (
      // From the system into the device
        .DATA_IN_FROM_PINS_P(data_in_from_pin_p), //Input pins
        .DATA_IN_FROM_PINS_N(data_in_from_pin_n), //Input pins
        .DATA_IN_TO_DEVICE(datain), //Output pins
    
        .BITSLIP(BITSLIP), //Input pin
        .CLK_IN_P(clk_in_from_pin_p),      // Differential clock from IOB
        .CLK_IN_N(clk_in_from_pin_n),      // Differential clock from IOB
        .CLK_DIV_OUT(clk_div_out_2),   // Slow clock output
        .IO_RESET(~rstn)  //system reset
    );
    
    endmodule

    其中,clk_div_out_1和clk_div_out_2是8分频得到的(ISERDESE2、 OSERDESE2核实现),OSERDESE2输出的LVDS 差分时钟可作为ISERDESE2的接收时钟。

  • 相关阅读:
    漫谈企业级SaaS的多租户设计
    网易实战分享|云信IM SDK接口设计实践
    WebRTC系列之音频的那些事
    如何科学地完成一场 AR 发布会?全在这份超细节活动策划 Xmind 里了
    移动社交如何玩?网易云信携手崽崽和Uki打造更多新场景!
    行业观察|智慧屏集中爆发,大屏市场能否迎来破局者?
    Docker文件系统实战
    文字检测模型EAST应用详解 ckpt pb的tf加载,opencv加载
    opencv dnn加载EAST的pb模型的一点问题
    百度开源:PaddleOCR与PaddlePaddle / paddle2onnx 实践一
  • 原文地址:https://www.cnblogs.com/yangjun1219/p/5565013.html
Copyright © 2011-2022 走看看