from : 好友博客:http://www.edabc.net/blog/?uid-20-action-viewspace-itemid-591
一、VGA时序
下面的图是本人画了一个晚上的结果,个人认为能够比较详细的阐述VGA的信号时序
![](http://www.edabc.net/blog/attachments/2009/04/20_2009042315471016LCo.jpg)
VGA的时序根据不同的显示分辨率和刷新频率会有变化,具体各种类型的时序信息可以参考下面的网站
这里非常详细的说明的每一种显示模式的VGA时序信息
http://www.epanorama.net/documents/pc/vga_timing.html
二、VGA电平
VSYNC,HSYNC为标准TTL电平,0V~3.3V
RGB的电平在0V~0.7V之间(0V为黑色,0.7V为全色)
三、程序顶层框图
![](http://www.edabc.net/blog/attachments/2009/04/20_200904231547181zoWo.jpg)
VGA产生行同步(HSYNC),场同步信号(VSYNC),并产生每个像素的地址输入单口ROM(显存)中,ROM输出该点需要显示的颜色值
四、单口ROM(显存)设计
程序的显示模式为800*600,72Hz刷新频率,像素频率为50MHz
每个像素需要显示的颜色存储在单口RAM中,每种颜色用8个字节表示
则如果要显示800*600分辨率,则需要800*600字节(480KB)的单口ROM
由于FPGA内部没有这么大的RAM,因此我把屏幕上100*100个像素组成的矩形作为一个逻辑像素(即显示同一种颜色)
这样只要8*6字节(48字节),用FPGA自带的RAM是很容易实现的
ROM中颜色存储地址表:
![](http://www.edabc.net/blog/attachments/2009/04/20_2009042315472312J3L.jpg)
将全屏划分成8*6的方格,每个方格的颜色存储在ROM中,VGA控制器不断产生行坐标(ROM水平地址)和场坐标(ROM垂直地址)
最后组合成ROM实际地址输入ROM中,ROM输出该地址的颜色值,显示在LCD中
五、程序设计
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
代码 1
module VGA(clk,rst_n,hsync,vsync,vga_r,vga_g,vga_b);
2![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
3
4![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
5
input clk; //50MHz
6![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
7
input rst_n; //复位信号
8![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
9
output hsync; //行同步信号
10![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
11
output vsync; //场同步信号
12![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
13
// R、G、B信号输出
14![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
15
output[1:0] vga_r;
16![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
17
output[2:0] vga_g;
18![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
19
output[2:0] vga_b;
20![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
21
//--------------------------------------------------
22![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
23
reg[10:0] x_cnt; //行坐标(这里包括了行同步、后沿、有效数据区、前沿)
24![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
25
reg[9:0] y_cnt; //列坐标(这里包括了场同步、后沿、有效数据区、前沿)
26![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
27
reg[5:0] Xcoloradd;
28![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
29
reg[2:0] Ycoloradd;
30![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
31
32![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
33
parameter
34![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
35
Left = 184,
36![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
37
PixelWidth = 100,
38![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
39
Top = 29;
40![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
41
42![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
43
always @ (posedge clk or negedge rst_n)
44![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
45
if(!rst_n) x_cnt <= 10'd0;
46![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
47
else if(x_cnt == 11'd1040) x_cnt <= 10'd0; //行计数记到1040
48![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
49
else x_cnt <= x_cnt+1'b1;
50![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
51
52![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
53
always @ (posedge clk or negedge rst_n)//产生行地址(ROM水平地址)
54![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
55
if(!rst_n) Xcoloradd <= 6'b000000;
56![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
57
else if(x_cnt >= Left && x_cnt <Left + PixelWidth) Xcoloradd <= 6'b000000;
58![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
59
else if(x_cnt >= Left + PixelWidth && x_cnt <Left + 2*PixelWidth) Xcoloradd <= 6'b000001;
60![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
61
else if(x_cnt >= Left + 2*PixelWidth && x_cnt <Left + 3*PixelWidth) Xcoloradd <= 6'b000010;
62![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
63
else if(x_cnt >= Left + 3*PixelWidth && x_cnt <Left + 4*PixelWidth) Xcoloradd <= 6'b000011;
64![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
65
else if(x_cnt >= Left + 4*PixelWidth && x_cnt <Left + 5*PixelWidth) Xcoloradd <= 6'b000100;
66![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
67
else if(x_cnt >= Left + 5*PixelWidth && x_cnt <Left + 6*PixelWidth) Xcoloradd <= 6'b000101;
68![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
69
else if(x_cnt >= Left + 6*PixelWidth && x_cnt <Left + 7*PixelWidth) Xcoloradd <= 6'b000110;
70![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
71
else if(x_cnt >= Left + 7*PixelWidth && x_cnt <Left + 8*PixelWidth) Xcoloradd <= 6'b000111;
72![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
73
else Xcoloradd <= 6'b110000;//背景颜色地址
74![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
75
76![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
77
always @ (posedge clk or negedge rst_n)
78![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
79
if(!rst_n) y_cnt <= 10'd0;
80![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
81
else if(y_cnt == 10'd666) y_cnt <= 10'd0; //场同步记到666
82![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
83
else if(x_cnt == 11'd1040) y_cnt <= y_cnt+1'b1;//每计数完一行,场同步就加一
84![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
85
86![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
87
always @ (posedge clk or negedge rst_n)//产生列地址(ROM垂直地址)
88![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
89
if(!rst_n) Ycoloradd <= 3'b000;
90![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
91
else if(y_cnt >= Top && y_cnt < Top + PixelWidth) Ycoloradd <= 3'b000;
92![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
93
else if(y_cnt >= Top + PixelWidth && y_cnt < Top + 2*PixelWidth) Ycoloradd <= 3'b001;
94![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
95
else if(y_cnt >= Top + 2*PixelWidth && y_cnt < Top + 3*PixelWidth) Ycoloradd <= 3'b010;
96![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
97
else if(y_cnt >= Top + 3*PixelWidth && y_cnt < Top + 4*PixelWidth) Ycoloradd <= 3'b011;
98![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
99
else if(y_cnt >= Top + 4*PixelWidth && y_cnt < Top + 5*PixelWidth) Ycoloradd <= 3'b100;
100![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
101
else if(y_cnt >= Top + 5*PixelWidth && y_cnt < Top + 6*PixelWidth) Ycoloradd <= 3'b101;
102![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
103
else Ycoloradd <= 3'b110;//背景颜色地址
104![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
105
//--------------------------------------------------
106![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
107
// signal port ROM
108![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
109
110![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
111
wire[7:0] color;
112![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
113
wire[5:0] coloradd;
114![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
115
116![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
117![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
assign coloradd =
{Ycoloradd,3'b000}|Xcoloradd;//将水平地址和垂直地址合成ROM实际地址
118![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
119
sprom u1(coloradd,clk,color);
120![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
121
122![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
123
//---------------------------------------------------
124![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
125
126![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
127
wire valid; //有效数据显示区标志,就是你在液晶屏幕上可以看到的区域
128![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
129
130![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
131
assign valid = (x_cnt > 10'd184) && (x_cnt < 10'd984)
132![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
133
134![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
135
&& (y_cnt > 10'd29) && (y_cnt < 10'd629);
136![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
137
//--------------------------------------------------
138![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
139
reg hsync_r,vsync_r;
140![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
141
142![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
143
always @ (posedge clk or negedge rst_n)
144![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
145
if (!rst_n) begin
146![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
147
hsync_r <= 1'b0;
148![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
149
vsync_r <= 1'b0;
150![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
151
end
152![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
153
else begin
154![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
155
hsync_r <= x_cnt >= 10'd120; //产生hsync信号(行同步)when x_cnt>=50,then hsync_r=1,else 0;低电平同步
156![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
157
vsync_r <= y_cnt >= 10'd6; //产生vsync信号(场同步)my LCD is low sync
158![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
159
end
160![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
161
assign hsync = hsync_r;
162![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
163
assign vsync = vsync_r;
164![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
165
166![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
167
//--------------------------------------------------
168![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
169
//颜色输出
170![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
171
assign vga_r[1] = valid ? color[7] : 1'b0;
172![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
173
assign vga_r[0] = valid ? color[6] : 1'b0;
174![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
175
176![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
177
assign vga_g[2] = valid ? color[5] : 1'b0;
178![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
179
assign vga_g[1] = valid ? color[4] : 1'b0;
180![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
181
assign vga_g[0] = valid ? color[3] : 1'b0;
182![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
183
184![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
185
assign vga_b[2] = valid ? color[2] : 1'b0;
186![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
187
assign vga_b[1] = valid ? color[1] : 1'b0;
188![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
189
assign vga_b[0] = valid ? color[0] : 1'b0;
190![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
191
192![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
193
endmodule194![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
六、后记
在这次程序中只在ROM中存储了一些随机的数,因此显示出来是一些小方格
如果ROM做的更大,完全可以存储一幅图像,显示在LCD中
不过由于由于用ROM做为显存,每次只能显示一幅静态的图像,而且没有加入字符库,不能显示字符
在下次的文章中,我将使用双口RAM,加上Nios II处理器,这样可以方便的显示各种字符