16位 565 DVP 接口实现
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