Sp6 PLL and PLL_DRP使用技巧小结

Sp6 PLL and PLL_DRP使用技巧小结

 

第一部分:SP6PLL资源与常见的使用方法

(1)SP6 PLL资源

1.Sp6包含了多个CMT模块,XC6SLX45T系列芯片包含有4个CM模块,每个时钟管理模块CMT包含了两个DCM和一个PLL;

2. PLL的主要目的是

l  用于消除时钟网络偏移

l  频率合成器

l  抖动过滤器(针对内部或者外部与CMT的DCMs相连时钟信号)

3.PLL模块的输入参考时钟和反馈时钟信号可以是:IBUFG、BUFG、IBUF、PLL输出、DCM输出;

4.PLL原语有两种:PLL_BASE和PLL_ADV

l PLL_BASE:提供了单个PLL最常用的功能时钟偏移消除、频率合成、相位转移、占空比设计。在绝大多数场合下,使用PLL_BASE就可以了;

l  PLL_ADV:除了PLL_BASE提供的功能外,还支持动态重新配置PLL的功能。

5.常见的配置方式:跟PLL模块反馈时钟信号有关

l  CLK_FEEDBACK=CLKFBOUT:压控振荡器的工作频率F = Fin *M/D

l  CLK_FEEDBACK=CLKOUT0:压控振荡器的工作频率F = Fin *M*O0/D

Fout = F/O

5.使用的约束条件

l  压控振荡器工作频率范围有限,这一点在sp6数据手册里有限定。

l  输入频率有最大值和最小值。

l  时钟信号占空比只有是离散的才可以编程控制

l  相位调整,最小单元是45度。

(2)配置方法

1.用于消除时钟网络偏移的情形

反馈回路:与参考时钟CLKIN频率相匹配的输出时钟(通常是CLKFBOUT或者CLKOUT),与BUFG相连并反馈给PLL的输入反馈管脚CLKFBIN;

输入线路:为进一步消除输入线路的时钟偏移,必须使用BUFIO2FB缓存器。

Ø  在这种情况下,所有的输出时钟与输入时钟有明确的相位关系。

 

2.PLL仅用作频率合成器的情形:

此时,PLL不能用于消除时钟网络偏移(skew),而是用来给其他的模块提供时钟频率。

PLL反馈路径设定为INTERNAL

下面程序来自于aurora 8B10B核产生的时钟模块程序

moduleaurora_8b10b_v5_3_simplex_CLOCK_MODULE  #

(

       parameter MULT         =  8,

       parameter DIVIDE       =  1,

       parameter CLK_PERIOD   =  16.0,

       parameter OUT0_DIVIDE  =  8,

       parameter OUT1_DIVIDE  =  2,

       parameter OUT2_DIVIDE  =  8,

       parameter OUT3_DIVIDE  =  2

 

)

(

   GT_CLK,

   GT_CLK_LOCKED,

   USER_CLK,

   SYNC_CLK,

   PLL_NOT_LOCKED

);

`define DLY #1

//*************************PortDeclarations*******************************

 

   input       GT_CLK;

   input       GT_CLK_LOCKED;

   output      USER_CLK;

   output      SYNC_CLK;

   output      PLL_NOT_LOCKED;

 

//************************Wire Declarations********************

 

   wire            clkfb_w;

   wire            clkout0_o;

   wire            clkout1_o;

   wire            clkout2_o;

   wire            clkout3_o;

   wire            locked_w;

 

//**********************Main Body of Code******************************

// Instantiate aPLL module to divide the reference clock.

    PLL_ADV # //parameters

    (

         .CLKFBOUT_MULT     (MULT),

         .DIVCLK_DIVIDE     (DIVIDE),

         .CLKFBOUT_PHASE    (0),

        

         .CLKIN1_PERIOD     (CLK_PERIOD),

         .CLKIN2_PERIOD     (10),  //Not used

        

         .CLKOUT0_DIVIDE    (OUT0_DIVIDE),

         .CLKOUT0_PHASE     (0),

        

         .CLKOUT1_DIVIDE    (OUT1_DIVIDE),

         .CLKOUT1_PHASE     (0),

 

         .CLKOUT2_DIVIDE    (OUT2_DIVIDE),

         .CLKOUT2_PHASE     (0),

        

         .CLKOUT3_DIVIDE    (OUT3_DIVIDE),

         .CLKOUT3_PHASE     (0)       

    )

    pll_adv_i  //实例化,管脚对应上

    (

         .CLKIN1            (GT_CLK),

         .CLKIN2            (1'b0),

         .CLKINSEL          (1'b1),

         .CLKFBIN           (clkfb_w),

         .CLKOUT0           (clkout0_o),

         .CLKOUT1           (clkout1_o),

         .CLKOUT2           (clkout2_o),

         .CLKOUT3           (clkout3_o),

         .CLKOUT4           (),

         .CLKOUT5           (),

         .CLKFBOUT          (clkfb_w),

         .CLKFBDCM          (),

         .CLKOUTDCM0        (),

         .CLKOUTDCM1        (),

         .CLKOUTDCM2        (),

         .CLKOUTDCM3        (),

         .CLKOUTDCM4        (),

         .CLKOUTDCM5        (),

         .DO                (),

         .DRDY              (),

         .DADDR             (5'd0),

         .DCLK              (1'b0),

         .DEN               (1'b0),

         .DI                (16'd0),

         .DWE               (1'b0),

         .REL               (1'b0),

         .LOCKED            (locked_w),

         .RST               (!GT_CLK_LOCKED)

    );

 

   // The PLL_NOT_LOCKED signal is created byinverting the PLL's locked signal.

    assign PLL_NOT_LOCKED  =   ~locked_w;

    // The User Clock is distributed on aglobal clock net.

    BUFG user_clk_net_i

    (

        .I(clkout0_o),

        .O(USER_CLK)

    );

    BUFG sync_clk_net_i

    (

        .I(clkout1_o),

        .O(SYNC_CLK)

);     

endmodule

3. PLL用来做外部输入时钟的抖动过滤器的情况

此时,可以认为PLL充当了缓存器的作用,在缓存器的输出端再生了输入时钟。

这种情况下,设定PLL的参数:BANDWIDTH=0

 

第二部分:SP6PLL_DRP参考设计分析与使用方法

(1)     PLL_DRP参考设计分析

参考设计中使用了CLKFBOUT作为反馈路径,不支持使用CLKOUT作为参考路径,可以动态改变PLL输出时钟信号的参数,如:频率、相位、占空比。

 

1.PLL可以动态重新配置的基础

Ø  PLL_ADV有动态配置的端口(port)

端口

属性

端口描述

DADDR[4:0]

Input

动态配置地址输入总线,提供了配置地址信息

DI[15:0]

Input

动态配置数据输入总线,提供了配置数据

DWE

Input

写使能总线,提供写控制信号以使用动态配置功能

DEN

Input

动态配置使能信号

DCLK

Input

动态配置时钟信号,为动态配置端口提供参考时钟信号

DO[15:0]

Output

输出数据总线

DRDY

Output

指示动态配置端口是否准备好,作为DEN信号的响应

 

Ø  PLL模块有四个用户可以访问的配置比特组,可以配置产生特定的时钟输出信号

Divider group(分频组)-- high time、low time、no count、edge

Phase group (相位组)--phase mux、delay time

Lock group (锁定组)-- 影响PLL检测时钟信号是否锁定的能力

Filter group (滤波组)--影响PLL的消除相位偏移和抖动过滤性能

 

2.参考设计采用关键技术有两点:状态机和常量函数。

Ø  使用状态机来驱动DRP端口,完成了以下工作:

1PLL寻址

2读取先前的值

3对需要修改的数据进行掩码处理

4设置新值

5向PLL DRP端口写入新值

状态机分析:

[1]状态机控制的寄存器状态信息---时序逻辑

²  给PLL_ADV模块的输出控制信号:DWE、DEN、DADDR、DI、RST_PLL

²  返回给Use Logic模块的输出信号:SRDY

 

²  内部控制信号:rom_addr(读取ROM的地址信号)、state_count()

 

[2]状态机状态跳转—时序逻辑

²  current

²  next_state

 

[3]状态机状态跳转与寄存器状态控制逻辑—-组合逻辑

使用case(current state)进行状态跳转

RESTART 完成初始化、复位工作

case (current_state)

RESTART: begin

next_daddr     = 5'h00;

           next_di        = 16'h0000;

           next_rom_addr  = 6'h00;

           next_rst_pll   = 1'b1;

           next_state     = WAIT_LOCK;

                  end

WAIT_LOCK检测PLL_ADV模块输出时钟信号是否已经锁定

==>WAIT_LOCK:begin 

next_rst_pll   = 1'b0;

           next_state_count =STATE_COUNT_CONST COUNT_CONST; //STATE_COUNT_CONST=23

           if(LOCKED) begin

               next_state  = WAIT_SEN;

               // Assert SRDY to indicate thatthe reconfiguration module is ready

               next_srdy   = 1'b1;

           end else begin

               // Keep waiting, locked has notasserted yet

               next_state  = WAIT_LOCK;

           end

        end

WAIT_SEN等待PLL_DRP配置使能信号,若PLL_DRP使能信号为高,则设定读取ROM的初始地址;不然,一直等待使能信号

==>WAIT_SEN: begin

           if(SEN) begin

               // SEN was asserted

               if(!SADDR) begin

                  // Reconfigure with the first(0) state

                  next_rom_addr = 8'h00;

               end else begin

                  // Reconfigure with thesecond (1) state

                  next_rom_addr =STATE_COUNT_CONST;

               end

               // Go on to address the PLL

               next_state = ADDRESS;

           end else begin

               // Keep waiting for SEN to be asserted

               next_state = WAIT_SEN;

           end

        end

ADDRESS寻址:PLL_ADV模块复位、DEN置位动态配置功能启动、PLL_ADV动态配置地址总线赋值。

==> ADDRESS: begin

           // Reset the DCM through the reconfiguration

           next_rst_pll  = 1'b1;

           // Enable a read from the PLL and set the PLL address

           next_den       = 1'b1;

           next_daddr     = rom_do[36:32];

           

           // Wait for the data to be ready

           next_state     = WAIT_A_DRDY;

        end

WAIT_A_DRDY等待来自PLL_ADV的应答信号—指示是否准备好,是否可以进行动态配置了。

==>WAIT_A_DRDY:begin

           if(DRDY) begin

               // Data is ready, mask out thebits to save

               next_state = BITMASK;

           end else begin

               // Keep waiting till data is ready

               next_state = WAIT_A_DRDY;

           end

        end

BITMASK :进行掩码处理,DO为来自PLL_ADV的输出数据

==> BITMASK: begin

           // Do the mask

           next_di     = rom_do[31:16] &DO;

           // Go on to set the bits

           next_state  = BITSET;

        end

BITSET:设置新值,ROM读取地址累加1

==>BITSET:begin

           // Set the bits that need to be assigned

           next_di           = rom_do[15:0] |DI;

           // Set the next address to read from ROM

           next_rom_addr     = rom_addr + 1'b1; //最初是从0或者23开始的。

           // Go on to write the data to the PLL

           next_state        = WRITE;

                  end

WRITE:PLL_ADV动态配置写使能置位为高、动态配置使能信号置位为高

==>WRITE:begin

           // Set WE and EN on PLL

           next_dwe          = 1'b1;

           next_den          = 1'b1;

           

           // Decrement the number of registers left to write

           next_state_count  = state_count -1'b1;

           // Wait for the write to complete

           next_state        = WAIT_DRDY;

        end

WAIT_DRDY:向PLL_ADV模块每写入一次配置数据,DRDY都会响应DEN信号,state_count初始值为23,原因是一次动态重新配置需要向PLL_ADV写入23次数据。若没有写完,则回到状态ADDRESS;若写完,则回到检测PLL_ADV输出时钟信号是否锁定状态WAIT_LOCK.

==> WAIT_DRDY :begin

           if(DRDY) begin

               // Write is complete

               if(state_count > 0) begin

                  // If there are moreregisters to write keep going

                  next_state  = ADDRESS;

               end else begin

                  // There are no moreregisters to write so wait for the PLL

                  // to lock

                  next_state  = WAIT_LOCK;

               end

           end else begin

               // Keep waiting for write tocomplete

               next_state     = WAIT_DRDY;

           end

        end

default: begin

                next_state = RESTART;

        end

     endcase

Ø  使用了常量函数法来实现ROM初始化工作。

 

3.参考设计的整体框图

 

PLL_DRP输入端口描述

端口名字

属性

端口描述

SADDR

Input

选择PLL的配置状态-state1或者state2;0表示state1,1表示state2

SEN

Input

PLL_DRP使能信号

SCLK

Input

PLL_DRP时钟信号,并且透过PLL_DRP传递给DCLK

RST

Input

复位信号

SRDY

output

在user给PLL_DRP一串配置信号后,置位,保持一个时钟周期高电平信号,告知user 下一次配置可以开始了。

 

(2)PLL_DRP使用方法

Ø  PLL_DRP的配置状态

DRP有两个可用的重配置状态,SI和S2。在两个状态间切换,有以下过程:

1等待SRDY信号

2SADDR端口指定加载哪个配置状态加载到PLL_DRP;

3上拉SEN信号,保持一个时钟周期,触发配置过程,并将所有的配置参数加载到PLL_DRP设计中。

4一旦配置完成,SRDY端口将被置位,PLL此时又回到可以重新配置的状态

 

Ø  修改参考设计

1.pll_drp_func.h文件不能修改;

2.在pll_drp.v的基础上进行修改;

3.建议可进行的唯一修改是额外增加配置状态,此时需要修改的地方有:1.所有的S#-(#代表数字)设置参数;常量函数调用;ROM初始化;以及SADDR端口需要增加位数以确保增加的状态可以被访问;状态机的WAIT_SEN状态需要更新以设置ROM初始配置地址。从代码来看,应该是比较简单的。

 

参考文档:

1. UG382—Spartan-6 FPGA ClockingResources

2. xapp879_PLL dynamic configuration

 

Wrote by shanekong

At Saturday, April 12, 2014

 

 

 

 

 

 

 

你可能感兴趣的:(Sp6 PLL and PLL_DRP使用技巧小结)