目录
1.color bar (彩条)颜色编码
这里使用的编码方式是RGB888,一个像素R,G,B分量各占八位。
8色彩条是指白色,青色,黄色,品红色,绿色,蓝色,红色,黑色,他们都是R,G,B分量各取0或者255(2*2*2=8)组成。
详细编码方案见常用RGB编码颜色见常用RGB颜色表_yh13572438258的博客-CSDN博客
2.VGA驱动原理
VGA显示器的驱动原理,大家知道,我们的显示器是不同的分辨率,而大多显示器的分辨率都是接近4:3的,所以我们采用640×480@60Hz这样的一个分辨率来实验。
下图是不同显示分辨率模式下的标准约束,显示前后沿又称为消隐前后肩。
开发板与VGA接口的电路图:
电路中的信号名总共有两类:VGA的场同步和行同步信号(VGA_VS,VGA_HS),控制VGA颜色的(R,G,B)。
行同步和场同步,是来驱动我们的VGA显示的两个信号,而GRB是控制VGA显示的颜色。
下面这个图是基于640×480@60Hz这个分辨率的具体参数:
而下面这个图是关于VGA显示的时序图,这只是咱们让显示器亮起来的一个时序图,并不指定在什么区域显示什么颜色。Blacking区又叫消隐区,由前肩,同步脉冲,后肩组成。行场同步信号又叫水平垂直同步信号。
接下来解释下这个图中信号,HSync和VSync分别是行同步信号和场同步信号,而其中的Video部分,就是显示的信号,但是真正有效的区域还是属于video中的“Addressable”Video,其余部分都是无效的,就是说在其他部分,都让其输出信号为“0”.可能这样说起来还是显得比较空洞,大家看下面这个图就会显得比较直接了。
在我们理解VGA时序的时候,我们也可以把VGA显示理解成“扫描”,而VGA扫描的开始是从屏幕的左上角开始,然后开始扫描第一行,第一行扫描完了,扫第二行,一直扫到屏幕的最后一行,然后回到初始位置开始扫描。在扫描的过程中,每一行的开始,有一个同步信号,就是图中的HSync,扫完整个屏幕结束后重新开始扫描有一个场同步信号VSync.
3.设计思路
主要使用两个计数器,分别来计行信号刷新到了哪个像素点和场信号计到了哪一行。然后在场信号计到了某一行的时候,就控制显示的颜色。当然,最重要的一点,需要记得给行信号和场信号加上同步信号(我们的板子上的同步信号是为低电平,同步信号为高或低,需要根据需要的同步信号的极性而定)。Horizontal synchronization = HS 行同步信号,Vertical synchronization = VS 场同步信号。
3.1Pixel clock = 25.175MHz说明每一个像素点刷新的时钟频率为25.175MHz,可以取25MHz,但开发板上的时钟为50MHz,可以二分频,也可以调用PLL这个ip核来生成我们的25MHz时钟。
3.2Hor Total Time = 31.778; // (usec) = 100 chars = 800 Pixels 代表每一行占用800个像素点(实际显示的只有640个像素点)
3.3Ver Total Time = 16.683; // (msec) = 525 lines 代表每一场有525行
3.4.根据其他的参数可以得知,行同步占用刷新96个像素点的时间,场同步占用2行,而行信号的有效显示为146~(146+640),场信号的有效显示为35~(35+480)。在其余的区域,是不给VGA显示信息的,就是说我们输出的RGB为0。
3.5若要使我们的显示器显示出8种颜色,我们可以先给显示的有效区域分成8个部分,640/8=80在一行有效区域的0~80显示一种颜色,在80~160列显示另外一种颜色,..........,以此类推,在剩下的560~640显示第三种颜色。
3.6顶层模块连接图
4.模块代码
4.1顶层代码
如下:
module vga_top(
clk,
rst_n,
vga_hs,
vga_vs,
data_en,
vga_rgb
);
input clk ;
input rst_n;
output vga_hs;
output vga_vs;
output [23:0] vga_rgb;
output data_en;
wire [9:0] w_h_pixel;
wire [9:0] w_v_pixel;
wire w_clk;
wire [23:0] pixel_data;
div_clk u1(
.clk (clk ),
.rst_n (rst_n ),
.div_clk (w_clk )
);
vga_driver u2(
.vga_clk (w_clk ),
.rst_n (rst_n ),
.pixel_data (pixel_data ),
.vga_hs (vga_hs ),
.vga_vs (vga_vs ),
.data_en (data_en ),
.vga_rgb (vga_rgb ),
.h_pixel (w_h_pixel ),
.v_pixel (w_v_pixel )
);
vga_display u3(
.vga_clk (w_clk ),
.rst_n (rst_n ),
.h_pixel (w_h_pixel ),
.v_pixel (w_v_pixel ),
.data_en (data_en ),
.pixel_data (pixel_data )
);
endmodule
4.2分频时钟模块
如下:
module div_clk(
clk,
rst_n,
div_clk
);
input clk;
inout rst_n;
output reg div_clk;
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
div_clk <= 1'b0;
else
div_clk <= ~div_clk;
end
endmodule
4.3 vga_driver模块
如下:
module vga_driver(
vga_clk,
rst_n,
pixel_data,
vga_hs,
vga_vs,
data_en,
vga_rgb,
h_pixel,
v_pixel
);
//---------------------------------
input vga_clk ;
input rst_n ;
input [23:0] pixel_data ;
//---------------------------------
output vga_hs ;//horizontal synchronization
output vga_vs ;//vertical synchronization
output [23:0] vga_rgb ;
output [ 9:0] h_pixel ;//horizontal valid pixel position
output [ 9:0] v_pixel ;//vertical valid pixel position
output reg data_en ;
//---------------------------------
parameter Hor_Total_Time = 10'd800 ; //horizontal sync signal cycles
parameter Hor_Sync = 10'd96 ; //horizontal sync pulse width
parameter Hor_Back_Porch = 10'd48 ; //horizontal back porch
parameter Hor_Active_Time = 10'd640 ; //horizontal active screen size
parameter Hor_Front_Porch = 10'd16 ; //horizontal front porch
//---------------------------------
parameter Ver_Total_Time = 10'd525 ; //vertical sync signal cycles
parameter Ver_Sync = 10'd2 ; //vertical sync pulse width
parameter Ver_Back_Porch = 10'd33 ; //vertical back porch
parameter Ver_Active_Time = 10'd480 ; //vertical active screen size
parameter Ver_Front_Porch = 10'd10 ; //vertical front porch
//---------------------------------
// Horizontal position counter.
reg [9:0] h_cnt;
always@(posedge vga_clk or negedge rst_n)
begin
if(!rst_n)
h_cnt <= 10'd1; //Count from 1, no 0
else
if(h_cnt == Hor_Total_Time)
h_cnt <= 10'd1;
else
h_cnt <= h_cnt + 1'b1;
end
//Vertical position counter.
reg [9:0] v_cnt;
always@(posedge vga_clk or negedge rst_n)
begin
if(!rst_n)
v_cnt <= 10'd1;
else
if(v_cnt == Ver_Total_Time && h_cnt == Hor_Total_Time)
v_cnt <= 10'd1;
else
if(h_cnt == Hor_Total_Time)
v_cnt <= v_cnt + 1'b1;
end
//HSYNC and VSYNC signal derivation.
assign vga_hs = (h_cnt < Hor_Sync) ? 1'b1 : 1'b0; //HSYNC polarization: this is 1 - positive
assign vga_vs = (v_cnt < Ver_Sync) ? 1'b1 : 1'b0; //VSYNC polarization: this is 1 - positive
//Data enable (blanking) signal derivation.
always@(*)
begin
data_en <= (h_cnt > (Hor_Sync + Hor_Back_Porch) && h_cnt <= (Hor_Sync + Hor_Back_Porch + Hor_Active_Time) && v_cnt > (Ver_Sync + Ver_Back_Porch) && v_cnt <= (Ver_Sync + Ver_Back_Porch + Ver_Active_Time));
end
assign vga_rgb = (data_en) ? pixel_data : 24'd0;
assign h_pixel = (data_en) ? (h_cnt - (Hor_Sync + Hor_Back_Porch) ) : 10'd0;
assign v_pixel = (data_en) ? (v_cnt - (Ver_Sync + Ver_Back_Porch) ) : 10'd0;
endmodule
4.4 vga_display 模块代码
module vga_display(
vga_clk,
rst_n,
h_pixel,
v_pixel,
data_en,
pixel_data
);
//---------------------------------
input vga_clk ;
input rst_n ;
input [9:0] h_pixel ;
input [9:0] v_pixel ;
input data_en ;
//---------------------------------
output reg [23:0] pixel_data;
//---------------------------------
parameter Hor_Active_Time = 10'd640 ; //horizontal active screen size
parameter Ver_Active_Time = 10'd480 ; //vertical active screen size
//---------------------------------
// color bars, RGB888
parameter WHITE = 24'hffffff ;
parameter CYAN = 24'h00ffff ;
parameter YELLOW = 24'hffff00 ;
parameter MAGENTA = 24'hff00ff ;
parameter BLUE = 24'h0000ff ;
parameter GREEN = 24'h00ff00 ;
parameter RED = 24'hff0000 ;
parameter BLACK = 24'h000000 ;
//---------------------------------
always@(posedge vga_clk or negedge rst_n)
begin
if(!rst_n)
pixel_data <= 24'd0;
else
if(h_pixel <= (Hor_Active_Time / 8) * 1 - 1'b1 ) //h_pixel begin from 0
pixel_data <= WHITE;
else
if(h_pixel <= (Hor_Active_Time / 8)* 2 - 1'b1 )
pixel_data <= CYAN;
else
if(h_pixel <= (Hor_Active_Time / 8)* 3 - 1'b1 )
pixel_data <= YELLOW;
else
if(h_pixel <= (Hor_Active_Time / 8)* 4 - 1'b1 )
pixel_data <= MAGENTA;
else
if(h_pixel <= (Hor_Active_Time / 8)* 5 - 1'b1 )
pixel_data <= BLUE;
else
if(h_pixel <= (Hor_Active_Time / 8)* 6 - 1'b1 )
pixel_data <=GREEN ;
else
if(h_pixel <= (Hor_Active_Time / 8)* 7 - 1'b1 )
pixel_data <= RED;
else
pixel_data <= BLACK;
end
endmodule
4.5 测试代码
`timescale 1ns/1ps
module vga_top_tb;
reg clk;
reg rst_n;
wire [7:0] vga_rgb;
wire vga_hs;
wire vga_vs;
wire data_en;
vga_top vga_inst (
.clk (clk ),
.rst_n (rst_n ),
.vga_rgb (vga_rgb ),
.vga_hs (vga_hs ),
.data_en (data_en ),
.vga_vs (vga_vs )
);
initial clk = 1;
always #10 clk = ~ clk;
initial
begin
rst_n = 0;
# 201
rst_n = 1;
repeat (3)
@ (posedge vga_vs);
$stop;
end
initial begin
$fsdbAutoSwitchDumpfile (1000,"vga_top.fsdb",13,"fsdb.log");
$fsdbDumpvars ;
$fsdbDumpflush;
end
endmodule
五、仿真结果图![](https://img-blog.csdnimg.cn/2a24bfe9133c46f2b25c7a19ecb5baea.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBA5Yas5aSp6YeM55qE5qOJ6KKE,size_20,color_FFFFFF,t_70,g_se,x_16)
六、makefile脚本
vcs:
vcs -sverilog -full64 +cli+4 vga_top.v vga_driver.v vga_display.v vga_top_tb.v div_clk.v \
-timescale=1ns/1ps \
-Mupdate +lint=all +notimingcheck +v2k \
-P ${DEBUSSY_HOME}/share/PLI/VCS/LINUX64/novas.tab \
${DEBUSSY_HOME}/share/PLI/VCS/LINUX64/pli.a \
+race=all \
-R \
-l run.log
verdi:
verdi -sv vga_top.v vga_driver.v vga_display.v vga_top_tb.v div_clk.v +define+GLS -top vga_top_000 &
驱动原理主要参考http://dengkanwen.com/70.html
代码参考链接:https://blog.csdn.net/qq_41467882/article/details/87078721