MMCM时钟动态调相

文章目录

  • 需要了解
  • 测试代码
  • 仿真一
  • 仿真二

今天调试时遇到DA输出信号杂散较大的问题。该DA自身具备调相功能(固定调相值为90°、180°、270°、360°),在调试过程中发现,通过改变DA的采样相位值,能一定程度的改善输出信号的质量,但并没有改善太多。考虑到目前硬件很难再有所改动,决定通过改动FPGA来小修小补。
初步的解决思路有两个:

  • 调节selectIO的数据延迟
  • 调节输出数据所在时钟域的时钟相位

这两个思路都尝试了,但奇怪的是,肉眼看不到有啥改善效果,一点都没看到。按理说,不应该啊,于是,一点点排查。最后排查到,调节时钟相位时,对应的MMCM IP设置中,没有选中USE Fine PS选项。以前知道动态调节时钟相位时,这个选项要勾上,但今天忘了选中了,浪费了一天时间来找这种问题。。。
下面对MMCM IP的动态调相功能仿真一下,加深一下印象。

需要了解

摘自ug472_7Series_Clocking的Dynamic Phase Shift Interface in the MMCM章节

  • The attributes CLKOUT[0:6]_USE_FINE_PS and CLKFBOUT_USE_FINE_PS select the output clocks to be dynamically phase shifted
  • When PSEN is asserted for one PSCLK clock period, a phase-shift increment/decrement is initiated
  • Each increment adds to the phase shift of the MMCM clock outputs by 1/56th of the VCO period
  • The number of PSCLK cycles is deterministic and is always 12 PSCLK cycles
  • An entire clock period (360 degrees) can always be phase shifted regardless of frequency. When the end of the period is reached, the phase shift wraps around round-robin style.

测试代码

下面是临时写的测试代码,未经上板验证,

library ieee;
    use ieee.std_logic_1164.all;
    use ieee.std_logic_unsigned.all;
library unisim;
    use unisim.vcomponents.all;

entity clk_wrapper is
port (
    ps_clk      : in  std_logic;
    ps_value    : in  std_logic_vector(7 downto 0);
    ps_start    : in  std_logic;
    mmcm_rst    : in  std_logic;
    mmcm_locked : out std_logic;
    clk_in      : in  std_logic;
    clk_out1    : out std_logic;
    clk_out2    : out std_logic
);
end clk_wrapper;

architecture Behavioral of clk_wrapper is

------------------------------------------------------------
--                  常量声明
------------------------------------------------------------
    constant    ST_IDLE         : std_logic_vector(3 downto 0) := X"0";
    constant    ST_PS_INCDEC    : std_logic_vector(3 downto 0) := X"1";
    constant    ST_PS_ING       : std_logic_vector(3 downto 0) := X"2";
    constant    ST_PS_DONE      : std_logic_vector(3 downto 0) := X"3";

------------------------------------------------------------
--                  component声明
------------------------------------------------------------
    component CLK_MMCM
        port(
            clk_out1          : out    std_logic;
            clk_out2          : out    std_logic;
            psclk             : in     std_logic;
            psen              : in     std_logic;
            psincdec          : in     std_logic;
            psdone            : out    std_logic;
            -- Status and control signals
            reset             : in     std_logic;
            locked            : out    std_logic;
            clk_in1           : in     std_logic
        );
    end component;

------------------------------------------------------------
--                  信号声明
------------------------------------------------------------   
    signal ps_en            : std_logic;
    signal ps_incdec        : std_logic;
    signal ps_done          : std_logic;

    signal state            : std_logic_vector(3 downto 0) := ST_IDLE;
    signal ps_value_used    : std_logic_vector(7 downto 0);
    signal ps_value_cur     : std_logic_vector(7 downto 0);
    
begin
    
    --------------------------------------------------------
    -- 例化时钟MMCM
    Inst_CLK_MMCM : CLK_MMCM
    port map(
        reset       => mmcm_rst,
        locked      => mmcm_locked,

        psclk       => ps_clk,
        psen        => ps_en, 
        psincdec    => ps_incdec,
        psdone      => ps_done,
        
        clk_in1     => clk_in,
        clk_out1    => clk_out1,
        clk_out2    => clk_out2
    );
    
    --------------------------------------------------------
    -- 状态机
    process(ps_clk)
    begin
        if rising_edge(ps_clk) then
            if mmcm_rst='1' then
                state <= ST_IDLE;
            else
                case state is
                    when ST_IDLE     =>
                        if(ps_start='1') then
                            state <= ST_PS_INCDEC;
                            ps_value_used <= ps_value;
                            ps_value_cur  <= (others=>'0');
                        else
                            state <= ST_IDLE;
                        end if;
                        ps_en <= '0';
                        ps_incdec <= '0';
                    when ST_PS_INCDEC =>
                        state       <= ST_PS_ING;
                        ps_en       <= '1';
                        ps_incdec   <= '1';
                        ps_value_cur <= ps_value_cur + 1;
                    when ST_PS_ING =>  
                        ps_en       <= '0';
                        ps_incdec   <= '0';
                        if(ps_done='1') then
                            if(ps_value_cur
                        state <= ST_IDLE;
                    when others =>
                        state <= ST_IDLE;
                end case;
            end if;     
        end if;
    end process;

end Behavioral;
`timescale 1ns / 1ps
module tb_clk_wrapper;

reg         clk_bufg;
reg         mmcm_rst;
reg         ps_clk;
reg         ps_start;
reg [7:0]   ps_value;
wire        mmcm_locked;
wire        clk_out1;
wire        clk_out2;

clk_wrapper  inst_clk_wrapper(
    .ps_clk      (ps_clk),
    .ps_value    (ps_value),
    .ps_start    (ps_start),
    .mmcm_rst    (mmcm_rst),
    .mmcm_locked (mmcm_locked),
    .clk_in      (clk_bufg),
    .clk_out1    (clk_out1),
    .clk_out2    (clk_out2)
);

//---------------------------------------------
//生成时钟
initial begin
    ps_clk = 1'b0;
    #(10.0/2);
    forever
    #(10.0/2) ps_clk = ~ps_clk;
end

initial begin
    clk_bufg = 1'b0;
    #(1.6/2);
    forever
    #(1.6/2) clk_bufg = ~clk_bufg;
end

//---------------------------------------------
//激励输入
initial begin
    mmcm_rst = 0;
    ps_start = 0;
    ps_value = 0;
    #100;
    
    mmcm_rst = 1;
    repeat (10) @(posedge ps_clk);
    mmcm_rst = 0;
    
    repeat (10000) @(posedge ps_clk);
    ps_start = 1;
    ps_value = 10;
    repeat (10) @(posedge ps_clk);
    ps_start = 0;
    ps_value = 10;
end

endmodule

仿真一

MMCM设置

  • clk_in --> 625MHz
  • clk_out1 --> 156.25MHz,选中USE Fine PS
  • clk_out2 --> 625MHz,选中USE Fine PS
    MMCM时钟动态调相_第1张图片
    从IP核的界面设置中可获知,FREQvco=625*4/2=1250MHz,对应的ps_step=1e6/1250/56=14.2857ps。对IP核进行仿真,设置调相数目为10,仿真波形如下,
    MMCM时钟动态调相_第2张图片
    观察仿真波形可知,当调一次相后,输入时钟与输出时钟1、2的延迟为14ps;当调10次相后,输入时钟与输出时钟1、2的延迟为143ps。
    注意,这个延迟是绝对时间,且输出时钟1与输出时钟2的延迟时间是一致的
    MMCM时钟动态调相_第3张图片
    再次放大局部波形,可以观察到,如手册所说,ps_done信号在ps_en之后的12个CLK后拉高
    MMCM时钟动态调相_第4张图片

仿真二

MMCM设置

  • clk_in --> 625MHz
  • clk_out1 --> 156.25MHz,选中USE Fine PS
  • clk_out2 --> 625MHz,不选中USE Fine PS
    MMCM时钟动态调相_第5张图片
    对IP核进行仿真,设置调相数目为10,仿真波形如下,从图中可知,仅输出时钟1相对输入时钟有延迟,输出时钟2相对输入时钟没有延迟
    MMCM时钟动态调相_第6张图片

你可能感兴趣的:(FPGA)