FPGA驱动VGA显示

驱动VGA显示

概述: VGA(Video Graphics Array),视频图形阵列,是一种视频传输标准,具有分辨率高、显示速度快、颜色丰富等优点,不支持音频传输。

说明: FPGA芯片采用了altera的Cyclon IV E系列的“EP4CE10F17C8”,软件环境-Quartus-Ⅱ。

文章目录1.VGA简介1.1 VGA接口1.2 VGA是如何实现显示的2. VGA通信协议2.1 VGA通信时序2.2 VGA时序解析3. FPGA驱动VGA显示彩条4. FPGA驱动VGA显示文字4.1 产生字库4.2 字库数据存入Memory-ROM_IP4.2.1 生成.mif文件4.2.2 ROM IP核4.3 verilog代码

1.VGA简介
1.1 VGA接口

●VGA接口:
FPGA驱动VGA显示

VGA是一种D型接口,采用非对称分布连接方式,共有15针,分三排,每排5个孔。

●VGA接口管脚表:

管脚 定义 管脚 定义

1
红基色(Red) FPGA驱动VGA显示
9
保留(各家定义不同)

2
绿基色(Green)FPGA驱动VGA显示
10
数字地

3
蓝基色(Blue) FPGA驱动VGA显示
11
地址码

4
地址码(ID Bit)
12
地址码

5
自测试(各家定义不同)
13
行同步

6
红地
14
场同步

7
绿地
15
地址码(各家定义不同)

8
蓝地

在15个管脚中,其中比较重要的是3根RGB彩色分量信号和2根扫描同步信号HSYNC和VSYNC。

●像素点构成: VGA显示器上每一个像素点可以有多种颜色,由三基色信号R、G、B组合构成。如果每个像素点采用3位二进制数表示(R、G、B信号各1位),则总共可以显示2×2×2=8种颜色,每个像素点采用8位二进制数表示(R、G、B信号分别为3、3、2),则总共可以显示8×8×4=256种颜色。

R(bit) G(bit) B(bit) 颜色个数

1
1
1
2×2×2=8

3
3
2
8×8×4=256

1.2 VGA是如何实现显示的

  要知道VGA显示器是不认识数字信号的,它只认识模拟信号。所谓它只认识模拟信号,即 在它的数据引脚1、2、3(RED、GREEN、BLUE)输入的不是简单的0、1数字信号,而是模拟电压(0V-0.714V)。1、2、3引脚具有不同的电压时,VGA显示器显示不同的颜色。

FPGA驱动VGA显示

但是FPGA要想产生模拟信号就需要借助DA,利用DA产生模拟信号,输出至VGA的RED、GREEN、BLUE基色数据线。也有利用电阻网络分流模拟DA实现的。

●VGA各种颜色如何实现的
在VGA接口的1、2、3引脚分别接至以下电压:

RED GREEN BLUE 颜色

0.714V
0V
0V
红色 FPGA驱动VGA显示

0V
0.714V
0V
绿色 FPGA驱动VGA显示

0V
0V
0.714V
蓝色FPGA驱动VGA显示

0V
0V
0.357V
半蓝色FPGA驱动VGA显示

0V
0V
0V
黑色FPGA驱动VGA显示

●利用电阻网络分流模拟DA
R-2R电阻网络分压原理:

(1)每个像素点采用3位二进制(R(1bit)、G(1bit)、B(1bit))
  例如VGA显示器要显示纯红色,则在RED引脚要输入0.714V电压,如果我们VGA_RED信号为1位电路如下图所示,那么(X+75)/3.3=75/0.714,计算得出X=271.6。
FPGA驱动VGA显示
将R1阻值选择为271.6Ω,仿真得出VGA_RED引脚输入电压确实为0.714V。
FPGA驱动VGA显示
(2)每个像素点采用8位二进制(R(3bit)、G(3bit)、B(2bit))
如果我们VGA_RED信号为3位电路如下图所示,那么(X+75)/3.3=75/0.714,计算得出X=271.6,X是通过三个电阻并联得到的。Rx||2Rx||4Rx=X,得出Rx=475.3Ω。
FPGA驱动VGA显示
将R1、R2、R3阻值选择为475.3Ω、950.6Ω、1.9012KΩ,并且将R1、R2、R3都接通至3.3V,得出VGA_RED节点电压为0.714V。
FPGA驱动VGA显示
上图的三个3.3V节点接至FPGA的三个输出引脚,就可以通过数字量去控制模拟量了。 例如FPGA三引脚输出数字量101,则对应以下电路(则会对应不同的颜色),VGA_RED节点电压为0.554V:
FPGA驱动VGA显示
VGA_GREEN、VGA_BLUE同理,我们就会得到以下完整的电路:
FPGA驱动VGA显示
原理很简单,之前说过,每个像素点采用8位二进制数表示(R、G、B信号分别为3、3、2)。观察上图得到以下对应关系:

RGB R(3bit) G(3bit) B(2bit)

8位二进制
D7、D6、D5
D4、D3、D2
D1、D0

对应硬件端口
VGA_R2、 VGA_R1、VGA_R0
VGA_G2、VGA_G1、VGA_G0
VGA_B1、VGA_B0

D7-D0分别映射到FPGA的8个IO口,就可以通过这8个IO口的数字量去控制VGA的颜色显示了。

2. VGA通信协议
2.1 VGA通信时序

FPGA驱动VGA显示
   从上图中看出,帧时序和行时序都有四部分:
●帧时序:

   帧时序的四个部分别是:同步脉冲(Sync o)、显示后沿(Back porch p)、显示时序段(Display interval q)和显示前沿(Front porchr)。其中同步脉冲(Sync o)、显示后沿(Back porch p)和显示前沿(Front porch r)是消隐区,RGB信号无效,屏幕不显示数据。显示时序段(Display interval q)是有效数据区。.

o p q r

同步脉冲(Sync)
显示后沿(Back porch)
显示时序段(Display interval)
显示前沿(Front porch)

RGB信号无效FPGA驱动VGA显示
RGB信号无效 FPGA驱动VGA显示
有效数据区 FPGA驱动VGA显示
RGB信号无效FPGA驱动VGA显示

●行时序:
   行时序的四个部分分别是:同步脉冲(Sync a)、显示后沿(Back porch b)、显示时序(Display interval c)和显示前沿(Front porchd)。其中同步脉冲(Sync a)、显示后沿(Back porch b)和显示前沿(Front porch d)是消隐区,RGB信号无效,屏幕不显示数据。显示时序段(Display interval c)是有效数据区。

a b c d

同步脉冲(Sync)
显示后沿(Back porch)
显示时序段(Display interval)
显示前沿(Front porch)

RGB信号无效FPGA驱动VGA显示
RGB信号无效 FPGA驱动VGA显示
有效数据区 FPGA驱动VGA显示
RGB信号无效FPGA驱动VGA显示

2.2 VGA时序解析

FPGA驱动VGA显示
   不同的分辨率,它的时序是不一样的。例如800*600@60Hz的VGA时序:
FPGA驱动VGA显示
FPGA驱动VGA显示

行时序(HSYNC数据线):

a b c d e

拉低的128个列像素
拉高的88个列像素
拉高的800个列像素
拉高的40个列像素
总共1056个列像素

帧时序(VSYNC数据线):

o p q r s

拉低的4个行像素
拉高的23个行像素
拉高的600个行像素
拉高的1个行像素
总共628个行像素

时钟频率:
628×1056×60约为40MHz。

3. FPGA驱动VGA显示彩条

电路图:
FPGA驱动VGA显示

重点都在代码里:

//行时序宏定义
`define HSYNC_A 16'd128
`define HSYNC_B 16'd216
`define HSYNC_C 16'd1016
`define HSYNC_D 16'd1056

//列时序宏定义
`define VSYNC_O 16'd4
`define VSYNC_P 16'd27
`define VSYNC_Q 16'd627
`define VSYNC_R 16'd628

//颜色定义
`define RED 8'hE0 //1110_0000(参照上面电路图)
`define GREEN 8'h1C //0001_1100(参照上面电路图)
`define BLUE 8'h03 //0000_0011(参照上面电路图)
`define YELLOW 8'hFC
`define BLACK 8'h00
module VGA
(
//输入
input CLK_50M,
input RST_N,
//输出
output reg VSYNC, //垂直同步端口
output reg HSYNC, //水平同步端口
output reg[7:0] VGA_DATA //数据端口

);

reg[15:0] hsync_cnt; //水平扫描计数器
reg[15:0] vsync_cnt; //垂直扫描计数器

reg vga_data_valid; //RGB数据信号有效区使能信号

//水平扫描(扫描1056个点)
always@(posedge CLK_40M or negedge RST_N)
begin
if(!RST_N)
hsync_cnt <= 16'd0;
else if(hsync_cnt == `HSYNC_D)
hsync_cnt <= 16'd0;
else
hsync_cnt <= hsync_cnt + 16'd1;
end

//垂直扫描(扫描628个点)
always@(posedge CLK_40M or negedge RST_N)
begin
if(!RST_N)
vsync_cnt <= 16'd0;
else if((vsync_cnt == `VSYNC_R) && (hsync_cnt == `HSYNC_D))
vsync_cnt <= 16'd0;
else if(hsync_cnt == `HSYNC_D)
vsync_cnt <= vsync_cnt + 16'd1;
else
vsync_cnt <= vsync_cnt;
end

//行时序
always@(posedge CLK_40M or negedge RST_N)
begin
if(!RST_N)
HSYNC <= 1'b0;
else if(hsync_cnt < `HSYNC_A) //a域为0
HSYNC <= 1'b0;
else
HSYNC <= 1'b1; //其他域为1
end

//列时序
always@(posedge CLK_40M or negedge RST_N)
begin
if(!RST_N)
VSYNC <= 1'b0;
else if(vsync_cnt < `VSYNC_O) //o域为0
VSYNC <= 1'b0;
else
VSYNC <= 1'b1; //其他域为1
end

//提取显示有效区(q域+c域)
always@(posedge CLK_40M or negedge RST_N)
begin
if(!RST_N)
vga_data_valid <= 1'b0;
else if((hsync_cnt > `HSYNC_B && hsync_cnt < `HSYNC_C) && (vsync_cnt > `VSYNC_P && vsync_cnt < `VSYNC_Q)) //数据有效区
vga_data_valid <= 1'b1;
else
vga_data_valid <= 1'b0;
end

//在数据有效区,在将数据送至VGA_RED、VGA_GREEN、VGA_BLUE数据引脚
always@(*)
begin
if(vga_data_valid)
begin
if(vsync_cnt >`VSYNC_P)//显示区
begin
if((hsync_cnt > `HSYNC_B) && (hsync_cnt < `HSYNC_B+10'd300))
VGA_DATA <= `RED; //红色 1110_0000
else if((hsync_cnt > `HSYNC_B+10'd300) && (hsync_cnt < `HSYNC_B+10'd400))
VGA_DATA <= `BLUE; //蓝色 0000_0111
else if((hsync_cnt > `HSYNC_B+10'd400) && (hsync_cnt < `HSYNC_B+10'd500))
VGA_DATA <= `YELLOW; //黄色 1111_1100
else if((hsync_cnt > `HSYNC_B+10'd500) && (hsync_cnt < `HSYNC_B+10'd800))
VGA_DATA <= `GREEN; //绿色 0001_1100
else
VGA_DATA <= `BLACK; //黑色 0000_0000
end
else
VGA_DATA <= `BLACK; //黑色
end
else
VGA_DATA <= `BLACK; //黑色
end

//PLL_IP获取40M时钟
wire CLK_40M;
PLL PLL_inst (
.inclk0 ( CLK_50M ),
.c0 ( CLK_40M )
);

显示效果:
FPGA驱动VGA显示

4. FPGA驱动VGA显示文字
4.1 产生字库

   玩过LCD、OLED屏幕的都知道显示字符、数字、汉字,首先要对其取模。我们借助的工具为PCtoLCD2002软件进行字模的提取。
取模格式设置:
FPGA驱动VGA显示

比如对“5V”取模,字模数组生成:
FPGA驱动VGA显示

生成的数组为:

{0x00,0x00,0x1F,0x98,0x10,0x84,0x11,0x04,0x11,0x04,0x10,0x88,0x10,0x70,0x00,0x00},/*"5",0*/
{0x10,0x00,0x1E,0x00,0x11,0xE0,0x00,0x1C,0x00,0x70,0x13,0x80,0x1C,0x00,0x10,0x00},/*"V",1*/

字模是如何对应字符的:
例如:数字‘5’的字模数组为:

{0x00,0x00,0x1F,0x98,0x10,0x84,0x11,0x04,0x11,0x04,0x10,0x88,0x10,0x70,0x00,0x00},/*"5",0*/

我们字符的大小为8*16:
FPGA驱动VGA显示
取模方式为:逐列式
则数组:

//第一列   第二例	第三列	   第四列     第五列   第六列     第七列    第8列
{0x00,0x00,0x1F,0x98,0x10,0x84,0x11,0x04,0x11,0x04,0x10,0x88,0x10,0x70,0x00,0x00},/*"5",0*/
//每列两个字节(16位),构成8*16大小的字符

将十六进制转换为二进制,并按行列录入至excel观察:
FPGA驱动VGA显示
第二例:0x1F98转换为二进制=1111110011000,对应excel_B列,以此类推。

4.2 字库数据存入Memory-ROM_IP

   生成的字库放置在存储器里面才能被我们调用,在这里选择了将数据放置置ROM_IP核内。

4.2.1 生成.mif文件

  .mif是配置存储器专用的文件格式,利用QuartusⅡ生成.mif文件:
FPGA驱动VGA显示
并将数据录入至.mif文件中:
FPGA驱动VGA显示
并将生成的.mif文件关联至创建的ROM IP核中。

4.2.2 ROM IP核

  创建的ROM IP核如下所示,输入为地址和时钟信号,输出为存储的数据,我们在使用数据时,在ROM的时钟沿给予ROM相应的地址即可在输出端口得到数据。
FPGA驱动VGA显示

4.3 verilog代码

时序:
FPGA驱动VGA显示
代码:

//行时序宏定义
`define HSYNC_A 16'd128
`define HSYNC_B 16'd216
`define HSYNC_C 16'd1016
`define HSYNC_D 16'd1056

//列时序宏定义
`define VSYNC_O 16'd4
`define VSYNC_P 16'd27
`define VSYNC_Q 16'd627
`define VSYNC_R 16'd628

//颜色定义
`define RED 8'hE0 //1110_0000(参照上面电路图)
`define GREEN 8'h1C //0001_1100(参照上面电路图)
`define BLUE 8'h03 //0000_0011(参照上面电路图)
`define YELLOW 8'hFC
`define BLACK 8'h00
module VGA
(
//输入
input CLK_50M,
input RST_N,
//输出
output reg VSYNC, //垂直同步端口
output reg HSYNC, //水平同步端口
output reg[7:0] VGA_DATA //数据端口

);

reg[15:0] hsync_cnt; //水平扫描计数器
reg[15:0] vsync_cnt; //垂直扫描计数器

reg vga_data_valid; //RGB数据信号有效区使能信号

//水平扫描
always@(posedge CLK_40M or negedge RST_N)
begin
if(!RST_N)
hsync_cnt <= 16'd0;
else if(hsync_cnt == `HSYNC_D)
hsync_cnt <= 16'd0;
else
hsync_cnt <= hsync_cnt + 16'd1;
end

//垂直扫描
always@(posedge CLK_40M or negedge RST_N)
begin
if(!RST_N)
vsync_cnt <= 16'd0;
else if((vsync_cnt == `VSYNC_R) && (hsync_cnt == `HSYNC_D))
vsync_cnt <= 16'd0;
else if(hsync_cnt == `HSYNC_D)
vsync_cnt <= vsync_cnt + 16'd1;
else
vsync_cnt <= vsync_cnt;
end

//行时序
always@(posedge CLK_40M or negedge RST_N)
begin
if(!RST_N)
HSYNC <= 1'b0;
else if(hsync_cnt < `HSYNC_A)
HSYNC <= 1'b0;
else
HSYNC <= 1'b1;
end

//列时序
always@(posedge CLK_40M or negedge RST_N)
begin
if(!RST_N)
VSYNC <= 1'b0;
else if(vsync_cnt < `VSYNC_O)
VSYNC <= 1'b0;
else
VSYNC <= 1'b1;
end

//提取显示有效区
always@(posedge CLK_40M or negedge RST_N)
begin
if(!RST_N)
vga_data_valid <= 1'b0;
else if((hsync_cnt > `HSYNC_B && hsync_cnt < `HSYNC_C) && (vsync_cnt > `VSYNC_P && vsync_cnt < `VSYNC_Q)) //数据有效区
vga_data_valid <= 1'b1;
else
vga_data_valid <= 1'b0;
end

//显示字符
reg [7:0] rom_add;
wire [15:0] rom_data;
wire [15:0] vga_x;
wire [15:0] vga_y;
assign vga_x = hsync_cnt - `HSYNC_B;
assign vga_y = vsync_cnt - `VSYNC_P;

assign display_en = (vga_x >= 10'd98) && (vga_x <= 10'd116) && (vga_y >= 10'd90) && (vga_y <= 10'd106);//开窗

//读取字库
always@(posedge CLK_40M or negedge RST_N)
begin
if(!RST_N)
rom_add <= 8'h0;
else if(display_en)
begin
if(vga_x == 10'd98) //5 x坐标
rom_add <= 8'h0; //看.mif文件中的地址
else if(vga_x == 10'd106) //v x坐标
rom_add <= 8'h08; //看.mif文件中的地址
else
rom_add <= rom_add + 1'b1;
end
else
rom_add <= 8'h0;
end

//显示
always@(*)
begin
if(display_en)
begin
if(rom_data[10'd106 - vga_y]) //从下往上刷(rom_data元素为16的列向量)
VGA_DATA <= `RED; //红色
else
VGA_DATA <= `YELLOW; //黑色
end
else
VGA_DATA <= `BLACK; //黑色
end

//ROM_IP 存放字库数据
ROM ROM_inst (
.address ( rom_add ),
.clock ( CLK_40M ),
.q ( rom_data )
);

//PLL_IP生成VGA需要的40M时钟
wire CLK_40M;
PLL PLL_inst (
.inclk0 ( CLK_50M ),
.c0 ( CLK_40M )
);

endmodule

显示效果:
FPGA驱动VGA显示

原创:https://www.panoramacn.com
源码网提供WordPress源码,帝国CMS源码discuz源码,微信小程序,小说源码,杰奇源码,thinkphp源码,ecshop模板源码,微擎模板源码,dede源码,织梦源码等。

专业搭建小说网站,小说程序,杰奇系列,微信小说系列,app系列小说

FPGA驱动VGA显示

免责声明,若由于商用引起版权纠纷,一切责任均由使用者承担。

您必须遵守我们的协议,如果您下载了该资源行为将被视为对《免责声明》全部内容的认可-> 联系客服 投诉资源
www.panoramacn.com资源全部来自互联网收集,仅供用于学习和交流,请勿用于商业用途。如有侵权、不妥之处,请联系站长并出示版权证明以便删除。 敬请谅解! 侵权删帖/违法举报/投稿等事物联系邮箱:2640602276@qq.com
未经允许不得转载:书荒源码源码网每日更新网站源码模板! » FPGA驱动VGA显示
关注我们小说电影免费看
关注我们,获取更多的全网素材资源,有趣有料!
120000+人已关注
分享到:
赞(0) 打赏

评论抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

您的打赏就是我分享的动力!

支付宝扫一扫打赏

微信扫一扫打赏