Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

[FPGA] [VHDL] CLK Divide with sync

Status
Not open for further replies.

stewij

Newbie level 5
Joined
Dec 1, 2006
Messages
10
Helped
0
Reputation
0
Reaction score
0
Trophy points
1,281
Activity points
1,363
error (10344): vhdl

Hello all,

I am looking for a solution for my problem.

I have 2 inputs, CLK_IN and SYNC, and 1 output, CLK_OUT
What I want is a clockdivider with a variable divide.

My CLK_IN is 24 MHz
My SYNC is between 1 and 200 Hz

My CLK_OUT must give 4096 pulses between 2 rising edges of the SYNC signal. So maybe someone can help me with that. This is what I already created but doesn't seem to work.

Thanks in advance

Stefan Wijdeven


Code:
LIBRARY IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

ENTITY DIVIDER IS
	PORT(
		CLK_IN	: IN std_logic;
		SYNC	: IN std_logic;
		CLK_OUT	: OUT std_logic

	);
END DIVIDER;

--  START DIVIDER
ARCHITECTURE RTL of DIVIDER is

signal i : integer range 0 to 24000000;	-- 25 bit
signal j : integer range 0 to 5860;	-- max divide at 1 hz
signal k : integer range 0 to 5860;

begin

	process(CLK_IN) begin	
		if rising_edge(CLK_IN) then
			i <= i +1;
		end if;
	end process;			

	process(CLK_IN, SYNC) begin	
		if rising_edge(SYNC) then
			j <= i / 4096;
								-- RESET i
			
		end if;
	end process;
	
	process(CLK_IN) begin
		if rising_edge(CLK_REF) then
			if k = 0 then
				CLK_OUT <= '1';
				k <= j;
								-- RESET j 
			else
				CLK_OUT <= '0';
				k <= k -1;
			end if;
		end if;
	end process;
	
end RTL;
 

stewij

Newbie level 5
Joined
Dec 1, 2006
Messages
10
Helped
0
Reputation
0
Reaction score
0
Trophy points
1,281
Activity points
1,363
good sync clk

Anyone? I want to continue on my project but this little feature needs to be made.
 

nand_gates

Advanced Member level 3
Joined
Jul 19, 2004
Messages
892
Helped
175
Reputation
350
Reaction score
51
Trophy points
1,308
Activity points
6,830
clock sync vhdl

Here is my solution to ur problem.
At least one cycle of sync should be done befor this circuit generates
4096 pulsese at clk_out.
Hope this helps!

Code:
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;

entity divider is
   port(
      clk_in  : in std_logic;
      rstn     : in std_logic;
      sync    : in std_logic;
      clk_out : out std_logic

   );
end divider;

--  start divider
architecture rtl of divider is
  signal period_counter : std_logic_vector(24 downto 0);  -- 25 bit counter to
                                                          -- measure sync period
  signal count_latch : std_logic_vector(11 downto 0);
  signal clock_out_cnt : std_logic_vector(11 downto 0);
  signal sync_r, sync_rr : std_logic;
  signal clock_out_cnt_zero : std_logic;
  signal sync_rising, sync_rising_r : std_logic;
  signal clk_out_int : std_logic;
begin
  clock_out_cnt_zero <= not  (clock_out_cnt(11) or clock_out_cnt(10) or clock_out_cnt(9)
                        or clock_out_cnt(8) or clock_out_cnt(7)  or clock_out_cnt(6)
                        or clock_out_cnt(5) or clock_out_cnt(4)  or clock_out_cnt(3)
                        or clock_out_cnt(2) or clock_out_cnt(1)  or clock_out_cnt(0));
  sync_rising_r <= (not sync_rr) and sync_r;
  sync_rising   <= (not sync_r) and sync; 
  clk_out <= clk_out_int;
  process (clk_in, rstn)
  begin  -- process  
    if rstn = '0' then               -- asynchronous reset (active low)
      sync_r <= '0';
      sync_rr <= '0';
    elsif clk_in'event and clk_in = '1' then  -- rising clock edge
      sync_r <= sync;
      sync_rr <= sync_r;
    end if;
  end process  ;

  period_counting: process (clk_in, rstn)
  begin  -- process period_counting
    if rstn = '0' then                  -- asynchronous reset (active low)
      period_counter <= (others => '0');
    elsif clk_in'event and clk_in = '1' then  -- rising clock edge
      if sync_rising_r = '1' then
        period_counter <= (others => '0');
      else
        period_counter <= period_counter + 1;
      end if;
    end if;
  end process period_counting;

  process (clk_in, rstn)
  begin  -- process
    if rstn = '0' then                  -- asynchronous reset (active low)
      clk_out_int <= '0';
      count_latch <= (others => '0');
      clock_out_cnt <= (others => '0'); 
    elsif clk_in'event and clk_in = '1' then  -- rising clock edge
      if sync_rising = '1'then
        count_latch <= period_counter(24 downto 13);
      end if;
      if clock_out_cnt_zero = '1' then
        clk_out_int <= not clk_out_int;
        clock_out_cnt <= count_latch;
      else
        clock_out_cnt <= clock_out_cnt - 1;
      end if;
    end if;
  end process;
end rtl;
 

    stewij

    Points: 2
    Helpful Answer Positive Rating

stewij

Newbie level 5
Joined
Dec 1, 2006
Messages
10
Helped
0
Reputation
0
Reaction score
0
Trophy points
1,281
Activity points
1,363
clk divide by 3

nand_gates said:
Here is my solution to ur problem.
At least one cycle of sync should be done befor this circuit generates
4096 pulsese at clk_out.
Hope this helps!
I will try this when I am at home. If it works I will be the happiest men on earth. I am tryin it for almost a week but can't get it fixed.

THANKS!!!!
 

stewij

Newbie level 5
Joined
Dec 1, 2006
Messages
10
Helped
0
Reputation
0
Reaction score
0
Trophy points
1,281
Activity points
1,363
syncing two clocks vhdl

Well it seems to work but I have a small problem.

The accuracy of the clk_out isn't stable. For example, at a sync freq of 10 hz the output generates 4095 pulses pro sync, Acceptable because we only mis one single pulse. But at a sync freq of 100 hz the output generates 4000 pulses pro sync which should be 4096. The difference is 96 pulses what is too much.

Is there any posible solution for this problem? THX in advance
 

nand_gates

Advanced Member level 3
Joined
Jul 19, 2004
Messages
892
Helped
175
Reputation
350
Reaction score
51
Trophy points
1,308
Activity points
6,830
vhdl counter sync

Little correction in the code!
But the problem you said is still there. This is because of truncation error.
To generate 4096 pulses I divdide the sync period count by 8192 and use
the trucated result to generate clk_out. You can make it more accurate by
using some kind of a lookup table for truncation. Hope you understand what
I say.
Code:
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;

entity divider is
   port(
      clk_in  : in std_logic;
      rstn     : in std_logic;
      sync    : in std_logic;
      clk_out : out std_logic

   );
end divider;

--  start divider
architecture rtl of divider is
  signal period_counter : std_logic_vector(24 downto 0);  -- 25 bit counter to
                                                          -- measure sync period
  signal count_latch : std_logic_vector(11 downto 0);
  signal clock_out_cnt : std_logic_vector(11 downto 0);
  signal sync_r, sync_rr : std_logic;
  signal clock_out_cnt_zero : std_logic;
  signal sync_rising : std_logic;
  signal clk_out_int : std_logic;
begin
  clock_out_cnt_zero <= not  (clock_out_cnt(11) or clock_out_cnt(10) or clock_out_cnt(9)
                        or clock_out_cnt(8) or clock_out_cnt(7)  or clock_out_cnt(6)
                        or clock_out_cnt(5) or clock_out_cnt(4)  or clock_out_cnt(3)
                        or clock_out_cnt(2) or clock_out_cnt(1)  or clock_out_cnt(0));
  sync_rising   <= (not sync_rr) and sync_r; 
  clk_out <= clk_out_int;
  process (clk_in, rstn)
  begin  -- process  
    if rstn = '0' then               -- asynchronous reset (active low)
      sync_r <= '0';
      sync_rr <= '0';
    elsif clk_in'event and clk_in = '1' then  -- rising clock edge
      sync_r <= sync;
      sync_rr <= sync_r;
    end if;
  end process  ;

  period_counting: process (clk_in, rstn)
  begin  -- process period_counting
    if rstn = '0' then                  -- asynchronous reset (active low)
      period_counter <= (others => '0');
    elsif clk_in'event and clk_in = '1' then  -- rising clock edge
      if sync_rising = '1' then
        period_counter <= (others => '0');
      else
        period_counter <= period_counter + 1;
      end if;
    end if;
  end process period_counting;

  process (clk_in, rstn)
  begin  -- process
    if rstn = '0' then                  -- asynchronous reset (active low)
      clk_out_int <= '0';
      count_latch <= (others => '0');
      clock_out_cnt <= (others => '0'); 
    elsif clk_in'event and clk_in = '1' then  -- rising clock edge
      if sync_rising = '1'then
        count_latch <= period_counter(24 downto 13);
      end if;
      if clock_out_cnt_zero = '1' then
        clk_out_int <= not clk_out_int;
        clock_out_cnt <= count_latch;
      else
        clock_out_cnt <= clock_out_cnt - 1;
      end if;
    end if;
  end process;
end rtl;
 

    stewij

    Points: 2
    Helpful Answer Positive Rating

stewij

Newbie level 5
Joined
Dec 1, 2006
Messages
10
Helped
0
Reputation
0
Reaction score
0
Trophy points
1,281
Activity points
1,363
vhdl synchronization of input signals

Well the modification u made by editing sync_rising_r -> sync_rising wasn't successful. Sometimes the output stops generating output pulses, lets say once a second. So I changed it back to sync_rising_r which seems to work better.

I don't really understand what you mean by using a lookup table. Maybe you could give a small example so I can understand what you mean.
 

nand_gates

Advanced Member level 3
Joined
Jul 19, 2004
Messages
892
Helped
175
Reputation
350
Reaction score
51
Trophy points
1,308
Activity points
6,830
vhdl sync detection

Consider the case for sync = 100hz
Period_count = 240000
latch_count = 29
clock_out pulses = 4007/4006 instead of 4096 misssing 89/90 pulses.
Here to increase clock_out pulses we can map 29 to 28
With this correction clock_out pulses = 4145 here 49 pulses more.

This is also not a good solution!
 

echo47

Advanced Member level 5
Joined
Apr 7, 2002
Messages
3,942
Helped
638
Reputation
1,274
Reaction score
89
Trophy points
1,328
Location
USA
Activity points
33,176
synchronizing two identical fpga

I don't speak VHDL, but maybe you can use this Verilog. It measures the frequency of SYNC by counting the period between the last two rising edges, and then outputs a (slightly jittery) square wave at "ratio" times that frequency. It's a frequency lock, not a phase lock.
Code:
module top (CLK_IN, SYNC, CLK_OUT);
  parameter         ratio = 4096;    // output/input frequency ratio
  input             CLK_IN, SYNC;
  reg         [2:0] qsync = 0;       // anti-metastability shift register
  reg               sync_edge = 0;   // detect rising edge of SYNC
  reg        [25:0] count = 0;       // measure SYNC period
  reg signed [25:0] sync_period = 0; // measured SYNC period
  reg signed [25:0] rate_count = 0;  // output rate accumulator
  output reg        CLK_OUT = 0;

  always @ (posedge CLK_IN) begin
    qsync <= {qsync,SYNC};
    sync_edge <= ~qsync[2] & qsync[1];
    count <= sync_edge ? 1 : count + 1;
    sync_period <= sync_edge ? count : sync_period;
    if (rate_count >= sync_period) begin
      rate_count <= rate_count + ratio * 2 - sync_period;
      CLK_OUT <= ~CLK_OUT;
    end else
      rate_count <= rate_count + ratio * 2;
  end
endmodule
 

    stewij

    Points: 2
    Helpful Answer Positive Rating

nand_gates

Advanced Member level 3
Joined
Jul 19, 2004
Messages
892
Helped
175
Reputation
350
Reaction score
51
Trophy points
1,308
Activity points
6,830
25m hz to 1hz counter vhdl

Little improved code. Here instead of 8192 I am dividing by 4096.

Code:
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;

entity divider is
   port(
      clk_in  : in std_logic;
      rstn     : in std_logic;
      sync    : in std_logic;
      clk_out : out std_logic

   );
end divider;

--  start divider
architecture rtl of divider is
  signal period_counter : std_logic_vector(24 downto 0);  -- 25 bit counter to
                                                          -- measure sync period
  signal count_latch : std_logic_vector(12 downto 0);
  signal clock_out_cnt : std_logic_vector(12 downto 0);
  signal sync_r, sync_rr : std_logic;
  signal clock_out_cnt_zero : std_logic;
  signal sync_rising : std_logic;
  signal clk_out_int : std_logic;
begin
  clock_out_cnt_zero <= not  (clock_out_cnt(11) or clock_out_cnt(10) or clock_out_cnt(9)
                        or clock_out_cnt(8) or clock_out_cnt(7)  or clock_out_cnt(6)
                        or clock_out_cnt(5) or clock_out_cnt(4)  or clock_out_cnt(3)
                        or clock_out_cnt(2) or clock_out_cnt(1)  or clock_out_cnt(0));
  sync_rising   <= (not sync_rr) and sync_r; 
  clk_out <= clk_out_int;
  process (clk_in, rstn)
  begin  -- process  
    if rstn = '0' then               -- asynchronous reset (active low)
      sync_r <= '0';
      sync_rr <= '0';
    elsif clk_in'event and clk_in = '1' then  -- rising clock edge
      sync_r <= sync;
      sync_rr <= sync_r;
    end if;
  end process  ;

  period_counting: process (clk_in, rstn)
  begin  -- process period_counting
    if rstn = '0' then                  -- asynchronous reset (active low)
      period_counter <= (others => '0');
    elsif clk_in'event and clk_in = '1' then  -- rising clock edge
      if sync_rising = '1' then
        period_counter <= (others => '0');
      else
        period_counter <= period_counter + 1;
      end if;
    end if;
  end process period_counting;

  process (clk_in, rstn)
  begin  -- process
    if rstn = '0' then                  -- asynchronous reset (active low)
      clk_out_int <= '0';
      count_latch <= (others => '0');
      clock_out_cnt <= (others => '0'); 
    elsif clk_in'event and clk_in = '1' then  -- rising clock edge
      if sync_rising = '1'then
        count_latch <= period_counter(24 downto 12);
      end if;
      if clock_out_cnt_zero = '1' then
        clock_out_cnt <= count_latch;
      else
        clock_out_cnt <= clock_out_cnt - 1;
      end if;
      if clock_out_cnt_zero = '1' or clock_out_cnt = ('0'&count_latch(12 downto 1))  then      
        clk_out_int <= not clk_out_int;
      end if;
    end if;
  end process;
end rtl;
 

    stewij

    Points: 2
    Helpful Answer Positive Rating

stewij

Newbie level 5
Joined
Dec 1, 2006
Messages
10
Helped
0
Reputation
0
Reaction score
0
Trophy points
1,281
Activity points
1,363
vhdl expression error

echo47 said:
I don't speak VHDL, but maybe you can use this Verilog. It measures the frequency of SYNC by counting the period between the last two rising edges, and then outputs a (slightly jittery) square wave at "ratio" times that frequency. It's a frequency lock, not a phase lock.
This works very well, the only problem I have is that I use a EPM570 CPLD from altera which has only 570 Logic Elements, your solution uses almost twice as much LE's as the solution that nand_gates found. It works much better but I dont have enough free LE's to use your solution in my architecture.

nand_gates said:
Little improved code. Here instead of 8192 I am dividing by 4096.
The accuracy improved but maybe dividing by 1024 makes it even better and I should have enough LE's to do that. So my last question is to make a version that divides through 1024.
 

stewij

Newbie level 5
Joined
Dec 1, 2006
Messages
10
Helped
0
Reputation
0
Reaction score
0
Trophy points
1,281
Activity points
1,363
vhdl sync two clocks

Well I updated the code so it uses the remainder of the divide. The only problem I have now is the following:

Error (10344): VHDL expression error at Clockdevider.vhd(69): expression has 13 elements, but must have 12 elements

This is line 69:
CNT_REST <= CNT_REST - (CNT_LATCH + 1);

Code:
LIBRARY IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;


ENTITY DIVIDER IS 
   PORT( 
      CLK_IN  : IN std_logic; 
      RESET   : IN std_logic; 
      SYNC    : IN std_logic; 
      CLK_OUT : OUT std_logic 

   ); 
END DIVIDER; 

--  start divider 

ARCHITECTURE RTL of DIVIDER is 

  SIGNAL period_counter : std_logic_vector(24 downto 0);  -- 25 bit counter to measure SYNC period
  SIGNAL CNT_LATCH : std_logic_vector(12 downto 0); 
  SIGNAL CLK_OUT_CNT : std_logic_vector(12 downto 0); 
  SIGNAL SYNC_r, SYNC_rr : std_logic; 
  SIGNAL CLK_OUT_CNT_ZERO : std_logic; 
  SIGNAL SYNC_rising, SYNC_rising_r : std_logic; 
  SIGNAL CLK_OUT_int : std_logic;
  SIGNAL CNT_REST : std_logic_vector(11 downto 0);
  SIGNAL USE_REST : std_logic;
 
begin 
  CLK_OUT_CNT_ZERO <= not (CLK_OUT_CNT(11) or CLK_OUT_CNT(10) or CLK_OUT_CNT(9) or CLK_OUT_CNT(8) or CLK_OUT_CNT(7)  or CLK_OUT_CNT(6) or CLK_OUT_CNT(5) or CLK_OUT_CNT(4)  or CLK_OUT_CNT(3) or CLK_OUT_CNT(2) or CLK_OUT_CNT(1)  or CLK_OUT_CNT(0)); 
  SYNC_rising_r <= (not SYNC_rr) and SYNC_r; 
  SYNC_rising   <= (not SYNC_r) and SYNC; 
  CLK_OUT <= CLK_OUT_int; 

	process (CLK_IN, RESET) begin  -- process  
    	if RESET = '1' then                
      			SYNC_r <= '0'; 
     			SYNC_rr <= '0'; 
	    elsif CLK_IN'event and CLK_IN = '1' then  -- rising clock edge 
				SYNC_r <= SYNC; 
				SYNC_rr <= SYNC_r; 
   		end if; 
	end process; 

	process (CLK_IN, RESET) begin  -- process period_counting 
		if RESET = '1' then                   
				period_counter <= (others => '0'); 
		elsif CLK_IN'event and CLK_IN = '1' then  -- rising clock edge 
      		if SYNC_rising_r = '1' then 
        			period_counter <= (others => '0'); 
      		else 
        			period_counter <= period_counter + 1; 
      		end if; 
    	end if; 
	end process; 

	process (CLK_IN, RESET) begin  -- process 
		if RESET = '1' then                   
				CLK_OUT_int <= '0'; 
				CNT_LATCH <= (others => '0'); 
				CLK_OUT_CNT <= (others => '0'); 
		elsif CLK_IN'event and CLK_IN = '1' then  -- rising clock edge 
			if SYNC_rising = '1' then 
					CNT_LATCH <= period_counter(24 downto 12);
					CNT_REST <= period_counter(11 downto 0); 
			elsif CLK_OUT_CNT_ZERO = '1' then 
				if CNT_REST >= (CNT_LATCH + 1) then
						CNT_REST <= CNT_REST - (CNT_LATCH + 1);
						USE_REST <= '1';
				else
						USE_REST <= '0';
				end if;	
			end if;
			if CLK_OUT_CNT_ZERO = '1' then 
        			CLK_OUT_CNT <= (CNT_LATCH + USE_REST); 
      		else 
      	  			CLK_OUT_CNT <= CLK_OUT_CNT - 1; 
      		end if; 
			if CLK_OUT_CNT_ZERO = '1' or CLK_OUT_CNT = ('0'&CNT_LATCH(12 downto 1)) then      
        			CLK_OUT_int <= not CLK_OUT_int; 
      		end if;
    	end if; 
	end process; 
end rtl;
 

stewij

Newbie level 5
Joined
Dec 1, 2006
Messages
10
Helped
0
Reputation
0
Reaction score
0
Trophy points
1,281
Activity points
1,363
xilinx expression has elements

Does anyone have a clue? I was thinking of using a variable or something
 

echo47

Advanced Member level 5
Joined
Apr 7, 2002
Messages
3,942
Helped
638
Reputation
1,274
Reaction score
89
Trophy points
1,328
Location
USA
Activity points
33,176
entity divider

If you add more arithmetic to your VHDL to improve its behavior, the number of logic elements will certainly grow. But try it and see! You may find a more efficient solution than my Verilog.

I can't think of any way to significantly simplify my Verilog module. Rearranging the arithmetic expressions may help Quartus optimize it better. (That sometimes happens with the Xilinx XST synthesizer.) Unfortunately, I don't have Quartus to try such experiments.

I'm looking back at your original message ... You never said that the output frequency needs to be 4096 times the input frequency. I assumed you needed a frequency multiplier, but is that correct? Would it be acceptable to simply generate a burst of 4096 high-speed pulses after each input pulse?
 

stewij

Newbie level 5
Joined
Dec 1, 2006
Messages
10
Helped
0
Reputation
0
Reaction score
0
Trophy points
1,281
Activity points
1,363
counter sync to clk

echo47 said:
If you add more arithmetic to your VHDL to improve its behavior, the number of logic elements will certainly grow. But try it and see! You may find a more efficient solution than my Verilog.

I can't think of any way to significantly simplify my Verilog module. Rearranging the arithmetic expressions may help qu(at)rtus optimize it better. (That sometimes happens with the Xilinx XST synthesizer.) Unfortunately, I don't have qu(at)rtus to try such experiments.

I'm looking back at your original message ... You never said that the output frequency needs to be 4096 times the input frequency. I assumed you needed a frequency multiplier, but is that correct? Would it be acceptable to simply generate a burst of 4096 high-speed pulses after each input pulse?
Well currently I am using the principe of your verilogfile into my own VHDL file because your solution is technicaly very good. The only problem I had was that it took me 1 full day to understand the exact working of your verilog file. But after that I realised that your solution is the best I can imagine. So I started rewriting your verilog file to a VHDL solution. And will try to save some LE's by dividing the input through 16 before I use the signal. I have also had a better specification of the SYNC signal, it will be between 40 and 120hz. The only thing thats important right now is that the output gives 4096 +- 1 pulses between the sync, the glitches aren't really a problem.
 

echo47

Advanced Member level 5
Joined
Apr 7, 2002
Messages
3,942
Helped
638
Reputation
1,274
Reaction score
89
Trophy points
1,328
Location
USA
Activity points
33,176
puls synchronisation vhdl

Hi stewij, If you simply translate my example from Verilog into VHDL, the synthesis results will probably be almost identical.

Many synthesis tools accept both Verilog and VHDL files in the same project, so you may not need to translate the Verilog just to try it. I can use your VHDL file in my Verilog environment. Both ModelSim and Xilinx XST are happy.

If your minimum input is 40 Hz instead of 1 Hz, then you can shorten all the registers in my example by 5 bits. That's a significant savings, but not a huge savings.

Just double-checking your requirements ... You requested "4096 pulses between 2 rising edges", but do you really need the output pulse frequency to be 4096 times the input pulse frequency? I think your answer will be "yes", however if you only need 4096 pulses and don't care about their frequency, then you don't need a fancy frequency multiplier. Here is simple module that generates a burst of 4096 pulses at 12 MHz (adjustable via 'xbits'). Sorry about the Verilog again!
Code:
module top (CLK_IN, SYNC, CLK_OUT);
  parameter         xbits = 0;      // more bits reduces the burst frequency
  input             CLK_IN, SYNC;
  reg         [1:0] qsync = 0;      // anti-metastability shift register
  reg               sync_edge = 0;  // detect rising edge of SYNC
  reg  [12+xbits:0] count = 0;
  output            CLK_OUT;        // a burst of 4096 pulses

  assign CLK_OUT = count[xbits];

  always @ (posedge CLK_IN) begin
    qsync <= {qsync,SYNC};
    sync_edge <= ~qsync[1] & qsync[0];
    count <= count ? count + 1 : count + sync_edge;
  end
endmodule
 

nand_gates

Advanced Member level 3
Joined
Jul 19, 2004
Messages
892
Helped
175
Reputation
350
Reaction score
51
Trophy points
1,308
Activity points
6,830
vhdl processes sync

Here goes the VHDL translation for echo47's code!

Code:
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;

entity sync is
generic (
  xbits : integer := 0);
  port (
    CLK_IN  : in  std_logic;
    SYNC    : in  std_logic;
    CLK_OUT : out std_logic);

end sync;
architecture behave of sync is
  signal qsync : std_logic_vector(1 downto 0) := "00";      -- anti-metastability shift register
  signal sync_edge : std_logic := '0';  -- detect rising edge of SYNC
  signal count : std_logic_vector(12+xbits downto 0) := (others => '0');
  constant count_zero : std_logic_vector(12+xbits downto 0) := (others=>'0');
begin  -- behave

process (CLK_IN)
  begin  -- process
    if CLK_IN'event and CLK_IN = '1' then  -- rising clock edge
      qsync <= qsync(0)&SYNC;
      sync_edge <= not qsync(1) and qsync(0);
      if (count /= count_zero) then
        count <= count + 1;  
      else
        count <= count + sync_edge;
      end if;
    end if;
  end process;
end behave;
 

stewij

Newbie level 5
Joined
Dec 1, 2006
Messages
10
Helped
0
Reputation
0
Reaction score
0
Trophy points
1,281
Activity points
1,363
vhdl for sync and counter

I decide to make a timing diagram, because 1 picture says more than 1000 words. The division isn't on scale but you will understand it.

https://images.elektroda.net/72_1166085231.JPG

What I said about the glitches, I tryed to tell the following about the CLK_OUT:

https://images.elektroda.net/95_1166086209.JPG

Ideal should be a 50% dutycycled CLK_OUT with 4096 pulses between the SYNC edges, but this will cost me a lot of LE's. So the second line is also usable.

The last solution isn't usable because it isn't spread evently, a little variation is no problem but just connecting the input 4096 times to the output and than waiting for next sync edge is unusable.

This is the code I am using currenty, based on the first Verilog version.
Code:
LIBRARY IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;


ENTITY DIVIDER IS 
   PORT( 
      CLK_IN  : IN std_logic; 
      RESET   : IN std_logic; 
      SYNC    : IN std_logic; 
      CLK_OUT : OUT std_logic 

   ); 
END DIVIDER; 

--  start divider 

ARCHITECTURE RTL of DIVIDER is 

  SIGNAL qsync			: std_logic_vector(2 downto 0);		-- anti-metastability shift register 
  SIGNAL sync_edge		: std_logic;						-- detect rising edge of SYNC
  SIGNAL count			: std_logic_vector(24 downto 0);	-- 25 bit counter to measure SYNC period
  SIGNAL sync_period	: std_logic_vector(24 downto 0);	-- 25 bit memory for measured SYNC period
  SIGNAL rate_count		: std_logic_vector(24 downto 0);	-- output rate accumulator
  SIGNAL CLK_OUT_int	: std_logic;

begin 
	CLK_OUT <= CLK_OUT_int;
	process (CLK_IN, RESET) begin  -- process  
    	if RESET = '1' then      
          		qsync <= (others => '0');
				sync_edge <= '0';
				count <= (others => '0');
				sync_period <= (others => '0');
				rate_count <= (others => '0');
				CLK_OUT_int <= '0';
		elsif CLK_IN'event and CLK_IN = '1' then  -- rising clock edge 
				qsync(0) <= SYNC;
				qsync(1) <= qsync(0);
				qsync(2) <= qsync(1);
				sync_edge <= (not qsync(2)) and qsync(1);
			if sync_edge = '1' then
					sync_period <= count;
					count <= (others => '0');
			else
					count <= count + '1';
			end if;
			if rate_count >= sync_period then
					rate_count <= rate_count + 8192 - sync_period;
					CLK_OUT_int <= not CLK_OUT_int;
			else
					rate_count <= rate_count + 8192;
			end if;
		end if; 
	end process; 
end rtl;

What I find the most amazing is the willing of you 2, to help me at this forum, THUMBS UP
 

dsp_

Member level 3
Joined
Mar 2, 2002
Messages
58
Helped
3
Reputation
6
Reaction score
0
Trophy points
1,286
Location
right here ... right now ...
Activity points
525
anti jitter vhdl

Hi,
I picked up the idea and started from the beginning.
It's possible to split up the counter, so you need only 1 instead of 2, saving about half the registers.
I'm surprised by it's simplicity ;)

Code:
module lock(CLK_IN, SYNC, CLK_OUT);
	 parameter delta = 2;
	 parameter lb_ratio = 12; //2**12 = 4096
	 parameter lb_reso = 20; //25 Mhz/40 Hz = 625E3 , lb(625E3) = 19,25-> 2**20
	 parameter lb_cnt = lb_reso - lb_ratio;
	 parameter cnt_init = 10;
    input CLK_IN;
    input SYNC;
    output reg CLK_OUT = 0;
	
	reg [lb_cnt-2:0] cnt = cnt_init;
	reg [lb_cnt-2:0] cnt_load = cnt_init; //clocks per toggle //25/40 * 10**6 / (2*ratio);
	reg [lb_ratio:0] r_cnt = 0;	//output half-clocks(toggle) per sync (set for fractional frequency)
	reg [1:0] qsync = 0;
	reg sync_flag=0;
		
	always @(posedge CLK_IN)
		begin
			qsync <= {qsync,SYNC};
			if(~qsync[1] & qsync[0]) sync_flag =1;
			cnt = cnt - 1;
			if(!cnt)
			begin
				CLK_OUT = ~CLK_OUT;
				cnt = cnt_load;
				r_cnt = r_cnt - 1;
				if(!r_cnt || sync_flag)
				begin
					cnt_load = !(r_cnt) ? cnt_load + delta : cnt_load - delta;
					sync_flag = 0;
				end
			end
		end

endmodule
It has a fixed slew rate which could limit it's usefulness, depending on how fast your sync changes.
One problem persists, in that way that when sync gets slower you miss a few pulses.
You could set the output frequency a little higher and blank out the last ones.
Although this requires you to count the output clocks.
Making it a hybrid of the frequency multiplier and the burst solution.

HTH
dsp_
 

    stewij

    Points: 2
    Helpful Answer Positive Rating

echo47

Advanced Member level 5
Joined
Apr 7, 2002
Messages
3,942
Helped
638
Reputation
1,274
Reaction score
89
Trophy points
1,328
Location
USA
Activity points
33,176
anti-jitter vhdl

dsp_'s technique gradually locks to the input SYNC period, and then outputs 4096 CLK_OUT pulses between SYNCs. The loop basically toggles between two coarse frequencies, and finely adjusts the frequency switch time so the overall result is 4096 pulses. The first portion of the 4096 output pulses has a frequency that is somewhat too high, the last portion has a frequency that is somewhat too low. If you don't mind the large frequency jitter, then this is a significantly smaller solution than mine.

Here's an oscilloscope display showing both designs running in a Spartan-3E (clocked at 25MHz not 24MHz) with approximately 100 Hz SYNC input. The yellow trace is mine.

Oh no! I forgot to tell my scope that Daylight Saving Time has ended.
 

Status
Not open for further replies.

Similar threads

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Top