数字锁相环(DPLL)研究与设计-面向FPGA/数字IC
我的学记|刘航宇的博客

数字锁相环(DPLL)研究与设计-面向FPGA/数字IC

刘航宇
3年前发布 /正在检测是否收录...
电子信息类专业“一站式”考研-简历-就业宝藏分享 电子信息类专业“一站式”考研-简历-就业宝藏分享

前言

随着数字电路技术的发展,数字锁相环在调制解调、频率合成、FM 立体声解码、彩色副载波同步、图象处理等各个方面得到了广泛的应用。数字锁相环不仅吸收了数字电路可靠性高、体积小、价格低等优点,还解决了模拟锁相环的直流零点漂移、器件饱和及易受电源和环境温度变化等缺点,此外还具有对离散样值的实时处理能力,已成为锁相技术发展的方向。
所谓数字PLL,就是指应用于数字系统的PLL,也就是说数字PLL中的各个模块都是以数字器件来实现的,是一个数字的电路。 数字锁相环的优点是电路最简单有效,可采用没有压控的晶振,降低了成本,提高了晶振的稳定性。但缺点是和模拟锁相环一样,一旦失去基准频率,输出频率立刻跳回振荡器本身的频率;另外还有一个缺点,就是当进行频率调整的时候,输出频率会产生抖动,频差越大,抖动会越大于密,不利于某些场合的应用。随着大规模、超高速的数字集成电路的发展,为数字锁相环路的研究与应用提供了广阔空间。由于晶体振荡器和数字调整技术的加盟,可以在不降低振荡器的频率稳定度的情况下,加大频率的跟踪范围,从而提高整个环路工作的稳定性与可靠性。
简单的说有两个不同来源的信号:一个信号是参考信号,这个信号一般是由芯片的晶振得到的信号,它具有信号的稳定性较好等优点,但是其频率是固定不变的。另一个信号是由芯片或者模块内部的压控振荡器得到的。这种由压控振荡器得到的信号可以是某范围内的任意频率的信号,但是这种信号的稳定型较差,容易受到外界干扰。
那么在实际使用过程中,我们需要一种频率能够变化的,同时质量较好的信号;或者对于一块芯片,我们需要不同的模块的内部时钟(这种时钟可以是压控振荡器产生)都能参考一个总的时钟来进行同步,从而避免两个模块内部时钟的差异而产生的数据传输的漂移等问题。因此,如何将压控振荡器得到的信号能够具有晶振信号的信号质量呢?
那就是通过PLL锁相环来实现,如图1所示。只要压控振荡器产生的时钟(下称输入信号)是参考信号的整数倍(或者整除倍),那么就能将输入信号先进行分频,后得到与参考信号频率相同的时钟,将分频后的信号和参考信号进行比较,从而使分频后的信号和参考信号保持相同的稳定的频率和相位。被分频后的信号稳定,也就是间接的表示输入信号的稳定。从而我们得到了一个频率在一定范围内可变的稳定的信号。
有上述可以看出,锁相环具有以下功能:
(1)能够将一个信号和另一参考信号同步;
(2)当这个信号是输出信号分频后得到的信号,PLL就能够得到参考信号的倍频信号(实际上倍频器很多都是利用了这个功能);
(3)当输入信号频率可变、分频系数可变时,PLL就能够得到在频率一定范围内稳定信号。
图片[1] - 数字锁相环(DPLL)研究与设计-面向FPGA/数字IC - 我的学记|刘航宇的博客

锁相环的原理和组成

锁相环(PLL)的作用我们已经大概了解了,其最主要功能的实现,是在于如何将两个频率不同、相位差始终在变化的信号,变成两个相同频率、相同相位的信号。
这里引入一个概念,首先我们都知道,对于三角函数,只有两个同频率的三角函数才能比较其相位差。但这里的相位差是指两个正弦函数的初始相位差。而实际上根据三角函数的欧拉定义的理解来看,我们可以把三角函数看做是在某个圆上逆时针运动的点到x轴的距离。那么频率就是点在圆上运动的角速度,频率越大,其运动的角速度越大。相位就是点在圆上的位置,而初始相位就是点在圆上开始运动时的位置。当两个点的运动角速度相同时,我们可以得到两个点的初始位置差,就是两个正弦函数频率相同时,得到初始相位差。这个差值在运动过程中一直是不变的。但是当两个点运动角速度不同时,我们去看它的初始位置差是没有意义的,因为两个点的位置差是一直在变的,而初始位置差只是一个开始的位置差,是个不变的量,所以说对于频率不同的三角函数,我们讨论起初始相位差是没有意义的。但是不代表不能比较某一时刻两个点的位置。也就是相位差,相位是存在的。
图片[2] - 数字锁相环(DPLL)研究与设计-面向FPGA/数字IC - 我的学记|刘航宇的博客
现在我们假设两个点在圆上赛跑,如图3所示,我们想让这两个点角速度相等。那么有一个办法就是以一个点为参考,参考点角速度不变,另一个点是速度可变点。每过一段时间,观察另一个点到参考点的位置,是在前,还是在后。如果在前,就让另一个点速度慢一点;如果在后,就让另一个点速度快一点。就这样不断调整另一个点的角速度,直到每次观察两个点都处于相同的位置。这样我们就可以认为这两个点达到了相同的速度。这种方法就是利用反馈调节来实现两个信号的同频同相。也就是锁相环(PLL)的实现原理。
首先通过一个鉴相器来得到两个信号之间的相位差。并根据相位差输出电压信号。然后通过滤波器稳压后得到稳定的电压信号,该信号驱动压控振荡器得到新的频率的信号。当两个信号存在相位差时,电压信号就会改变,从而使受控信号不断变化。直到当两个信号没有相位差时,电压信号不再改变,从而使受控信号保持当前频率,这时,受控信号不再变化了,就叫做受控信号被锁定了。
由上所述,一个锁相环由鉴相器、滤波器、振荡器三部分组成。外部输入是参考信号,内部输入和总的输出是受控信号。

数字锁相环的原理和组成

在数字电路中,原来模拟信号正弦波、余弦波的频率和相位变成了0和1的脉冲信号,那么我们如何理解数字信号中的频率和相位呢?对于脉冲信号来说,我们可以把频率理解为在某固定时间内脉冲出现的个数,为了方便表示,我们把上升沿的出现视为脉冲的出现,把相邻两个脉冲出现的时间t求倒数,就得到了该信号在这个时刻处的信号频率。而对于相位,相位差就是指,存在两个脉冲信号,以一个脉冲信号为参考,在其出现脉冲后,到另一个信号出现脉冲之间的时间差就是相位差,当另一个信号脉冲晚于参考信号脉冲出现的时间,称之为另一个信号的相位滞后于参考信号。当另一个信号的脉冲出现在参考信号之前,称之为另一个信号的相位提前于参考信号。
上述是一种较为简单的描述方式,适合初识脉冲信号的读者理解。而实际上,对于脉冲信号的频率、相位等问题,严格来说这样理解有一点点问题,但是对于我们来搭建数字锁相环DPLL来说足够了。其实这种三角函数和信号之间的转化,其根本的原理来源于傅里叶变换,从而我们对一个时间域上的信号(例如脉冲信号)可以进行频率域(其代表的三角函数的合成)上的分析。
我们知道了在数字电路中,脉冲信号也有了频率和相位的属性。那么我们的参考信号是以来时钟源的固定频率的信号,因为信号的质量比较好,所以该信号两个脉冲之间的时间差均是相同的,误差很小。我们在参考信号出现上升沿时,观察受控信号此时的状态。如果受控信号为高电平,我们就认为此时受控信号超前于参考信号;反之,如果受控信号是低电平,则认为此时的受控信号滞后于参考信号。当出现超前状态时,鉴相器会输出一个超前信号,超前信号会作用于振荡器,使得振荡器发出的受控信号频率降低。而滞后信号会使振荡器发出的受控信号频率升高,从而实现受控信号频率的反馈调节。
如图4所示,当参考信号出现上升沿时,受控信号为低电平,此时输出一个滞后信号。(由于模块只在时钟为上升沿时触发,所以超前信号的触发延迟了半个时钟周期)
图片[3] - 数字锁相环(DPLL)研究与设计-面向FPGA/数字IC - 我的学记|刘航宇的博客
由此我们能够大概了解了数字锁相环中如何看待脉冲信号的频率和相位,如何处理得到相位差以及相位差如何在锁相环中起作用来实现信号频率的反馈控制。同模拟的锁相环(PLL)类似,数字锁相环(DPLL)也是由:数字鉴相器(Digital Phase Detector)、数字缓冲器(Digital Buffer)、数字振荡器(Digital Controlled Oscillator)三个模块构成,其外部输入为参考信号,内部输入和输出为受控信号。下面我们就来具体讨论如何用verilog实现各个模块。

数字鉴相器设计DPD

实现一个数字锁相环(DPLL),最重要的部分就是实现数字鉴相器(DPD)和数字振荡器(DF)。并且,这两个模块并不是独立存在的,而是说,数字振荡器的实现方式和数字振荡器的实现方式相互影响。所以只有两个模块共同设计,才能较好的实现一个数字锁相环的功能。
首先我们来具体讨论一下一个数字鉴相器应该具有那些功能和特性:
顾名思义,数字鉴相器就是能够鉴别两个数字信号相位的差别,并通过信号将这种差别表示出来。由上文我们已经知道了,对于两个矩形方波信号,其相位差可以看做是两个信号先后出现上升沿(或下降沿)之间的时间差。为了方便表示,假设以其中一个信号作为参考信号,另一个信号为受控信号,当参考信号出现上升沿(或下降沿)时,观察另一个信号是否已经出现了上升沿(或下降沿)。
如果还未出现上升沿(或下降沿),则叫做“受控信号滞后于参考信号”,或者简称“滞后”;如果已经出现了上升沿(或下降沿),则叫做“受控信号提前于参考信号”,或者简称“提前”。
而判断上升沿(或下降沿)是否已经出现,方法就是看当参考信号出现上升沿时,受控信号是1还是0:当受控信号为0,表示上升沿还没出现,所以是“滞后”;当受控信号为1,表示上升沿已经出现,所以是“提前”。对于下降沿也是按照同样的方法考虑。
图片[4] - 数字锁相环(DPLL)研究与设计-面向FPGA/数字IC - 我的学记|刘航宇的博客
目前为止,我们已经有两个输入,参考信号和受控信号;两个输出,滞后信号和提前信号。如何通过verilog实现上述的输入输出关系呢?首先先讲异或与门,通过图4的描述,我们可以很容易看出来:滞后信号是参考信号与受控信号先异或,异或的结果和受控信号相与得到;提前信号是参考信号与受控信号先异或,异或的结果和参考信号相与得到。再加上一个RST的复位信号,我们可以得到如下图5电路:
图片[5] - 数字锁相环(DPLL)研究与设计-面向FPGA/数字IC - 我的学记|刘航宇的博客
根据这个关系,来调节受控信号的频率,从而使受控信号的频率和参考信号最终相同。
再考虑,如果按照上述方法调节,当受控信号和参考信号频率相差很大时,就会出现刚开始有一段时间,受控信号的频率是不断变化,不可预知的。这样的调节效果实时性并不好,需要时间来稳定。因此读者想到,如果能够在参考信号出现上升沿时,就让受控信号也出现上升沿,相当于两个人在赛跑时,当一个人从起点出发时,无论另一个人在哪,强制让另一个人也回到原点,两个人一起从原点出发。这样就能使受控信号和参考信号强制达到相同的频率,只是此时受控信号的占空比不是50%。然后再根据滞后和提前信号,调节受控信号的占空比,从而最终达到50%的占空比。
按照这种方法,鉴相器就需要一个信号输出来表示上升沿的出现。再考虑到电路中的总的时钟源,我们这里采用触发的方法来实现。同时将上述的异或与门加入到代码中可以得到数字鉴相器的代码。但是在实际运用过程中发现,可能存在着受控信号先出现上升沿,从而过早的出现了提前或者滞后信号,导致数字振荡器的计数器上限呈现一个周期变化的不可控的数值的情况。为了避免这种情况,需要仔细考虑参考信号和受控信号如何生成提前和滞后信号这个问题,而不是简单的用异或来实现。如图6表示这种关系。
图片[6] - 数字锁相环(DPLL)研究与设计-面向FPGA/数字IC - 我的学记|刘航宇的博客
按照上述代码写出来的数字鉴相器,具有更好的性能。根据这个表格,通过类似状态机的方法,来实现提前信号和滞后信号的输出。
此外异或门配合D触发器方式也可以实现鉴相器效果仍可应用于本设计中。示例代码如下:

module DPD_2 (
    input      reference_signal,    // 参考时钟输入(来自外部晶振或基准源)
    input      controlled_signal,     // 反馈时钟输入(来自VCO分频后的时钟)
    input      rst,      // 异步复位信号,高电平有效
    input        clk,
    output reg lead_signal_wire,         // 相位超前指示信号(输出到电荷泵)
    output reg lag_signal_wire,        // 相位滞后指示信号(输出到电荷泵)
    output        bothEdge
);

// 延迟寄存器:用于检测两个时钟的到达顺序
reg ref_flag, fb_flag;
reg ref_nflag, fb_nflag;

reg lead_signal,lead_signal_n;
reg lag_signal,lag_signal_n;

reg reference_signal_d1,reference_signal_d2;
reg controlled_signal_d1,controlled_signal_d2;
wire bothEdge_fb;


reg fb_flag_d1,fb_flag_d2,fb_nflag_d1,fb_nflag_d2;
reg ref_flag_d1,ref_flag_d2,ref_nflag_d1,ref_nflag_d2;

always @(posedge clk or negedge rst)  
begin
    if(!rst) begin
        reference_signal_d1 <= 'd0;
        controlled_signal_d1 <= 'd0;
        fb_flag_d1 <= 'd0;
        fb_flag_d2 <= 'd0;
        fb_nflag_d1 <= 'd0;
        fb_nflag_d2 <= 'd0;
        ref_flag_d1 <= 'd0;
        ref_flag_d2 <= 'd0;
        ref_nflag_d1 <= 'd0;
        ref_nflag_d2 <= 'd0;
    end
    else  begin
        reference_signal_d1 <= reference_signal;
        reference_signal_d2 <= reference_signal_d1;
        controlled_signal_d1 <= controlled_signal;
        controlled_signal_d2 <= controlled_signal_d1;
        fb_flag_d1 <= fb_flag;
        fb_flag_d2 <= fb_flag_d1;
        fb_nflag_d1 <= fb_nflag;
        fb_nflag_d2 <= fb_nflag_d1;
        ref_flag_d1 <= fb_flag;
        ref_flag_d2 <= ref_flag_d1;
        ref_nflag_d1 <= ref_nflag;
        ref_nflag_d2 <= ref_nflag_d1;    

    end
end    

assign    bothEdge = reference_signal  & (~reference_signal_d1);

wire bothEdge_n;
assign  bothEdge_n = (~reference_signal)  & reference_signal_d1; //


assign    bothEdge_fb = controlled_signal  & (~controlled_signal_d1);
wire bothEdge_fb_n; //控制下降沿
assign  bothEdge_fb_n = (~controlled_signal)  & controlled_signal_d1; //




// 参考时钟延迟寄存器:在reference_signal上升沿采样
// 功能:标记参考时钟是否到来
always @(posedge reference_signal or negedge rst) begin
    if (!rst)  begin
        ref_flag <= 1'b0;   // 复位时清零
        ref_nflag <= 1'b0;
    end
    else  begin     
        ref_flag <= 1'b1;  // 参考时钟到来后置1
        ref_nflag <= 1'b0;
    end
end

// 反馈时钟延迟寄存器:在controlled_signal上升沿采样
// 功能:标记反馈时钟是否到来
always @(posedge controlled_signal or negedge rst) begin
    if (!rst) begin 
        fb_flag <= 1'b0;   // 复位时清零
        fb_nflag <= 1'b0;
    end
    else begin 
        fb_flag <= 1'b1;  // 反馈时钟到来后置1
        fb_nflag <= 1'b0;
    end
end

// 主逻辑:检测相位关系 - 谁先来谁占优
// 在参考时钟上升沿判断:如果反馈时钟还没来,说明参考超前



always @(posedge reference_signal_d2) begin
    if (!fb_flag_d2) lag_signal   <= 1'b1;   // fb_dly为0表示controlled_signal尚未到达,reference_signal超前
    else         lag_signal   <= 1'b0;  // fb_dly为1表示controlled_signal已到,两者已对齐或参考滞后
end

// 在反馈时钟上升沿判断:如果参考时钟还没来,说明反馈超前(即参考滞后)
always @(posedge controlled_signal_d2) begin
    if (!ref_flag_d2) lead_signal <= 1'b1;  // ref_dly为0表示reference_signal尚未到达,controlled_signal超前
    else         lead_signal <= 1'b0;  // ref_dly为1表示reference_signal已到,两者已对齐或反馈滞后
end


//下降沿
always @(negedge reference_signal or negedge rst) begin
    if (!rst) begin
      ref_nflag <= 1'b0;   // 复位时清零
      ref_flag <= 1'b0;
    end 
    else  begin  
        ref_nflag <= 1'b1;  // 参考时钟到来后置1
        ref_flag <= 1'b0;
    end
end

always @(negedge controlled_signal or negedge rst) begin
    if (!rst) begin fb_nflag <= 1'b0;   // 复位时清零
                fb_flag <= 1'b0;
    end
    else    begin      
           fb_nflag <= 1'b1;  // 反馈时钟到来后置1
        fb_flag <= 1'b0;
    end
end

always @(negedge reference_signal_d2) begin
    if (!fb_nflag_d2) lag_signal_n  <= 1'b1;   // fb_dly为0表示controlled_signal尚未到达,reference_signal超前
    else         lag_signal_n   <= 1'b0;  // fb_dly为1表示controlled_signal已到,两者已对齐或参考滞后
end

// 在反馈时钟上升沿判断:如果参考时钟还没来,说明反馈超前(即参考滞后)
always @(negedge controlled_signal_d2) begin
    if (!ref_nflag_d2) lead_signal_n <= 1'b1;  // ref_dly为0表示reference_signal尚未到达,controlled_signal超前
    else         lead_signal_n <= 1'b0;  // ref_dly为1表示reference_signal已到,两者已对齐或反馈滞后
end


// 消毛刺逻辑:在任一时钟下降沿清零lead_signal_wire/lag_signal_wire信号
// 防止多脉冲叠加,确保每个周期只产生一个有效脉冲
/*
always @(negedge reference_signal or negedge controlled_signal) begin
    {lead_signal_wire, lag_signal_wire} <= 2'b00;  // 在时钟下降沿同时复位两个输出
end
*/



always @(posedge clk or negedge rst) begin
    if (!rst) begin
        lead_signal_wire <= 'b0;
        lag_signal_wire <= 'b0;
    end
    //else if(bothEdge & bothEdge_fb) begin
    else if((bothEdge & bothEdge_fb) | (bothEdge_n & bothEdge_fb_n)) begin
        lead_signal_wire <= 'b0;
        lag_signal_wire <= 'b0;
    end
    else begin
        lead_signal_wire <= lead_signal | lead_signal_n;
        lag_signal_wire <= lag_signal | lag_signal_n;
    end
end


endmodule

数字振荡器(DCO)

现在我们已经构造出来了一个数字鉴相器,接下来我们将继续探讨如何实现一个数字振荡器(DCO)。
实现一个固定脉冲频率的信号,我们可以通过已知的时钟源,分频得到一定频率范围内的脉冲。具体实现方法就是通过计数器的方式,当出现时钟脉冲时,计数器+1,计数器上限就是分频系数,当计数器的数小于上限的1/2时,输出1,当计数器的数大于上限的1/2时,输出0,当计数器的数超过上限时,计数器归零。这样就能实现对时钟源的分频。
根据上述方法,只要改变计数器的上下限,就能改变分频系数,从而改变输出信号的频率。再参考上文受控信号和滞后提前信号的关系,我们就能通过根据滞后提前信号,改变计数器上下限,来实现对受控信号频率的控制。当计数器上限增加时,分频系数增加,频率减小;当计数器上限减小时,分频系数减小,频率增加;因此有:
滞后信号——>受控信号的频率小——>增加受控信号的频率——>计数器上限减小
提前信号——>受控信号的频率大——>减小受控信号的频率——>计数器上限增加
此外根据上述对上升沿触发同步的说法,当出现上升沿触发信号时,受控信号应强制产生上升沿,即受控信号强制从该脉冲周期的开始处开始,即计数器的数回到0从新开始计数。
综上所述,再加上复位信号,一个数字振荡器的所有构成就有了。到这里,一个数字锁相环(DPLL)其实就已经能够实现了,因为数字滤波器(DB)只是让受控信号的抗干扰能力更强,如图所示是仿真后的结果:
图片[7] - 数字锁相环(DPLL)研究与设计-面向FPGA/数字IC - 我的学记|刘航宇的博客

数字缓冲器(DB)

下面再介绍一下数字缓冲器,来使受控信号的抗干扰能力更强。前面我们知道了,持续一个时钟周期的提前信号或者滞后信号能够使数字振荡器的计数器上限加一或者减一。当我的预设的数字振荡器的计数器上限与实际的参考信号的频率对应的计数器上限两个数值相差很大时,就有可能出现锁相环调节时间过长等现象。为了解决这种情况,如果能够让原来持续一个周期的提前信号或滞后信号成倍数的增加,变成持续n个周期的提前信号或者滞后信号,就能够使数字振荡器的计数器上限修改更快,从而更快的到达参考频率附近。但是相应的,受控信号的频率精度就会降低。也就是说,牺牲精度,追求速度。
同时考虑另外一种情况,如果我对速度要求不高,但是对于精度要求较高,同时在信号传输过程中可能存在干扰,导致接收到的提前信号或滞后信号不是完全真实的信号,此时就可以通过一个累加器,只有接受到n个周期的提前信号,或者滞后信号,才对数字振荡器输出一个进位信号或者借位信号,此时数字振荡器的计数器上限才只加减1,这样就能有效的提高精度,减少信号干扰带来的影响。但是这种做法牺牲了数字锁相换锁定的时间。
综上所述,一个时钟周期的提前或滞后信号,对应n个时钟周期的借位或进位信号,是提高锁定速度,降低锁定精度。想法,n个时钟周期的提前或滞后信号,对应一个时钟周期的借位或进位信号,是提高锁定精度,降低锁定速度。因此在实际运用中,应该按照自己的工程需要,合理选择比值。
上述过程的实现方法,是通过一个计数器,当接收到一个提前或滞后信号时,计数器加a,当输出一个进位或借位信号时,计数器减b,调节a和b的比值,就能实现上述过程。
数字缓冲器的仿真效果:
1、分时效果
图片[8] - 数字锁相环(DPLL)研究与设计-面向FPGA/数字IC - 我的学记|刘航宇的博客
2、倍时效果
图片[9] - 数字锁相环(DPLL)研究与设计-面向FPGA/数字IC - 我的学记|刘航宇的博客

数字锁相环(DPLL)的实现

所有的子模块都已经实现了,剩下的数字锁相环的实现,根据实际的要求,将上述几个模块进行例化就行。例化后的测试结果如图9所示,可以看到受控信号逐渐与参考信号对齐达到锁相环效果。
图片[10] - 数字锁相环(DPLL)研究与设计-面向FPGA/数字IC - 我的学记|刘航宇的博客
为了方便起见,对输出信号进行2分频,再次观察输出结果,输出相当于2倍频了,成功完成PD、DCO、Divider等模块正确设计。
图片[11] - 数字锁相环(DPLL)研究与设计-面向FPGA/数字IC - 我的学记|刘航宇的博客

电路硬件与性能评估

图11为电路硬件图从图中可以看出各模块的连接关系,每个模块由基本门电路构成。通过性能优化后的的电路如图12所示。
图片[12] - 数字锁相环(DPLL)研究与设计-面向FPGA/数字IC - 我的学记|刘航宇的博客
利用SMIC180nm工艺进行电路综合,
时序报告:周期2ns
图片[13] - 数字锁相环(DPLL)研究与设计-面向FPGA/数字IC - 我的学记|刘航宇的博客
面积报告:2119um2
图片[14] - 数字锁相环(DPLL)研究与设计-面向FPGA/数字IC - 我的学记|刘航宇的博客
功耗报告:uw级别
图片[15] - 数字锁相环(DPLL)研究与设计-面向FPGA/数字IC - 我的学记|刘航宇的博客

工程代码下载

支付宝支付
价格: 2.00 元
温馨提示:免登录付款后7天内可重复阅读隐藏内容,登录用户付款后可永久阅读隐藏的内容。付费后如无反应,刷新网页即可阅读。 付费可读
© 版权声明
THE END
喜欢就支持一下吧
点赞 4 分享 赞赏
评论 共1条
取消
  1. 头像
    小胖
     · 
    回复

    太棒了