第三章 鉴频鉴相器PFD设计
鉴频鉴相器,简称PFD,是PLL中我最喜欢的一个模块。为什么?因为它虽然结构简单,却藏着不少设计上的门道。说白了,PFD就是PLL的“眼睛”——它负责比较参考时钟和反馈时钟的相位差、频率差,然后告诉后面的电荷泵该怎么调整。
我个人习惯把PFD看作一个“三态判决器”。它输出三个状态:UP、DOWN,或者什么都不做。UP表示反馈时钟慢了,需要加速;DOWN表示反馈时钟快了,需要减速;都不输出,说明锁定了。
3.1 PFD的工作原理
先说说最基本的PFD结构。它由两个D触发器和一些组合逻辑组成。每个D触发器的时钟端分别接参考时钟和反馈时钟,数据端都接高电平。触发器的输出经过一个与门后,复位两个触发器。
工作过程是这样的:
- 参考时钟上升沿到来,UP信号拉高
- 反馈时钟上升沿到来,DOWN信号拉高
- 当UP和DOWN同时为高,与门输出复位信号,两个触发器同时清零
你想想看,如果参考时钟领先于反馈时钟,那么UP信号就会比DOWN信号宽。这个宽度,正好等于两个时钟的相位差。电荷泵根据这个宽度来充电,VCO的控制电压就会上升,频率跟着提高。
反过来也一样。反馈时钟领先,DOWN信号更宽,电荷泵放电,VCO频率降低。
我在项目中遇到过一个问题:当参考时钟和反馈时钟频率不同时,PFD也能正常工作。这就是“鉴频”能力的来源。频率高的时钟,它的上升沿来得更频繁,对应的输出信号就会持续占主导,直到频率拉平为止。
核心要点:PFD同时具备鉴相和鉴频能力。锁定状态下,UP和DOWN都是窄脉冲,宽度等于复位延迟。这个窄脉冲宽度,就是后面要说的死区问题的根源。
3.2 死区问题及消除方法
死区,这是PFD设计里最让人头疼的问题。什么叫死区?就是当相位差非常小的时候,PFD“看不见”这个误差,不输出任何调整信号。
为什么会这样?
原因在于复位路径的延迟。当UP和DOWN同时为高时,与门输出复位信号,这个复位信号需要经过一些门电路才能清零触发器。如果相位差小于这个复位延迟,那么UP和DOWN还没来得及产生有效宽度,就被复位了。
我曾经在一个2.4GHz的PLL项目中吃过这个亏。仿真时一切正常,流片回来发现锁定后的相位噪声比预期差了10dB。查了整整两周,最后定位到是死区问题。PFD在锁定状态下根本不响应微小相位误差,导致VCO的控制电压纹波过大。
警告:死区会导致PLL锁定后的相位噪声恶化。更严重的是,它可能造成PLL永远无法精确锁定,始终在目标频率附近来回摆动。
消除死区的方法,业内主流做法是:在复位路径上故意增加延迟。
具体来说,就是在与门输出到触发器复位端之间,插入几个反相器或缓冲器。这样做的目的是:即使相位差为零,UP和DOWN也会产生一个最小宽度的脉冲。这个脉冲宽度由复位延迟决定,通常设计为几百皮秒到几纳秒。
我建议的最小脉冲宽度设计原则:
| PLL工作频率 | 建议最小脉冲宽度 | 复位延迟单元数 |
|---|---|---|
| < 100 MHz | 2-3 ns | 4-6级反相器 |
| 100 MHz - 1 GHz | 500 ps - 1 ns | 2-4级反相器 |
| > 1 GHz | 100-300 ps | 1-2级反相器 |
注意,这个最小脉冲宽度不能太大。太宽了,电荷泵每次都会充放电,造成控制电压纹波增大,同样会恶化相位噪声。这是个trade-off,需要根据具体应用来权衡。
设计技巧:我个人习惯在复位路径上使用可编程延迟链。这样可以在芯片测试时调整最小脉冲宽度,找到最优值。虽然面积会大一点,但调试起来方便很多。
3.3 PFD的电路实现
好了,理论说完了,来看看实际电路怎么搭。下面是一个经典的PFD电路结构:
// PFD核心电路(Verilog描述)
module pfd (
input clk_ref, // 参考时钟
input clk_fb, // 反馈时钟
input rst_n, // 异步复位
output up, // UP信号
output down // DOWN信号
);
reg up_reg, down_reg;
wire reset;
// 两个D触发器
always @(posedge clk_ref or negedge rst_n) begin
if (!rst_n)
up_reg <= 1'b0;
else if (reset)
up_reg <= 1'b0;
else
up_reg <= 1'b1;
end
always @(posedge clk_fb or negedge rst_n) begin
if (!rst_n)
down_reg <= 1'b0;
else if (reset)
down_reg <= 1'b0;
else
down_reg <= 1'b1;
end
// 复位逻辑(带延迟消除死区)
assign reset = up_reg & down_reg;
// 延迟链(消除死区)
// 实际电路中用缓冲器实现
// delay_chain #(.STAGES(4)) u_delay (.in(reset), .out(reset_delayed));
assign up = up_reg;
assign down = down_reg;
endmodule
这个代码看起来简单,但实际流片时要注意几个地方:
- 复位信号的同步问题:复位信号直接清零触发器,如果复位路径上的延迟不一致,可能导致UP和DOWN的脉冲宽度不对称
- 毛刺抑制:组合逻辑输出的复位信号可能有毛刺,建议在复位路径上加一个简单的滤波电路
- 版图布局:两个D触发器要尽量靠近,减少走线延迟差异
下面我画了一张PFD的工作状态图,帮你理清整个逻辑:
这张图展示了PFD的三个状态和转换关系。正常锁定时,PFD在空闲状态和UP/DOWN状态之间来回切换。如果相位差很小,UP和DOWN几乎同时出现,然后立即复位回到空闲状态。
嗯,这里要注意:图中的虚线路径表示异常情况。比如在UP状态下,如果反馈时钟的上升沿先于参考时钟到达(这通常不会发生,因为UP状态是由参考时钟触发的),就会直接跳转到DOWN状态。实际电路中,这种路径很少用到,但设计时还是要考虑进去,防止毛刺导致误触发。
最后说一个我踩过的坑:PFD的复位信号一定要做异步处理。我曾经图省事,直接用组合逻辑的复位信号去清零触发器,结果在高速PLL中出现了严重的亚稳态问题。后来老老实实加了同步器,问题才解决。
好了,PFD的设计就讲到这里。记住三个关键词:三态输出、死区消除、复位延迟。把这三点吃透了,PFD设计基本不会出大问题。
本章小结:
- PFD通过比较参考时钟和反馈时钟的上升沿,输出UP/DOWN信号
- 死区由复位路径延迟引起,通过增加复位延迟可以消除
- 最小脉冲宽度需要权衡死区消除和纹波噪声
- 电路实现时注意复位同步和版图对称性