nexys3练手——vga显示

来源:互联网 发布:python 爬虫要学多久 编辑:程序博客网 时间:2024/05/16 06:16

最近做了vga显示的实验,主要过程就是提取图片rgb数据存放在rom ip core里面,然后通过vga输出到显示器显示图片。

实验参考了黑金社区的博客:http://www.cnblogs.com/kingst/archive/2010/09/21/1832196.html。

首先我们要了解vga的概念,

VGA是什么?估计有接触过电脑的朋友多少也是知道。粗略认识VGA可分为,VGA硬件接口,和VGA协议。VGA硬件接口没有什么好学的,VGA时序才是正点。

VGA协议,主要有5个输入信号,亦是 HSYNC Signal, VSYNC Signal, RGB Signal。说简单一点,HSYNC Signal 是“列同步信号”, VSYNC Signal是“行同步信号”,RGB Signal是“红色-绿色-蓝色 颜色信号”。

VGA的扫描是固定的。一帧的屏幕是由“m行扫描”和“n列填充”组成。假设以 800 x 600 x 75Hz 为例的显示标准 (我所用的显示器就是这个标准), 那么宏观上它有 600 行 和 800列为一行。宏观上,一帧屏幕的显示是由600行从上至下扫描,800列从左至右填充,然而微观上,一行的行扫描是由超过800个列填充完成,一帧图像超过600行扫描。实际上是VGA的时序在作怪。

vga时序可以从:http://www.tinyvga.com/vga-timing 方便的查找,拿我们的800*600*75hz来讲:

HSYNC Signal 是用来控制“列填充”, 而一个HSYNC Signal 可以分为 4个段,也就是 a (同步段) , b(后廊段),c(激活段),d(前廊段)。HSYNC Signal 的a 是拉低的80 个列像素 ,b是拉高的160个列像素,至于c 是拉高的 800 个列像素,而最后的 d 是拉高的 16 个列像素。 一列总共有1056 个列像素。

VSYNC Signal 是用来控制“行扫描”。而一个 VSYNC Signal 同样可以分为 4 个段, 也是 o (同步段) , p(后廊段),q(激活段),r(前廊段)。VSYNC Signal 的o 是拉低的3个行像素 ,p是拉高的21个行像素,至于q 是拉高的 600 个行像素,而最后的 r 是拉高的 1 个行像素。 一行总共有625个行像素。

显示图片是发生在HSYNC的c段与VSYNC的q段交叉部分,即有效区域。

了解了大致原理后我们来编写vga模块:

vga_module.v 是组合模块,而且它包含了 clk_50.v , sync_module.v 和vga_control_module.v .

1.clk_50是一个分频模块,因为这个显示标准的需要的时钟约为50Mhz,系统时钟为100M,我们需要进行分频得到需要的时钟。代码如下

module clk_50(clk,rst,clk_50    );input clk;input rst;output clk_50;reg clk_50;always@(posedge clk)if(!rst) clk_50 <= 0;elseclk_50 <= ~clk_50;endmodule

2. sync_module.v 是对HSYNC Signal 和 VSYNC Signal 控制的“功能模块”。他扮演了“VGA驱动的核心”的角色。除此之外,sync_module.v还输出当前的 x地址(Column_Addr_Sig),y地址 ( Row_Addr_Sig ) 和有效区域信号(Ready_Sig)。代码如下

module sync_module(clk,rst,vsync,hsync,ready,column_addr,row_addr);input clk;input rst;output hsync;//列同步output vsync;//行同步output ready;//有效区域标志output [10:0] column_addr;output [10:0] row_addr;//列像素计数reg [10:0] count_h;always@(posedge clk or negedge rst)if(!rst)count_h <= 11'd0;else if(count_h == 11'd1056)count_h <= 11'd0;elsecount_h <= count_h + 1'b1;//行像素计数reg [10:0] count_v;always@(posedge clk or negedge rst)if(!rst)count_v <= 11'd0;else if(count_v == 11'd625)count_v <= 11'd0;else if(count_h == 11'd1056)count_v <= count_v + 1'b1;//有效区域reg isready;always@(posedge clk or negedge rst)if(!rst)isready <= 1'b0;else if((count_h > 11'd240 && count_h < 11'd1040) && (count_v > 11'd24 && count_v < 11'd624))isready <= 1'b1;elseisready <= 1'b0;//outputassign hsync = (count_h <= 11'd80) ? 1'b0 : 1'b1;assign vsync = (count_v <= 11'd3) ? 1'b0 : 1'b1;assign ready = isready;assign column_addr = isready ? count_h -11'd241 : 11'd0;assign row_addr = isready ? count_v -11'd25 : 11'd0;endmodule

3.vga_control_module.v 是“图像控制的核心”控制模块,有关 Red, Green, Blue 信号的控制,x地址和y地址的控制,图像显示控制,帧控制,完全都是在这个模块中完成操作。我这次选了一个180*156的图片,因为板子片上ram资源的576K的限制,取了3位的rgb数据,提取数据的软件是用pic2mif,下面是控制代码:

module vga_ctrl_module(clk,rst,ready,column_addr,row_addr,rom_addr,rom_data,red,green,blue    );input clk;input rst;input ready;input [10:0] column_addr;input [10:0] row_addr;input [2:0] rom_data;output [14:0] rom_addr;output [2:0] red;output [2:0] green;output [1:0] blue;////这样会发现要显示的左上角一块也是背景色,代码有问题。//reg [7:0] m;//读取当前行地址////always@(posedge clk or negedge rst)//if(!rst)//m <= 8'd0;//else if(ready && row_addr < 11'd156)//m <= row_addr[7:0];//else//m <= 8'd0;////reg [7:0] n;//读取当前列地址////always@(posedge clk or negedge rst)//if(!rst)//n <= 8'd0;//else if(ready && column_addr < 11'd180)//n <= column_addr[7:0];//else//n <= 8'd0;////assign rom_addr = m*180 + n;//对应rom中rgb地址////////assign red = ready ? {rom_data[2],rom_data[2],rom_data[2]} : 3'b000;//assign green = ready ? {rom_data[1],rom_data[1],rom_data[1]} : 3'b111;//assign blue = ready ? {rom_data[0],rom_data[0]} : 2'b00;//确定显示区域180*156并赋rom里的值reg isrectangle;reg [14:0] rom_addr;reg [7:0] m,n;always@(posedge clk or negedge rst)if(!rst)isrectangle <= 1'b0;else if((column_addr > 11'd0 && column_addr < 11'd180) && (row_addr > 0 && row_addr < 156))beginisrectangle <= 1'b1;m<=row_addr;n<=column_addr;rom_addr <= m * 180  + n;endelse beginisrectangle <= 1'b0;rom_addr <= 0;//这样就使得非显示区域以外的像素点显示rom里第一个rgb值,而第一个设为了000,即黑色end//assign red = (ready && isrectangle) ? {rom_data[2],rom_data[2],rom_data[2]} : 3'b000;//为什么改了:后面的值以后确定的显示区域也受了影响??//assign green = (ready && isrectangle) ? {rom_data[1],rom_data[1],rom_data[1]} : 3'b000;//assign blue = (ready && isrectangle) ? {rom_data[0],rom_data[0]} : 2'b00;assign red = {rom_data[2],rom_data[2],rom_data[2]} ;assign green = {rom_data[1],rom_data[1],rom_data[1]} ;assign blue =  {rom_data[0],rom_data[0]} ;endmodule

N3板子的vga接口的电路图如下:


最后是顶层模块vga_module:

module vga_module(clk,rst,hsync,vsync,red,green,blue    );input clk;input rst;output hsync;output vsync;output [2:0] red;output [2:0] green;output [1:0] blue;wire clk_50;clk_50 inst_clk_50(.clk(clk),.rst(rst),.clk_50(clk_50));wire [10:0] row_addr;wire [10:0] column_addr;wire ready;sync_module inst_sync_module(.clk(clk_50),.rst(rst),.hsync(hsync),.vsync(vsync),.column_addr(column_addr),.row_addr(row_addr),.ready(ready));wire [14:0] rom_addr;wire [2:0] rom_data;pic_rom your_instance_name (  .clka(clk_50), // input clka  .addra(rom_addr), // input [14 : 0] addra  .douta(rom_data) // output [2 : 0] douta  );vga_ctrl_module inst_vga_ctrl_module(.clk(clk_50),.rst(rst),.ready(ready),.column_addr(column_addr),.row_addr(row_addr),.rom_addr(rom_addr),.rom_data(rom_data),.red(red),.green(green),.blue(blue));endmodule


经过测试显示成功,下一步准备,在rom模块和vga模块之间加一个异步fifo模块,学习下fifo模块的使用。
0 0
原创粉丝点击