1 概述
该方案用于生成RGB信号,通过lvds接口驱动逻辑输出,点亮并驱动BP101WX-206液晶屏幕。
参考:下面为参考文章,内容非常详细。Xilinx LVDS Output——原语调用_vivado原语_ShareWow丶的博客http://t.csdn.cn/Zy37p
2 功能描述
MMCM模块为时钟模块,负责将系统时钟变频与输出,产生各模块所需要的时钟;data_generator模块用于生成各种数据与信号,并传输给lvds_output_driver模块,lvds_output_driver模块将这些数据进行并串转换并按指定的lvds格式输出给液晶屏。
3 模块详细设计
MMCM模块用于时钟的变频与输出,data_generator模块用于生成8bit RGB数据,行场同步信号(h_sync、v_sync)和数据使能信号data_en,并传输给lvds_output_driver模块,该模块将这些数据进行并串转换并按指定格式输出给液晶屏。具体详细设计图如下:
3.1 MMCM模块
以下为时钟模块MMCM的接口示意图输出65Mhz和455Mhz的时钟,输出locked作为其他模块的复位信号,改模块采用IP核实现。
3.2 Data_generator模块设计
手册中给出的时序信息如下图:
依照这样的逻辑,画出大致的设计时序图:
3.3 lvds_output_driver模块设计
该模块的详细设计如下:
手册中的输出逻辑时序如下:
4 详细代码设计
4.1 data_generator模块详细设计
/*
this module is used for data generation
BP101WX1-206
1280 * 800 pixel
*/
//count H_SYNC
always @(posedge i_clk_65mhz or posedge i_rst) begin
if (i_rst) begin
cnt_h <= 0;
end
else if (end_cnt_h) begin
cnt_h <= 0;
end
else begin
cnt_h <= cnt_h + 1;
end
end
assign end_cnt_h = cnt_h == (H_TOTAL - 1);
//count V_SYNC
always @(posedge i_clk_65mhz or posedge i_rst) begin
if (i_rst) begin
cnt_v <= 0;
end
else if (end_cnt_h) begin
if (end_cnt_v) begin
cnt_v <= 0;
end
else begin
cnt_v <= cnt_v + 1;
end
end
end
assign end_cnt_v = end_cnt_h && (cnt_v == (V_TOTAL - 1));
//OUTPUT h_sync v_sync DE
always @(posedge i_clk_65mhz or posedge i_rst) begin
if (i_rst) begin
o_h_sync <= 1;
end
else if ((cnt_h == H_FRONT - 1) || (cnt_h == H_FRONT + H_SYNC - 1)) begin
o_h_sync <= ~o_h_sync;
end
end
always @(posedge i_clk_65mhz or posedge i_rst) begin
if (i_rst) begin
o_v_sync <= 1;
end
else if ((cnt_v == V_FRONT - 1 && end_cnt_h) || (cnt_v == V_FRONT + V_SYNC - 1 && end_cnt_h)) begin
o_v_sync <= ~o_v_sync;
end
end
always @(posedge i_clk_65mhz or posedge i_rst) begin
if (i_rst) begin
o_data_en <= 0;
end
else if ((cnt_h == H_BLANK - 1 && cnt_v >= V_BLANK) || (cnt_h == H_TOTAL - 1 && cnt_v >= V_BLANK)) begin
o_data_en <= ~o_data_en;
end
end
//RGB data generation
assign x_cnt = (cnt_h >= H_BLANK)? cnt_h - (H_BLANK - 1) : 0;
assign y_cnt = (cnt_v >= V_BLANK)? cnt_v - (V_BLANK) : 0;
always @(posedge i_clk_65mhz or posedge i_rst) begin
if (i_rst) begin
rgb_data <= 0;
end
/* else if (x_cnt == h_vo || y_cnt == v_vo) begin
rgb_data <= 24'hff_00_00;
end */
else if (x_cnt == 0 || x_cnt == 639 || x_cnt == 1279) begin
rgb_data <= 24'hff_00_00;
end
else if (y_cnt == 0 || y_cnt == 20 || y_cnt == 40) begin
rgb_data <= 24'hff_00_00;
end
else begin
rgb_data <= 24'hffffff;
end
end
assign {o_red_data, o_gre_data, o_blu_data} = rgb_data;
4.2 lvds_output_driver详细设计
// CLK
OSERDESE2 #(
.DATA_RATE_OQ ("SDR" ), // DDR, SDR
.DATA_RATE_TQ ("SDR" ), // DDR, BUF, SDR
.DATA_WIDTH (7 ), // 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)
)
OSERDES_clk_inst (
.OFB ( ), // 1-bit output: Feedback path for data
.OQ (oserdes_clk ), // 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 (i_clk_455mhz ), // 1-bit input: High speed clock
.CLKDIV (i_clk_65mhz ), // 1-bit input: Divided clock
// D1 - D8: 1-bit (each) input: Parallel data inputs (1-bit each)
.D1 (CLK_PATTERN[0] ),
.D2 (CLK_PATTERN[1] ),
.D3 (CLK_PATTERN[2] ),
.D4 (CLK_PATTERN[3] ),
.D5 (CLK_PATTERN[4] ),
.D6 (CLK_PATTERN[5] ),
.D7 (CLK_PATTERN[6] ),
.D8 ( ),
.OCE (1'b1 ), // 1-bit input: Output data clock enable
.RST (i_rst ), // 1-bit input: Reset
// SHIFTIN1 / SHIFTIN2: 1-bit (each) input: Data input expansion (1-bit each)
.SHIFTIN1 (1'b0 ),
.SHIFTIN2 (1'b0 ),
// 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
);
OBUFDS #(
.IOSTANDARD ("DEFAULT" ), // Specify the output I/O standard
.SLEW ("SLOW" ) // Specify the output slew rate
) OBUFDS_CLK_inst (
.O (tx_clk_p ), // Diff_p output (connect directly to top-level port)
.OB (tx_clk_n ), // Diff_n output (connect directly to top-level port)
.I (oserdes_clk ) // Buffer input
);
// 1 PAIR
OSERDESE2 #(
.DATA_RATE_OQ ("SDR" ), // DDR, SDR
.DATA_RATE_TQ ("SDR" ), // DDR, BUF, SDR
.DATA_WIDTH (7 ), // 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)
)
OSERDES_data_inst0 (
.OFB ( ), // 1-bit output: Feedback path for data
.OQ (oserdes_data[0]), // 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 (i_clk_455mhz ), // 1-bit input: High speed clock
.CLKDIV (i_clk_65mhz ), // 1-bit input: Divided clock
// D1 - D8: 1-bit (each) input: Parallel data inputs (1-bit each)
.D1 (i_gre_data[0] ),
.D2 (i_red_data[5] ),
.D3 (i_red_data[4] ),
.D4 (i_red_data[3] ),
.D5 (i_red_data[2] ),
.D6 (i_red_data[1] ),
.D7 (i_red_data[0] ),
.D8 ( ),
.OCE (1'b1 ), // 1-bit input: Output data clock enable
.RST (i_rst ), // 1-bit input: Reset
// SHIFTIN1 / SHIFTIN2: 1-bit (each) input: Data input expansion (1-bit each)
.SHIFTIN1 (1'b0 ),
.SHIFTIN2 (1'b0 ),
// 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
);
OBUFDS #(
.IOSTANDARD ("DEFAULT" ), // Specify the output I/O standard
.SLEW ("SLOW" ) // Specify the output slew rate
) OBUFDS_DATA_inst0 (
.O (lvds_data_p[0] ), // Diff_p output (connect directly to top-level port)
.OB (lvds_data_n[0] ), // Diff_n output (connect directly to top-level port)
.I (oserdes_data[0]) // Buffer input
);
// 2 PAIR
OSERDESE2 #(
.DATA_RATE_OQ ("SDR" ), // DDR, SDR
.DATA_RATE_TQ ("SDR" ), // DDR, BUF, SDR
.DATA_WIDTH (7 ), // 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)
)
OSERDES_data_inst1 (
.OFB ( ), // 1-bit output: Feedback path for data
.OQ (oserdes_data[1]), // 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 (i_clk_455mhz ), // 1-bit input: High speed clock
.CLKDIV (i_clk_65mhz ), // 1-bit input: Divided clock
// D1 - D8: 1-bit (each) input: Parallel data inputs (1-bit each)
.D1 (i_blu_data[1] ),
.D2 (i_blu_data[0] ),
.D3 (i_gre_data[5] ),
.D4 (i_gre_data[4] ),
.D5 (i_gre_data[3] ),
.D6 (i_gre_data[2] ),
.D7 (i_gre_data[1] ),
.D8 ( ),
.OCE (1'b1 ), // 1-bit input: Output data clock enable
.RST (i_rst ), // 1-bit input: Reset
// SHIFTIN1 / SHIFTIN2: 1-bit (each) input: Data input expansion (1-bit each)
.SHIFTIN1 (1'b0 ),
.SHIFTIN2 (1'b0 ),
// 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
);
OBUFDS #(
.IOSTANDARD ("DEFAULT" ), // Specify the output I/O standard
.SLEW ("SLOW" ) // Specify the output slew rate
) OBUFDS_DATA_inst1 (
.O (lvds_data_p[1] ), // Diff_p output (connect directly to top-level port)
.OB (lvds_data_n[1] ), // Diff_n output (connect directly to top-level port)
.I (oserdes_data[1]) // Buffer input
);
// 3 PAIR
OSERDESE2 #(
.DATA_RATE_OQ ("SDR" ), // DDR, SDR
.DATA_RATE_TQ ("SDR" ), // DDR, BUF, SDR
.DATA_WIDTH (7 ), // 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)
)
OSERDES_data_inst2 (
.OFB ( ), // 1-bit output: Feedback path for data
.OQ (oserdes_data[2]), // 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 (i_clk_455mhz ), // 1-bit input: High speed clock
.CLKDIV (i_clk_65mhz ), // 1-bit input: Divided clock
// D1 - D8: 1-bit (each) input: Parallel data inputs (1-bit each)
.D1 (i_data_en ),
.D2 (i_v_sync ),
.D3 (i_h_sync ),
.D4 (i_blu_data[5] ),
.D5 (i_blu_data[4] ),
.D6 (i_blu_data[3] ),
.D7 (i_blu_data[2] ),
.D8 ( ),
.OCE (1'b1 ), // 1-bit input: Output data clock enable
.RST (i_rst ), // 1-bit input: Reset
// SHIFTIN1 / SHIFTIN2: 1-bit (each) input: Data input expansion (1-bit each)
.SHIFTIN1 (1'b0 ),
.SHIFTIN2 (1'b0 ),
// 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
);
OBUFDS #(
.IOSTANDARD ("DEFAULT" ), // Specify the output I/O standard
.SLEW ("SLOW" ) // Specify the output slew rate
) OBUFDS_DATA_inst2 (
.O (lvds_data_p[2] ), // Diff_p output (connect directly to top-level port)
.OB (lvds_data_n[2] ), // Diff_n output (connect directly to top-level port)
.I (oserdes_data[2]) // Buffer input
);
// 4 PAIR
OSERDESE2 #(
.DATA_RATE_OQ ("SDR" ), // DDR, SDR
.DATA_RATE_TQ ("SDR" ), // DDR, BUF, SDR
.DATA_WIDTH (7 ), // 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)
)
OSERDES_data_inst3 (
.OFB ( ), // 1-bit output: Feedback path for data
.OQ (oserdes_data[3]), // 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 (i_clk_455mhz ), // 1-bit input: High speed clock
.CLKDIV (i_clk_65mhz ), // 1-bit input: Divided clock
// D1 - D8: 1-bit (each) input: Parallel data inputs (1-bit each)
.D1 (DON_CR ),
.D2 (i_blu_data[7] ),
.D3 (i_blu_data[6] ),
.D4 (i_gre_data[7] ),
.D5 (i_gre_data[6] ),
.D6 (i_red_data[7] ),
.D7 (i_red_data[6] ),
.D8 ( ),
.OCE (1'b1 ), // 1-bit input: Output data clock enable
.RST (i_rst ), // 1-bit input: Reset
// SHIFTIN1 / SHIFTIN2: 1-bit (each) input: Data input expansion (1-bit each)
.SHIFTIN1 (1'b0 ),
.SHIFTIN2 (1'b0 ),
// 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
);
OBUFDS #(
.IOSTANDARD ("DEFAULT" ), // Specify the output I/O standard
.SLEW ("SLOW" ) // Specify the output slew rate
) OBUFDS_DATA_inst3 (
.O (lvds_data_p[3] ), // Diff_p output (connect directly to top-level port)
.OB (lvds_data_n[3] ), // Diff_n output (connect directly to top-level port)
.I (oserdes_data[3]) // Buffer input
);
4.3 顶层设计
module a_top (
input clk , // sys_clk
output pwm_pannel , // backlight
output o_tx_clk_p ,
output o_tx_clk_n ,
output [3:0] lvds_data_p ,
output [3:0] lvds_data_n
);
wire clk_65mhz ;
wire clk_455mhz ;
wire rst ;
wire [7:0] red_data ;
wire [7:0] gre_data ;
wire [7:0] blu_data ;
wire h_sync ;
wire v_sync ;
wire data_en ;
assign pwm_pannel = 1;
// MMCM
clk_wiz_0 u_clk_wiz_0(
/* output */ .clk_out1 (clk_65mhz ),
/* output */ .clk_out2 (clk_455mhz ),
/* output */ .locked (rst ),
/* input */ .clk_in1 (clk )
);
data_generator u_data_generator(
/* input */ .i_clk_65mhz (clk_65mhz ), //input 65MHz clk, period : 15.38ns
/* input */ .i_rst (!rst ),
/* output [7:0] */ .o_red_data (red_data ),
/* output [7:0] */ .o_gre_data (gre_data ),
/* output [7:0] */ .o_blu_data (blu_data ),
/* output reg */ .o_h_sync (h_sync ),
/* output reg */ .o_v_sync (v_sync ),
/* output reg */ .o_data_en (data_en )
);
lvds_output_driver u_lvds_output_driver(
/* input */ .i_clk_455mhz (clk_455mhz ),
/* input */ .i_clk_65mhz (clk_65mhz ),
/* input */ .i_rst (!rst ),
/* input [7:0] */ .i_red_data (red_data ),
/* input [7:0] */ .i_gre_data (gre_data ),
/* input [7:0] */ .i_blu_data (blu_data ),
/* input */ .i_v_sync (v_sync ),
/* input */ .i_h_sync (h_sync ),
/* input */ .i_data_en (data_en ),
/* output */ .tx_clk_p (o_tx_clk_p ),
/* output */ .tx_clk_n (o_tx_clk_n ),
/* output [3:0] */ .lvds_data_p (lvds_data_p),
/* output [3:0] */ .lvds_data_n (lvds_data_n)
);
endmodule //a_top