-- file:dpd.vhd ------------------------------------------ -- detects the phase difference -- between two input frequencies. -- The design is From: B. Razavi, -- "Monolithic phase locked loops and -- clock recovery circuits", IEEE press. -- -- -- By Ahmed Allam -- November 1999. -- University of Alberta, EE552. -------------------------------------- -- Compiles with no known -- errors. --------------------------------------- --library ieee; --use ieee.std_logic_1164.all; --use ieee.std_logic_arith.all; ----use ieee.std_logic_unsigned.all; --use ieee.numeric_std.all; -- See http://www.lothar-miller.de/s9y/categories/16-Numeric_Std library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.NUMERIC_STD.ALL; -- -- OSC_in = Oscillator Clock -- PPS1_in = 1PPS signal from GPS -- qa = Clock high -- qb = Clock low -- PPS1_reset - Reset 1pps counter , active low -- PPS1_out - Output 1pps pulse -- entity ph_det is generic ( Osc_freq: natural := 10000000; Cnt_width: natural := 24 ); port ( OSC_in : in std_logic; PPS1_in : in std_logic; PPS1_reset : in std_logic; -- Has week pullup in cpld enabled , and therefore is Active low PPS1_out : out std_logic; qa : out std_logic; qb : out std_logic; qab_xor : out std_logic ); end ph_det ; architecture archtry3 of ph_det is signal set_high, qa_int, qb_int,res,dly :std_logic; signal PPS1_reset_flag :std_logic :='0'; -- https://www.eevblog.com/forum/fpga/derived-clocks-best-practices/msg2909692/#msg2909692 signal cnt : unsigned(Cnt_width-1 downto 0) := (others => '0'); signal cntNext : unsigned(Cnt_width-1 downto 0) := (others => '0'); signal cmp : std_logic := '0'; signal cmpNext : std_logic := '0'; -- -- dly is (hopefully) a delay buffer. Preventing excact a,b inputs to create no output at all -- This should introduce a short delay , before the FF*s are reset. -- -- Attribute used to force the dly to be an inverting buffer, and not be absorbed the the logic block -- See https://www.intel.com/content/www/us/en/programmable/quartushelp/15.0/mergedProjects/hdl/vhdl/vhdl_file_dir_keep.htm -- attribute keep : boolean; attribute keep of dly: signal is true; component d2 port ( inpu_c, d_in,reset:in std_logic ; q_out :buffer std_logic ); end component d2; begin -- 1PPS resync to Osc_in -- PPS1_sync: process(OSC_in,PPS1_reset) -- begin -- if PPS1_reset = '1' then -- PPS1_out <= '0'; -- elsif rising_edge(Osc_in) then -- PPS1_out <= PPS1_flag; -- end if; -- end process PPS1_sync; -- -- -- 1PPS Clock enabler here -- PPS1_reset_flag <= not PPS1_reset when rising_edge(OSC_in); -- Invert PPS1_reset as it is Active low (weak pullup in cpld) cmpNext <= '1' when cnt = OSC_freq-1 else '0'; cntNext <= to_unsigned(0, Cnt_width) when cmpNext='1' else cnt+1; -- Ex1 - 55 LE used --cntNext <= to_unsigned(0, Cnt_width) when (cmpNext='1' or PPS1_reset_flag = '1') else cnt+1; -- Ex2 - 39 LE Used --cntNext <= to_unsigned(0, Cnt_width) when (cmpNext='1' or PPS1_reset = '0') else cnt+1; -- Ex3 - 38 LE Used cnt <= cntNext when rising_edge(OSC_in); cmp <= cmpNext when rising_edge(OSC_in); --pps1_out <= cmp when cmp='1' and rising_edge(OSC_in); pps1_out <= cmp when rising_edge(OSC_in); -- -- PFD Begins here -- set_high <= '1'; d0: d2 port map ( inpu_c => Osc_in, reset => res, d_in => set_high, q_out => qa_int ); d1: d2 port map ( inpu_c => PPS1_in, reset => res, d_in => set_high, q_out => qb_int ); dly <= not (qb_int and qa_int); res <= not dly; --lcell inst1(.in(dly),.out(res)); qa <= qa_int; qb <= qb_int; qab_xor <= qa_int xor qb_int; end archtry3;