cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 
verse
Visitor
Visitor
1,197 Views
Registered: ‎06-19-2018

problem with pll accuracy

Jump to solution

Hello,

i have a problem with pll accuracy which means :

For a ddr data transfer i generate two clocks with 180 degree phase.

The data is sampled at a possibly slower clock rate, so the data is transferred through a fifo.

I found, that the pll with 100MHz input, multiplicator 16, divider 16 -> 100MHz output doesn't generate exacly 100MHz output.

I added counter to fifo in and out and frequency in and out. Master counter counts 500000000 samples.

The result with pll is : output-count is 500000000, but input is 500004096 ( may vary a little). This means, that Pll-output is somewhat slower than input. I tested other multiplicators like 8 and 12 to check dependency of vco, but result is the quite the same (other counter values, but pll-output too slow every time).

At least it was expected that pll would be sometimes faster or slower depending on regulation, but it is always slower.

I also tested a MMCME2_BASE at multiplicator 12 (100MHz in, VCO 1200MHz, 100MHz out), but result is the same, output clock is slower, counter is 500010228..500010965 / 5000000000.

If i wipe out the pll and use equal clocks on both sides, every counter counts 500000000 (equal clocks means 100MHz by Oszillator and 100MHz by analog external PLL with Oscillator as input).

The count is done by generating a start_signal and a stop signal by the master counter counting 500000000.

Theese signal are syncronised to the second clock the other counter runs on.

This all means, that the fifo is written faster than read and i loose data by overflow.

 

Best regards,

Stefan Verse

 

 

The design is a little big - so here the code for the MMCME2_BASE instantiation, but the pll is quite the same :

   MMCME2_BASE_inst : MMCME2_BASE
   generic map (
      BANDWIDTH => "LOW",  -- Jitter programming (OPTIMIZED, HIGH, LOW)
      CLKFBOUT_MULT_F => 12.0,    -- Multiply value for all CLKOUT (2.000-64.000).
      CLKFBOUT_PHASE => 0.0,     -- Phase offset in degrees of CLKFB (-360.000-360.000).
      CLKIN1_PERIOD => 10.0,      -- Input clock period in ns to ps resolution (i.e. 33.333 is 30 MHz).
      -- CLKOUT0_DIVIDE - CLKOUT6_DIVIDE: Divide amount for each CLKOUT (1-128)
      CLKOUT1_DIVIDE => 6,
      CLKOUT2_DIVIDE => 1,
      CLKOUT3_DIVIDE => 1,
      CLKOUT4_DIVIDE => 1,
      CLKOUT5_DIVIDE => 1,
      CLKOUT6_DIVIDE => 1,
      CLKOUT0_DIVIDE_F => 12.0,   -- Divide amount for CLKOUT0 (1.000-128.000).
      -- CLKOUT0_DUTY_CYCLE - CLKOUT6_DUTY_CYCLE: Duty cycle for each CLKOUT (0.01-0.99).
      CLKOUT0_DUTY_CYCLE => 0.5,
      CLKOUT1_DUTY_CYCLE => 0.5,
      CLKOUT2_DUTY_CYCLE => 0.5,
      CLKOUT3_DUTY_CYCLE => 0.5,
      CLKOUT4_DUTY_CYCLE => 0.5,
      CLKOUT5_DUTY_CYCLE => 0.5,
      CLKOUT6_DUTY_CYCLE => 0.5,
      -- CLKOUT0_PHASE - CLKOUT6_PHASE: Phase offset for each CLKOUT (-360.000-360.000).
      CLKOUT0_PHASE => 0.0,
      CLKOUT1_PHASE => 0.0,
      CLKOUT2_PHASE => 0.0,
      CLKOUT3_PHASE => 0.0,
      CLKOUT4_PHASE => 0.0,
      CLKOUT5_PHASE => 0.0,
      CLKOUT6_PHASE => 0.0,
      CLKOUT4_CASCADE => FALSE,  -- Cascade CLKOUT4 counter with CLKOUT6 (FALSE, TRUE)
      DIVCLK_DIVIDE => 1,        -- Master division value (1-106)
      REF_JITTER1 => 0.1,        -- Reference input jitter in UI (0.000-0.999).
      STARTUP_WAIT => FALSE      -- Delays DONE until MMCM is locked (FALSE, TRUE)
   )
   port map (
      -- Clock Outputs: 1-bit (each) output: User configurable clock outputs
      CLKOUT0 => clkout0_mmcm_filt,     -- 1-bit output: CLKOUT0
      CLKOUT0B => clkout1_mmcm_filt,   -- 1-bit output: Inverted CLKOUT0
      CLKOUT1 => idelay_ref_clk_s,     -- 1-bit output: CLKOUT1
      CLKOUT1B => open,   -- 1-bit output: Inverted CLKOUT1
      CLKOUT2 => open,     -- 1-bit output: CLKOUT2
      CLKOUT2B => open,   -- 1-bit output: Inverted CLKOUT2
      CLKOUT3 => open,     -- 1-bit output: CLKOUT3
      CLKOUT3B => open,   -- 1-bit output: Inverted CLKOUT3
      CLKOUT4 => open,     -- 1-bit output: CLKOUT4
      CLKOUT5 => open,     -- 1-bit output: CLKOUT5
      CLKOUT6 => open,     -- 1-bit output: CLKOUT6
      -- Feedback Clocks: 1-bit (each) output: Clock feedback ports
      CLKFBOUT => mmc_fb_clk_s,   -- 1-bit output: Feedback clock
      CLKFBOUTB => open, -- 1-bit output: Inverted CLKFBOUT
      -- Status Ports: 1-bit (each) output: MMCM status ports
      LOCKED => dll2_locked_s,       -- 1-bit output: LOCK
      -- Clock Inputs: 1-bit (each) input: Clock input
      CLKIN1 => tx_clk_i,       -- 1-bit input: Clock
      -- Control Ports: 1-bit (each) input: MMCM control ports
      PWRDWN => '0',       -- 1-bit input: Power-down
      RST => dll2_reset_s,             -- 1-bit input: Reset
      -- Feedback Clocks: 1-bit (each) input: Clock feedback ports
      CLKFBIN => mmc_fb_clk_s      -- 1-bit input: Feedback clock
   );

 

and the code for the two clocks ( thers are global buffer on .clkout0_mmcm_filt and clkout1_mmcm_filt) :

 

ddr_clk_i is pll-output,

clk_i is pll-input

the counters are free running and update time_store_s and freq_store_s  every 5 seconds

 

    signal time_cnt_s            : std_logic_vector(31 downto 0);
    signal freq_cnt_s            : std_logic_vector(31 downto 0);
    signal time_store_s            : std_logic_vector(31 downto 0);
    signal freq_store_s            : std_logic_vector(31 downto 0);
    signal cnt_active_s            : std_logic;
    signal cnt_active_p1_s        : std_logic;
    signal store_s                : std_logic;
    signal store_p1_s            : std_logic;
    signal store_p2_s            : std_logic;
    signal clear_s                : std_logic;
    signal clear_p1_s            : std_logic;
    signal clear_p2_s            : std_logic;
    signal state_s                : std_logic_vector(2 downto 0);

    constant c_idle        : std_logic_vector(2 downto 0) := "000";
    constant c_clear    : std_logic_vector(2 downto 0) := "001";
    constant c_run        : std_logic_vector(2 downto 0) := "010";
    constant c_store    : std_logic_vector(2 downto 0) := "100";

 

    process(reset_i,ddr_clk_i)

    begin
        if reset_i='1' then
            state_s <= c_idle;
            time_cnt_s <= (others => '0');
            time_store_s <= (others => '0');
            clear_s <= '1';
            store_s <= '0';
            cnt_active_s <= '0';
            store_p2_s <= '0';
            clear_p2_s <= '0';
        elsif rising_edge(ddr_clk_i) then
            store_p2_s <= store_p1_s;
            clear_p2_s <= clear_p1_s;
            if state_s=c_idle then
                time_cnt_s <= (others => '0');
                state_s <= c_clear;
                clear_s <= '1';
                store_s <= '0';
                cnt_active_s <= '0';
            elsif state_s=c_clear then
                clear_s <= '1';
                time_cnt_s <= (others => '0');
                if clear_p2_s='1' then
                    state_s <= c_run;
                    clear_s <= '0';
                    store_s <= '0';
                    cnt_active_s <= '1';
                end if;
            elsif state_s=c_run then
                cnt_active_s <= '1';
                time_cnt_s <= time_cnt_s + '1';
                if time_cnt_s = "00011101110011010110010100000000" then    -- 500000000 -> 5 sec
                    state_s <= c_store;
                    clear_s <= '0';
                    store_s <= '1';
                    cnt_active_s <= '0';
                    time_store_s <= time_cnt_s;
                end if;
            elsif state_s=c_store then
                store_s <= '1';
                time_cnt_s <= (others => '0');
                valid_cnt_s <= (others => '0');
                if store_p2_s='1' then
                    state_s <= c_idle;
                    clear_s <= '0';
                    store_s <= '0';
                    cnt_active_s <= '0';
                end if;
            else
                state_s <= c_idle;
            end if;
        end if;
    end process;

 

    process(clk_i)
    begin
        if rising_edge(clk_i) then
            store_p1_s <= store_s;
            clear_p1_s <= clear_s;
            cnt_active_p1_s <= cnt_active_s;
            
            if store_p1_s='1' then
                freq_store_s <= freq_cnt_s;
            end if;
            if clear_p1_s='1' then
                freq_cnt_s <= (others => '0');
            elsif cnt_active_p1_s='1' then
                freq_cnt_s <= freq_cnt_s + '1';
            end if;
        end if;
    end process;

0 Kudos
Reply
1 Solution

Accepted Solutions
verse
Visitor
Visitor
1,337 Views
Registered: ‎06-19-2018

Problem solved. Confirm PLLs are ok.

 

The bug was - as so often- a copy paste error.

As mentionend before the design has more than one pll and uses a self resetting state machine if the pll looses lock.

So pll reset is set at startup and when pll looses lock - this is a freerunning counter, that reset the pll periodically until lock is active again.

By copy-paste this machine for the second pll the lines watching pll-locked of second pll were not renamed and so pll-lock wasn't observed. The states of the signals pll2_locked_p1_s and pll2_locked_p2_s were undefined.

 

Thanks for help,

sometimes we just need a hint to look somewhere else ....

and yes, the reasons for the bug is 50 cm in front of the monitor.

 

View solution in original post

5 Replies
bruce_karaffa
Scholar
Scholar
1,188 Views
Registered: ‎06-21-2017

Are you waiting for the pll/MMCM to lock before starting both counters?

0 Kudos
Reply
drjohnsmith
Teacher
Teacher
1,173 Views
Registered: ‎07-09-2009

Is this real or simulation ?

 

if real, have you simulated ?

    I'd suggest if you do to shorten the counters to 5ms instead of 5 seconds,

 

Suggest you also look at entering constants as constants, 

   e.g this would read better as a constant

 "00011101110011010110010100000000"

such as 

constant fred = B" "0001_1101_1100_1101_0110_0101_0000_0000";  

 

As for the problem ,

 

I'd be very surprised if the PLL is loosing clocks.

 

I only have a small screen here, so looking at the code is difficult,

   I hmaving difficulty working out how you have the two clocks connected , the state machine and the fifo

      can you do a simple block diagram for us ?

 

<== If this was helpful, please feel free to give Kudos, and close if it answers your question ==>
0 Kudos
Reply
verse
Visitor
Visitor
1,123 Views
Registered: ‎06-19-2018

Some news from the front.

I have extracted my code and set up a simple project with jhust the counters and a PLL.

Result is PLL is ok, counters are the same.

In my bigger project with the same clocks and PLL the counters differ from each other - i try to find out other reasons for it.

I'm sure the PLL is locked, but i will check it. Maybe i have a problem with a glitch on the pll-reset line or something like that.

 

 

Concerning the question to the state machine - this is quite easy.

The state machine starts in idle and goes to clear the reference counter is cleared. The slave counter gets clear_p1_s and clears the counter.

State machine waits for clear_p2_s to be shure slave counter is cleared, then moves on to run - reference counter counts to 500000000 and slave counter does also because of cnt_active_p1_flag.

State mschine moves to store and stores counter value and set store_s.

Slave counter sees store_p1_s and stops counting and stores the slave counter.

State machine wait for Handshake store_p2_s to be shure both counters are stored. The restarts from idle.

 

0 Kudos
Reply
verse
Visitor
Visitor
1,338 Views
Registered: ‎06-19-2018

Problem solved. Confirm PLLs are ok.

 

The bug was - as so often- a copy paste error.

As mentionend before the design has more than one pll and uses a self resetting state machine if the pll looses lock.

So pll reset is set at startup and when pll looses lock - this is a freerunning counter, that reset the pll periodically until lock is active again.

By copy-paste this machine for the second pll the lines watching pll-locked of second pll were not renamed and so pll-lock wasn't observed. The states of the signals pll2_locked_p1_s and pll2_locked_p2_s were undefined.

 

Thanks for help,

sometimes we just need a hint to look somewhere else ....

and yes, the reasons for the bug is 50 cm in front of the monitor.

 

View solution in original post

drjohnsmith
Teacher
Teacher
1,112 Views
Registered: ‎07-09-2009

 

Oh I've been there so often , 

well done for comming back

 

 

and good luck

<== If this was helpful, please feel free to give Kudos, and close if it answers your question ==>
0 Kudos
Reply