1 module lcd_dvp_drive
2 #(
3 parameter VBP= 21, //OK
4 parameter VFP= 18, //OK
5 parameter VSW= 6 , //OK
6 parameter VDP= 480 ,//524
7
8 parameter HBP= 106, //ok
9 parameter HFP= 16, //ok
10 parameter HSW= 16 , //ok
11 parameter HDP= 720 //840
12
13 )
14 (
15 clk_i , //时钟输入 840*524*2*60=52.819MHZ//实测53.82MHZ
16
17 rst_i , //复位输入
18 display_on , //显示开关输入
19 data_rgb_i , //16位红色数据输入
20 data_rdy_o , //数据输入请求信号输出
21
22 hsync_o , //行同步信号输出
23 vsync_o , //场同步信号输出
24 lcd_de , //LCD输出有效标志
25
26 pclk_o , //数据时钟输出
27 Serial_data8_o , //8位数据输出
28 xpos_o , //当前行计数输出
29 ypos_o , //当前列计数输出
30 lcd_bl , //背光开关控制 1亮背光 0灭背光
31 out_vsync //帧复位,高有效
32 );
33 localparam [16:0] HBP_X2= (HBP+HBP);//每个像素发送两次8位数据
34 localparam [16:0] HFP_X2= (HFP+HFP);//每个像素发送两次8位数据
35 localparam [16:0] HSW_X2= (HSW+HSW);//每个像素发送两次8位数据
36 localparam [16:0] HDP_X2= (HDP+HDP);//每个像素发送两次8位数据
37 localparam [16:0] H_TOTAL= (HSW_X2+HBP_X2+HDP_X2+HFP_X2);//每个像素发送两次8位数据
38 localparam [16:0] V_TOTAL= (VBP+VFP+VSW+VDP);
39
40 input wire [0:0] clk_i;
41 input wire [0:0] rst_i;
42
43 input wire [0:0] display_on;
44 input wire [15:0] data_rgb_i;
45
46 output wire [0:0] data_rdy_o;
47
48 output wire [0:0] hsync_o;
49 output wire [0:0] vsync_o;
50
51 output wire [0:0] pclk_o;
52 output wire [7:0] Serial_data8_o;
53
54 output wire [15:0] xpos_o;
55 output wire [15:0] ypos_o;
56
57 output wire lcd_bl;
58 output wire out_vsync;
59 output wire lcd_de;
60
61 reg [16:0] H_X2CNT_R;
62 reg h_cnt_flag;
63
64 reg [16:0] V_CNT_R;
65
66 reg hsync_r;
67 reg vsync_r;
68 reg enable_r;
69 reg lcd_bl_r;
70 reg [7:0] Serial_data8_r;
71
72
73
74 //行计数
75 always @(negedge clk_i or negedge rst_i )
76 begin
77 if(rst_i==1'b0 || display_on==1'b0 )
78 begin
79 h_cnt_flag<=1'b0;
80 end
81 else
82 begin
83 h_cnt_flag<=~h_cnt_flag;
84 end
85 end
86
87 always @(negedge clk_i or negedge rst_i )
88 begin
89 if(rst_i==1'b0 || display_on==1'b0 )
90 begin
91 H_X2CNT_R<=17'd0;
92 end
93 else if(H_X2CNT_R>=H_TOTAL-1'D1)
94 begin
95 H_X2CNT_R<=17'd0;
96 end
97 else
98 H_X2CNT_R<=H_X2CNT_R+1'd1;
99
100 end
101
102
103 //列计数
104 always @(negedge clk_i or negedge rst_i )
105 begin
106 if(rst_i==1'b0 || display_on==1'b0 )
107 V_CNT_R<=17'd0;
108 else if((V_CNT_R>=(V_TOTAL-1'D1)) && (H_X2CNT_R>=(H_TOTAL-1'D1)))
109 V_CNT_R<=17'D0;
110 else if(H_X2CNT_R>=H_TOTAL-1'D1)
111 V_CNT_R<=V_CNT_R+1'd1;
112 else
113 V_CNT_R<=V_CNT_R;
114
115 end
116
117 //输出VSYNC信号
118 always @(negedge clk_i or negedge rst_i )
119 begin
120 if(rst_i==1'b0 || display_on==1'b0 )
121 vsync_r<=1'b0;
122 else if((V_CNT_R>=(V_TOTAL-1'D1)) && (H_X2CNT_R>=H_TOTAL-1'D1))
123 vsync_r<=1'b0;
124 else if((V_CNT_R>=(VSW-1'd1))&&(H_X2CNT_R>=H_TOTAL-1'D1))
125 vsync_r<=1'b1;
126 else
127 vsync_r<=vsync_r;
128
129 end
130
131
132 //输出HSYNC信号
133 always @(negedge clk_i or negedge rst_i )
134 begin
135 if(rst_i==1'b0 || display_on==1'b0 )
136 hsync_r<=1'b0;
137 else if((H_X2CNT_R<HSW_X2-1'd1) ||(H_X2CNT_R>=H_TOTAL-1'd1))
138 hsync_r<=1'b0;
139 else
140 hsync_r<=1'b1;
141
142 end
143
144 //输出ENABLE信号
145 always @(negedge clk_i or negedge rst_i )
146 begin
147 if(rst_i==1'b0 || display_on==1'b0 )
148 enable_r<=1'b0;
149 else if((H_X2CNT_R>(HSW_X2+HBP_X2-2'd2)) && (H_X2CNT_R<(HSW_X2+HBP_X2+HDP_X2-1'd1)) && (V_CNT_R>(VSW+VBP-1'd1)) && (V_CNT_R<=(VSW+VBP+VDP-1'd1)))
150 enable_r<=1'b1;
151 else
152 enable_r<=1'b0;
153 end
154
155
156
157
158 //向外发出数据输入请求
159 assign data_rdy_o=((H_X2CNT_R>(HSW_X2+HBP_X2-2'd2)) && (H_X2CNT_R<(HSW_X2+HBP_X2+HDP_X2-1'd1)) && (V_CNT_R>(VSW+VBP-1'd1)) && (V_CNT_R<=(VSW+VBP+VDP-1'd1)))? 1'b1:1'b0;
160
161 //输出当前行计数
162 //assign xpos_o = (data_rdy_o) ? (H_X2CNT_R-HSW_X2-HBP_X2):16'd0;
163
164 reg [15:0]xpos_r;
165 always @(negedge clk_i or negedge rst_i )
166 begin
167 if(rst_i==1'b0 || display_on==1'b0 )
168 xpos_r<=16'd0;
169 else if((H_X2CNT_R>(HSW_X2+HBP_X2-2'd2)) && (H_X2CNT_R<(HSW_X2+HBP_X2+HDP_X2-1'd1)) && (V_CNT_R>(VSW+VBP-1'd1)) && (V_CNT_R<=(VSW+VBP+VDP-1'd1)))
170 xpos_r<=(H_X2CNT_R+1'D1-HSW_X2-HBP_X2)/2'D2;
171 else
172 xpos_r<=16'd0;
173
174 end
175 //输出当前列计数
176 //assign ypos_o = (data_rdy_o) ? (V_CNT_R-VSW-VBP):16'd0;
177 reg [15:0] ypos_r;
178 always @(negedge clk_i or negedge rst_i )
179 begin
180 if(rst_i==1'b0 || display_on==1'b0 )
181 ypos_r<=16'd0;
182 else if((V_CNT_R>(VSW+VBP-1'D1)) && (V_CNT_R<=(VSW+VBP+VDP-1'd1)))
183 ypos_r<=V_CNT_R-VSW-VBP;
184 else
185 ypos_r<=16'd0;
186
187 end
188
189
190
191
192 //输出显示数据
193 always @(negedge clk_i or negedge rst_i )
194 begin
195 if(rst_i==1'b0 || display_on==1'b0 )
196 begin
197 Serial_data8_r<=8'b0;
198 end
199 else if(h_cnt_flag==1'b1)
200 Serial_data8_r<=data_rgb_i[15:8];
201
202 else if(h_cnt_flag==1'b0)
203 Serial_data8_r<=data_rgb_i[7:0];
204 else
205 begin
206 Serial_data8_r<=8'b0;
207 end
208
209 end
210
211 always @(negedge clk_i or negedge rst_i )
212 begin
213 if(rst_i==1'b0 || display_on==1'b0 )
214 lcd_bl_r<=1'b0;
215 else if(ypos_o>2'd2)
216 begin
217 lcd_bl_r<=1'b1;
218 end
219 else
220 begin
221 lcd_bl_r<=lcd_bl_r;
222 end
223 end
224
225 //帧复位,高有效
226 assign out_vsync = ((H_X2CNT_R <= 100) && (V_CNT_R == 1)) ? 1'b1 : 1'b0;
227
228 assign hsync_o=(display_on==1'b1 )? hsync_r:1'b0 ;
229 assign vsync_o=(display_on==1'b1 )? vsync_r:1'b0 ;
230 assign lcd_de =(display_on==1'b1 )? enable_r:1'b0 ;
231 assign lcd_bl =(display_on==1'b1 )? lcd_bl_r:1'b0 ;
232
233
234 assign Serial_data8_o=(((H_X2CNT_R>(HSW_X2+HBP_X2-2'd1)) && (H_X2CNT_R<(HSW_X2+HBP_X2+HDP_X2)) && (V_CNT_R>(VSW+VBP-1'd1)) && (V_CNT_R<=(VSW+VBP+VDP-1'd1))))? Serial_data8_r:8'b0 ;
235
236 //输出PCLK信号
237 assign pclk_o=(display_on==1'b1 )? clk_i:16'b0 ;
238 assign xpos_o=(display_on==1'b1 )? xpos_r:16'b0 ;
239 assign ypos_o=(display_on==1'b1 )? ypos_r:16'b0 ;
240
241
242
243
244 endmodule
1 `timescale 1ns/100ps
2 module lcd_dvp_drive_tb();
3
4 reg clk_i;
5 reg rst_i;
6 reg display_on;
7 reg [15:0] data_rgb_i;
8 wire hsync_o ;
9 wire vsync_o ;
10 wire lcd_de ;
11 wire pclk_o ;
12 wire[7:0] Serial_data8_o;
13 wire xpos_o ;
14 wire ypos_o ;
15 wire lcd_bl ;
16 wire out_vsync ;
17 wire data_rdy_o ;
18
19
20 initial begin
21 clk_i=1'b0;
22 display_on=0;
23 data_rgb_i=16'h0000;
24 rst_i=1'b0;
25 #200;
26 rst_i=1'b1;
27 #200;
28 display_on=1;
29 @(data_rdy_o==1'b1)
30 data_rgb_i=16'hf800;
31
32 @(posedge vsync_o )
33 #200;
34 @(posedge vsync_o )
35 #200;
36 @(posedge vsync_o )
37 #200;
38 $stop;
39
40
41 end
42 always #0.5 clk_i<=~clk_i;
43
44
45
46
47 lcd_dvp_drive
48 #(
49 .VBP(16'd 21 ),//OK
50 .VFP(16'd 18 ),//OK
51 .VSW(16'd 6 ),//OK
52 .VDP(16'd 480 ),//524
53 .HBP(16'd 106 ),//ok
54 .HFP(16'd 16 ),//ok
55 .HSW(16'd 16 ),//ok
56 .HDP(16'd 720 ) //840
57
58 )
59 u_lcd_dvp_drive
60 (
61 .clk_i ( clk_i ) , //时钟输入 840*524*2*60=52.819MHZ//实测53.82MHZ
62 .rst_i ( rst_i ) , //复位输入
63 .display_on ( display_on ) , //显示开关输入
64 .data_rgb_i ( data_rgb_i ) , //16位红色数据输入
65 .data_rdy_o ( data_rdy_o ) , //数据输入请求信号输出
66 .hsync_o ( hsync_o ) , //行同步信号输出
67 .vsync_o ( vsync_o ) , //场同步信号输出
68 .lcd_de ( lcd_de ) , //LCD输出有效标志
69 .pclk_o ( pclk_o ) , //数据时钟输出
70 .Serial_data8_o( Serial_data8_o) , //8位数据输出
71 .xpos_o ( xpos_o ) , //当前行计数输出
72 .ypos_o ( ypos_o ) , //当前列计数输出
73 .lcd_bl ( lcd_bl ) , //背光开关控制 1亮背光 0灭背光
74 .out_vsync ( out_vsync ) //帧复位,高有效
75 );
76
77
78 endmodule
![]()
![]()
![]()
![]()
![]()