本次实验需要编写4个模块,分别为ID读取模块,时钟分频模块,LCD显示模块和LCD驱动模块。
ID读取模块:
实验中每次复位后,ID的读取只有一次 。
module rd_id(
input clk,
input rst_n,
input [23:0] lcd_rgb,
output reg [15:0] lcd_id
);
reg rd_flag;
always @ (posedge clk or negedge rst_n) begin
if(!rst_n)
rd_flag <= 1'b0;
else if(rd_flag == 1'b0) begin
rd_flag <= 1'b1;
case({lcd_rgb[7],lcd_rgb[15],lcd_rgb[23]})
3'b000 : lcd_id <= 16'h4342;
3'b001 : lcd_id <= 16'h7084;
3'b010 : lcd_id <= 16'h7016;
3'b100 : lcd_id <= 16'h4384;
3'b101 : lcd_id <= 16'h1018;
default : lcd_id <= 16'd0;
endcase
end
end
endmodule
时钟分频模块
module clk_div(
input clk,
input rst_n,
input [15:0] lcd_id,
output reg lcd_pclk
);
reg clk_25m;
reg clk_12_5m;
reg div_4_cnt;
always @ (posedge clk or negedge rst_n) begin
if(!rst_n)
clk_25m <= 1'b0;
else
clk_25m <= ~clk_25m;
end
always @ (posedge clk or negedge rst_n) begin
if(!rst_n) begin
clk_12_5m <= 1'b0;
div_4_cnt <= 1'b0;
end
else begin
div_4_cnt <= div_4_cnt + 1'b1;
if(div_4_cnt == 1'b1)
clk_12_5m <= ~ clk_12_5m;
end
end
always @ (*) begin
case(lcd_id)
16'h4342 : lcd_pclk = clk_12_5m;
16'h7084 : lcd_pclk = clk_25m;
16'h7016 : lcd_pclk = clk;
16'h4384 : lcd_pclk = clk_12_5m;
16'h1018 : lcd_pclk = clk;
default : lcd_pclk = 1'b0;
endcase
end
endmodule
lcd驱动模块:
module lcd_driver(
input lcd_pclk,
input rst_n,
input [15:0] lcd_id,
input [23:0] pixel_data,
output [11:0] pixel_xpos,
output [11:0] pixel_ypos,
output reg [11:0] h_disp,
output reg [11:0] v_disp,
output lcd_de,
output lcd_hs,
output lcd_vs,
output lcd_bl,
output lcd_clk,
output [23:0] lcd_rgb
);
//4342
parameter H_SYNC_4342 = 12'd41;
parameter H_BACK_4342 = 12'd2;
parameter H_DISP_4342 = 12'd480;
parameter H_FRONT_4342 = 12'd2;
parameter H_TOTAL_4342 = 12'd525;
parameter V_SYNC_4342 = 12'd10;
parameter V_BACK_4342 = 12'd2;
parameter V_DISP_4342 = 12'd272;
parameter V_FRONT_4342 = 12'd2;
parameter V_TOTAL_4342 = 12'd286;
//7084
parameter H_SYNC_7084 = 12'd128;
parameter H_BACK_7084 = 12'd88;
parameter H_DISP_7084 = 12'd800;
parameter H_FRONT_7084 = 12'd40;
parameter H_TOTAL_7084 = 12'd1056;
parameter V_SYNC_7084 = 12'd2;
parameter V_BACK_7084 = 12'd33;
parameter V_DISP_7084 = 12'd480;
parameter V_FRONT_7084 = 12'd10;
parameter V_TOTAL_7084 = 12'd525;
//7016
parameter H_SYNC_7016 = 12'd20;
parameter H_BACK_7016 = 12'd140;
parameter H_DISP_7016 = 12'd1024;
parameter H_FRONT_7016 = 12'd160;
parameter H_TOTAL_7016 = 12'd1344;
parameter V_SYNC_7016 = 12'd3;
parameter V_BACK_7016 = 12'd20;
parameter V_DISP_7016 = 12'd600;
parameter V_FRONT_7016 = 12'd12;
parameter V_TOTAL_7016 = 12'd635;
//4384
parameter H_SYNC_4384 = 12'd41;
parameter H_BACK_4384 = 12'd2;
parameter H_DISP_4384 = 12'd480;
parameter H_FRONT_4384 = 12'd2;
parameter H_TOTAL_4384 = 12'd525;
parameter V_SYNC_4384 = 12'd10;
parameter V_BACK_4384 = 12'd2;
parameter V_DISP_4384 = 12'd272;
parameter V_FRONT_4384 = 12'd2;
parameter V_TOTAL_4384 = 12'd286;
//1018
parameter H_SYNC_1018 = 12'd10;
parameter H_BACK_1018 = 12'd80;
parameter H_DISP_1018 = 12'd1280;
parameter H_FRONT_1018 = 12'd70;
parameter H_TOTAL_1018 = 12'd1440;
parameter V_SYNC_1018 = 12'd3;
parameter V_BACK_1018 = 12'd10;
parameter V_DISP_1018 = 12'd800;
parameter V_FRONT_1018 = 12'd10;
parameter V_TOTAL_1018 = 12'd823;
reg [11:0] h_sync;
reg [11:0] h_back;
reg [11:0] h_total;
reg [11:0] v_sync;
reg [11:0] v_back;
reg [11:0] v_total;
reg [11:0] h_cnt;
reg [11:0] v_cnt;
wire data_req;
wire lcd_en;
assign lcd_bl = 1'b1;
assign lcd_vs = 1'b1;
assign lcd_hs = 1'b1;
assign lcd_clk = lcd_pclk;
assign lcd_de = lce_en;
assign lce_en = (h_cnt >= h_sync + h_back) && (h_cnt <= h_sync + h_back + h_disp)
&& (v_cnt >= v_sync + v_back) && (v_cnt <= v_sync + v_back + v_disp)
? 1'b1 : 1'b0;
assign data_req = (h_cnt >= h_sync + h_back - 1'b1) && (h_cnt <= h_sync + h_back + h_disp
-1'b1)
&& (v_cnt >= v_sync + v_back) && (v_cnt <= v_sync + v_back + v_disp)
? 1'b1 : 1'b0;
assign pixel_xpos = data_req ? (h_cnt - (h_sync + h_back - 1'b1)) : 12'd0;
assign pixel_ypos = data_req ? (v_cnt - (v_sync + v_back - 1'b1)) : 12'd0;
assign lcd_rgb = lcd_en ? pixel_data : 24'd0;
always @ (*) begin
case(lcd_id)
16'h4342 : begin
h_sync = H_SYNC_4342;
h_back = H_BACK_4342;
h_total = H_TOTAL_4342;
v_sync = V_SYNC_4342;
v_back = V_BACK_4342;
v_total = V_TOTAL_4342;
end
16'h7084 : begin
h_sync = H_SYNC_7084;
h_back = H_BACK_7084;
h_disp = H_DISP_7084;
h_total = H_TOTAL_7084;
v_sync = V_SYNC_7084;
v_back = V_BACK_7084;
v_disp = V_DISP_7084;
v_total = V_TOTAL_7084;
end
16'h7016 : begin
h_sync = H_SYNC_7016;
h_back = H_BACK_7016;
h_disp = H_DISP_7016;
h_total = H_TOTAL_7016;
v_sync = V_SYNC_7016;
v_back = V_BACK_7016;
v_disp = V_DISP_7016;
v_total = V_TOTAL_7016;
end
16'h4384 : begin
h_sync = H_SYNC_4384;
h_back = H_BACK_4384;
h_disp = H_DISP_4384;
h_total = H_TOTAL_4384;
v_sync = V_SYNC_4384;
v_back = V_BACK_4384;
v_disp = V_DISP_4384;
v_total = V_TOTAL_4384;
end
16'h1018 : begin
h_sync = H_SYNC_1018;
h_back = H_BACK_1018;
h_disp = H_DISP_1018;
h_total = H_TOTAL_1018;
v_sync = V_SYNC_1018;
v_back = V_BACK_1018;
v_disp = V_DISP_1018;
v_total = V_TOTAL_1018;
end
default : begin
h_sync = H_SYNC_4342;
h_back = H_BACK_4342;
h_disp = H_DISP_4342;
h_total = H_TOTAL_4342;
v_sync = V_SYNC_4342;
v_back = V_BACK_4342;
v_disp = V_DISP_4342;
v_total = V_TOTAL_4342;
end
endcase
end
always @ (posedge lcd_pclk or negedge rst_n) begin
if(!rst_n)
h_cnt <= 12'd0;
else begin
if(h_cnt == h_total - 1'b1)
h_cnt <= 12'd0;
else
h_cnt <= h_cnt + 1'b1;
end
end
always @ (posedge lcd_pclk or negedge rst_n) begin
if(!rst_n)
v_cnt <= 12'd0;
else begin
if(h_cnt == h_total - 1'b1) begin
if(v_cnt == v_total - 1'b1)
v_cnt <= 12'd0;
else
v_cnt <= v_cnt + 1'b1;
end
end
end
endmodule
lcd显示模块:
module lcd_display(
input lcd_pclk,
input rst_n,
input [11:0] pixel_xpos,
input [11:0] pixel_ypos,
input [11:0] h_disp,
input [11:0] v_disp,
output reg [23:0] pixel_data
);
parameter WHITE = 24'hffffff;
parameter BLACK = 24'h000000;
parameter RED = 24'hff0000;
parameter GREEN = 24'h00ff00;
parameter BLUE = 24'h0000ff;
always @ (posedge lcd_pclk or negedge rst_n) begin
if(!rst_n)
pixel_data <= BLACK;
else begin
if(pixel_xpos >= 12'd0 && pixel_xpos <= h_disp/5*1)
pixel_data <= WHITE;
else if(pixel_xpos >= h_disp/5*1 && pixel_xpos <= h_disp/5*2)
pixel_data <= BLACK;
else if(pixel_xpos >= h_disp/5*2 && pixel_xpos <= h_disp/5*3)
pixel_data <= RED;
else if(pixel_xpos >= h_disp/5*3 && pixel_xpos <= h_disp/5*4)
pixel_data <= GREEN;
else
pixel_data <= BLUE;
end
end
endmodule
用头文件将四个模块的端口连接起来,再添加约束文件。
首先根据系统时钟和复位信号,在刚开始时,只读取一次id,在读取了屏幕id之后,根据id赋予对应的时钟(这里有二分频和四分分频的程序,可以推出其他频率信号的程序),赋予时钟之后,需要对lcd屏进行驱动,程序中要有对应的前沿、后沿、显示区域、行同步、等信息,还有就是一些信号名的定义,这里需要对行和桢的显示区域进行统计,并根据不同区域划分(在先熟程序中体现)显示不同的颜色。