原创 【原创】基于Verilog的VGA显示控制(有源码)

2008-12-1 16:04 16940 9 31 分类: FPGA/CPLD

最近一直在玩转自己板子上的VGA模块,前几天做了一个基于Verilog的VGA显示控制,拿出来和大家分享一下。






一、VGA时序


下面的图是本人画了一个晚上的结果,个人认为能够比较详细的阐述VGA的信号时序。


点击看大图


VGA的时序根据不同的显示分辨率和刷新频率会有变化,具体各种类型的时序信息可以参考下面的网站,这里非常详细的说明的每一种显示模式的VGA时序信息。


http://www.tinyvga.com/vga-timing


<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />

 


二、VGA电平


 


VSYNCHSYNC为标准TTL电平,0V~3.3V


RGB的电平在0V~0.7V之间(0V为黑色,0.7V为全色)。


 





 

三、程序顶层框图


点击看大图


VGA产生行同步(HSYNC),场同步信号(VSYNC),并产生每个像素的地址输入单口ROM(显存)中,ROM输出该点需要显示的颜色值。


 





 

四、单口ROM(显存)设计


程序的显示模式为800*60072Hz刷新频率,像素频率为50MHz。每个像素需要显示的颜色存储在单口RAM中,每种颜色用8个字节表示,则如果要显示800*600分辨率,则需要800*600字节(480KB)的单口ROM,由于FPGA内部没有这么大的RAM(我用的是ep<?xml:namespace prefix = st1 ns = "urn:schemas-microsoft-com:office:smarttags" />2c8),因此我把屏幕上100*100个像素组成的矩形作为一个逻辑像素(即显示同一种颜色),这样只要8*6字节(48字节),用FPGA自带的RAM是很容易实现的。


ROM中颜色存储地址表


点击看大图


将全屏划分成8*6的方格,每个方格的颜色存储在ROM中,VGA控制器不断产生行坐标(ROM水平地址)和场坐标(ROM垂直地址),最后组合成ROM实际地址输入ROM中,ROM输出该地址的颜色值,显示在LCD中。


 





 


五、程序设计


 


VGA控制器程序


module VGA(clk,rst_n,hsync,vsync,vga_r,vga_g,vga_b);


 


input clk;       //50MHz


input rst_n;    //复位信号


output hsync;  //行同步信号


output vsync; //场同步信号


// RGB信号输出


output[1:0] vga_r;


output[2:0] vga_g;


output[2:0] vga_b;


//--------------------------------------------------


reg[10:0] x_cnt;      //行坐标(这里包括了行同步、后沿、有效数据区、前沿)


reg[9:0] y_cnt;      //列坐标(这里包括了场同步、后沿、有效数据区、前沿)


reg[5:0] Xcoloradd;


reg[2:0] Ycoloradd;


 


parameter


      Left = 184,


      PixelWidth = 100,


      Top  = 29;


     


always @ (posedge clk or negedge rst_n)


       if(!rst_n) x_cnt <= 10'd0;


       else if(x_cnt == 11'd1040) x_cnt <= 10'd0;           //行计数记到1040


       else x_cnt <= x_cnt+1'b1;


 


always @ (posedge clk or negedge rst_n)//产生行地址(ROM水平地址)


       if(!rst_n) Xcoloradd <= 6'b000000;


       else if(x_cnt >= Left && x_cnt <Left + PixelWidth) Xcoloradd <= 6'b000000;


       else if(x_cnt >= Left + PixelWidth && x_cnt <Left + 2*PixelWidth) Xcoloradd <= 6'b000001;


       else if(x_cnt >= Left + 2*PixelWidth && x_cnt <Left + 3*PixelWidth) Xcoloradd <= 6'b000010;


       else if(x_cnt >= Left + 3*PixelWidth && x_cnt <Left + 4*PixelWidth) Xcoloradd <= 6'b000011;


       else if(x_cnt >= Left + 4*PixelWidth && x_cnt <Left + 5*PixelWidth) Xcoloradd <= 6'b000100;


       else if(x_cnt >= Left + 5*PixelWidth && x_cnt <Left + 6*PixelWidth) Xcoloradd <= 6'b000101;


       else if(x_cnt >= Left + 6*PixelWidth && x_cnt <Left + 7*PixelWidth) Xcoloradd <= 6'b000110;


       else if(x_cnt >= Left + 7*PixelWidth && x_cnt <Left + 8*PixelWidth) Xcoloradd <= 6'b000111;


       else Xcoloradd <= 6'b110000;//背景颜色地址


 


always @ (posedge clk or negedge rst_n)


       if(!rst_n) y_cnt <= 10'd0;


       else if(y_cnt == 10'd666) y_cnt <= 10'd0;             //场同步记到666


       else if(x_cnt == 11'd1040) y_cnt <= y_cnt+1'b1;//每计数完一行,场同步就加一


     


always @ (posedge clk or negedge rst_n)//产生列地址(ROM垂直地址)


       if(!rst_n) Ycoloradd <= 3'b000;


       else if(y_cnt >= Top && y_cnt < Top + PixelWidth) Ycoloradd <= 3'b000;


       else if(y_cnt >= Top + PixelWidth && y_cnt < Top + 2*PixelWidth) Ycoloradd <= 3'b001;


       else if(y_cnt >= Top + 2*PixelWidth && y_cnt < Top + 3*PixelWidth) Ycoloradd <= 3'b010;


       else if(y_cnt >= Top + 3*PixelWidth && y_cnt < Top + 4*PixelWidth) Ycoloradd <= 3'b011;


       else if(y_cnt >= Top + 4*PixelWidth && y_cnt < Top + 5*PixelWidth) Ycoloradd <= 3'b100;


       else if(y_cnt >= Top + 5*PixelWidth && y_cnt < Top + 6*PixelWidth) Ycoloradd <= 3'b101;


       else Ycoloradd <= 3'b110;//背景颜色地址


//--------------------------------------------------


// signal port ROM


 


wire[7:0] color;


wire[5:0] coloradd;


 


assign coloradd = {Ycoloradd,3'b000}|Xcoloradd;//将水平地址和垂直地址合成ROM实际地址


sprom u1(coloradd,clk,color);


 


//---------------------------------------------------


 


wire valid;      //有效数据显示区标志,就是你在液晶屏幕上可以看到的区域


 


assign valid = (x_cnt > 10'd184) && (x_cnt < 10'd984)


 


           && (y_cnt > 10'd29) && (y_cnt < 10'd629);


//--------------------------------------------------


reg hsync_r,vsync_r;


 


always @ (posedge clk or negedge rst_n)


   if (!rst_n) begin


              hsync_r <= 1'b0;


      vsync_r <= 1'b0;


      end


   else begin


      hsync_r <= x_cnt >= 10'd120;  //产生hsync信号(行同步)when x_cnt>=50,then hsync_r=1,else 0;低电平同步


      vsync_r <= y_cnt >= 10'd6;   //产生vsync信号(场同步)my LCD is low sync


      end


assign hsync = hsync_r;


assign vsync = vsync_r;


 


//--------------------------------------------------


//颜色输出


assign vga_r[1] = valid ? color[7] : 1'b0;


assign vga_r[0] = valid ? color[6] : 1'b0;


 


assign vga_g[2] = valid ?  color[5] : 1'b0;


assign vga_g[1] = valid ?  color[4] : 1'b0;


assign vga_g[0] = valid ?  color[3] : 1'b0;


 


assign vga_b[2] = valid ? color[2] : 1'b0;  


assign vga_b[1] = valid ? color[1] : 1'b0;


assign vga_b[0] = valid ? color[0] : 1'b0;


 


endmodule


 





 

六、运行结果


b09dd80b-bcfb-48c6-b064-62cb6d9c4a3d.jpg


相机不好,拍的不太清晰,大家将就看看。


 





 


七、后记


 


在这次程序中只在ROM中存储了一些随机的数,因此显示出来是一些小方格,如果ROM做的更大,完全可以存储一幅图像,显示在LCD中。


不过由于由于用ROM做为显存,每次只能显示一幅静态的图像,而且没有加入字符库,不能显示字符,在下次的文章中,我将使用双口RAM,加上Nios II处理器,这样可以方便的显示各种字符。


 

文章评论22条评论)

登录后参与讨论

用户377235 2013-4-28 22:07

不错的文章

用户377235 2012-12-13 20:45

sprom u1(coloradd,clk,color); Could not find module/primitive 'sprom' 在哪啊

用户333178 2011-6-14 08:54

来学习下,虽然还不怎么看得懂 呵呵

jinkeyou112_614503351 2010-1-28 21:41

thanks a lot!

用户1506654 2009-10-6 19:46

补充一下,我用的是EP2C20F484这块板子!

用户1506654 2009-10-6 19:39

我也想问一下,我在编译的时候提示没有定义sprom模块!请问那是你的一个库函数吗?还是别的什么东西?期待你的解答,谢谢!

用户251222 2009-9-14 16:54

怎么往ROM中存数据?

用户251222 2009-9-12 15:05

大哥,sprom模块哪去了?

用户198286 2009-5-1 00:25

LZ的文章有参考作用,谢谢。 虽然还是有些没搞懂

用户1554589 2009-4-23 18:15

谢谢了,很好用
相关推荐阅读
用户1332143 2009-08-16 21:47
时序电路亚稳态分析
这篇文章是我对电子设计中,亚稳态问题的一种分析和总结。文章通过对数字电路中器件的工作机制的介绍,引出亚稳态问题的发生机制。并通过对亚稳态问题发生机制的探讨,用以得到一种能够清楚地,有的放矢地解决亚稳态...
用户1332143 2009-08-16 10:52
【推荐】ADF4350配置软件下载
p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">  随着现代半导体工艺的不断发展, 几十纳米级的CMOS工艺给数字电路带来了很大的恩惠, 但对模拟...
用户1332143 2009-08-14 12:47
【原创】基于NiosII及FT245BM的USB接口设计
以前做的一个项目,FPGA接收AD采集数据后,通过串口发送回PC机,由于串口传输速率较低,对于实时性要求较高的场合不太适用,因此站长选用FT245BM芯片来实现USB接口传输,本文主要讲解FT245B...
用户1332143 2009-08-13 14:56
【原创】MAXII:UFM中晶振的使用
MAXII系列CPLD中带有UFM模块,本文主要讲解UFM中晶振的使用,具体内容请点击下面链接MAXII:UFM中晶振的使用...
用户1332143 2009-03-01 21:53
【原创】如何使用FPGA进行信号调制
       最近要做一个通信收发系统项目,以前对收发器的射频前段关注的比较多,而对基带部分的信号处理一直没有仔细研究。因此,正好借这个项目,熟悉整个基带部分的信号处理流程。       基带部分主要...
用户1332143 2009-02-27 21:56
寒假回来——FPGA市场评论
寒假在家里电脑不能上网,好久没来更新自己的博客了,首先感谢大家对我博客的支持。回来后马上开始了一个863项目,一直没有时间来写博客,今天总算有时间,上来看看。回来这段时间关注了下FPGA的相关新闻,发...
EE直播间
更多
我要评论
22
9
关闭 站长推荐上一条 /3 下一条