您现在的位置是:首页 >技术教程 >verilog驱动LCD显示彩条、字符网站首页技术教程
verilog驱动LCD显示彩条、字符
verilog驱动LCD显示彩条、字符
一、简介
LCD(liquid crystal display):液晶显示器
TFT:薄膜晶体管
LCD屏幕接口:常见的LCD屏幕接口有:RGB、MCU、LVDS、MIPI等
RGB LCD接口原理图:其中MISO、MOSI是IIC接口;SCK、MISO、MOSI、CS可以组成SPI协议
实验平台:开拓者开发板
二、LCD驱动时序
刷新一帧的时间:
公式:(场同步信号 + 场同步后沿 + 显示整个一帧的时间 + 场同步前沿)*(行同步信号的宽度 + 行同步后沿 + 一行持续的时间 + 行同步前沿)
最终算出来的51.2M就是在这个分辨率下的LCD驱动时钟的 频率,
LCD屏幕的时序参数:
管脚说明:
三、程序设计
(1)确定LCD的尺寸型号:
module rd_id(
input clk , //时钟
input rst_n , //复位,低电平有效
input [15:0] lcd_rgb, //RGB LCD像素数据,用于读取ID
output reg [15:0] lcd_id //LCD屏ID
);
//reg define
reg rd_flag; //读ID标志
//*****************************************************
//** main code
//*****************************************************
//获取LCD ID M2:B4 M1:G5 M0:R4
always @(posedge clk or negedge rst_n) begin
if(!rst_n) begin
rd_flag <= 1'b0;
lcd_id <= 16'd0;
end
else begin
if(rd_flag == 1'b0) begin
rd_flag <= 1'b1;
case({lcd_rgb[4],lcd_rgb[10],lcd_rgb[15]})//lcd_rgb数据的4、10、15位可以确定lcd的型号,将这三个位拼接起来
3'b000 : lcd_id <= 16'h4342; //4.3' RGB LCD RES:480x272
3'b001 : lcd_id <= 16'h7084; //7' RGB LCD RES:800x480
3'b010 : lcd_id <= 16'h7016; //7' RGB LCD RES:1024x600
3'b100 : lcd_id <= 16'h4384; //4.3' RGB LCD RES:800x480
3'b101 : lcd_id <= 16'h1018; //10' RGB LCD RES:1280x800
default : lcd_id <=16'h0;
endcase
end
end
end
endmodule
(2)时钟的分频:
module clk_div(
input clk, //50Mhz
input rst_n,
input [15:0] lcd_id,
output reg lcd_pclk
);
reg clk_25m;
reg clk_12_5m;
reg div_4_cnt;
//时钟2分频,FPGA系统时钟为50M,分频后输出25MHz时钟
always @(posedge clk or negedge rst_n) begin
if(!rst_n)
clk_25m <= 1'b0;//初始值为0
else
clk_25m <= ~clk_25m;//时钟的上升沿一到clk_25m就翻转,即从0变为1,
end
//时钟4分频 输出12.5MHz时钟
always @(posedge clk or negedge rst_n) begin
if(!rst_n) begin
div_4_cnt <= 1'b0;
clk_12_5m <= 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
//匹配不同尺寸的LCD
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_25m;
16'h1018 : lcd_pclk = clk;
default : lcd_pclk = 0;
endcase
end
endmodule
这个是2分频的时序图,clk_25M一个时钟周期就翻转一次,从实现了clk_25M的周期为2倍的Tclk
//时钟2分频,FPGA系统时钟为50M,分频后输出25MHz时钟
always @(posedge clk or negedge rst_n) begin
if(!rst_n)
clk_25m <= 1'b0;//初始值为0
else
clk_25m <= ~clk_25m;//时钟的上升沿一到clk_25m就翻转,即从0变为1,
end
对下面的代码进行分析,这个是四分频的时序图Tclk_12_5m=4Tclk
//时钟4分频 输出12.5MHz时钟
always @(posedge clk or negedge rst_n) begin
if(!rst_n) begin
div_4_cnt <= 1'b0;
clk_12_5m <= 1'b0;
end
else begin
div_4_cnt <= div_4_cnt + 1'b1;//这条语句和第9行代码是同时进行的
if(div_4_cnt == 1'b1) //所以第9行的div_4_cnt此时还是为0,需要等到下一个posedge clk的到来。
clk_12_5m <= ~clk_12_5m;
end
end
(3)LCD的驱动:
module lcd_driver(
input lcd_pclk, //时钟
input rst_n, //复位,低电平有效
input [15:0] lcd_id, //LCD屏ID
input [15: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 reg lcd_bl, //LCD 背光控制信号
output lcd_clk, //LCD 像素时钟
output [15:0] lcd_rgb, //LCD RGB565颜色数据
output reg lcd_rst
);
//parameter define
// 4.3' 480*272
parameter H_SYNC_4342 = 11'd41; //行同步
parameter H_BACK_4342 = 11'd2; //行显示后沿
parameter H_DISP_4342 = 11'd480; //行有效数据
parameter H_FRONT_4342 = 11'd2; //行显示前沿
parameter H_TOTAL_4342 = 11'd525; //行扫描周期
parameter V_SYNC_4342 = 11'd10; //场同步
parameter V_BACK_4342 = 11'd2; //场显示后沿
parameter V_DISP_4342 = 11'd272; //场有效数据
parameter V_FRONT_4342 = 11'd2; //场显示前沿
parameter V_TOTAL_4342 = 11'd286; //场扫描周期
// 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; //场扫描周期
// 7' 1024*600
parameter H_SYNC_7016 = 11'd20; //行同步
parameter H_BACK_7016 = 11'd140; //行显示后沿
parameter H_DISP_7016 = 11'd1024; //行有效数据
parameter H_FRONT_7016 = 11'd160; //行显示前沿
parameter H_TOTAL_7016 = 11'd1344; //行扫描周期
parameter V_SYNC_7016 = 11'd3; //场同步
parameter V_BACK_7016 = 11'd20; //场显示后沿
parameter V_DISP_7016 = 11'd600; //场有效数据
parameter V_FRONT_7016 = 11'd12; //场显示前沿
parameter V_TOTAL_7016 = 11'd635; //场扫描周期
// 10.1' 1280*800
parameter H_SYNC_1018 = 11'd10; //行同步
parameter H_BACK_1018 = 11'd80; //行显示后沿
parameter H_DISP_1018 = 11'd1280; //行有效数据
parameter H_FRONT_1018 = 11'd70; //行显示前沿
parameter H_TOTAL_1018 = 11'd1440; //行扫描周期
parameter V_SYNC_1018 = 11'd3; //场同步
parameter V_BACK_1018 = 11'd10; //场显示后沿
parameter V_DISP_1018 = 11'd800; //场有效数据
parameter V_FRONT_1018 = 11'd10; //场显示前沿
parameter V_TOTAL_1018 = 11'd823; //场扫描周期
// 4.3' 800*480
parameter H_SYNC_4384 = 11'd128; //行同步
parameter H_BACK_4384 = 11'd88; //行显示后沿
parameter H_DISP_4384 = 11'd800; //行有效数据
parameter H_FRONT_4384 = 11'd40; //行显示前沿
parameter H_TOTAL_4384 = 11'd1056; //行扫描周期
parameter V_SYNC_4384 = 11'd2; //场同步
parameter V_BACK_4384 = 11'd33; //场显示后沿
parameter V_DISP_4384 = 11'd480; //场有效数据
parameter V_FRONT_4384 = 11'd10; //场显示前沿
parameter V_TOTAL_4384 = 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_clk = lcd_pclk; //LCD像素时钟
assign lcd_de = lcd_en; //LCD数据有效信号
//使能RGB565数据输出
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;
//RGB565数据输出
assign lcd_rgb = lcd_en ? pixel_data : 16'd0;
//行场时序参数
always @(posedge lcd_pclk) begin
case(lcd_id)
16'h4342 : 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
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 <= 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
always@ (posedge lcd_pclk or negedge rst_n) begin
if(!rst_n)begin
lcd_rst<=0;
lcd_bl<=0;
end
else begin
lcd_rst<=1;
lcd_bl<=1;//LCD的背光
end
end
endmodule
(4) 显示模块
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 [15:0] pixel_data //像素数据
);
//parameter define
parameter WHITE = 16'b11111_111111_11111; //白色
parameter BLACK = 16'b00000_000000_00000; //黑色
parameter RED = 16'b11111_000000_00000; //红色
parameter GREEN = 16'b00000_111111_00000; //绿色
parameter BLUE = 16'b00000_000000_11111; //蓝色
//根据当前像素点坐标指定当前像素点颜色数据,在屏幕上显示彩条
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
(5)顶层文件
module lcd_rgb_colorbar(
input sys_clk, //系统时钟
input sys_rst_n, //系统复位
//RGB LCD接口
output lcd_de, //LCD 数据使能信号
output lcd_hs, //LCD 行同步信号
output lcd_vs, //LCD 场同步信号
output lcd_clk, //LCD 像素时钟
inout [15:0] lcd_rgb, //LCD RGB565颜色数据
output lcd_rst,
output lcd_bl
);
wire [15:0] lcd_id ; //LCD屏ID
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 [15:0] pixel_data; //像素数据
wire [15:0] lcd_rgb_o ; //输出的像素数据
wire [15:0] lcd_rgb_i ; //输入的像素数据
//*****************************************************
//** main code
//*****************************************************
//像素数据方向切换
assign lcd_rgb = lcd_de ? lcd_rgb_o : {16{1'bz}};
assign lcd_rgb_i = lcd_rgb;
//读LCD ID模块
rd_id u_rd_id(
.clk (sys_clk ),
.rst_n (sys_rst_n),
.lcd_rgb (lcd_rgb_i),
.lcd_id (lcd_id )
);
//时钟分频模块
clk_div u_clk_div(
.clk (sys_clk ),
.rst_n (sys_rst_n),
.lcd_id (lcd_id ),
.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 ),
.lcd_id (lcd_id ),
.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_clk (lcd_clk ),
.lcd_rgb (lcd_rgb_o ),
.lcd_rst (lcd_rst ),
.lcd_bl (lcd_bl)
);
endmodule
--晓凡 2023年5月3日于桂林书
verilog驱动LCD显示彩条、字符
一、简介
LCD(liquid crystal display):液晶显示器
TFT:薄膜晶体管
LCD屏幕接口:常见的LCD屏幕接口有:RGB、MCU、LVDS、MIPI等
RGB LCD接口原理图:其中MISO、MOSI是IIC接口;SCK、MISO、MOSI、CS可以组成SPI协议
二、LCD驱动时序
刷新一帧的时间:
公式:(场同步信号 + 场同步后沿 + 显示整个一帧的时间 + 场同步前沿)*(行同步信号的宽度 + 行同步后沿 + 一行持续的时间 + 行同步前沿)
最终算出来的51.2M就是在这个分辨率下的LCD驱动时钟的 频率,
LCD屏幕的时序参数:
管脚说明:
三、程序设计
(1)确定LCD的尺寸型号:
module rd_id(
input clk , //时钟
input rst_n , //复位,低电平有效
input [15:0] lcd_rgb, //RGB LCD像素数据,用于读取ID
output reg [15:0] lcd_id //LCD屏ID
);
//reg define
reg rd_flag; //读ID标志
//*****************************************************
//** main code
//*****************************************************
//获取LCD ID M2:B4 M1:G5 M0:R4
always @(posedge clk or negedge rst_n) begin
if(!rst_n) begin
rd_flag <= 1'b0;
lcd_id <= 16'd0;
end
else begin
if(rd_flag == 1'b0) begin
rd_flag <= 1'b1;
case({lcd_rgb[4],lcd_rgb[10],lcd_rgb[15]})//lcd_rgb数据的4、10、15位可以确定lcd的型号,将这三个位拼接起来
3'b000 : lcd_id <= 16'h4342; //4.3' RGB LCD RES:480x272
3'b001 : lcd_id <= 16'h7084; //7' RGB LCD RES:800x480
3'b010 : lcd_id <= 16'h7016; //7' RGB LCD RES:1024x600
3'b100 : lcd_id <= 16'h4384; //4.3' RGB LCD RES:800x480
3'b101 : lcd_id <= 16'h1018; //10' RGB LCD RES:1280x800
default : lcd_id <=16'h0;
endcase
end
end
end
endmodule
(2)时钟的分频:
module clk_div(
input clk, //50Mhz
input rst_n,
input [15:0] lcd_id,
output reg lcd_pclk
);
reg clk_25m;
reg clk_12_5m;
reg div_4_cnt;
//时钟2分频,FPGA系统时钟为50M,分频后输出25MHz时钟
always @(posedge clk or negedge rst_n) begin
if(!rst_n)
clk_25m <= 1'b0;//初始值为0
else
clk_25m <= ~clk_25m;//时钟的上升沿一到clk_25m就翻转,即从0变为1,
end
//时钟4分频 输出12.5MHz时钟
always @(posedge clk or negedge rst_n) begin
if(!rst_n) begin
div_4_cnt <= 1'b0;
clk_12_5m <= 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
//匹配不同尺寸的LCD
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_25m;
16'h1018 : lcd_pclk = clk;
default : lcd_pclk = 0;
endcase
end
endmodule
这个是2分频的时序图,clk_25M一个时钟周期就翻转一次,从实现了clk_25M的周期为2倍的Tclk
//时钟2分频,FPGA系统时钟为50M,分频后输出25MHz时钟
always @(posedge clk or negedge rst_n) begin
if(!rst_n)
clk_25m <= 1'b0;//初始值为0
else
clk_25m <= ~clk_25m;//时钟的上升沿一到clk_25m就翻转,即从0变为1,
end
对下面的代码进行分析,这个是四分频的时序图Tclk_12_5m=4Tclk
//时钟4分频 输出12.5MHz时钟
always @(posedge clk or negedge rst_n) begin
if(!rst_n) begin
div_4_cnt <= 1'b0;
clk_12_5m <= 1'b0;
end
else begin
div_4_cnt <= div_4_cnt + 1'b1;//这条语句和第9行代码是同时进行的
if(div_4_cnt == 1'b1) //所以第9行的div_4_cnt此时还是为0,需要等到下一个posedge clk的到来。
clk_12_5m <= ~clk_12_5m;
end
end
(3)LCD的驱动:
module lcd_driver(
input lcd_pclk, //时钟
input rst_n, //复位,低电平有效
input [15:0] lcd_id, //LCD屏ID
input [15: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 reg lcd_bl, //LCD 背光控制信号
output lcd_clk, //LCD 像素时钟
output [15:0] lcd_rgb, //LCD RGB565颜色数据
output reg lcd_rst
);
//parameter define
// 4.3' 480*272
parameter H_SYNC_4342 = 11'd41; //行同步
parameter H_BACK_4342 = 11'd2; //行显示后沿
parameter H_DISP_4342 = 11'd480; //行有效数据
parameter H_FRONT_4342 = 11'd2; //行显示前沿
parameter H_TOTAL_4342 = 11'd525; //行扫描周期
parameter V_SYNC_4342 = 11'd10; //场同步
parameter V_BACK_4342 = 11'd2; //场显示后沿
parameter V_DISP_4342 = 11'd272; //场有效数据
parameter V_FRONT_4342 = 11'd2; //场显示前沿
parameter V_TOTAL_4342 = 11'd286; //场扫描周期
// 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; //场扫描周期
// 7' 1024*600
parameter H_SYNC_7016 = 11'd20; //行同步
parameter H_BACK_7016 = 11'd140; //行显示后沿
parameter H_DISP_7016 = 11'd1024; //行有效数据
parameter H_FRONT_7016 = 11'd160; //行显示前沿
parameter H_TOTAL_7016 = 11'd1344; //行扫描周期
parameter V_SYNC_7016 = 11'd3; //场同步
parameter V_BACK_7016 = 11'd20; //场显示后沿
parameter V_DISP_7016 = 11'd600; //场有效数据
parameter V_FRONT_7016 = 11'd12; //场显示前沿
parameter V_TOTAL_7016 = 11'd635; //场扫描周期
// 10.1' 1280*800
parameter H_SYNC_1018 = 11'd10; //行同步
parameter H_BACK_1018 = 11'd80; //行显示后沿
parameter H_DISP_1018 = 11'd1280; //行有效数据
parameter H_FRONT_1018 = 11'd70; //行显示前沿
parameter H_TOTAL_1018 = 11'd1440; //行扫描周期
parameter V_SYNC_1018 = 11'd3; //场同步
parameter V_BACK_1018 = 11'd10; //场显示后沿
parameter V_DISP_1018 = 11'd800; //场有效数据
parameter V_FRONT_1018 = 11'd10; //场显示前沿
parameter V_TOTAL_1018 = 11'd823; //场扫描周期
// 4.3' 800*480
parameter H_SYNC_4384 = 11'd128; //行同步
parameter H_BACK_4384 = 11'd88; //行显示后沿
parameter H_DISP_4384 = 11'd800; //行有效数据
parameter H_FRONT_4384 = 11'd40; //行显示前沿
parameter H_TOTAL_4384 = 11'd1056; //行扫描周期
parameter V_SYNC_4384 = 11'd2; //场同步
parameter V_BACK_4384 = 11'd33; //场显示后沿
parameter V_DISP_4384 = 11'd480; //场有效数据
parameter V_FRONT_4384 = 11'd10; //场显示前沿
parameter V_TOTAL_4384 = 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_clk = lcd_pclk; //LCD像素时钟
assign lcd_de = lcd_en; //LCD数据有效信号
//使能RGB565数据输出
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;
//RGB565数据输出
assign lcd_rgb = lcd_en ? pixel_data : 16'd0;
//行场时序参数
always @(posedge lcd_pclk) begin
case(lcd_id)
16'h4342 : 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
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 <= 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
always@ (posedge lcd_pclk or negedge rst_n) begin
if(!rst_n)begin
lcd_rst<=0;
lcd_bl<=0;
end
else begin
lcd_rst<=1;
lcd_bl<=1;//LCD的背光
end
end
endmodule
(4) 显示模块
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 [15:0] pixel_data //像素数据
);
//parameter define
parameter WHITE = 16'b11111_111111_11111; //白色
parameter BLACK = 16'b00000_000000_00000; //黑色
parameter RED = 16'b11111_000000_00000; //红色
parameter GREEN = 16'b00000_111111_00000; //绿色
parameter BLUE = 16'b00000_000000_11111; //蓝色
//根据当前像素点坐标指定当前像素点颜色数据,在屏幕上显示彩条
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
(5)顶层文件
module lcd_rgb_colorbar(
input sys_clk, //系统时钟
input sys_rst_n, //系统复位
//RGB LCD接口
output lcd_de, //LCD 数据使能信号
output lcd_hs, //LCD 行同步信号
output lcd_vs, //LCD 场同步信号
output lcd_clk, //LCD 像素时钟
inout [15:0] lcd_rgb, //LCD RGB565颜色数据
output lcd_rst,
output lcd_bl
);
wire [15:0] lcd_id ; //LCD屏ID
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 [15:0] pixel_data; //像素数据
wire [15:0] lcd_rgb_o ; //输出的像素数据
wire [15:0] lcd_rgb_i ; //输入的像素数据
//*****************************************************
//** main code
//*****************************************************
//像素数据方向切换
assign lcd_rgb = lcd_de ? lcd_rgb_o : {16{1'bz}};
assign lcd_rgb_i = lcd_rgb;
//读LCD ID模块
rd_id u_rd_id(
.clk (sys_clk ),
.rst_n (sys_rst_n),
.lcd_rgb (lcd_rgb_i),
.lcd_id (lcd_id )
);
//时钟分频模块
clk_div u_clk_div(
.clk (sys_clk ),
.rst_n (sys_rst_n),
.lcd_id (lcd_id ),
.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 ),
.lcd_id (lcd_id ),
.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_clk (lcd_clk ),
.lcd_rgb (lcd_rgb_o ),
.lcd_rst (lcd_rst ),
.lcd_bl (lcd_bl)
);
endmodule
--晓凡 2023年5月3日于桂林书