1 LCD屏幕简介
LCD屏幕,即液晶显示屏(Liquid Crystal Display),是一种使用液晶材料来显示图像的屏幕技术。液晶本身并不发光,因此LCD屏幕通常需要背光源来照亮液晶以显示图像。
1.1 分辨率
分辨率是指屏幕上水平方向和垂直方向像素点的数量。分辨率通常以两个数字表示,例如1920x1080,其中第一个数字表示屏幕水平方向的像素点数,第二个数字表示垂直方向的像素点数。这个例子中的分辨率意味着屏幕有1920个像素宽和1080个像素高,也就是这个屏幕一列 1080 个像素点,一共 1920 列。
1.2 像素格式
//RGB565转RGB888
assign rgb888_data[23:16] = {rom_rd_data[15:11], rom_rd_data[13:11]}; //red
assign rgb888_data[15:8] = {rom_rd_data[10:5], rom_rd_data[6:5]}; //green
assign rgb888_data[7:0] = {rom_rd_data[4:0], rom_rd_data[2:0]}; //blue
1.3 屏幕接口
本次实验用的是正点原子ATK-7084(7寸,800*480)RGB LCD 屏幕,RGB LCD 接口的信号线如下表所示:
行同步信号(HSYNC):
行同步信号用于同步显示器的水平扫描过程。在逐行扫描的显示器中,电子束从屏幕的左上角开始,逐行向右扫描,每扫描完一行后,电子束需要回到屏幕的左侧准备开始下一行的扫描。在这个过程中,行同步信号会在每行扫描结束时发出,指示电子束应该回到屏幕的左侧。这个信号通常是一个短暂的脉冲,其宽度和持续时间根据显示器的分辨率和刷新率而定。
场同步信号(VSYNC):
场同步信号则用于同步显示器的垂直扫描过程。在完成一整屏(即所有行)的扫描后,电子束需要回到屏幕的左上角开始新的一帧。场同步信号在这一过程中发出,指示电子束应该回到屏幕的顶部。这个信号通常在一帧结束时出现,标志着新的一帧即将开始。
1.4 像素时钟
LCD像素时钟是液晶显示器(LCD)中的一个关键参数,它定义了LCD面板能够更新显示多少像素的速率。像素时钟以赫兹(Hz)为单位,表示每秒钟可以传输的像素数量。
像素时钟的计算通常基于显示器的分辨率和刷新率。例如,一个分辨率为1920x1080的显示器,如果刷新率为60Hz,那么像素时钟的计算方法如下:
像素时钟=水平分辨率×垂直分辨率×刷新率
像素时钟=1920×1080×60
像素时钟=124,416,000Hz
这意味着该显示器每秒可以传输大约1.24亿个像素。
2 实验任务
3 实验设计
lcd_rgb_colorbar.v
`timescale 1ns / 1ps
module lcd_rgb_colorbar (
input sys_clk_p, //系统差分输入时钟
input sys_clk_n, //系统差分输入时钟
input sys_rst_n, //系统复位
//RGB LCD接口
output lcd_de, //LCD 数据使能信号
output lcd_hs, //LCD 行同步信号
output lcd_vs, //LCD 场同步信号
output lcd_bl, //LCD 背光控制信号
output lcd_clk, //LCD 像素时钟
output lcd_rst, //LCD复位
output [23:0] lcd_rgb //LCD RGB888颜色数据
);
//wire define
wire lcd_pclk; //LCD像素时钟
wire [10:0] pixel_xpos; //当前像素点横坐标
wire [10:0] pixel_ypos; //当前像素点纵坐标
wire [10:0] h_disp; //LCD屏水平分辨率
wire [10:0] v_disp; //LCD屏垂直分辨率
wire [23:0] pixel_data; //像素数据
//*****************************************************
//** main code
//*****************************************************
//转换差分信号
IBUFDS diff_clock (
.I (sys_clk_p), //系统差分输入时钟
.IB(sys_clk_n), //系统差分输入时钟
.O (sys_clk) //输出系统时钟
);
//时钟分频模块
clk_div u_clk_div (
.clk (sys_clk),
.rst_n(sys_rst_n),
.lcd_pclk(lcd_pclk)
);
//LCD显示模块
lcd_display u_lcd_display (
.lcd_pclk (lcd_pclk),
.rst_n (sys_rst_n),
.pixel_xpos(pixel_xpos),
.pixel_ypos(pixel_ypos),
.h_disp (h_disp),
.v_disp (v_disp),
.pixel_data(pixel_data)
);
//LCD驱动模块
lcd_driver u_lcd_driver (
.lcd_pclk(lcd_pclk),
.rst_n (sys_rst_n),
.pixel_data(pixel_data),
.pixel_xpos(pixel_xpos),
.pixel_ypos(pixel_ypos),
.h_disp (h_disp),
.v_disp (v_disp),
.lcd_de (lcd_de),
.lcd_hs (lcd_hs),
.lcd_vs (lcd_vs),
.lcd_bl (lcd_bl),
.lcd_clk(lcd_clk),
.lcd_rst(lcd_rst),
.lcd_rgb(lcd_rgb)
);
endmodule
clk_div.v
时钟分频模块,对系统时钟进行分频,生成驱动lcd屏幕的时钟。
`timescale 1ns / 1ps
module clk_div (
input clk, //100MHz
input rst_n,
output reg lcd_pclk
);
reg clk_25m;
reg div_4_cnt;
//时钟4分频 输出25MHz时钟
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
div_4_cnt <= 1'b0;
clk_25m <= 1'b0;
end else begin
div_4_cnt <= div_4_cnt + 1'b1;
if (div_4_cnt == 1'b1) clk_25m <= ~clk_25m;
end
end
always @(*) begin
lcd_pclk = clk_25m;
end
endmodule
lcd_driver.v
`timescale 1ns / 1ps
module lcd_driver (
input lcd_pclk, //时钟
input rst_n, //复位,低电平有效
input [23:0] pixel_data, //像素数据
output [10:0] pixel_xpos, //当前像素点横坐标
output [10:0] pixel_ypos, //当前像素点纵坐标
output reg [10:0] h_disp, //LCD屏水平分辨率
output reg [10:0] v_disp, //LCD屏垂直分辨率
//RGB LCD接口
output lcd_de, //LCD 数据使能信号
output lcd_hs, //LCD 行同步信号
output lcd_vs, //LCD 场同步信号
output lcd_bl, //LCD 背光控制信号
output lcd_clk, //LCD 像素时钟
output lcd_rst, //LCD复位
output [23:0] lcd_rgb //LCD RGB888颜色数据
);
//parameter define
// 7' 800*480
parameter H_SYNC_7084 = 11'd128; //行同步
parameter H_BACK_7084 = 11'd88; //行显示后沿
parameter H_DISP_7084 = 11'd800; //行有效数据
parameter H_FRONT_7084 = 11'd40; //行显示前沿
parameter H_TOTAL_7084 = 11'd1056; //行扫描周期
parameter V_SYNC_7084 = 11'd2; //场同步
parameter V_BACK_7084 = 11'd33; //场显示后沿
parameter V_DISP_7084 = 11'd480; //场有效数据
parameter V_FRONT_7084 = 11'd10; //场显示前沿
parameter V_TOTAL_7084 = 11'd525; //场扫描周期
//reg define
reg [10:0] h_sync;
reg [10:0] h_back;
reg [10:0] h_total;
reg [10:0] v_sync;
reg [10:0] v_back;
reg [10:0] v_total;
reg [10:0] h_cnt;
reg [10:0] v_cnt;
//wire define
wire lcd_en;
wire data_req;
//*****************************************************
//** main code
//*****************************************************
//RGB LCD 采用DE模式时,行场同步信号需要拉高
assign lcd_hs = 1'b1; //LCD行同步信号
assign lcd_vs = 1'b1; //LCD场同步信号
assign lcd_bl = 1'b1; //LCD背光控制信号
assign lcd_rst = 1'b1; //LCD 复位
assign lcd_clk = lcd_pclk; //LCD像素时钟
assign lcd_de = lcd_en; //LCD数据有效信号
//使能RGB888数据输出
assign lcd_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)) : 11'd0;
assign pixel_ypos = data_req ? (v_cnt - (v_sync + v_back - 1'b1)) : 11'd0;
//RGB888数据输出
assign lcd_rgb = lcd_en ? pixel_data : 24'd0;
//行场时序参数
always @(*) 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
//行计数器对像素时钟计数
always @(posedge lcd_pclk or negedge rst_n) begin
if (!rst_n) h_cnt <= 11'd0;
else begin
if (h_cnt == h_total - 1'b1) h_cnt <= 11'd0;
else h_cnt <= h_cnt + 1'b1;
end
end
//场计数器对行计数
always @(posedge lcd_pclk or negedge rst_n) begin
if (!rst_n) v_cnt <= 11'd0;
else begin
if (h_cnt == h_total - 1'b1) begin
if (v_cnt == v_total - 1'b1) v_cnt <= 11'd0;
else v_cnt <= v_cnt + 1'b1;
end
end
end
endmodule
lcd_display.v
lcd显示模块,主要是向该模块输入坐标信息,然后输出该坐标的像素信息。
`timescale 1ns / 1ps
module lcd_display (
input lcd_pclk, //时钟
input rst_n, //复位,低电平有效
input [10:0] pixel_xpos, //当前像素点横坐标
input [10:0] pixel_ypos, //当前像素点纵坐标
input [10:0] h_disp, //LCD屏水平分辨率
input [10:0] v_disp, //LCD屏垂直分辨率
output reg [23:0] pixel_data //像素数据
);
//parameter define
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 >= 11'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
pin.xdc
#IO管脚约束
#时钟周期约束
create_clock -name sys_clk_p -period 10.000 [get_ports sys_clk_p]
#时钟
set_property IOSTANDARD DIFF_HSTL_I_12 [get_ports sys_clk_p]
set_property IOSTANDARD DIFF_HSTL_I_12 [get_ports sys_clk_n]
set_property PACKAGE_PIN AE5 [get_ports sys_clk_p]
set_property PACKAGE_PIN AF5 [get_ports sys_clk_n]
#复位
set_property -dict {PACKAGE_PIN AH11 IOSTANDARD LVCMOS33} [get_ports sys_rst_n]
#LCD接口
set_property -dict {PACKAGE_PIN W14 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb[0]}]
set_property -dict {PACKAGE_PIN Y14 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb[1]}]
set_property -dict {PACKAGE_PIN W13 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb[2]}]
set_property -dict {PACKAGE_PIN Y13 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb[3]}]
set_property -dict {PACKAGE_PIN W12 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb[4]}]
set_property -dict {PACKAGE_PIN Y12 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb[5]}]
set_property -dict {PACKAGE_PIN W11 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb[6]}]
set_property -dict {PACKAGE_PIN AA12 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb[7]}]
set_property -dict {PACKAGE_PIN AC14 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb[8]}]
set_property -dict {PACKAGE_PIN AD15 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb[9]}]
set_property -dict {PACKAGE_PIN AC13 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb[10]}]
set_property -dict {PACKAGE_PIN AD14 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb[11]}]
set_property -dict {PACKAGE_PIN AE15 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb[12]}]
set_property -dict {PACKAGE_PIN AA13 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb[13]}]
set_property -dict {PACKAGE_PIN AE14 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb[14]}]
set_property -dict {PACKAGE_PIN AB13 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb[15]}]
set_property -dict {PACKAGE_PIN AG14 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb[16]}]
set_property -dict {PACKAGE_PIN AB15 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb[17]}]
set_property -dict {PACKAGE_PIN AH14 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb[18]}]
set_property -dict {PACKAGE_PIN AB14 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb[19]}]
set_property -dict {PACKAGE_PIN AG13 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb[20]}]
set_property -dict {PACKAGE_PIN AE13 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb[21]}]
set_property -dict {PACKAGE_PIN AH13 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb[22]}]
set_property -dict {PACKAGE_PIN AF13 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb[23]}]
set_property -dict {PACKAGE_PIN J11 IOSTANDARD LVCMOS33} [get_ports lcd_hs]
set_property -dict {PACKAGE_PIN K12 IOSTANDARD LVCMOS33} [get_ports lcd_vs]
set_property -dict {PACKAGE_PIN J10 IOSTANDARD LVCMOS33} [get_ports lcd_de]
set_property -dict {PACKAGE_PIN J12 IOSTANDARD LVCMOS33} [get_ports lcd_bl]
set_property -dict {PACKAGE_PIN K13 IOSTANDARD LVCMOS33} [get_ports lcd_clk]
set_property -dict {PACKAGE_PIN F10 IOSTANDARD LVCMOS33} [get_ports lcd_rst]