摘要
文章为学习记录。选用 VGA 显示模式 640x480@60,结合002–基于Verilog HDL的VGA显示器驱动设计(一)的VGA行同步时序、VGA场同步时序和VGA时序图给出驱动程序设计并输出像素点坐标、生成像素数据信息,并进行仿真。
一、简要说明
VGA 使用RGB565 图像显示模式,一个像素点位宽为 16bit,高 5 位表示红色,低 5位表示蓝色,中间 6 位表示绿色。另外,还有RGB232、RGB888 等,数据位宽越大,表示颜色种类越多,显示图像越细腻。
如下图,FPGA 输出的图像信息为数字信号,VGA 接口只能识别模拟信号,可以使用权电阻网络实现数模转换。三路模拟信号的电压高低由输入的数字信号决定。输入的 R、G、B 数字信号不同,输出的三原色红、绿、蓝模拟电压不同,颜色深浅不同,三原色相结合可以产生多种颜色。
二、整体框图
整个框图包含四个模块:
三、RTL
1.clk_gen
模块用于生成分频时钟。VGA 显示模式 640x480@60,理论时钟频率应为 25.175MHz,为了便于时钟生成,使用 25MHz 的时钟代替 25.175MHz 的时钟。
PLL配置:(1)和(2)
(1)
(2)
2.vga_ctrl
模块用于驱动 VGA 显示器,将输入像素点信息,按照 VGA 时序扫描显示到 VGA 显示器。并输出信号(pix_x,pix_y)作为 VGA 有效显示区域像素点坐标。
module vga_ctrl(
input wire vga_clk ,
input wire sys_rst_n ,
input wire [15:0] pix_data ,
output wire [9:0] pix_x ,
output wire [9:0] pix_y ,
output wire hsync ,
output wire vsync ,
output wire [15:0] rgb
);
//parameter define
parameter H_SYNC = 10'd96 ,
H_BACK = 10'd40 ,
H_LEFT = 10'd8 ,
H_VALID = 10'd640 ,
H_RIGHT = 10'd8 ,
H_FRONT = 10'd8 ,
H_TOTAL = 10'd800 ;
parameter V_SYNC = 10'd2 ,
V_BACK = 10'd25 ,
V_TOP = 10'd8 ,
V_VALID = 10'd480 ,
V_BOTTOM = 10'd8 ,
V_FRONT = 10'd2 ,
V_TOTAL = 10'd525 ;
//wire define
wire rgb_valid ;
wire pix_data_req ;
//reg define
reg [9:0] cnt_h ;
reg [9:0] cnt_v ;
//cnt_h:
always@(posedge vga_clk or negedge sys_rst_n)
begin
if(sys_rst_n == 1'b0)
cnt_h <= 10'd0 ;
else if(cnt_h == H_TOTAL - 1'd1)
cnt_h <= 10'd0 ;
else
cnt_h <= cnt_h + 1'd1 ;
end
//hsync:
assign hsync = (cnt_h <= H_SYNC - 1'd1) ? 1'b1 : 1'b0 ;
//cnt_v:
always@(posedge vga_clk or negedge sys_rst_n)
begin
if(sys_rst_n == 1'b0)
cnt_v <= 10'd0 ;
else if(cnt_h == H_TOTAL - 1'd1)
begin
if(cnt_v == V_TOTAL - 1'd1)
cnt_v <= 10'd0 ;
else
cnt_v <= cnt_v + 1'd1 ;
end
else
cnt_v <= cnt_v ;
end
//vsync:
assign vsync = (cnt_v <= V_SYNC - 1'd1) ? 1'b1 : 1'b0 ;
//rgb_valid:
assign rgb_valid = (((cnt_h >= H_SYNC + H_BACK + H_LEFT)
&& (cnt_h < H_SYNC + H_BACK + H_LEFT + H_VALID))
&&((cnt_v >= V_SYNC + V_BACK + V_TOP)
&& (cnt_v < V_SYNC + V_BACK + V_TOP + V_VALID)))
? 1'b1 : 1'b0;
//pix_data_req:
assign pix_data_req = (((cnt_h >= H_SYNC + H_BACK + H_LEFT - 1'b1)
&& (cnt_h < H_SYNC + H_BACK + H_LEFT + H_VALID - 1'b1))
&&((cnt_v >= V_SYNC + V_BACK + V_TOP)
&& (cnt_v < V_SYNC + V_BACK + V_TOP + V_VALID)))
? 1'b1 : 1'b0;
//pix_x,pix_y:
assign pix_x = (pix_data_req == 1'b1)
? (cnt_h - (H_SYNC + H_BACK + H_LEFT - 1'b1)) : 10'h3ff;
assign pix_y = (pix_data_req == 1'b1)
? (cnt_v - (V_SYNC + V_BACK + V_TOP)) : 10'h3ff;
//rgb:
assign rgb = (rgb_valid == 1'b1) ? pix_data : 16'b0 ;
endmodule
3.vga_pic
vga_pic模块接收 模块 vga_ctrl 传入的像素点坐标(pix_x,pix_y)信号,并以此为约束条件产生并回传像素点色彩信息。该模块可产生想要生成的图像像素点信息。
module vga_pic
(
input wire vga_clk , //输入工作时钟,频率25MHz
input wire sys_rst_n , //输入复位信号,低电平有效
input wire [9:0] pix_x , //输入VGA有效显示区域像素点X轴坐标
input wire [9:0] pix_y , //输入VGA有效显示区域像素点Y轴坐标
output reg [15:0] pix_data //输出像素点色彩信息
);
//parameter define
parameter H_VALID = 10'd640 , //行有效数据
V_VALID = 10'd480 ; //场有效数据
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; //灰色
//pix_data:
always@(posedge vga_clk or negedge sys_rst_n)
begin
if(sys_rst_n == 1'b0)
pix_data <= 16'd0;
else if((pix_x >= 0) && (pix_x < (H_VALID/10)*1))
pix_data <= RED;
else if((pix_x >= (H_VALID/10)*1) && (pix_x < (H_VALID/10)*2))
pix_data <= ORANGE;
else if((pix_x >= (H_VALID/10)*2) && (pix_x < (H_VALID/10)*3))
pix_data <= YELLOW;
else if((pix_x >= (H_VALID/10)*3) && (pix_x < (H_VALID/10)*4))
pix_data <= GREEN;
else if((pix_x >= (H_VALID/10)*4) && (pix_x < (H_VALID/10)*5))
pix_data <= CYAN;
else if((pix_x >= (H_VALID/10)*5) && (pix_x < (H_VALID/10)*6))
pix_data <= BLUE;
else if((pix_x >= (H_VALID/10)*6) && (pix_x < (H_VALID/10)*7))
pix_data <= PURPPLE;
else if((pix_x >= (H_VALID/10)*7) && (pix_x < (H_VALID/10)*8))
pix_data <= BLACK;
else if((pix_x >= (H_VALID/10)*8) && (pix_x < (H_VALID/10)*9))
pix_data <= WHITE;
else if((pix_x >= (H_VALID/10)*9) && (pix_x < H_VALID))
pix_data <= GRAY;
else
pix_data <= BLACK;
end
endmodule
4.vga_colorbar
module vga_colorbar(
input wire sys_clk,
input wire sys_rst_n,
output wire hsync,
output wire vsync,
output wire [15:0] rgb
);
//wire define
wire clk_25m ;
wire locked ;
wire rst_n ;
wire [9:0] pix_x ;
wire [9:0] pix_y ;
wire [15:0] pix_data;
//rst_n:
assign rst_n = (sys_rst_n & locked);
//------------- clk_gen_inst -------------
clk_gen clk_gen_inst
(
// Clock out ports
.clk_out1(clk_25m), // output clk_out1
// Status and control signals
.reset(~sys_rst_n), // input reset
.locked(locked), // output locked
// Clock in ports
.clk_in1(sys_clk) // input clk_in1
);
//------------- vga_ctrl_inst --
vga_ctrl vga_ctrl_inst
(
.vga_clk (clk_25m ),
.sys_rst_n (rst_n ),
.pix_data (pix_data ),
.pix_x (pix_x ),
.pix_y (pix_y ),
.hsync (hsync ),
.vsync (vsync ),
.rgb (rgb )
);
//------------- vga_pic_inst ---
vga_pic vga_pic_inst
(
.vga_clk (clk_25m ),
.sys_rst_n (rst_n ),
.pix_x (pix_x ),
.pix_y (pix_y ),
.pix_data (pix_data )
);
endmodule
四、Testbench
1.仿真代码
module tb_vga_colorbar();
//reg define
reg sys_clk ;
reg sys_rst_n ;
//wire define
wire hsync ;
wire [15:0] rgb ;
wire vsync ;
//sys_rst_n:
initial
begin
sys_rst_n = 1'b0;
#201
sys_rst_n = 1'b1;
#1_300_000
$stop;
end
//sys_clk:
initial
begin
sys_clk = 1'b1;
end
always #5 sys_clk = ~sys_clk ;
//------------- vga_colorbar_inst -------------
vga_colorbar vga_colorbar_inst
(
.sys_clk (sys_clk ),
.sys_rst_n (sys_rst_n ),
.hsync (hsync ),
.vsync (vsync ),
.rgb (rgb )
);
endmodule
2. 仿真分析
rgb_valid 信号只有在图像显示有效区域保持高电平,其他区域为低电平;pix_data_req 信号超前 rgb_valid 信号一个时钟周期;
pix_x 信号在图像显示有效区域循环计数,计数范围 0-639,计数 640 次;
pix_y 信号在图像显示有效区域循环计数,计数范围 0-479,计数 480 次;
rgb 在 rgb_valid 信号有效时,被赋值为 pix_data,rgb_valid 信号无效时,赋值为 0。