前言
随着社会的飞速发展,很多电子设备为了方便观察性能和实现更多的功能,都会为其配备一块显示屏,这也促进了显示设备的发展与迭代。到现在为止,图像显示技术的发展已经非常完善了,但在大型图像处理速度上还有提升的空间,还得去研究创造。
FPGA在图像显示领域的应用也十分的广泛,其中的一些视频传输接口便是FPGA与显示设备连接的桥梁,常见的图像传输接口有VGA接口、HDMI接口、DVI接口、DP接口等,本次实验我们就来简单地讲解一下VGA接口的功能与实现,对其他接口感兴趣的小伙伴们可以自行去了解,这里就不过多赘述了。
一、VGA简介
VGA的全称是Video Graphics Array,即视频图形阵列,是一个使用模拟信号进行视频传输的标准。VGA在1987年被IBM公司推出以来,因其具有分辨率高、显示速度快、显示色彩丰富等优点,在彩色显示器领域得到了广泛的应用。
如图所示就是VGA接口,由两部分组成,其中小孔的部分叫做母口,另一个叫做公口。由于接口体积较大的原因,现在我们的笔记本上已经逐渐淘汰掉了这种接口,但在我们的台式机显示器上,仍然有许多显示器在使用VGA接口进行图像的传输显示。
VGA接口定义及各引脚功能说明如下图所示,我们一般只用到其中的1(RED)、2(GREEN)、3(BLUE)、13(HSYNC)、14(VSYNC)信号。引脚1、2、3分别输出红、绿、蓝三原色模拟信号,电压变化范围为0~0.714V,0V表示无色,0.714V代表满色;引脚13、14输出TTL电平标准的行/场同步信号,其他引脚功能见下图。
在VGA视频传输标准中,视频图像被分解成红、绿、蓝三原色信号,经过数模转换后,在行同步和场同步信号的同步下分别在三个独立的通道内传输。行/场同步信号时序如下图所示:
在有了行同步信号和场同步信号的时序图以后,根据不同的时序参数,我们就可以来设计VGA显示的项目工程了。
二、VGA彩条显示实验
1、实验任务
在经过前面对VGA工作原理的学习以后,这里我们就按照VGA的时序来完成彩条显示的实验设计,要求如下:
分辨率:640*480@60
在显示器上显示等宽的红、橙、黄、绿、青、蓝、紫、黑、白、灰彩条。
2、程序设计
① vga顶层模块:
/*====================================*
filename : vga_colorbar_top.v
description : VGA彩条显示顶层模块
time : 2022-12-29
author : 卡夫卡与海
*=====================================*/
module vga_colorbar_top(
input clk ,//系统时钟
input rst_n ,//复位
output vga_hsync ,//行同步信号
output vga_vsync ,//场同步信号
output [15:0] vga_rgb //数据输出(红绿蓝)
);
//信号定义
wire vga_clk ;//vga工作时钟 25MHZ
wire locked ;
wire vga_reset ;
wire [9:0] pix_x ;
wire [9:0] pix_y ;
wire [15:0] pix_data ;
assign vga_reset = rst_n && locked;
//模块例化
//PLL
CLK_PLL CLK_PLL_inst (
.areset (~rst_n ),
.inclk0 (clk ),
.c0 (vga_clk),
.locked (locked )
);
//vga控制模块
vga_control u_vga_control(
/*input */.clk_25 (vga_clk ),//时钟 25MHZ
/*input */.rst_n (vga_reset),//复位
/*input [15:0] */.pix_data (pix_data ),//输入图像数据
/*output [9:0] */.pix_x (pix_x ),//横坐标
/*output [9:0] */.pix_y (pix_y ),//纵坐标
/*output */.hsync (vga_hsync),//行同步信号
/*output */.vsync (vga_vsync),//场同步信号
/*output [15:0] */.vga_rgb (vga_rgb ) //输出图像数据(RGB565格式)
);
//vga显示模块
vga_display u_vga_display(
/*input */.clk_25 (vga_clk ),//VGA驱动时钟
/*input */.rst_n (vga_reset),//复位
/*input [9:0] */.pix_x (pix_x ),//横坐标
/*input [9:0] */.pix_y (pix_y ),//纵坐标
/*output reg [15:0] */.pix_data (pix_data ) //数据
);
endmodule
② vga控制模块:
/*===============================*
filename : vga_control.v
description : VGA控制模块
time : 2022-12-28
author : 卡夫卡与海
*================================*/
module vga_control(
input clk_25 ,//时钟 25MHZ
input rst_n ,//复位
input [15:0] pix_data ,//输入图像数据
output [9:0] pix_x ,//横坐标
output [9:0] pix_y ,//纵坐标
output hsync ,//行同步信号
output vsync ,//场同步信号
output [15:0] vga_rgb //输出图像数据(RGB565格式)
);
//参数定义
//显示模式:640*480@60
parameter H_SYNC = 96 ,//行同步
H_BACK = 48 ,//行显示后沿
H_DISP = 640,//行有效数据
H_FRONT = 16 ,//行显示前沿
H_TOTAL = 800;//行扫描周期
parameter V_SYNC = 2 ,//场同步
V_BACK = 33 ,//场显示后沿
V_DISP = 480,//场有效数据
V_FRONT = 10 ,//场显示前沿
V_TOTAL = 525;//场扫描周期
//信号定义
reg [9:0] cnt_h ;//行计数器
reg [9:0] cnt_v ;//场计数器
wire rgb_vaild ;//数据有效信号
wire data_req ;//数据请求信号
//cnt_h
always @(posedge clk_25 or negedge rst_n)begin
if(!rst_n)begin
cnt_h <= 10'd0;
end
else begin
if(cnt_h < H_TOTAL - 1)begin
cnt_h <= cnt_h + 1'b1;
end
else begin
cnt_h <= 10'd0;
end
end
end
//cnt_v
always @(posedge clk_25 or negedge rst_n)begin
if(!rst_n)begin
cnt_v <= 10'd0;
end
else if(cnt_h == H_TOTAL - 1)begin
if(cnt_v < V_TOTAL - 1)begin
cnt_v <= cnt_v + 1'b1;
end
else begin
cnt_v <= 10'd0;
end
end
end
//rgb_vaild 数据输出有效信号
assign rgb_vaild = ((cnt_h >= H_BACK + H_SYNC)
&&(cnt_h < H_SYNC + H_BACK + H_DISP)
&&(cnt_v >= V_SYNC + V_BACK)
&&(cnt_v < V_SYNC + V_BACK + V_DISP))
? 1'b1 : 1'b0;
//data_req 像素点颜色数据输入请求信号
assign data_req = (((cnt_h >= H_SYNC + H_BACK - 1)
&& (cnt_h < H_SYNC + H_BACK + H_DISP - 1))
&& ((cnt_v >= V_SYNC + V_BACK)
&& (cnt_v < V_SYNC + V_BACK + V_DISP)))
? 1'b1 : 1'b0;
//输出
//pix_x 横坐标
assign pix_x = (data_req==1'b1)?(cnt_h - (H_SYNC+H_BACK-1)):10'h3ff;
//pix_y 纵坐标
assign pix_y = (data_req==1'b1)?(cnt_v - (V_SYNC+V_BACK-1)):10'h3ff;
//hsync
assign hsync = (cnt_h <= H_SYNC - 1) ? 1'b0 : 1'b1;
//vsync
assign vsync = (cnt_v <= V_SYNC - 1) ? 1'b0 : 1'b1;
//vga_rgb
assign vga_rgb = (rgb_vaild == 1'b1) ? pix_data : 16'd0;
endmodule
③ vga显示模块:
/*===============================*
filename : vga_display.v
description : VGA显示模块
time : 2022-12-29
author : 卡夫卡与海
*================================*/
module vga_display(
input clk_25 ,//VGA驱动时钟
input rst_n ,//复位
input [9:0] pix_x ,//横坐标
input [9:0] pix_y ,//纵坐标
output reg [15:0] pix_data //数据
);
//参数定义
parameter H_DISP = 10'd640,//分辨率一行
V_DISP = 10'd480;//分辨率一列
//颜色参数 RGB565格式
parameter RED = 16'hF800,//红
ORANGE = 16'hFC00,//橙
YELLOW = 16'hFFE0,//黄
GREEN = 16'h07E0,//绿
CYAN = 16'h07FF,//青
BLUE = 16'h001F,//蓝
PURPPLE = 16'hF81F,//紫
BLACK = 16'h0000,//黑
WHITE = 16'hFFFF,//白
GRAY = 16'hD69A;//灰
always @(posedge clk_25 or negedge rst_n)begin
if(!rst_n)begin
pix_data <= BLACK;
end
else if(pix_x >= 0 && pix_x <((H_DISP/10) * 1))begin
pix_data <= RED;//红
end
else if(pix_x >= ((H_DISP/10) * 1) && pix_x <((H_DISP/10) * 2))begin
pix_data <= ORANGE;//橙
end
else if(pix_x >= ((H_DISP/10) * 2) && pix_x <((H_DISP/10) * 3))begin
pix_data <= YELLOW;//黄
end
else if(pix_x >= ((H_DISP/10) * 3) && pix_x <((H_DISP/10) * 4))begin
pix_data <= GREEN;//绿
end
else if(pix_x >= ((H_DISP/10) * 4) && pix_x <((H_DISP/10) * 5))begin
pix_data <= CYAN;//青
end
else if(pix_x >= ((H_DISP/10) * 5) && pix_x <((H_DISP/10) * 6))begin
pix_data <= BLUE;//蓝
end
else if(pix_x >= ((H_DISP/10) * 6) && pix_x <((H_DISP/10) * 7))begin
pix_data <= PURPPLE;//紫
end
else if(pix_x >= ((H_DISP/10) * 7) && pix_x <((H_DISP/10) * 8))begin
pix_data <= BLACK;//黑
end
else if(pix_x >= ((H_DISP/10) * 8) && pix_x <((H_DISP/10) * 9))begin
pix_data <= WHITE;//白
end
else if(pix_x >= ((H_DISP/10) * 9) && pix_x < H_DISP)begin
pix_data <= GRAY;//灰
end
else begin
pix_data <= BLACK;
end
end
endmodule
④ vga仿真模块:
/*==================================*
filename : vga_top_tb.v
description : VGA顶层模块仿真
time : 2022-12-28
author : 卡夫卡与海
*===================================*/
`timescale 1ns/1ns
module vga_top_tb();
reg clk ;//50MHZ
reg rst_n ;
wire hsync ;
wire vsync ;
wire [15:0] vga_rgb ;
//产生时钟、复位
initial begin
clk = 1'b1;
rst_n = 1'b0;
#20
rst_n = 1'b1;
end
always #10 clk = ~clk;
//模块例化
vga_colorbar_top u_vga_colorbar_top(
/*input */.clk (clk ),//系统时钟
/*input */.rst_n (rst_n ),//复位
/*output */.vga_hsync (hsync ),//行同步信号
/*output */.vga_vsync (vsync ),//场同步信号
/*output [15:0] */.vga_rgb (vga_rgb) //数据输出(红绿蓝)
);
endmodule
在VGA顶层模块中有一个PLL的IP核,这是因为我们板子的晶振时钟是50MHZ,而我们VGA需要的时钟是25MHZ,这里就调用了一个锁相环IP核。当然,这里的时钟分频也可以用代码来实现,只不过调用IP核快一点罢了。
⑤ 板极验证:
板极验证效果如上图所示,屏幕上显示等宽的红、橙、黄、绿、青、蓝、紫、黑、白、灰共10跟彩条,说明上板验证成功。
总结
VGA接口的逻辑还是比较简单的,主要是要弄清楚它的显示时序以及那些参数设置,不然图像显示出来是不对的。我们这次是用的RGB565的格式进行显示的,除此之外还有RGB332,RGB888等显示格式,通道数越多,说明可以显示的色彩越丰富。
除了进行彩条显示之外,还可以尝试着去利用VGA接口显示文字、表情包等其它图像,大概的操作就是将图像数据存储到ROM中,然后从ROM中取出数据赋值给相应的RGB通道就可以了,感兴趣的可以去尝试一下!!!
没有回复内容