dmm
dmm

Reputation: 109

Synthesis error in VHDL clock synchronizer

I am trying to implement clock synchronization and clock divider in the following piece of VHDL code. The clocks(clk_rx and clk_tx) should synchronize at the rising and falling edges of 'RX' signal on the bus. I can simulate the following but it is not synthesizable in ISE since i am using " RX'EVENT ". Could any one suggest an alternative for this? (Verilog also will work)

-------------------------------------------- CLOCK DIVIDER----------------------------------------------------------------------------------------

PROCESS (CLK_I, RX)
BEGIN
   IF (RX'EVENT) THEN
      clk_cnt <= to_unsigned(0,clk_cnt'LENGTH);  
   ELSIF (CLK_I'EVENT AND CLK_I = '1') THEN
       IF clk_cnt >2499 THEN
         clk_cnt <= to_unsigned(0,clk_cnt'LENGTH); 
      ELSE  
         clk_cnt <= clk_cnt + 1;    
       END IF;
   END IF;
END PROCESS;


clk_rx <= '1' WHEN  clk_cnt = 1250 ELSE '0';  -----clk_rx=1 only at the half of the counter period----------clk enable
clk_tx <= '1' WHEN  clk_cnt = 2499 ELSE '0';

Upvotes: 0

Views: 1498

Answers (4)

dmm
dmm

Reputation: 109

Thank you very much for your support.

I modified the code as @Joe and @MortenZdk suggested. Now I am able to synthesize it. I have to detect both posedge and negedge of "RX". So I changed the code as follows:

PROCESS(CLK_I)  -- Stabilizing the RX signal to avoid meta stable state
begin
  if rising_edge(CLK_I) then    
    rx_meta <= RX; 
    rx_sync <= rx_meta;      
  end if;
END PROCESS;

PROCESS (CLK_I)
BEGIN              
   IF (CLK_I'EVENT AND CLK_I = '1') THEN
     tmp_RX <= rx_sync;
     IF (rx_sync /= tmp_RX) THEN
       clk_cnt <= to_unsigned(0,clk_cnt'LENGTH);  
     ELSE
       IF clk_cnt >2499 THEN
         clk_cnt <= to_unsigned(0,clk_cnt'LENGTH); 
       ELSE  
         clk_cnt <= clk_cnt + 1;    
       END IF;
     END IF;
     -- Clock generate as single cycle pulse    
     clk_rx <= '0';
     IF clk_cnt = 1250 THEN
        clk_rx <= '1';
     END IF;
     clk_tx <= '0';
     IF clk_cnt = 2500 THEN
       clk_tx <= '1';
     END IF;

   END IF;
END PROCESS;

Upvotes: 0

Morten Zilmer
Morten Zilmer

Reputation: 15924

You can find a suggestion for code below. Note the following properties:

  • clk_rx_o (clk_rx) and clk_rx_o (clk_tx) are generated as outputs from flip-flops, since to avoid glitches which may occur if the signals are generated based on combinatorial compare of cnt outside the process
  • rx_i is synchronized by two flip-flops, assuming that it is not already synchronous to clk_i
  • Clock division is by 2501, since cnt goes from 0 .. 2500 due to wrap when (cnt > 2499). For division by 2500 use (cnt >= 2499) instead.
  • VHDL coding style: All signal names are lower case, as are VHDL statements, consistent spacing around expressions for readability

Code:

library ieee;
use ieee.std_logic_1164.all;

entity mdl is
  port(
    clk_i    : in  std_logic;
    rx_i     : in  std_logic;
    clk_rx_o : out std_logic;
    clk_tx_o : out std_logic);
end entity;

library ieee;
use ieee.numeric_std.all;

architecture syn of mdl is

  signal rx_meta : std_logic;
  signal rx_sync : std_logic;
  signal cnt     : std_logic_vector(12 - 1 downto 0);

begin

  -- rx_i sync to clk_i
  process (clk_i) is
  begin
    if rising_edge(clk_i) then
      rx_meta <= rx_i;
      rx_sync <= rx_meta;
    end if;
  end process;

  process (clk_i) is
  begin
    if rising_edge(clk_i) then
      -- Clock align and divide
      if rx_sync = '1' then
        cnt <= std_logic_vector(to_unsigned(0, cnt'length));
      else
        if unsigned(cnt) > 2499 then
          cnt <= std_logic_vector(to_unsigned(0, cnt'length));
        else
          cnt <= std_logic_vector(unsigned(cnt) + 1);
        end if;
      end if;
      -- Clock generate as single cycle pulse
      clk_rx_o <= '0';
      if unsigned(cnt) = 1250 then
        clk_rx_o <= '1';
      end if;
      clk_tx_o <= '0';
      if unsigned(cnt) = 2499 then
        clk_tx_o <= '1';
      end if;
    end if;
  end process;

end architecture;

Upvotes: 1

nio
nio

Reputation: 5289

Try this code. There are still no flip flops in my code to solve metastability of RX as @Joe Hass explains.

But there is a scheme for synchronizing the RX signal.

PROCESS (CLK_I, RX)
BEGIN
   IF (CLK_I'EVENT AND CLK_I = '1') THEN
       IF (RX='1') THEN
          clk_cnt <= to_unsigned(0,clk_cnt'LENGTH);  
       ELSE
           IF clk_cnt >2499 THEN
               clk_cnt <= to_unsigned(0,clk_cnt'LENGTH); 
           ELSE  
               clk_cnt <= clk_cnt + 1;    
           END IF;
      END IF;
   END IF;
END PROCESS;

Upvotes: 0

user1619508
user1619508

Reputation:

The problem is not simply that you are using RX'EVENT, it's that you have a CLK_I'EVENT conditional inside an RX'EVENT condition. That's just not synthesizable.

Assuming that CLK_I is much higher frequency than RX'EVENT, try sampling RX using CLK_I. If the previous value of RX is low and the current value is high, then synchronously reset clk_cnt on CLK_I'EVENT. Note that if RX is truly asynchronous to CLK_I you need to worry about metastability and you should add 2 flip-flops to synchronize RX before you look for a change from 0 to 1.

Upvotes: 1

Related Questions