以前自己调试过视频信号,无非就时钟加行场同步加数据线,如果视频信号出问题,第一看现象,第二测频率,反正出问题不是消隐信号出问题,就是时钟频率出问题。通过这种方式也调试成功过几个显示屏,然后就以为自己对视频信号的调试已经有丰富的经验了,直到这次需要自己用FPGA写一个VGA的驱动程序,才发现原来自己还是半桶水。

  这次谈一下将RGB888的视频信号转换为VGA信号时的调试心得,使用ADV7123将数字信号转换为VGA信号。

  首先谈一下VGA,在这个网站上可以能看到各种VGA信号的标准:http://tinyvga.com/vga-timing

  以1600*1200分辨率为例(这次我就是要产生一个这样的视频)

  假如1秒显示60场,一场是1200行,一行有1600个像素点,那么时钟频率就是60*1200*1600=115.2MHz,但是实际上不能这样满打满算。如果从现在的思维来考虑,因为行和场同步信号需要一定的建立时间,因此需要的时钟频率会更高一些,但是只要高一点点,给行场同步信号一定的建立时间就可以了,但是实际频率162MHz与计算得到的115.2MHz差别未免也太大了吧。因为这是一个历史问题,以前的显示器是用电子枪扫描的,电子枪扫完一行后需要回到行首,这段时间叫行消隐时间,电子枪扫完一场(到达屏幕的右下角)后需要回到左上角,这段时间叫场消隐时间。由于行消隐和场消隐的存在,以至于实际扫描一帧的时间要比算出来的满打满算的时间要多。

  消隐时间在以前是为了让电子枪归位而设定的,今天虽然行场同步的建立时间可以很短,但是毕竟是一代标准,不能轻易改变,因此消隐信号仍然保留了。

  在网上很多地方可以找到VGA的时序说明,我这边粗略说一下。

  一个行同步周期内包含4个段:行消隐前肩、行同步时间、行消隐后肩、行有效时间,如上图所示,1600*1200的标准中,行有效时间包含了1600个时钟,对应了1600个有效像素点,行消隐前肩包含64个时钟,行同步时间包含192个时钟,行消隐后肩包含304个时钟,所以一行加起来一共2160个时钟。

  同样的,一个场同步周期内包含4个段:场消隐前肩、场同步时间、场消隐后肩、场有效时间,如上图所示,1600*1200的标准中,场有效时间包含了1200个行周期,对应显示器能显示出来的1200行,场消隐前肩包含1个行周期,场同步时间包含3个行周期,场消隐后肩包含46个行周期,所以一场加起来一共有1250个行周期。

  接下来是重点了,行和场都包含有4个时间段,这4个时间段究竟是怎么排布的,网上我找到两种说法:

  我使用这两种时序产生VGA信号,然后我用ADV7604来采,结果显示老不正常,我一直以为是BLANK信号(ADV7123有个BLANK信号,其实就是消隐信号)的原因,改来改去总不对,但是它采标准的1600*1200的图像是正常的,因此我干脆直接自己采一下标准的1600*1200的VGA信号。

  我使用逻辑分析仪采行场同步和红色通道的(也可以是其他通道)信号,行场同步可以直接接逻辑分析仪,而彩色信号是一个模拟信号,最大电压是0.714V,逻辑分析仪采不到。当红色通道为0.714V时表示的是最红的那个颜色,因此我使用了一个放大器,将0.714V放大到5V,然后再接入逻辑分析仪。接着只要采一个纯红的视频就OK了,但问题是纯红的视频哪里来,我找到一个很妙的办法,我外接了一个HDMI转VGA的接头,这样相当于外扩了一个VGA的显示器,然后新建1个PPT,把背景改为纯红,然后PPT设定为演讲者模式(具体操作我忘了,我是早就设好的,这个网上一搜就能搜到),按win+R键将投影选择扩展,然后放映PPT。这个时候神奇的事情来了,第二显示器显示的是纯红的,没有半点杂质,而我的主显示器的可以将PPT最小化,这样就能在主显示器中运行逻辑分析仪软件了。

  运行之后,采到的波形如下图所示:

  注意到1个问题,场同步的同步时间段中包含有3个完整的行同步,同步时间段之前有1个没有数据的行同步,同步时间段之后包含46个没有数据的行同步,那这不就水落石出了吗,4个时间段的排序如下图,前肩后面是同步时间,接着是后肩,然后是有效数据,所以之前找到的那两种说法似乎不太对。

  同样的,行同步信号中的4个时间段也是这样排的。

上图中abcd4个段分别表示行消隐前肩、行同步时间、行消隐后肩和行有效时间。

还有一个比较重要的点,之前没提到,就是ADV7123的BLANK信号,这个信号用于关断输出,当BLANK信号为低时,关断输出,当BLANK信号为高时才能有输出,当然如果此时RGB信号本来就为0那肯定还是没有输出的,因此如果把RGB信号控制好,是完全不需要BLANK信号的。

  有了这个,那程序就好写了,直接附上程序:

  1 module vga_out (
2 input sys_clk,
3 input sys_rst_n,
4
5 output vga_clk,
6 output reg vga_hs,
7 output reg vga_vs,
8 output reg vga_blk,
9
10 output reg [7:0] vga_r,
11 output reg [7:0] vga_g,
12 output reg [7:0] vga_b
13 );
14
15 wire locked;
16 wire rst_n;
17
18 reg [11:0] hcnt;
19 reg [11:0] vcnt;
20
21 assign rst_n = sys_rst_n & locked;
22
23 pll_clk u_pll_clk (
24 .areset (~sys_rst_n),
25 .inclk0 (sys_clk),
26 .c0 (vga_clk),
27 .locked (locked)
28 );
29
30 //162M标准,1600*1200*60 75KHz
31 parameter H_DISP = 12'd1600; // 有效行数
32 parameter H_FRONT = 12'd64; // 行消隐前肩
33 parameter H_SYNC = 12'd192; // 行同步
34 parameter H_BACK = 12'd304; // 行消隐后肩
35 parameter H_TOTAL = 12'd2160; // 行总数
36
37 parameter V_DISP = 12'd1200; // 有效列数
38 parameter V_FRONT = 12'd1; // 列消隐前肩
39 parameter V_SYNC = 12'd3; // 列同步
40 parameter V_BACK = 12'd46; // 列消隐后肩
41 parameter V_TOTAL = 12'd1250; // 列总数
42
43
44 //行同步信号发生器
45 always @ (posedge vga_clk or negedge rst_n)
46 begin
47 if (!rst_n) begin
48 hcnt <= 0;
49 vga_hs <= 1;
50 end
51
52 else begin
53 if (hcnt < H_TOTAL-1)
54 hcnt <= hcnt+1'b1;
55 else
56 hcnt <= 0;
57
58 if((hcnt >= H_FRONT) && (hcnt < H_FRONT+H_SYNC))
59 vga_hs <= 0;
60 else
61 vga_hs <= 1;
62 end
63 end
64
65 // 场同步信号发生器
66 always @ (negedge vga_hs or negedge rst_n)
67 begin
68 if (!rst_n) begin
69 vcnt <= 0;
70 vga_vs <= 1;
71 end
72
73 else begin
74 if (vcnt < V_TOTAL-1)
75 vcnt <= vcnt+1'b1;
76 else
77 vcnt <= 0;
78
79 if((vcnt >= V_FRONT) && (vcnt < V_FRONT+V_SYNC))
80 vga_vs <= 0;
81 else
82 vga_vs <= 1;
83 end
84 end
85
86 //消影信号
87 always @(posedge vga_clk or negedge rst_n) begin
88 if (!rst_n)
89 vga_blk <= 1'b0;
90
91 if (vga_clk) begin
92 if (vcnt < V_FRONT + V_SYNC + V_BACK)
93 vga_blk <= 1'b0;
94 else if (hcnt < H_FRONT + H_SYNC + H_BACK)
95 vga_blk <= 1'b0;
96 else
97 vga_blk <= 1'b1;
98 end
99 end
100
101 /*
102 //横条纹
103 always @(posedge vga_clk) begin
104 if (vcnt < (V_DISP >> 3) * 1 + V_FRONT + V_SYNC + V_BACK) begin
105 vga_r <= 8'b1111_1111;
106 vga_g <= 8'b0000_0000;
107 vga_b <= 8'b1000_0000;
108 end
109
110 else if (vcnt < (V_DISP >> 3) * 2 + V_FRONT + V_SYNC + V_BACK) begin
111 vga_r <= 8'b0000_0000;
112 vga_g <= 8'b0000_0000;
113 vga_b <= 8'b1111_1111;
114 end
115
116 else if (vcnt < (V_DISP >> 3) * 3 + V_FRONT + V_SYNC + V_BACK) begin
117 vga_r <= 8'b0000_0000;
118 vga_g <= 8'b1111_1111;
119 vga_b <= 8'b0000_0000;
120 end
121
122 else if (vcnt < (V_DISP >> 3) * 4 + V_FRONT + V_SYNC + V_BACK) begin
123 vga_r <= 8'b0000_0000;
124 vga_g <= 8'b1111_1111;
125 vga_b <= 8'b1111_1111;
126 end
127
128 else if (vcnt < (V_DISP >> 3) * 5 + V_FRONT + V_SYNC + V_BACK) begin
129 vga_r <= 8'b1111_1111;
130 vga_g <= 8'b0000_0000;
131 vga_b <= 8'b0000_0000;
132 end
133
134 else if (vcnt < (V_DISP >> 3) * 6 + V_FRONT + V_SYNC + V_BACK) begin
135 vga_r <= 8'b1111_1111;
136 vga_g <= 8'b0000_0000;
137 vga_b <= 8'b1111_1111;
138 end
139
140 else if (vcnt < (V_DISP >> 3) * 7 + V_FRONT + V_SYNC + V_BACK) begin
141 vga_r <= 8'b1111_1111;
142 vga_g <= 8'b1111_1111;
143 vga_b <= 8'b0000_0000;
144 end
145
146 else if (vcnt < V_TOTAL) begin
147 vga_r <= 8'b1111_1111;
148 vga_g <= 8'b1111_1111;
149 vga_b <= 8'b1111_1111;
150 end
151 end
152 */
153
154
155 //竖条纹
156 always @(posedge vga_clk) begin
157 if (hcnt < H_FRONT + H_SYNC + H_BACK) begin //前消隐+同步时间段+后消隐期无颜色(黑色)
158 vga_r <= 8'b0000_0000;
159 vga_g <= 8'b0000_0000;
160 vga_b <= 8'b0000_0000;
161 end
162
163 else if (hcnt < (H_DISP >> 3) * 1 + H_FRONT + H_SYNC + H_BACK) begin
164 vga_r <= 8'b1111_1111;
165 vga_g <= 8'b0000_0000;
166 vga_b <= 8'b1000_0000;
167 end
168
169 else if (hcnt < (H_DISP >> 3) * 2 + H_FRONT + H_SYNC + H_BACK) begin
170 vga_r <= 8'b0000_0000;
171 vga_g <= 8'b0000_0000;
172 vga_b <= 8'b1111_1111;
173 end
174
175 else if (hcnt < (H_DISP >> 3) * 3 + H_FRONT + H_SYNC + H_BACK) begin
176 vga_r <= 8'b0000_0000;
177 vga_g <= 8'b1111_1111;
178 vga_b <= 8'b0000_0000;
179 end
180
181 else if (hcnt < (H_DISP >> 3) * 4 + H_FRONT + H_SYNC + H_BACK) begin
182 vga_r <= 8'b0000_0000;
183 vga_g <= 8'b1111_1111;
184 vga_b <= 8'b1111_1111;
185 end
186
187 else if (hcnt < (H_DISP >> 3) * 5 + H_FRONT + H_SYNC + H_BACK) begin
188 vga_r <= 8'b1111_1111;
189 vga_g <= 8'b0000_0000;
190 vga_b <= 8'b0000_0000;
191 end
192
193 else if (hcnt < (H_DISP >> 3) * 6 + H_FRONT + H_SYNC + H_BACK) begin
194 vga_r <= 8'b1111_1111;
195 vga_g <= 8'b0000_0000;
196 vga_b <= 8'b1111_1111;
197 end
198
199 else if (hcnt < (H_DISP >> 3) * 7 + H_FRONT + H_SYNC + H_BACK) begin
200 vga_r <= 8'b1111_1111;
201 vga_g <= 8'b1111_1111;
202 vga_b <= 8'b0000_0000;
203 end
204
205 else if (hcnt < H_TOTAL) begin
206 vga_r <= 8'b1111_1111;
207 vga_g <= 8'b1111_1111;
208 vga_b <= 8'b1111_1111;
209 end
210 end
211
212 endmodule

需要注意的是,PLL锁相环产生的时钟要是162MHz。

最新文章

  1. 【jq】c#零基础学习之路(4)抽象类和密封
  2. js获取新浪天气接口
  3. python数学运算的类型转换
  4. JS读写cookie以及中文乱码解决
  5. Adding Value To Combo List at Runtime in Oracle Forms
  6. 【转】Android 实现蘑菇街购物车动画效果
  7. 10.8 OSInstall破解
  8. 关闭ES动态创建type
  9. 关于模板pair的用法
  10. EXT.NET复杂布局(二)——报表
  11. 如何优化Cocos2d-X游戏的内存
  12. SQLAlchemy 教程 —— 基础入门篇
  13. Python(十) Python 中的 *args 和 **kwargs
  14. Mybatis进阶学习笔记——关系查询——一对多查询
  15. 获取MyBatis
  16. 【C】——使用creat()函数需要注意的事项
  17. EditText输入属性
  18. numpy.random.randn()与rand()的区别【转】
  19. iOS Socket编程-C语言版(UDP)
  20. 【校招面试 之 C/C++】第31题 C++ 11新特性(二)之nullptr关键字

热门文章

  1. metinfo小于v6.2.0版本通杀SQL盲注漏洞分析
  2. android studio 找不到真机设备
  3. SpringBoot 与 SpringSecurity
  4. APK 的前世今生:从 Android 源码到 apk 的编译打包流程
  5. 游标数据练习java
  6. day114:MoFang:基于支付宝沙箱测试环境完成创建充值订单接口&amp;服务端处理支付结果的同步通知和异步通知
  7. [LeetCode]Minimum Moves to Equal Array Elements1,2
  8. .NET 云原生架构师训练营(模块二 基础巩固 EF Core 更新和迁移)--学习笔记
  9. 行业动态 | DataStax 2021年新年预测
  10. 【函数分享】每日PHP函数分享(2021-1-8)