PFGA/ZYNQ驱动LCD
前言
硬件是zynq 7010开发板,lcd采用RGB888接口,VGA时序。
对于普通的 VGA 显示器,共有 5 个信号:R、G、B 三基色;HS(行同步
信号);VS(场同步信号)。对于时序驱动,VGA 显示器要严格遵循“VGA”工业标准,我们选取分辨率为 480x272@60Hz 模式。通常我们用的显示器都满足工业标准,因此我们设计 VGA 控制器时要参考显示器的技术规格。下图是 VGA 行、场扫描的时序图:
VGA 扫描,基本元素是行扫描,多行组成一帧,下图显示一行的时序,其中“Active”
Video 是一行视频的有效像素,大部分分辨率时钟中 Top/Left Border 和 Bottom / Right
Border 都是 0。“Blanking”是一行的同步时间,“Blanking”时间加上 Active” Video 时间就
是一行的时间。“Blanking”又分为“Front Porch”、“Sync”、“Back Porch”三段。
lcd
产生VGA时序
module lcd(
input clk ,
input rst ,
output vpg_clk , //显示屏时钟
output vpg_de , //显示屏使能
output vpg_disp, //显示屏显示模式
output reg vpg_hs , //行同步信号
output reg vpg_vs , //场同步信号
output reg [12:0] cnt_h, //行计数器
output reg [12:0] cnt_v //场计数器
//output reg[23:0] RGB //像素点 rgb值
);
//--------------------------vga时序参数--------------------
//场同步信号
parameter H_TOTAL = 525 - 1;
parameter H_SYNC = 41 - 1;
parameter H_START = 43 - 1;//数据开始结束计算值
parameter H_END = 523 - 1;
//行同步信号
parameter V_TOTAL = 286 - 1;
parameter V_SYNC = 10 - 1;
parameter V_START = 12 - 1;//数据开始结束计算值
parameter V_END = 284 - 1;
//场图像数据
parameter IMG_X = 150;//方块x
parameter IMG_Y = 150;//方块x
parameter SCREEN_X = 480;//屏幕水平长度
parameter SCREEN_Y = 272;//屏幕垂直长度
//---------------------------信号-----------------------
/*
reg [11:0] x; //方块左上角横坐标
reg flag_x; //方块水平移动方向指示信号
reg [11:0] y; //方块左上角纵坐标
reg flag_y; //方块垂直移动方向指示信号
*/
wire locked; //时钟稳定信号
assign vpg_de = (cnt_h >= H_START) && (cnt_h < H_END) &&
(cnt_v >= V_START) && (cnt_v < V_END);
assign vpg_disp = 1'b1;
clk_wiz_0 clock
(
.clk_out1(vpg_clk),
.reset(~rst),
.locked(locked),
.clk_in1(clk)
);
//-----------------------cnt_h-----------------------
always @(posedge vpg_clk)
begin
if(!rst)
cnt_h <= 'd0;
else if(cnt_h >= H_TOTAL)
cnt_h <= 'd0;
else
cnt_h <= cnt_h + 1'b1;
end
//-----------------------cnt_v-----------------------
always @(posedge vpg_clk)
begin
if(!rst)
cnt_v <= 'd0;
else if(cnt_v >= V_TOTAL && cnt_h >= H_TOTAL)
cnt_v <= 'd0;
else if(cnt_h >= H_TOTAL)
cnt_v <= cnt_v + 1'b1;
end
//--------------------------vpg_hs-----------------------
always @(posedge vpg_clk)
begin
if(!rst)
vpg_hs <= 1'b1;
else if(cnt_h >= H_TOTAL)
vpg_hs <= 1'b1;
else if(cnt_h >= H_SYNC)
vpg_hs <= 1'b0;
else
vpg_hs <= vpg_hs;
end
//--------------------------vpg_vs-----------------------
always @(posedge vpg_clk)
begin
if(!rst)
vpg_vs <= 1'b1;
else if(cnt_v >= V_TOTAL && cnt_h >= H_TOTAL)
vpg_vs <= 1'b1;
else if(cnt_v >= V_SYNC && cnt_h >= H_SYNC)
vpg_vs <= 1'b0;
else
vpg_vs <= vpg_vs;
end
endmodule
lcd_display
图像显示
例:显示一个移动的方块
module lcd_display(
input vpg_clk,
input rst ,
input wire [12:0] cnt_h, //行计数器
input wire [12:0] cnt_v, //场计数器
output reg[23:0] RGB
);
//--------------------------vga时序参数--------------------
//场同步信号
parameter H_TOTAL = 525 - 1;
parameter H_SYNC = 41 - 1;
parameter H_START = 43 - 1;//数据开始结束计算值
parameter H_END = 523 - 1;
//行同步信号
parameter V_TOTAL = 286 - 1;
parameter V_SYNC = 10 - 1;
parameter V_START = 12 - 1;//数据开始结束计算值
parameter V_END = 284 - 1;
//场图像数据
parameter IMG_X = 150;//方块x
parameter IMG_Y = 150;//方块x
parameter SCREEN_X = 480;//屏幕水平长度
parameter SCREEN_Y = 272;//屏幕垂直长度
reg [11:0] x; //方块左上角横坐标
reg flag_x; //方块水平移动方向指示信号
reg [11:0] y; //方块左上角纵坐标
reg flag_y; //方块垂直移动方向指示信号
/*
------------------------图像的显示
*/
//--------------------------x-----------------------------
always @(posedge vpg_clk)
begin
if(!rst)
x <= 1'b0;
else if(flag_x == 1'b0 && cnt_v == V_TOTAL && cnt_h == H_TOTAL)
x <= x + 1'b1;
else if(flag_x == 1'b1 && cnt_v == V_TOTAL && cnt_h == H_TOTAL)
x <= x - 1'b1;
end
//移动方块左上角移动方向指示信号
always @(posedge vpg_clk ) begin
if (!rst) begin
flag_x <= 1'b0;
end
else if (flag_x == 1'b0 && cnt_v ==V_TOTAL && cnt_h == H_TOTAL && x==(H_END - H_START - IMG_X - 1'b1)) begin
flag_x <= 1'b1;
end
else if (flag_x == 1'b1 && cnt_v ==V_TOTAL && cnt_h == H_TOTAL && x=='d1) begin
flag_x <= 1'b0;
end
end
//--------------------------y-----------------------------
always @(posedge vpg_clk)
begin
if(!rst)
y <= 1'b1;
else if(flag_y == 1'b0 && cnt_v == V_TOTAL && cnt_h == H_TOTAL)
y <= y + 1'b1;
else if(flag_y == 1'b1 && cnt_v == V_TOTAL && cnt_h == H_TOTAL)
y <= y - 1'b1;
end
//移动方块左上角垂直移动方向指示信号
always @(posedge vpg_clk ) begin
if (!rst) begin
flag_y <= 1'b0;
end
else if (flag_y == 1'b0 && cnt_v ==V_TOTAL && cnt_h == H_TOTAL && y==(V_END - V_START - IMG_Y - 1'b1)) begin
flag_y <= 1'b1;
end
else if (flag_y == 1'b1 && cnt_v ==V_TOTAL && cnt_h == H_TOTAL && y=='d1 ) begin
flag_y <= 1'b0;
end
end
//RGB
always @(posedge vpg_clk ) begin
if (!rst) begin
RGB <='d0;
end
else if(cnt_h >= H_START + x && cnt_h <= H_START + IMG_X + x && cnt_v >= V_START + y && cnt_v <= V_START +IMG_Y + y)begin
RGB <= 24'hFFB6C1;//输出方块
end
else if (cnt_h >= H_START && cnt_h < H_END && cnt_v >=V_START && cnt_v < V_END && cnt_h[4:0] >= 'd20) begin
RGB <=24'h00FF00;//green
end
else if (cnt_h >=H_START && cnt_h <H_END && cnt_v >=V_START && cnt_v <V_END && (cnt_h[4:0]>='d10 && cnt_h[2:0]<'d20)) begin
RGB <=24'h0000FF;//bulue
end
else if (cnt_h >=H_START && cnt_h <H_END && cnt_v >=V_START && cnt_v <V_END && cnt_h[4:0]<'d10) begin
RGB <=24'hFF0000;//red
end
else begin
RGB <= 'd0;
end
end
endmodule
lcd_top
模块的例化
module lcd_top(
input clk ,
input rst ,
output vpg_clk , //显示屏时钟
output vpg_de , //显示屏使能
output vpg_disp, //显示屏显示模式
output wire vpg_hs , //行同步信号
output wire vpg_vs , //场同步信号
output wire[23:0] RGB //像素点 rgb值
);
wire [12:0] cnt_h;
wire [12:0] cnt_v;
lcd inst(
.clk (clk) ,
.rst (rst) ,
.vpg_clk (vpg_clk) , //显示屏时钟
.vpg_de (vpg_de) , //显示屏使能
.vpg_disp (vpg_disp) , //显示屏显示模式
.vpg_hs (vpg_hs) , //行同步信号
.vpg_vs (vpg_vs) , //场同步信号
.cnt_h (cnt_h) , //行计数器
.cnt_v (cnt_v) //场计数器
);
lcd_display lcd_display_inst(
.vpg_clk (vpg_clk) ,
.rst (rst) ,
.cnt_h (cnt_h) ,
.cnt_v (cnt_v) ,
.RGB (RGB)
);
endmodule
纯FPGA小白正在学习FPGA如有错误或者建议希望大佬多多提点。后面会实现显示图片和串口传图等。