Reputation: 109
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
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
Reputation: 15924
You can find a suggestion for code below. Note the following properties:
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
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
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