Verilog的VGA显示控制
from : 好友博客:http://www.edabc.net/blog/?uid-20-action-viewspace-itemid-591
下面的图是本人画了一个晚上的结果,个人认为能够比较详细的阐述VGA的信号时序

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为全色)
三、程序顶层框图
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中颜色存储地址表:
将全屏划分成8*6的方格,每个方格的颜色存储在ROM中,VGA控制器不断产生行坐标(ROM水平地址)和场坐标(ROM垂直地址)
最后组合成ROM实际地址输入ROM中,ROM输出该地址的颜色值,显示在LCD中
五、程序设计
代码
module VGA(clk,rst_n,hsync,vsync,vga_r,vga_g,vga_b);2

3
4

5
input clk; //50MHz6

7
input rst_n; //复位信号8

9
output hsync; //行同步信号10

11
output vsync; //场同步信号12

13
// R、G、B信号输出14

15
output[1:0] vga_r;16

17
output[2:0] vga_g;18

19
output[2:0] vga_b;20

21
//--------------------------------------------------22

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

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

27
reg[5:0] Xcoloradd;28

29
reg[2:0] Ycoloradd;30

31
32

33
parameter34

35
Left = 184,36

37
PixelWidth = 100,38

39
Top = 29;40

41
42

43
always @ (posedge clk or negedge rst_n)44

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

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

49
else x_cnt <= x_cnt+1'b1;50

51
52

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

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

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

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

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

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

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

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

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

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

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

75
76

77
always @ (posedge clk or negedge rst_n)78

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

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

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

85
86

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

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

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

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

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

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

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

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

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

105
//--------------------------------------------------106

107
// signal port ROM108

109
110

111
wire[7:0] color;112

113
wire[5:0] coloradd;114

115
116

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

119
sprom u1(coloradd,clk,color);120

121
122

123
//---------------------------------------------------124

125
126

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

129
130

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

133
134

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

137
//--------------------------------------------------138

139
reg hsync_r,vsync_r;140

141
142

143
always @ (posedge clk or negedge rst_n)144

145
if (!rst_n) begin146

147
hsync_r <= 1'b0;148

149
vsync_r <= 1'b0;150

151
end152

153
else begin154

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

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

159
end160

161
assign hsync = hsync_r;162

163
assign vsync = vsync_r;164

165
166

167
//--------------------------------------------------168

169
//颜色输出170

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

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

175
176

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

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

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

183
184

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

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

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

191
192

193
endmodule194

六、后记
在这次程序中只在ROM中存储了一些随机的数,因此显示出来是一些小方格
如果ROM做的更大,完全可以存储一幅图像,显示在LCD中
不过由于由于用ROM做为显存,每次只能显示一幅静态的图像,而且没有加入字符库,不能显示字符
在下次的文章中,我将使用双口RAM,加上Nios II处理器,这样可以方便的显示各种字符
posted on 2009-11-29 10:12 Homography Matrix 阅读(10231) 评论(4) 收藏 举报



assign coloradd 
浙公网安备 33010602011771号