[X]关闭

HDMI驱动与涉及内容详讲

文档创建者:自恋狂vip
浏览次数:11814
最后更新:2016-02-09
HDMI涉及到很多知识:图像色彩空间的转换、VerilogVHDL的混用、原语的使用以及ADV7511的配置。下面我们将一一道来:
为了对HDMI的深入理解,我们做一个这样的工程:里面数据流包含VGAHDMI两种方式的显示。下面是我们工程的接口。
HDMI的接口包括:hdmi_d(数据端口)hdmi_clk(驱动时钟)hdmi_de(使能端)hdmi_hsync(行同步信号)hdmi_vsync(场同步信号)hdmi_scl(ADV7511IIC时钟线)hdmi_sda(ADV7511IIC数据线)
VGA的接口包括:vga_hs(行同步信号)vga_vs(场同步信号)vga_r(红色数据端)vga_g(绿色数据端)vga_b(蓝色数据端)



我们的工程中HDMI的数据流需要先通过RGB444转换到RGB422格式,该转换过程由convert_444_422模块完成,转换后的RGB422格式通过colour_space_conversion来完成RGB422转换为YcbCr格式,YcbCr的数据格式通过hdmi_ddr_output来完成HDMI数据格式的输出转换,下面是我们整个工程的RTL图。


我们在新建工程前期需要很多参考资料:


ADV7511是需要配置出HDMI输出格式的芯片,我们需要阅读其参考资料;
code文件夹是我们格式配置与输出的相应代码文件夹;
DSP48E1是Xilinx原语,可以通过其进行数据乘法计算;
oddr是Xilinx原语,用于数据的采样方式改变,可以在时钟上升沿和下降沿都进行数据采样;
plle2_base是Xilinx原语,学过单片机的伙伴们都熟悉pll(锁相环),是用于时钟的倍频处理;

reference是杂项,里面还有一些其他的参考资料。

Ø  ADV7511
ADV7511可以输出YCbCr需要的格式,可以通过IIC配置该芯片。下面是该芯片的参考资料,其中链接为:https://ez.analog.com/docs/DOC-1740


其中 ADV7511_Programming_Guide和ADV7511_Hardware_Users_Guide是最重要的,我们可以通过查看该文档,来对ADV7511的寄存器进行配置。
   我们查看ADV7511_Programming_Guide文档的第39页中的Table27,可以配置出YcbCr的位宽数和格式类型,设置其寄存器就可以按照我们的需求输出相应的格式。



下面是我们的寄存器配置数据:
/////////////////////       Config Data LUT       //////////////////////////     
always@(*)
begin
       case(LUT_INDEX)
//     -- Powerup please!  reg_addr value
        0  :     LUT_DATA =    {8'h41,8'h00};   //16'h4110;      
//-- These valuse must be set as follows
        1  :     LUT_DATA =    16'h9803;
        2  :     LUT_DATA =    16'h9AE0;   
        3  :     LUT_DATA =     16'h9C30;     
        4  :     LUT_DATA =    16'h9D61;   
        5  :     LUT_DATA =    16'hA2A4;   
        6  :     LUT_DATA =    16'hA3A4;   
        7  :     LUT_DATA =    16'hE0D0;   
        8  :     LUT_DATA =    16'h5512;     
        9  :     LUT_DATA =    16'hF900;
//--Input mode     
        10 :     LUT_DATA =    16'h1506;  //input ID = 0x6 = 0110 = 8,10,12 bit YCbCr4:2:2 (DDR with separate syncs)
        11 :     LUT_DATA =    16'h4810;  // [4:3] = 01 = right justified
        12   :       LUT_DATA =   16'h1637; // 0011_0111  OutputFormat = 4:4:4, 8 bit, style 2 , YCbCr
        13   :       LUT_DATA =   16'h1700;     
        14:     LUT_DATA =    16'hD03C;
//--Output mode  
        15:     LUT_DATA =    16'hAF04;   
        16:     LUT_DATA =    16'h4c04;      
        17:     LUT_DATA =    16'h4000;
//--Here is the YCrCb => RGB conversion, as per programming guide
//--This is table 57 - HDTV YCbCr (16 to 255) to RGB (0 to 255)      
//-- (Cr * A1       +      Y * A2       +    Cb * A3)/4096 +     A4    = Red
        18:     LUT_DATA =    16'h18E7;     
        19:     LUT_DATA =    16'h1934;     
        20:     LUT_DATA =    16'h1A04;
        21:     LUT_DATA =    16'h1BAD;
        22:     LUT_DATA =    16'h1C00;
        23:     LUT_DATA =    16'h1D00;
        24:     LUT_DATA =    16'h1E1C;
        25:     LUT_DATA =    16'h1F1B;
//--(Cr * B1  +      Y * B2       +    Cb * B3)/4096 +     B4    = Green
        26:     LUT_DATA =    16'h201D;
        27:     LUT_DATA =    16'h21DC;
        28:     LUT_DATA =    16'h2204;
        29:     LUT_DATA =    16'h23AD;
        30:     LUT_DATA =    16'h241F;
        31:     LUT_DATA =    16'h2524;
        32:     LUT_DATA =    16'h2601;
        33:     LUT_DATA =    16'h2735;
//--(Cr * C1   +      Y * C2       +    Cb * C3)/4096 +     C4    = Blue
        34:     LUT_DATA =    16'h2800;
        35:     LUT_DATA =    16'h2900;
        36:     LUT_DATA =    16'h2A04;
        37:     LUT_DATA =    16'h2BAD;
        38:     LUT_DATA =    16'h2C08;
        39:     LUT_DATA =    16'h2D7C;
        40:     LUT_DATA =    16'h2E1B;   
        41:     LUT_DATA =    16'h2F77;     
//--Extra space filled with FFFFs to signify end of data   
       default:  LUT_DATA =     16'hFFFF;
       endcase
end


ADV7511_Programming_Guide文档的第16页中的I2C,可以查到我们ADV7511的寄存器地址为0x72or 0x7A


下面是我们IIC时序生成代码:
modulesccb_control(
       input clk,  //25mhz
       input sclk_100k,
       input i2c_negclk,
       input EN,
       input[23:0] wr_data,
       output reg trans_finished,
       output ack,
       output sccb_sclk,
       inout sccb_data
    );
//---------------------------------------------
//  计数器
//---------------------------------------------
reg[5:0]sccb_count = 0;
always@(posedgeclk) begin
       if(i2c_negclk)
              begin
      if(EN==0 || trans_finished == 1)
              sccb_count<=6'd0;
              else if(sccb_count< 6'd63)
         sccb_count <= sccb_count+1'b1;
              end
       else
      sccb_count <= sccb_count;
end
always@(posedgeclk) begin
//I2CWrite: ID-Address + SUB-Address + W-Data
if(i2c_negclk)
        begin
        if(EN)      
                            begin
               case(sccb_count)
                                          6'd0 :     begin            //idle
                                                               sccb_sclk_reg<= 1;
                                                               sccb_data_reg<= 1;
                                                               wr_ack_1<= 1;
                                                               wr_ack_2<= 1;
                                                               wr_ack_3<= 1;
                                                               trans_finished<= 0;
                                                               end                                                  
                                          6'd1  :  sccb_data_reg<= 0;
                                          6'd2  :        sccb_sclk_reg<= 0;    //start
                                                   
                                          6'd3  :  sccb_data_reg<= wr_data[23]; //start wr id       addr
                                          6'd4  :  sccb_data_reg<= wr_data[22];              
                                          6'd5  :  sccb_data_reg<= wr_data[21];
                                          6'd6  :  sccb_data_reg<= wr_data[20];                                 
                                          6'd7  :  sccb_data_reg<= wr_data[19];
                                          6'd8  :  sccb_data_reg<= wr_data[18];            
                                          6'd9  :  sccb_data_reg <= wr_data[17];
                                          6'd10:   sccb_data_reg <= wr_data[16];
                                          6'd11:  sccb_data_reg <= 1'd0;                                                            
                                //6'd12 :       wr_ack_1      <= sccb_data;            
                                    6'd12 : wr_ack_1      <= 1'd0;
                                          6'd13:   sccb_data_reg <= 1'd0;
                                          
                                          6'd14  :       sccb_data_reg<= wr_data[15]; //start wr sub addr
                                          6'd15  :       sccb_data_reg<= wr_data[14];            
                                          6'd16  :       sccb_data_reg<= wr_data[13];
                                          6'd17  :       sccb_data_reg<= wr_data[12];                                 
                                          6'd18  :       sccb_data_reg<= wr_data[11];
                                          6'd19  :       sccb_data_reg<= wr_data[10];            
                                          6'd20  :       sccb_data_reg<= wr_data[9];
                                          6'd21  :       sccb_data_reg<= wr_data[8];
                                          6'd22:   sccb_data_reg <= 1'd0;
                                   //     6'd23 :       wr_ack_2      <= sccb_data;      
                                      6'd23 : wr_ack_2      <= 1'd0;
                                          6'd24  :       sccb_data_reg<= 1'd0;
                                          
                                          6'd25  :       sccb_data_reg<= wr_data[7]; //start wr reg value
                                          6'd26  :       sccb_data_reg<= wr_data[6];
                                          6'd27  :       sccb_data_reg<= wr_data[5];
                                          6'd28  :       sccb_data_reg<= wr_data[4];
                                          6'd29  :       sccb_data_reg <= wr_data[3];
                                          6'd30  :       sccb_data_reg<= wr_data[2];
                                          6'd31:   sccb_data_reg <= wr_data[1];
                                          6'd32  :       sccb_data_reg<= wr_data[0];
                                          6'd33:   sccb_data_reg <= 1'd0;
                                                               
                                   //     6'd34 :   wr_ack_3      <= sccb_data;
                  6'd34 :  wr_ack_3     <= 1'd0;                             
                                          6'd35  :       sccb_data_reg<= 1'd0;
                                                        
                                          6'd36  :       begin
                                                               sccb_data_reg<= 0;  
                                                               sccb_sclk_reg<= 0;
                                                               end
                                          6'd37  :       sccb_sclk_reg<= 1;
                                          6'd38  : begin
                                                   sccb_data_reg  <= 1;   //stop
                                                   trans_finished <= 1;
                                                               end
                                     default : begin sccb_sclk_reg <= 1;sccb_data_reg <= 1; end
                             endcase
                                     end
         else begin
                            sccb_sclk_reg <=1;
                            sccb_data_reg <=1;
                            trans_finished <=0;
                            end
              end
end
//---------------------------------------------
//---------------------------------------------
regsccb_data_reg = 0;
regsccb_sclk_reg = 0;
regwr_ack_1 = 0,wr_ack_2 = 0,wr_ack_3 = 0;
assign  sccb_sclk = ((sccb_count>= 4  && sccb_count <=11)|| (sccb_count == 13) ||      
                                    (sccb_count>= 15 &&  sccb_count <=22) || (sccb_count == 24) ||
                                    (sccb_count>= 26 &&  sccb_count <=33) || (sccb_count == 35)) ?sclk_100k : sccb_sclk_reg;
                                                                                                                                                                                             
assign   sccb_data = ((sccb_count == 12|| sccb_count== 13 )||
                   (sccb_count == 23||sccb_count == 24 )||
                                           (sccb_count == 34|| sccb_count == 35 )) ? 1'bz: sccb_data_reg;
                                          
                                                                                                                                                                                    
//assign       sccb_sclk = (sccb_count>= 4  && sccb_count <= 30) ? sclk_100k : sccb_sclk_reg;
                                          
//assign   sccb_data = ((sccb_count == 12)||(sccb_count== 21)||(sccb_count == 30))? 1'bz : sccb_data_reg;
                                          
      
assign   ack = (wr_ack_1|wr_ack_2|wr_ack_3) ;  //一轮寄存器写是否完成
endmodule
&#216;  code
下面是我们的代码截图文件,包括顶层文件hdmi_display、pll分频倍频、vga_generator文件、rgb444转换422、colour_space_conversionRGB422到YcbCr色彩空间转换、hdmi输出以及IIC时序生成和ADV7511寄存器配置,最后还有我们的时序约束文件。


&#216;  DSP48E1
Thisdesign element is a versatile, scalable, hard IP block within 7 series devicesthat allows for the creation of compact, high-speed, arithmetic-intensiveoperations, such as those seen for many DSP algorithms. Some of the functionscapable within the block include multiplication, addition, subtraction,accumulation, shifting, logical operations and pattern detection.

DSP48E1原语可以在我们的ISE软件安装路径里找到,其路径为:软件版本/ISE_DS/ ISE/ doc/ usengliah/ isehelp/ 7series


DSP48E1的相关参考资料如下:
第一个为DSP48E1原语的路径截图;第二个文件为DSP48E1的原语及例化介绍;第三个是最详细的原语端口介绍及例化模板详情;最后一个为DSP48E1的PDF文档说明(http://www.xilinx.com/support/documentation/user_guides/ug479_7Series_DSP48E1.pdf)。


下面是我们从第三个文件libs_le_dsp48e1里找到的Verilog例化模板:
Verilog Instantiation Template
// DSP48E1: 48-bitMulti-Functional Arithmetic Block
//          7 Series
// Xilinx HDL Libraries Guide,version 14.7

DSP48E1 #(
  // Feature Control Attributes: Data Path Selection
  .A_INPUT("DIRECT"),               // Selects A input source,"DIRECT" (A port) or "CASCADE" (ACIN port)
  .B_INPUT("DIRECT"),               // Selects B input source,"DIRECT" (B port) or "CASCADE" (BCIN port)
  .USE_DPORT("FALSE"),              // Select D port usage (TRUE orFALSE)
  .USE_MULT("MULTIPLY"),            // Select multiplier usage("MULTIPLY", "DYNAMIC", or "NONE")
  // Pattern Detector Attributes: Pattern Detection Configuration
  .AUTORESET_PATDET("NO_RESET"),    // "NO_RESET", "RESET_MATCH","RESET_NOT_MATCH"
  .MASK(48'h0000All ones),         // 48-bit mask value for pattern detect (1=ignore)
  .PATTERN(48'h000All zeros),      // 48-bit pattern match for pattern detect
  .SEL_MASK("MASK"),                // "C","MASK", "ROUNDING_MODE1", "ROUNDING_MODE2"
  .SEL_PATTERN("PATTERN"),          // Select pattern value("PATTERN" or "C")
  .USE_PATTERN_DETECT("NO_PATDET"), // Enable pattern detect("PATDET" or "NO_PATDET")
  // Register Control Attributes: Pipeline Register Configuration
  .ACASCREG(1),                    // Number of pipeline stages between A/ACIN and ACOUT (0, 1 or 2)
  .ADREG(1),                       // Number of pipeline stages for pre-adder (0 or 1)
  .ALUMODEREG(1),                  // Number of pipeline stages for ALUMODE (0 or 1)
  .AREG(1),                        // Number of pipeline stages for A (0, 1 or 2)
  .BCASCREG(1),                    // Number of pipeline stages between B/BCIN and BCOUT (0, 1 or 2)
  .BREG(1),                        // Number of pipeline stages for B (0, 1 or 2)
  .CARRYINREG(1),                  // Number of pipeline stages for CARRYIN (0 or 1)
  .CARRYINSELREG(1),               // Number of pipeline stages for CARRYINSEL (0 or 1)
  .CREG(1),                        // Number of pipeline stages for C (0 or 1)
  .DREG(1),                        // Number of pipeline stages for D (0 or 1)
  .INMODEREG(1),                   // Number of pipeline stages for INMODE (0 or 1)
  .MREG(1),                        // Number of multiplier pipeline stages (0 or 1)
  .OPMODEREG(1),                   // Number of pipeline stages for OPMODE (0 or 1)
  .PREG(1),                        // Number of pipeline stages for P (0 or 1)
  .USE_SIMD("ONE48")                // SIMD selection("ONE48", "TWO24", "FOUR12")
)
DSP48E1_inst (
  // Cascade: 30-bit (each) output: Cascade Ports
  .ACOUT(ACOUT),                  // 30-bit output: A port cascade output
  .BCOUT(BCOUT),                   // 18-bit output: B port cascade output
  .CARRYCASCOUT(CARRYCASCOUT),    // 1-bit output: Cascade carry output
  .MULTSIGNOUT(MULTSIGNOUT),      // 1-bit output: Multiplier sign cascade output
  .PCOUT(PCOUT),                  // 48-bit output: Cascade output
  // Control: 1-bit (each) output: Control Inputs/Status Bits
  .OVERFLOW(OVERFLOW),            // 1-bit output: Overflow in add/acc output
  .PATTERNBDETECT(PATTERNBDETECT), // 1-bit output: Pattern bar detectoutput
  .PATTERNDETECT(PATTERNDETECT),  // 1-bit output: Pattern detect output
  .UNDERFLOW(UNDERFLOW),          // 1-bit output: Underflow in add/acc output
  // Data: 4-bit (each) output: Data Ports
  .CARRYOUT(CARRYOUT),            // 4-bit output: Carry output
  .P(P),                           // 48-bit output:Primary data output
  // Cascade: 30-bit (each) input: Cascade Ports
  .ACIN(ACIN),                    // 30-bit input: A cascade data input
  .BCIN(BCIN),                    // 18-bit input: B cascade input
  .CARRYCASCIN(CARRYCASCIN),      // 1-bit input: Cascade carry input
  .MULTSIGNIN(MULTSIGNIN),        // 1-bit input: Multiplier sign input
  .PCIN(PCIN),                    // 48-bit input: P cascade input
  // Control: 4-bit (each) input: Control Inputs/Status Bits
  .ALUMODE(ALUMODE),              // 4-bit input: ALU control input
  .CARRYINSEL(CARRYINSEL),        // 3-bit input: Carry select input
  .CEINMODE(CEINMODE),            // 1-bit input: Clock enable input for INMODEREG
  .CLK(CLK),                      // 1-bit input: Clock input
  .INMODE(INMODE),                // 5-bit input: INMODE control input
  .OPMODE(OPMODE),                // 7-bit input: Operation mode input
  .RSTINMODE(RSTINMODE),          // 1-bit input: Reset input for INMODEREG
  // Data: 30-bit (each) input: Data Ports
  .A(A),                          // 30-bit input: A data input
  .B(B),                          // 18-bit input: B data input
  .C(C),                          // 48-bit input: C data input
  .CARRYIN(CARRYIN),              // 1-bit input: Carry input signal
  .D(D),                          // 25-bit input: D data input
  // Reset/Clock Enable: 1-bit (each) input: Reset/Clock Enable Inputs
  .CEA1(CEA1),                    // 1-bit input: Clock enable input for 1st stage AREG
  .CEA2(CEA2),                    // 1-bit input: Clock enable input for 2nd stage AREG
  .CEAD(CEAD),                    // 1-bit input: Clock enable input for ADREG
  .CEALUMODE(CEALUMODE),           // 1-bit input: Clock enable input forALUMODERE
  .CEB1(CEB1),                    // 1-bit input: Clock enable input for 1st stage BREG
  .CEB2(CEB2),                    // 1-bit input: Clock enable input for 2nd stage BREG
  .CEC(CEC),                       // 1-bit input: Clock enable inputfor CREG
  .CECARRYIN(CECARRYIN),          // 1-bit input: Clock enable input for CARRYINREG
  .CECTRL(CECTRL),                // 1-bit input: Clock enable input for OPMODEREG and CARRYINSELREG
  .CED(CED),                      // 1-bit input: Clock enable input for DREG
  .CEM(CEM),                      // 1-bit input: Clock enable input for MREG
  .CEP(CEP),                      // 1-bit input: Clock enable input for PREG
  .RSTA(RSTA),                    // 1-bit input: Reset input for AREG
  .RSTALLCARRYIN(RSTALLCARRYIN),  // 1-bit input: Reset input for CARRYINREG
  .RSTALUMODE(RSTALUMODE),        // 1-bit input: Reset input for ALUMODEREG
  .RSTB(RSTB),                     // 1-bit input: Reset input for BREG
  .RSTC(RSTC),                    // 1-bit input: Reset input for CREG
  .RSTCTRL(RSTCTRL),              // 1-bit input: Reset input for OPMODEREG and CARRYINSELREG
  .RSTD(RSTD),                    // 1-bit input: Reset input for DREG and ADREG
  .RSTM(RSTM),                    // 1-bit input: Reset input for MREG
  .RSTP(RSTP)                     // 1-bit input: Reset input for PREG
);

// Endof DSP48E1_inst instantiation
&#216;  oddr
This design element is adedicated output register for use in transmitting dual data rate (DDR) signalsfrom FPGA devices. The ODDR interface with the FPGA fabric is not limited toopposite clock edges. It can be configured to present date from the FPGA fabricat the same clock edge. This feature allows designers to avoid additionaltiming complexities and CLB usage. The ODDR also works with SelectIO&#8482; features.
ODDR Modes:
This element has two modes ofoperation. These modes are set by the DDR_CLK_EDGE attribute.
OPPOSITE_EDGE mode - The datatransmit interface uses classic DDR methodology. Given a data and clock at pinD1-2 and C respectively, D1 is sampled at every positive edge of clock C and D2is sampled at every negative edge of clock C. Q changes every clock edge.
SAME_EDGE mode - Data is stilltransmitted at the output of the ODDR by opposite edges of clock C. However,the two inputs to the ODDR are clocked with a positive clock edge of clocksignal C and an extra register is clocked with a negative clock edge of clocksignal C. Using this feature, DDR data can now be presented into the ODDR atthe same clock edge.
oddr 原语也可以在我们的ISE软件安装路径里找到,其路径同样为:软件版本/ISE_DS/ ISE/ doc/ usengliah/ isehelp/ 7series

我们的oddr的参考资料为下面两个文件,其中第一个为oddr原语的端口及例化详细介绍,第二个为oddr的详细介绍PDF文档,其下载链接在(http://www.xilinx.com/support/documentation/user_guides/ug471_7Series_SelectIO.pdf


下面是ODDR的例化模块模板代码:
Verilog Instantiation Template
// ODDR: Output Double Data RateOutput Register with Set, Reset
//       and Clock Enable.
//       7 Series
// Xilinx HDL Libraries Guide,version 14.7

ODDR #(
  .DDR_CLK_EDGE("OPPOSITE_EDGE"), // "OPPOSITE_EDGE"or "SAME_EDGE"
  .INIT(1'b0),    // Initial valueof Q: 1'b0 or 1'b1
  .SRTYPE("SYNC") // Set/Reset type: "SYNC" or"ASYNC"
) ODDR_inst (
  .Q(Q),   // 1-bit DDR output
  .C(C),   // 1-bit clock input
  .CE(CE), // 1-bit clock enable input
  .D1(D1), // 1-bit data input (positive edge)
  .D2(D2), // 1-bit data input (negative edge)
  .R(R),   // 1-bit reset
  .S(S)    // 1-bit set
);

// Endof ODDR_inst instantiation
在我们的工程中使用的ODDR例化:
//hdmi时钟生成  
ODDR#(
    .DDR_CLK_EDGE("SAME_EDGE"),
    .INIT(1'b0),
    .SRTYPE("SYNC")
    ) ODDR_hdmi_clk (
    .C(clk90),
    .Q(hdmi_clk),  
    .D1(1'b1),
    .D2(1'b0),
    .CE(1'b1),
    .R(1'b0),
    .S(1'b0)
    );
//hdmi使能端生成
    ODDR#(
       .DDR_CLK_EDGE("SAME_EDGE"),
       .INIT(1'b0),
       .SRTYPE("SYNC")
       ) ODDR_hdmi_de (
       .C(clk),
       .Q(hdmi_de),  
       .D1(de_in),
       .D2(de_in),
       .CE(1'b1),
       .R(1'b0),
       .S(1'b0)
       );
//生成语句来采样hdmi数据
   generate
       genvar i;
  for(i=0;i<=7;i=i+1) begin: inst_generate
        ODDR#(
               .DDR_CLK_EDGE("SAME_EDGE"),
               .INIT(1'b0),
               .SRTYPE("SYNC")
               )  ODDR_hdmi_d (
               .C(clk),
               .Q(hdmi_d[i+8]),  
               .D1(y),
               .D2(c),
               .CE(1'b1),
               .R(1'b0),
               .S(1'b0)
               );        
end         
endgenerate
&#216;&#216;  plle2_base
PLLE2是Xilinx原语,可以倍频和分频,通过该原语可以替代clockIP,来生成需要的时钟频率。
The PLLE2 is a mixed signal blockdesigned to support frequency synthesis, clock network deskew, and jitterreduction. The clock outputs can each have an individual divide (1 to 128),phase shift, and duty cycle based on the same VCO frequency. Output clocks arephase aligned to each other (unless phase shifted) and aligned to the inputclock with a proper feedback configuration.
ThePLLE2 complements the MMCM by supporting higher speed clocking while the MMCMhas more features to handle most general clocking needs. The PLLE2_BASE isintended for most uses of this PLL component while the PLLE2_ADV is intendedfor use when clock switch-over or dynamic reconfiguration is required.


下面是我们的PLLE2参考文件,其中第一个文件是我们plle2的端口说明和例化模拟文件,第二个是我们的原语路径截图,第三个是我们的端口例化注释。


VerilogInstantiation Template
//PLLE2_BASE: Base Phase Locked Loop (PLL)
//             7 Series
//Xilinx HDL Libraries Guide, version 14.7
PLLE2_BASE#(
   .BANDWIDTH("OPTIMIZED"),  // OPTIMIZED, HIGH, LOW
   .CLKFBOUT_MULT(5),        // Multiply value for all CLKOUT,(2-64)
   .CLKFBOUT_PHASE(0.0),     // Phase offset in degrees of CLKFB,(-360.000-360.000).
   .CLKIN1_PERIOD(0.0),      // Input clock period in ns to psresolution (i.e. 33.333 is 30 MHz).
   // CLKOUT0_DIVIDE - CLKOUT5_DIVIDE: Divideamount for each CLKOUT (1-128)
   .CLKOUT0_DIVIDE(1),
   .CLKOUT1_DIVIDE(1),
   .CLKOUT2_DIVIDE(1),
   .CLKOUT3_DIVIDE(1),
   .CLKOUT4_DIVIDE(1),
   .CLKOUT5_DIVIDE(1),
   // CLKOUT0_DUTY_CYCLE - CLKOUT5_DUTY_CYCLE:Duty cycle for each CLKOUT (0.001-0.999).
   .CLKOUT0_DUTY_CYCLE(0.5),
   .CLKOUT1_DUTY_CYCLE(0.5),
   .CLKOUT2_DUTY_CYCLE(0.5),
   .CLKOUT3_DUTY_CYCLE(0.5),
   .CLKOUT4_DUTY_CYCLE(0.5),
   .CLKOUT5_DUTY_CYCLE(0.5),
   // CLKOUT0_PHASE - CLKOUT5_PHASE: Phaseoffset for each CLKOUT (-360.000-360.000).
   .CLKOUT0_PHASE(0.0),
  .CLKOUT1_PHASE(0.0),
   .CLKOUT2_PHASE(0.0),
   .CLKOUT3_PHASE(0.0),
   .CLKOUT4_PHASE(0.0),
   .CLKOUT5_PHASE(0.0),
   .DIVCLK_DIVIDE(1),        // Master division value, (1-56)
   .REF_JITTER1(0.0),        // Reference input jitter in UI,(0.000-0.999).
   .STARTUP_WAIT("FALSE")    // Delay DONE until PLL Locks,("TRUE"/"FALSE")
)
PLLE2_BASE_inst(
   // Clock Outputs: 1-bit (each) output: Userconfigurable clock outputs
   .CLKOUT0(CLKOUT0),   // 1-bit output: CLKOUT0
   .CLKOUT1(CLKOUT1),   // 1-bit output: CLKOUT1
   .CLKOUT2(CLKOUT2),   // 1-bit output: CLKOUT2
   .CLKOUT3(CLKOUT3),   // 1-bit output: CLKOUT3
   .CLKOUT4(CLKOUT4),   // 1-bit output: CLKOUT4
   .CLKOUT5(CLKOUT5),   // 1-bit output: CLKOUT5
   // Feedback Clocks: 1-bit (each) output:Clock feedback ports
   .CLKFBOUT(CLKFBOUT), // 1-bit output:Feedback clock
   .LOCKED(LOCKED),     // 1-bit output: LOCK
   .CLKIN1(CLKIN1),     // 1-bit input: Input clock
   // Control Ports: 1-bit (each) input: PLLcontrol ports
   .PWRDWN(PWRDWN),     // 1-bit input: Power-down
   .RST(RST),           // 1-bit input: Reset
   // Feedback Clocks: 1-bit (each) input:Clock feedback ports
   .CLKFBIN(CLKFBIN)    // 1-bit input: Feedback clock
);
//End of PLLE2_BASE_inst instantiation
Generatea 75MHz pixel clock and one with 90 degree phase shift from the 100MHz systemclock.
方法一:
pllmy_pll
   (// Clock in ports
    .CLK_IN1(clk_100),      // IN
    // Clock out ports
    .CLK_OUT1(clk0),      //OUT
    .CLK_OUT2(clk),       //OUT
    .CLK_OUT3(clk90));    // OUT
方法二:
        wire clkfb;
        PLLE2_BASE #(
   .BANDWIDTH("OPTIMIZED"),  // OPTIMIZED, HIGH, LOW
   .CLKFBOUT_MULT(8),        // Multiply value for all CLKOUT,(2-64)
   .CLKFBOUT_PHASE(0.0),     // Phase offset in degrees of CLKFB,(-360.000-360.000).
   .CLKIN1_PERIOD(10),      // Input clock period in ns to psresolution (i.e. 33.333 is 30 MHz).
   // CLKOUT0_DIVIDE - CLKOUT5_DIVIDE: Divideamount for each CLKOUT (1-128)
   .CLKOUT0_DIVIDE(8),         // 100MHz
   .CLKOUT1_DIVIDE(20),         // 100*4/10 = 40MHz
   .CLKOUT2_DIVIDE(20),         // 100*4/10 = 40MHz
   .CLKOUT3_DIVIDE(1),
   .CLKOUT4_DIVIDE(1),
   .CLKOUT5_DIVIDE(1),
   // CLKOUT0_DUTY_CYCLE - CLKOUT5_DUTY_CYCLE:Duty cycle for each CLKOUT (0.001-0.999).
   .CLKOUT0_DUTY_CYCLE(0.5),
   .CLKOUT1_DUTY_CYCLE(0.5),
   .CLKOUT2_DUTY_CYCLE(0.5),
   .CLKOUT3_DUTY_CYCLE(0.5),
   .CLKOUT4_DUTY_CYCLE(0.5),
   .CLKOUT5_DUTY_CYCLE(0.5),
   // CLKOUT0_PHASE - CLKOUT5_PHASE: Phaseoffset for each CLKOUT (-360.000-360.000).
   .CLKOUT0_PHASE(0.0),
   .CLKOUT1_PHASE(0.0),
   .CLKOUT2_PHASE(135),
   .CLKOUT3_PHASE(0.0),
   .CLKOUT4_PHASE(0.0),
   .CLKOUT5_PHASE(0.0),
   .DIVCLK_DIVIDE(1),        // Master division value, (1-56)
   .REF_JITTER1(0.0),        // Reference input jitter in UI,(0.000-0.999).
   .STARTUP_WAIT("FALSE")    // Delay DONE until PLL Locks,("TRUE"/"FALSE")
)
PLLE2_BASE_inst(
   // Clock Outputs: 1-bit (each) output: Userconfigurable clock outputs
   .CLKOUT0(clk0),   // 1-bit output: CLKOUT0
   .CLKOUT1(clk),   // 1-bit output: CLKOUT1
   .CLKOUT2(clk90),   // 1-bit output: CLKOUT2
   .CLKOUT3(),  // 1-bit output: CLKOUT3
   .CLKOUT4(),  // 1-bit output: CLKOUT4
   .CLKOUT5(),  // 1-bit output: CLKOUT5
   // Feedback Clocks: 1-bit (each) output:Clock feedback ports
   .CLKFBOUT(clkfb), // 1-bit output: Feedbackclock
   .LOCKED(),     // 1-bit output: LOCK
   .CLKIN1(clk_100),     // 1-bit input: Input clock
   // Control Ports: 1-bit (each) input: PLLcontrol ports
   .PWRDWN(0),     // 1-bit input: Power-down
   .RST(0),           // 1-bit input: Reset
   // Feedback Clocks: 1-bit (each) input:Clock feedback ports
   .CLKFBIN(clkfb)    // 1-bit input: Feedback clock
);
ü  RGB2YcbCr
RGB和YcbCr之间的转换有公式可依:
               
Y  =  0.2573*R + 0.5013*G + 0.0969*B + 16                           (1)
Cb  =  -0.147*R - 0.2907*G + 0.4378*B + 128                          (2)
Cr  =  0.4378*R - 0.3676*G - 0.0702*B + 128                          (3)
               
由于Verilog不支持浮点运算,但是可以做整数的乘法和除法,乘法的实现我们采用移位操作,因为Verilog最擅长移位操作,这样会提高运行效率,因此我们将上面三个公式先向左移8位,扩大256倍,最后再进行左移运算。
                                   
FPGA富含乘法器、加法器和移位寄存器,如果直接使用上面的公式进行计算,理论上是可以计算出的,不过其消耗的资源比较多,效率也比较低,而且最重要的是当表达式小于0的时候,运算就是出现错误,为此,我们对公式的运算进行整合,将128放到公式里面,这样就可以避免括号内出现负数的情况,其公式修改如下所示:
                           
                                    
经过公式的变形,我们就可以避免负数的产生,其分析如下:
Y一定是正数;
对Cb进行分析:
将第二个公式进行变形:
                             
                                
因为RGB最大为255,所以公式(3-13)里的RGB最大都取不到1,当R和G取最大,B取最小时候,Cb最小,其值最小为1。
对Cr进行分析:
将第三个公式进行变形:
                                      
                       
当B和G取最大,R取最小时候,Cr最小,其值最小为0。
/******************************    计算Y ***********************************************
         条件:32768 = 2^15;      
               r1_in = 2 * r ,      g1_in = 2 * g,        b1_in = 2 * b;
                           a_r1= (2^15)*r1_in, a_g1 = (2^15)*g1_in, a_b1 = (2^15)*b1_in
                           b_r1=(2^2)*8432,    b_g1 = (2^2)*16425,   b_b1 = (2^2)*3176                                 
      
y = ( 8432 * r + 16425 * g +  3176 * b) / 32768 + 16 = 0.2573*r + 0.5013*g+ 0.0969b + 16
(2^15)*Y = ( 8432 * r + 16425 * g+  3176 * b) + 2^4*2^15 =  ( 8432 * r + 16425 * g +  3176 * B) + 2^19
(2^15)*Y*2 = ( 8432 * r1_in +16425 * g1_in +  3176 * b1_in) + 2^19*2
(2^16)*Y = ( 8432 * r1_in + 16425* g1_in +  3176 * b1_in) + 2^20
((2^16)*(2^2)*(2^15))*Y  = (b_r1*a_r1 + b_g1*a_g1 + b_b1*a_b1)+(2^20)*(2^2)*(2^15)
(2^33)*Y = (b_r1*a_r1 + b_g1*a_g1 + b_b1*a_b1) + 2^37
(2^33)*Y = (b_r1*a_r1 + b_g1*a_g1 + b_b1*a_b1) + c1
**********************************************************************************/
/**********************************  计算Cb Cr *********************************************
     条件:32768 = 2^15;
              r2_in = 2*r,           g2_in = 2*g,            b2_in = 2*b
           a_r2 = (2^15)*r2_in    a_g2 = (2^15)*g2_in     a_b2= (2^15)*b2_in
                      r, g, b 前面的系数都扩大了4 倍
cb = (-4818 * r -  9527 * g + 14345 * B) / 32768 + 128 =-0.147*r - 0.2907*g + 0.4378*b + 128
cr = (14345 * r - 12045 * g -  2300 * B) / 32768 + 128 = 0.4378*r - 0.3676*g- 0.0702*b + 128
(2^15)*Cb = (-4818 * r -  9527 * g + 14345 * B) + (2^15)*(2^7)
(2^15)*Cb = (-4818 * r -  9527 * g + 14345 * B) + (2^22)
(2^15)*Cb*(2^2)*(2*2^15) = (b_r2 * a_r2 + b_g2*a_g2 + b_b2 *a_b2) + (2^22)*(2^2)*(2*2^15)
(2^33)*Cb = (b_r2 * a_r2 + b_g2 *a_g2 + b_b2*a_b2) + (2^40)
(2^33)*Cb = (b_r2 * a_r2 + b_g2 *a_g2 + b_b2*a_b2) + c2
***********************************************************************************/

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x

发表评论已发布 1

rongzhai

发表于 2016-2-9 11:40:26 | 显示全部楼层

很不错,厉害啊
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则