1,www.fpga4fun.com是一个非常好的站,深入浅出讲解。此代码主要部分来源于其HDMI部分的代码。
2.,使用SYSCLK.TAOBAO.COM购买的兼容ZEDBOARD板子以及视频输出扩展板。
3,实现了640X480 分辨率输出:
4,需要两个时钟,一个是像素点时钟PIXCEL—CLK ,另外一个是10倍于PIXCEL_CLK的HDMI数据输出时钟。当640X480分辨率时,这两个时钟分别是 25M和250M。
5,代码如下 :
//THIS HARDWARE ONLY SUPPORT TO 640X480!!!!!!
`define VGA_640x480_60HZ_25MHz
//`define VGA_800x600_60HZ_40MHz
//`define VGA_1024x768_60HZ_65MHz
//`define VGA_1440x900_60HZ_106_5MHz
//`define VGA_1280x1024_60HZ_108MHz
//`define VGA_1600x1200_60HZ_175_5MHz
//`define VGA_1920x1080_60HZ_148_5MHz
`ifdef VGA_640x480_60HZ_25MHz
//640x480@60HZ_25MHz clock.
`define H_ACTIVE 640
`define H_FRONT 16
`define H_SYNC 96
`define H_BACK 48
`define V_ACTIVE 480
`define V_FRONT 11
`define V_SYNC 2
`define V_BACK 31
`endif
`ifdef VGA_800x600_60HZ_40MHz
//800x600@60HZ_40MHz clock.
`define H_SYNC 128
`define H_BACK 88
`define H_ACTIVE 800
`define H_FRONT 40
`define V_SYNC 4
`define V_BACK 23
`define V_ACTIVE 600
`define V_FRONT 1
`endif
`ifdef VGA_1024x768_60HZ_65MHz
//1024x768@60HZ_65MHz clock.
`define H_SYNC 136
`define H_BACK 160
`define H_ACTIVE 1024
`define H_FRONT 24
`define V_SYNC 6
`define V_BACK 29
`define V_ACTIVE 768
`define V_FRONT 3
`endif
`ifdef VGA_1440x900_60HZ_106_5MHz
//1440x900@60HZ_106.5MHz clock.
`define H_SYNC 152
`define H_BACK 232
`define H_ACTIVE 1440
`define H_FRONT 80
`define V_SYNC 6
`define V_BACK 25
`define V_ACTIVE 900
`define V_FRONT 3
`endif
`ifdef VGA_1280x1024_60HZ_108MHz
//1280x1024@60HZ_108MHz clock.
`define H_SYNC 112
`define H_BACK 248
`define H_ACTIVE 1280
`define H_FRONT 48
`define V_SYNC 3
`define V_BACK 38
`define V_ACTIVE 1024
`define V_FRONT 1
`endif
`ifdef VGA_1600x1200_60HZ_175_5MHz
//1600x1200@65HZ_175.5MHz clock.
`define H_SYNC 192
`define H_BACK 304
`define H_ACTIVE 1600
`define H_FRONT 64
`define V_SYNC 3
`define V_BACK 46
`define V_ACTIVE 1200
`define V_FRONT 1
`endif
`ifdef VGA_1920x1080_60HZ_148_5MHz
//1920x1080_60HZ_148_5MHz clock.
`define H_SYNC 44
`define H_BACK 148
`define H_ACTIVE 1920
`define H_FRONT 88
`define V_SYNC 5
`define V_BACK 36
`define V_ACTIVE 1080
`define V_FRONT 4
`endif
//`define H_TOTAL ( H_SYNC + H_BACK + H_ACTIVE + H_FRONT )
//`define V_TOTAL ( V_SYNC + V_BACK + V_ACTIVE + V_FRONT )
// (c) fpga4fun.com & KNJN LLC 2013
module HDMI_test_TOP(
input clk_i, // 25MHz
output [2:0] TMDSp, TMDSn,
output TMDSp_clock, TMDSn_clock
);
wire pclk,pclkx10;
DCM_PLL U (
.clk_in1(clk_i), //CLK100M IN
.clk_out1(pclk),//CLK25M_OUT
.clk_out2(pclkx10),//CLK25M_OUT
.locked(),
.reset(1'b0)
);
HDMI_test #(
.H_ACTIVE (`H_ACTIVE ) ,
.H_FRONT ( `H_FRONT ) ,
.H_SYNC ( `H_SYNC ) ,
.H_BACK (`H_BACK ),
.V_ACTIVE (`V_ACTIVE ) ,
.V_FRONT (`V_FRONT ) ,
.V_SYNC (`V_SYNC ) ,
.V_BACK ( `V_BACK )
) uu(
.pixclk(pclk), // 25MHz
.clk_TMDS(pclkx10),
.TMDSp( TMDSp),
.TMDSn( TMDSn),
.TMDSp_clock(TMDSp_clock ),
.TMDSn_clock( TMDSn_clock )
);
endmodule
/*
`ifdef VGA_640x480_60HZ_25MHz
//640x480@60HZ_25MHz clock.
parameter H_ACTIVE = 640 ;
parameter H_FRONT = 16 ;
parameter H_SYNC = 96 ;
parameter H_BACK = 48 ;
parameter V_ACTIVE = 480 ;
parameter V_FRONT = 11 ;
parameter V_SYNC = 2 ;
parameter V_BACK = 31 ;
`endif
*/
module HDMI_test #(
parameter integer H_ACTIVE = `H_ACTIVE ,
parameter integer H_FRONT = `H_FRONT ,
parameter integer H_SYNC = `H_SYNC ,
parameter integer H_BACK = `H_BACK ,
parameter integer V_ACTIVE = `V_ACTIVE ,
parameter integer V_FRONT = `V_FRONT ,
parameter integer V_SYNC = `V_SYNC ,
parameter integer V_BACK = `V_BACK
) (
input pixclk, clk_TMDS, // 25MHz
output [2:0] TMDSp, TMDSn,
output TMDSp_clock, TMDSn_clock
);
parameter integer H_TOTAL = H_SYNC + H_BACK + H_ACTIVE + H_FRONT;
parameter integer V_TOTAL = V_SYNC + V_BACK + V_ACTIVE + V_FRONT;
reg [31:0] CounterX, CounterY;
reg hSync, vSync, DrawArea;
always @(posedge pixclk) DrawArea <= (CounterX<H_ACTIVE) && (CounterY<V_ACTIVE);
always @(posedge pixclk) CounterX <= (CounterX==(H_TOTAL-1)) ? 0 : CounterX+1;
always @(posedge pixclk) if(CounterX==(H_TOTAL-1)) CounterY <= (CounterY==(V_TOTAL-1)) ? 0 : CounterY+1;
always @(posedge pixclk) hSync <= (CounterX>=(H_FRONT+H_ACTIVE)) && (CounterX<(H_FRONT+H_ACTIVE+H_SYNC));
always @(posedge pixclk) vSync <= (CounterY>=(V_FRONT+V_ACTIVE)) && (CounterY<(V_FRONT+V_ACTIVE+V_SYNC));
wire [7:0] W = {8{CounterX[7:0]==CounterY[7:0]}};
wire [7:0] A = {8{CounterX[7:5]==3'h2 && CounterY[7:5]==3'h2}};
reg [7:0] red, green, blue;
always @(posedge pixclk) red <= ({CounterX[5:0] & {6{CounterY[4:3]==~CounterX[4:3]}}, 2'b00} | W) & ~A;
always @(posedge pixclk) green <= (CounterX[7:0] & {8{CounterY[6]}} | W) & ~A;
always @(posedge pixclk) blue <= CounterY[7:0] | W | A;
wire [9:0] TMDS_red, TMDS_green, TMDS_blue;
TMDS_encoder encode_R(.clk(pixclk), .VD(red ), .CD(2'b00) , .VDE(DrawArea), .TMDS(TMDS_red));
TMDS_encoder encode_G(.clk(pixclk), .VD(green), .CD(2'b00) , .VDE(DrawArea), .TMDS(TMDS_green));
TMDS_encoder encode_B(.clk(pixclk), .VD(blue ), .CD({vSync,hSync}), .VDE(DrawArea), .TMDS(TMDS_blue));
//wire clk_TMDS, DCM_TMDS_CLKFX; // 25MHz x 10 = 250MHz
//DCM_SP #(.CLKFX_MULTIPLY(10)) DCM_TMDS_inst(.CLKIN(pixclk), .CLKFX(DCM_TMDS_CLKFX), .RST(1'b0));
//BUFG BUFG_TMDSp(.I(DCM_TMDS_CLKFX), .O(clk_TMDS));
reg [3:0] TMDS_mod10=0; // modulus 10 counter
reg [9:0] TMDS_shift_red=0, TMDS_shift_green=0, TMDS_shift_blue=0;
reg TMDS_shift_load=0;
always @(posedge clk_TMDS) TMDS_shift_load <= (TMDS_mod10==4'd9);
always @(posedge clk_TMDS)
begin
TMDS_shift_red <= TMDS_shift_load ? TMDS_red : TMDS_shift_red [9:1];
TMDS_shift_green <= TMDS_shift_load ? TMDS_green : TMDS_shift_green[9:1];
TMDS_shift_blue <= TMDS_shift_load ? TMDS_blue : TMDS_shift_blue [9:1];
TMDS_mod10 <= (TMDS_mod10==4'd9) ? 4'd0 : TMDS_mod10+4'd1;
end
OBUFDS OBUFDS_red (.I(TMDS_shift_red [0]), .O(TMDSp[2]), .OB(TMDSn[2]));
OBUFDS OBUFDS_green(.I(TMDS_shift_green[0]), .O(TMDSp[1]), .OB(TMDSn[1]));
OBUFDS OBUFDS_blue (.I(TMDS_shift_blue [0]), .O(TMDSp[0]), .OB(TMDSn[0]));
OBUFDS OBUFDS_clock(.I(pixclk), .O(TMDSp_clock), .OB(TMDSn_clock));
endmodule
module TMDS_encoder(
input clk,
input [7:0] VD, // video data (red, green or blue)
input [1:0] CD, // control data
input VDE, // video data enable, to choose between CD (when VDE=0) and VD (when VDE=1)
output reg [9:0] TMDS = 0
);
wire [3:0] Nb1s = VD[0] + VD[1] + VD[2] + VD[3] + VD[4] + VD[5] + VD[6] + VD[7];
wire XNOR = (Nb1s>4'd4) || (Nb1s==4'd4 && VD[0]==1'b0);
wire [8:0] q_m = {~XNOR, q_m[6:0] ^ VD[7:1] ^ {7{XNOR}}, VD[0]};
reg [3:0] balance_acc = 0;
wire [3:0] balance = q_m[0] + q_m[1] + q_m[2] + q_m[3] + q_m[4] + q_m[5] + q_m[6] + q_m[7] - 4'd4;
wire balance_sign_eq = (balance[3] == balance_acc[3]);
wire invert_q_m = (balance==0 || balance_acc==0) ? ~q_m[8] : balance_sign_eq;
wire [3:0] balance_acc_inc = balance - ({q_m[8] ^ ~balance_sign_eq} & ~(balance==0 || balance_acc==0));
wire [3:0] balance_acc_new = invert_q_m ? balance_acc-balance_acc_inc : balance_acc+balance_acc_inc;
wire [9:0] TMDS_data = {invert_q_m, q_m[8], q_m[7:0] ^ {8{invert_q_m}}};
wire [9:0] TMDS_code = CD[1] ? (CD[0] ? 10'b1010101011 : 10'b0101010100) : (CD[0] ? 10'b0010101011 : 10'b1101010100);
always @(posedge clk) TMDS <= VDE ? TMDS_data : TMDS_code;
always @(posedge clk) balance_acc <= VDE ? balance_acc_new : 4'h0;
endmodule
约束文件如下 :
set_property PACKAGE_PIN Y9 [get_ports {clk_i}]
set_property IOSTANDARD LVCMOS33 [get_ports {clk_i}]
set_property PACKAGE_PIN L21 [get_ports {TMDSp[0]}]
set_property IOSTANDARD LVDS_25 [get_ports {TMDSp[0]}]
set_property PACKAGE_PIN L22 [get_ports {TMDSn[0]}]
set_property IOSTANDARD LVDS_25 [get_ports {TMDSn[0]}]
set_property PACKAGE_PIN R19 [get_ports {TMDSp[1]}]
set_property IOSTANDARD LVDS_25 [get_ports {TMDSp[1]}]
set_property PACKAGE_PIN T19 [get_ports {TMDSn[1]}]
set_property IOSTANDARD LVDS_25 [get_ports {TMDSn[1]}]
set_property PACKAGE_PIN K19 [get_ports {TMDSp[2]}]
set_property IOSTANDARD LVDS_25 [get_ports {TMDSp[2]}]
set_property PACKAGE_PIN K20 [get_ports {TMDSn[2]}]
set_property IOSTANDARD LVDS_25 [get_ports {TMDSp[2]}]
set_property PACKAGE_PIN L17 [get_ports {TMDSp_clock}]
set_property IOSTANDARD LVDS_25 [get_ports {TMDSp_clock}]
set_property PACKAGE_PIN M17 [get_ports {TMDSn_clock}]
set_property IOSTANDARD LVDS_25 [get_ports {TMDSn_clock}]