simplifying design: generating pixel clock from modulo-5 clock.

This commit is contained in:
Bruno Levy
2021-04-26 19:09:32 +02:00
parent 3265cd4f62
commit 1ccb77145c

View File

@@ -9,7 +9,10 @@ module HDMI_test_hires(
// (D=Differential)
);
/******** Video mode constants **************************************************/
/******** Video mode constants and clocks ****************************************/
wire pixclk; // pixel clock
wire half_clk_TMDS; // TMDS clock at half freq (5*pixclk)
// Select mode by uncommenting one of the lines below
`define MODE_640x480
@@ -17,89 +20,136 @@ module HDMI_test_hires(
//`define MODE_1280x1024
`ifdef MODE_640x480
// 640x480, pixclk=25 MHz
localparam GFX_width = 640;
localparam GFX_height = 480;
localparam GFX_h_front_porch = 16;
localparam GFX_h_sync_width = 96;
localparam GFX_h_back_porch = 48;
localparam GFX_v_front_porch = 10;
localparam GFX_v_sync_width = 2;
localparam GFX_v_back_porch = 32;
localparam CLKFB_DIV = 10;
localparam CLKI_DIV = 1;
localparam CLKOP_DIV = 2;
localparam CLKOS_DIV = 4;
localparam CLKOS2_DIV = 20;
wire pixclk_;
// 640x480, pixclk=25 MHz
localparam GFX_width = 640;
localparam GFX_height = 480;
localparam GFX_h_front_porch = 16;
localparam GFX_h_sync_width = 96;
localparam GFX_h_back_porch = 48;
localparam GFX_v_front_porch = 10;
localparam GFX_v_sync_width = 2;
localparam GFX_v_back_porch = 32;
// The PLL
(* FREQUENCY_PIN_CLKI="25" *)
(* FREQUENCY_PIN_CLKOP="125" *)
(* ICP_CURRENT="12" *) (* LPF_RESISTOR="8" *) (* MFG_ENABLE_FILTEROPAMP="1" *) (* MFG_GMCREF_SEL="2" *)
EHXPLLL #(
.CLKI_DIV(1),
.CLKOP_DIV(5),
.CLKOP_CPHASE(2),
.CLKOP_FPHASE(0),
.CLKOS_ENABLE("ENABLED"),
.CLKOS_DIV(25),
.CLKOS_CPHASE(2),
.CLKOS_FPHASE(0),
.CLKFB_DIV(5)
) pll_i (
.CLKI(pclk),
.CLKOP(half_clk_TMDS),
.CLKFB(half_clk_TMDS),
.CLKOS(pixclk_),
.PHASESEL0(1'b0),
.PHASESEL1(1'b0),
.PHASEDIR(1'b1),
.PHASESTEP(1'b1),
.PHASELOADREG(1'b1),
.PLLWAKESYNC(1'b0),
.ENCLKOP(1'b0)
);
`endif
`ifdef MODE_1024x768
// 1024x768, pixel clock=65Mhz
localparam GFX_width = 1024;
localparam GFX_height = 768;
localparam GFX_h_front_porch = 24;
localparam GFX_h_sync_width = 136;
localparam GFX_h_back_porch = 160;
localparam GFX_v_front_porch = 3;
localparam GFX_v_sync_width = 6;
localparam GFX_v_back_porch = 29;
localparam CLKI_DIV = 1;
localparam CLKFB_DIV = 26;
localparam CLKOP_DIV = 2;
localparam CLKOS_DIV = 4;
localparam CLKOS2_DIV = 20;
wire pixclk_;
// 1024x768, pixel clock=65Mhz
localparam GFX_width = 1024;
localparam GFX_height = 768;
localparam GFX_h_front_porch = 24;
localparam GFX_h_sync_width = 136;
localparam GFX_h_back_porch = 160;
localparam GFX_v_front_porch = 3;
localparam GFX_v_sync_width = 6;
localparam GFX_v_back_porch = 29;
// The PLL
(* FREQUENCY_PIN_CLKI="25" *)
(* FREQUENCY_PIN_CLKOP="325" *)
(* ICP_CURRENT="12" *) (* LPF_RESISTOR="8" *) (* MFG_ENABLE_FILTEROPAMP="1" *) (* MFG_GMCREF_SEL="2" *)
EHXPLLL #(
.CLKI_DIV(1),
.CLKOP_DIV(2),
.CLKOP_CPHASE(1),
.CLKOP_FPHASE(0),
.CLKOS_ENABLE("ENABLED"),
.CLKOS_DIV(10),
.CLKOS_CPHASE(1),
.CLKOS_FPHASE(0),
.CLKFB_DIV(13)
) pll_i (
.CLKI(pclk),
.CLKOP(half_clk_TMDS),
.CLKFB(half_clk_TMDS),
.CLKOS(pixclk_),
.PHASESEL0(1'b0),
.PHASESEL1(1'b0),
.PHASEDIR(1'b1),
.PHASESTEP(1'b1),
.PHASELOADREG(1'b1),
.PLLWAKESYNC(1'b0),
.ENCLKOP(1'b0)
);
`endif
`ifdef MODE_1280x1024
localparam GFX_width = 1280;
localparam GFX_height = 1024;
localparam GFX_h_front_porch = 48;
localparam GFX_h_sync_width = 112;
localparam GFX_h_back_porch = 248;
localparam GFX_v_front_porch = 1;
localparam GFX_v_sync_width = 3;
localparam GFX_v_back_porch = 38;
localparam CLKI_DIV = 1;
localparam CLKFB_DIV = 43;
localparam CLKOP_DIV = 2;
localparam CLKOS_DIV = 4;
localparam CLKOS2_DIV = 20;
wire pixclk_;
// 1280x1024, pixel clock=108MHz
localparam GFX_width = 1280;
localparam GFX_height = 1024;
localparam GFX_h_front_porch = 48;
localparam GFX_h_sync_width = 112;
localparam GFX_h_back_porch = 248;
localparam GFX_v_front_porch = 1;
localparam GFX_v_sync_width = 3;
localparam GFX_v_back_porch = 38;
// The PLL
(* FREQUENCY_PIN_CLKI="25" *)
(* FREQUENCY_PIN_CLKOP="541.667" *)
(* ICP_CURRENT="12" *) (* LPF_RESISTOR="8" *) (* MFG_ENABLE_FILTEROPAMP="1" *) (* MFG_GMCREF_SEL="2" *)
EHXPLLL #(
.CLKI_DIV(3),
.CLKOP_DIV(1),
.CLKOP_CPHASE(0),
.CLKOP_FPHASE(0),
.CLKOS_ENABLE("ENABLED"),
.CLKOS_DIV(5),
.CLKOS_CPHASE(0),
.CLKOS_FPHASE(0),
.CLKFB_DIV(65)
) pll_i (
.CLKI(pclk),
.CLKOP(half_clk_TMDS),
.CLKFB(half_clk_TMDS),
.CLKOS(pixclk_),
.PHASESEL0(1'b0),
.PHASESEL1(1'b0),
.PHASEDIR(1'b1),
.PHASESTEP(1'b1),
.PHASELOADREG(1'b1),
.PLLWAKESYNC(1'b0),
.ENCLKOP(1'b0)
);
`endif
localparam GFX_line_width = GFX_width + GFX_h_front_porch + GFX_h_sync_width + GFX_h_back_porch;
localparam GFX_lines = GFX_height + GFX_v_front_porch + GFX_v_sync_width + GFX_v_back_porch;
/******** Pixel clock and TMDS clock *********************************************/
wire pixclk; // pixel clock
wire clk_TMDS; // TMDS clock (10*pixclk)
wire half_clk_TMDS; // TMDS clock at half freq (5*pixclk)
(* ICP_CURRENT="12" *) (* LPF_RESISTOR="8" *) (* MFG_ENABLE_FILTEROPAMP="1" *) (* MFG_GMCREF_SEL="2" *)
EHXPLLL #(
.CLKOP_FPHASE(0),
.CLKOP_CPHASE(0),
.OUTDIVIDER_MUXA("DIVA"),
.CLKOP_ENABLE("ENABLED"),
.CLKOP_DIV(CLKOP_DIV),
.CLKOS_ENABLE("ENABLED"),
.CLKOS_DIV(CLKOS_DIV),
.CLKOS_CPHASE(0),
.CLKOS_FPHASE(0),
.CLKOS2_ENABLE("ENABLED"),
.CLKOS2_DIV(CLKOS2_DIV),
.CLKOS2_CPHASE(0),
.CLKOS2_FPHASE(0),
.CLKFB_DIV(CLKFB_DIV),
.CLKI_DIV(CLKI_DIV),
.FEEDBK_PATH("INT_OP")
) pll_i (
.CLKI(pclk),
.CLKOP(clk_TMDS), // 250
.CLKOS(half_clk_TMDS), // 125
.CLKOS2(pixclk) // 25
);
/******** X,Y,hSync,vSync,DrawArea ***********************************************/
reg [10:0] GFX_X, GFX_Y;
@@ -145,15 +195,15 @@ TMDS_encoder encode_B(.clk(pixclk), .VD(blue ), .CD({vSync,hSync}), .VDE(DrawAre
// The counter counts modulo 5 instead of modulo 10 (because we shift two
// bits at each clock)
reg [4:0] TMDS_mod5=1;
wire TMDS_shift_load = TMDS_mod5[4];
always @(posedge half_clk_TMDS) TMDS_mod5 <= {TMDS_mod5[3:0],TMDS_mod5[4]};
assign pixclk = TMDS_mod5[4];
// Shifter now shifts two bits at each clock
reg [9:0] TMDS_shift_red=0, TMDS_shift_green=0, TMDS_shift_blue=0;
always @(posedge half_clk_TMDS) begin
TMDS_shift_red <= TMDS_shift_load ? TMDS_red : TMDS_shift_red [9:2];
TMDS_shift_green <= TMDS_shift_load ? TMDS_green : TMDS_shift_green[9:2];
TMDS_shift_blue <= TMDS_shift_load ? TMDS_blue : TMDS_shift_blue [9:2];
TMDS_shift_red <= pixclk ? TMDS_red : TMDS_shift_red [9:2];
TMDS_shift_green <= pixclk ? TMDS_green : TMDS_shift_green[9:2];
TMDS_shift_blue <= pixclk ? TMDS_blue : TMDS_shift_blue [9:2];
end
// DDR serializers: they send D0 at the rising edge and D1 at the falling edge.