3. 像素时钟与同步信号:HSYNC、VSYNC、PCLK 的时序关系与硬件实现
各位同学,今天我们来聊聊显示接口里最基础、也最容易踩坑的三个信号——像素时钟(PCLK)、行同步(HSYNC)和场同步(VSYNC)。
说白了,这三个信号就是显示设备的“节拍器”和“坐标轴”。没有它们,像素数据就是一盘散沙,不知道该往哪放、什么时候放。
我刚开始做显示通路设计时,总觉得同步信号很简单——不就是几个脉冲嘛。结果第一次调 VGA 接口,画面斜着飘,折腾了两天才发现是 HSYNC 的极性搞反了。嗯,从那以后我再也不敢小看这三个信号了。
3.1 三个信号各自扮演什么角色?
先给个直观的类比。你想想看,把一帧图像送到屏幕上,就像在一张纸上逐行写字:
- PCLK(像素时钟):每来一个脉冲,就写一个像素点。它是整个链路的基准节拍。
- HSYNC(行同步):写完一行,换到下一行。它告诉屏幕“该换行了”。
- VSYNC(场同步):写完一帧,回到第一行。它告诉屏幕“新的一帧开始了”。
这三个信号必须严格对齐,否则画面就会出现撕裂、偏移或者闪烁。
关键认知:PCLK 是频率基准,HSYNC 和 VSYNC 是时序基准。三者缺一不可,时序偏差超过一个 PCLK 周期,画面就可能出问题。
3.2 标准时序:前肩、后肩、同步脉冲
每个同步信号都不是简单的“拉高拉低”。它们都包含三个段:同步脉冲(Sync Pulse)、后肩(Back Porch)和前肩(Front Porch)。
我习惯用 VGA 640×480 @60Hz 的标准来举例,因为这个参数最经典,也最容易理解。
| 参数 | 行(HSYNC) | 场(VSYNC) |
|---|---|---|
| 同步脉冲宽度 | 96 PCLK | 2 行 |
| 后肩 | 48 PCLK | 33 行 |
| 有效数据 | 640 PCLK | 480 行 |
| 前肩 | 16 PCLK | 10 行 |
| 总长 | 800 PCLK | 525 行 |
你看,一行实际有 800 个 PCLK,但只有 640 个是有效像素。剩下的 160 个 PCLK 就是消隐区(Blanking Interval)。
我的经验:设计计数器时,一定要把总长算清楚。我见过有人只数有效像素,结果同步脉冲位置全错,画面直接歪到屏幕外面去了。
3.3 时序关系图:用 SVG 画出来
光说数字不够直观。我画了一张时序关系图,把 PCLK、HSYNC 和 VSYNC 的配合关系展示出来。
从图上可以清楚看到:PCLK 一直在跑,HSYNC 在每行结束时拉低(或拉高,取决于极性),VSYNC 在每帧结束时动作。有效数据只出现在同步脉冲之间的区域。
3.4 硬件实现:计数器状态机
在 FPGA 或 ASIC 里,生成这三个信号最常用的方法就是计数器 + 有限状态机。
我个人习惯用两个计数器:一个行计数器(H_CNT),一个场计数器(V_CNT)。H_CNT 从 0 数到 799(对应 800 PCLK 总长),每数完一圈,V_CNT 加 1。V_CNT 从 0 数到 524(对应 525 行总长),数完一圈就是一帧。
代码实现大概是这样的:
// 行计数器
always @(posedge pclk or negedge rst_n) begin
if (!rst_n)
h_cnt <= 10'd0;
else if (h_cnt == 10'd799)
h_cnt <= 10'd0;
else
h_cnt <= h_cnt + 10'd1;
end
// 场计数器
always @(posedge pclk or negedge rst_n) begin
if (!rst_n)
v_cnt <= 10'd0;
else if (h_cnt == 10'd799) begin
if (v_cnt == 10'd524)
v_cnt <= 10'd0;
else
v_cnt <= v_cnt + 10'd1;
end
end
// HSYNC 生成(负极性)
assign hsync = (h_cnt >= 10'd656 && h_cnt <= 10'd751) ? 1'b0 : 1'b1;
// VSYNC 生成(负极性)
assign vsync = (v_cnt >= 10'd490 && v_cnt <= 10'd491) ? 1'b0 : 1'b1;
// 有效数据使能
assign de = (h_cnt < 10'd640) && (v_cnt < 10'd480);
注意:不同显示标准(VGA、DVI、HDMI)的同步极性可能不同。有些标准要求 HSYNC 和 VSYNC 是正极性(高电平有效),有些是负极性(低电平有效)。我曾经在移植 IP 时忘了改极性,结果画面全黑,查了三天才发现是极性配置寄存器写反了。
3.5 避坑指南:我踩过的几个坑
- 计数器边界:H_CNT 和 V_CNT 的结束值一定要用“总长-1”。比如 800 个 PCLK,计数器从 0 到 799。用 800 做比较会多出一个时钟周期,画面会偏移一整行。
- 同步脉冲位置:HSYNC 脉冲必须在后肩之后、前肩之前。如果脉冲位置偏移,显示器可能会丢失同步,画面闪烁或黑屏。
- DE 信号:有效数据使能(DE)必须与 PCLK 对齐。我建议用寄存器打一拍再输出,避免组合逻辑产生的毛刺。
- 跨时钟域:如果 PCLK 来自 PLL,复位释放时要等 PLL 锁定。否则计数器可能从随机值开始,导致第一帧时序错乱。
3.6 小结
像素时钟、行同步、场同步,这三个信号构成了显示时序的骨架。理解它们的时序关系,是设计像素处理通路的第一步。
记住一个原则:PCLK 是心跳,HSYNC 是行坐标,VSYNC 是帧坐标。三者配合好,画面就稳了。