Commit ae69ccba authored by Peter Jansweijer's avatar Peter Jansweijer

Add even_odd detector. Detect the alignment of 10MHz and 125MHz at the first…

Add even_odd detector. Detect the alignment of 10MHz and 125MHz at the first 10MHz edge after PPS-in. Software reset the LTC6950 when misaligned.
parent 0d9c9fae
Pipeline #394 failed with stages
in 22 minutes and 40 seconds
files = [
"even_odd_det.vhd",
"wr_spec7_pkg.vhd",
"xwrc_board_spec7.vhd",
]
......
-------------------------------------------------------------------------------
-- Title : 10MHz-1PPS even/odd 125 MHz reference clock phase detector
-- Project : WR PTP Core and EMPIR 17IND14 WRITE
-- URL : http://www.ohwr.org/projects/wr-cores/wiki/Wrpc_core
-- : http://empir.npl.co.uk/write/
-------------------------------------------------------------------------------
-- File : even_odd_det.vhd
-- Author(s) : Peter Jansweijer <peterj@nikhef.nl>
-- Company : Nikhef
-- Created : 2020-08-24
-- Last update: 2020-08-24
-- Standard : VHDL'93
-------------------------------------------------------------------------------
-- Description: When a PLL is used to generate 125 MHz from 10 MHz then the PLL
-- can lock on the even or odd 10MHz phase w.r.t. the 1 PPS. This
-- module detects where (even/odd) the lock was achieved.
--
-------------------------------------------------------------------------------
-- Copyright (c) 2020 Nikhef
-------------------------------------------------------------------------------
-- GNU LESSER GENERAL PUBLIC LICENSE
--
-- This source file is free software; you can redistribute it
-- and/or modify it under the terms of the GNU Lesser General
-- Public License as published by the Free Software Foundation;
-- either version 2.1 of the License, or (at your option) any
-- later version.
--
-- This source is distributed in the hope that it will be
-- useful, but WITHOUT ANY WARRANTY; without even the implied
-- warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-- PURPOSE. See the GNU Lesser General Public License for more
-- details.
--
-- You should have received a copy of the GNU Lesser General
-- Public License along with this source; if not, download it
-- from http://www.gnu.org/licenses/lgpl-2.1.html
--
-------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
library work;
use work.gencores_pkg.all;
library unisim;
use unisim.vcomponents.all;
entity even_odd_det is
port (
rst_n_i : in std_logic;
clk_ref_i : in std_logic;
clk_10m_ext_i : in std_logic;
clk_sys_62m5_i : in std_logic;
pps_i : in std_logic;
even_odd_n_o : out std_logic;
enable_sync_i : in std_logic;
sync_done_o : out std_logic;
sync_o : out std_logic
);
end entity even_odd_det;
architecture rtl of even_odd_det is
-----------------------------------------------------------------------------
-- Signals
-----------------------------------------------------------------------------
signal rst : std_logic;
signal clk_10m_ext_pos : std_logic;
signal clk_10m_ext_neg : std_logic;
signal clk_10m_ext_pos_del : std_logic;
signal rising_pps : std_logic;
signal rising_clk_10m : std_logic;
signal arm_clk_10m_det : std_logic;
signal even_odd_n : std_logic;
signal enable_sync : std_logic;
signal enable : std_logic;
signal sync_done : std_logic;
begin -- architecture rtl
rst <= not rst_n_i;
cmp_iddr: IDDR
generic map (
DDR_CLK_EDGE => "SAME_EDGE")
port map (
Q1 => clk_10m_ext_pos,
Q2 => clk_10m_ext_neg,
C => clk_ref_i,
CE => '1',
D => clk_10m_ext_i,
R => rst,
S => '0');
-- If rising_edge clk_10m_ext_i is during clk_ref_i = '1' ("even") then
-- clk_10m_ext_pos and clk_10m_ext_neg are asserted at the same time
-- else ("odd") clk_10m_ext_pos is asserted before clk_10m_ext_neg in.
process (clk_ref_i, rst_n_i)
begin
if (rst_n_i = '0') then
clk_10m_ext_pos_del <= '0';
even_odd_n <= '0';
elsif rising_edge(clk_ref_i) then
clk_10m_ext_pos_del <= clk_10m_ext_pos;
-- detect a rising edge clk_10m_ext_pos (always 1 clk_ref_i tick
-- after the clock tick in which ppsi had a rising edge).
if (clk_10m_ext_pos_del = '0' and clk_10m_ext_pos = '1') then
-- detect simultanious assertion of clk_10m_ext_neg
if clk_10m_ext_neg = '1' then
even_odd_n <= '1';
else
even_odd_n <= '0';
end if;
end if;
end if;
end process;
-- detect rising edge PPS
cmp_pps_rising_edge: gc_sync_ffs
generic map (
g_sync_edge => "positive")
port map (
clk_i => clk_ref_i,
rst_n_i => rst_n_i,
data_i => pps_i,
ppulse_o => rising_pps);
-- detect rising edge clk_10m
cmp_clk_10m_rising_edge: gc_sync_ffs
generic map (
g_sync_edge => "positive")
port map (
clk_i => clk_ref_i,
rst_n_i => rst_n_i,
data_i => clk_10m_ext_i,
ppulse_o => rising_clk_10m);
-----------------------------------------------------------------------------
-- After rising edge PPS wait for first rising edge clk_10m and
-- trigger a sync clk_ref_62m5 divider if enabled.
-----------------------------------------------------------------------------
process (clk_ref_i, rst_n_i)
begin
if rst_n_i = '0' then
arm_clk_10m_det <= '0';
elsif rising_edge(clk_ref_i) then
if rising_pps = '1' then
arm_clk_10m_det <= '1';
elsif arm_clk_10m_det = '1' and rising_clk_10m = '1' then
arm_clk_10m_det <= '0';
end if;
end if;
end process;
-- update even_odd_n and synchronize clk_ref div2 divider if enabled
process (clk_ref_i, rst_n_i)
begin
if rst_n_i = '0' then
even_odd_n_o <= '0';
sync_o <= '0';
elsif rising_edge(clk_ref_i) then
sync_o <= '0';
if arm_clk_10m_det = '1' and rising_clk_10m = '1' then
even_odd_n_o <= even_odd_n;
if enable = '1' then
sync_o <= '1';
end if;
end if;
end if;
end process;
-----------------------------------------------------------------------------
-- sync sequence enable and done
-----------------------------------------------------------------------------
-- synchronize enable_sync_i (clk_sys_62m5_i domain) to clk_ref_i
cmp_sync_ffs_enable_sync_i: gc_sync_ffs
generic map (
g_sync_edge => "positive")
port map (
clk_i => clk_ref_i,
rst_n_i => rst_n_i,
data_i => enable_sync_i,
ppulse_o => enable_sync);
process (clk_ref_i, rst_n_i)
begin
if rst_n_i = '0' then
enable <= '0';
elsif rising_edge(clk_ref_i) then
if enable_sync = '1' then
enable <= '1';
elsif arm_clk_10m_det = '1' and rising_clk_10m = '1' then
enable <= '0';
end if;
end if;
end process;
sync_done <= not enable;
-- synchronize sync_done (clk_10m_ext_i domain) to clk_sys_62m5_i domain
cmp_sync_ffs_sync_done: gc_sync_ffs
generic map (
g_sync_edge => "positive")
port map (
clk_i => clk_sys_62m5_i,
rst_n_i => rst_n_i,
data_i => sync_done,
synced_o => sync_done_o);
end architecture rtl;
......@@ -247,6 +247,7 @@ entity xwrc_board_spec7 is
---------------------------------------------------------------------------
-- Buttons, LEDs and PPS output
---------------------------------------------------------------------------
led_act_o : out std_logic;
led_link_o : out std_logic;
btn1_i : in std_logic := '1';
......@@ -275,6 +276,11 @@ architecture struct of xwrc_board_spec7 is
-- PLLs, clocks
signal clk_ref_62m5 : std_logic := '0';
signal clk_ref_sync : std_logic := '0';
signal sync_enable : std_logic;
signal even_odd_n : std_logic;
signal sync_polarity : std_logic;
signal sync_done : std_logic;
signal sync_clk_ref_62m5 : std_logic;
signal clk_ref_locked : std_logic;
signal clk_sys_62m5 : std_logic;
--signal pll_locked : std_logic;
......@@ -329,9 +335,23 @@ architecture struct of xwrc_board_spec7 is
(c_slave_gpio => x"00000f00"
);
constant c_num_gpio_pins : integer := 13;
constant c_num_gpio_pins : integer := 15;
signal gpio_out, gpio_in, gpio_oen : std_logic_vector(c_num_gpio_pins-1 downto 0);
component even_odd_det is
port (
rst_n_i : in std_logic;
clk_ref_i : in std_logic;
clk_10m_ext_i : in std_logic;
clk_sys_62m5_i : in std_logic;
pps_i : in std_logic;
even_odd_n_o : out std_logic;
enable_sync_i : in std_logic;
sync_done_o : out std_logic;
sync_o : out std_logic
);
end component even_odd_det;
begin -- architecture struct
-----------------------------------------------------------------------------
......@@ -378,14 +398,33 @@ begin -- architecture struct
I => clk_125m_gtx_buf,
O => clk_ref_125m);
clk_ref_sync <= '0';
cmp_even_odd_det: even_odd_det
port map (
rst_n_i => areset_n_i,
clk_ref_i => clk_ref_125m,
clk_10m_ext_i => clk_10m_ext_i,
clk_sys_62m5_i => clk_sys_62m5,
pps_i => pps_ext_i,
even_odd_n_o => even_odd_n,
enable_sync_i => sync_enable,
sync_done_o => sync_done,
sync_o => sync_clk_ref_62m5);
-- PLL sync signal synchronizes the LTC6950 but it waits for the proper
-- 10 MHz cycle before re-enabling the clock. This means that it shifts
-- one 10 Mhz cycle which means that the PPS/10MHz relation to 125 MHz
-- generated clock isn't affected. So the sync signal doesn't have the
-- wanted effect => so don't use it.
pll_sync_o <= '0';
-- clk_ref_62m5 = clk_125m_gtx_buf (125.000 MHz Div2)
-- Possibly synchronize the divider.
-- Synchronize the divider as well whenever the pll is synced.
-- Asynchronous reset is used since clk_ref_125m is lost during
-- pll_sync action.
process(clk_ref_125m)
begin
if rising_edge(clk_ref_125m) then
if clk_ref_sync = '1' then
if sync_clk_ref_62m5 = '1' then
clk_ref_62m5 <= '0';
else
clk_ref_62m5 <= not clk_ref_62m5;
......@@ -757,8 +796,8 @@ begin -- architecture struct
pll_reset_n_o <= gpio_out(4);
gpio_in(5) <= pll_lock_i;
gpio_in(6) <= pll_status_i;
pll_sync_o <= gpio_out(7); --'0'; -- Not Used by PLL, default drive '0'
sync_enable <= gpio_out(7); -- trigger PLL sync sequence
-- External clock multiplexers
pll_wr_mode_o <= gpio_out(9 downto 8);
-- Bootstrap clock
......@@ -770,6 +809,9 @@ begin -- architecture struct
eeprom_sda <= '0' when (gpio_out(12) = '0') else 'Z';
gpio_in(12) <= eeprom_sda;
gpio_in(13) <= even_odd_n; -- 10MHz/1PPS phase w.r.t. clk_ref_125m
gpio_in(14) <= sync_done;
sfp_rate_select_o <= '1';
onewire_oen_o <= onewire_en(0);
......
-------------------------------------------------------------------------------
-- Title : PLL synchronizer
-- Project : WR PTP Core and EMPIR 17IND14 WRITE
-- URL : http://www.ohwr.org/projects/wr-cores/wiki/Wrpc_core
-- : http://empir.npl.co.uk/write/
-------------------------------------------------------------------------------
-- File : pll_synchronizer.vhd
-- Author(s) : Peter Jansweijer <peterj@nikhef.nl>
-- Company : Nikhef
-- Created : 2020-08-11
-- Last update: 2020-08-11
-- Standard : VHDL'93
-------------------------------------------------------------------------------
-- Description: When a PLL is used to generate 125 MHz from 10 MHz then the PLL
-- can lock on the even or odd 10MHz phase w.r.t. the 1 PPS. This
-- module detects where (even/odd) the lock was achieved.
--
-------------------------------------------------------------------------------
-- Copyright (c) 2020 Nikhef
-------------------------------------------------------------------------------
-- GNU LESSER GENERAL PUBLIC LICENSE
--
-- This source file is free software; you can redistribute it
-- and/or modify it under the terms of the GNU Lesser General
-- Public License as published by the Free Software Foundation;
-- either version 2.1 of the License, or (at your option) any
-- later version.
--
-- This source is distributed in the hope that it will be
-- useful, but WITHOUT ANY WARRANTY; without even the implied
-- warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-- PURPOSE. See the GNU Lesser General Public License for more
-- details.
--
-- You should have received a copy of the GNU Lesser General
-- Public License along with this source; if not, download it
-- from http://www.gnu.org/licenses/lgpl-2.1.html
--
-------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
library work;
use work.gencores_pkg.all;
library unisim;
use unisim.vcomponents.all;
entity pll_synchronizer is
port (
rst_n_i : in std_logic;
clk_ref_i : in std_logic;
clk_10m_ext_i : in std_logic;
clk_sys_62m5_i : in std_logic;
pps_i : in std_logic;
enable_sync_i : in std_logic;
sync_done_o : out std_logic;
pll_sync_o : out std_logic
);
end entity pll_synchronizer;
architecture rtl of pll_synchronizer is
-----------------------------------------------------------------------------
-- Signals
-----------------------------------------------------------------------------
signal sync : std_logic;
signal sync_ext : std_logic := '0';
signal pll_sync : std_logic;
signal pll_sync_ext : std_logic;
signal rising_pps : std_logic;
signal rising_clk_10m : std_logic;
signal arm_clk_10m_det : std_logic := '0';
signal enable_sync : std_logic;
signal enable : std_logic := '0';
signal done : std_logic;
signal sync_done : std_logic;
begin -- architecture rtl
-- detect rising edge PPS
cmp_pps_rising_edge: gc_sync_ffs
generic map (
g_sync_edge => "positive")
port map (
clk_i => clk_ref_i,
rst_n_i => rst_n_i,
data_i => pps_i,
ppulse_o => rising_pps);
-- detect rising edge clk_10m
cmp_clk_10m_rising_edge: gc_sync_ffs
generic map (
g_sync_edge => "positive")
port map (
clk_i => clk_ref_i,
rst_n_i => rst_n_i,
data_i => clk_10m_ext_i,
ppulse_o => rising_clk_10m);
-- After rising edge PPS wait for first rising edge clk_10m and
-- trigger a sync if enabled.
process (clk_ref_i)
begin
if rst_n_i = '0' then
arm_clk_10m_det <= '0';
elsif rising_edge(clk_ref_i) then
if rising_pps = '1' then
arm_clk_10m_det <= '1';
elsif arm_clk_10m_det = '1' and rising_clk_10m = '1' then
arm_clk_10m_det <= '0';
end if;
end if;
end process;
sync <= '1' when enable = '1' and arm_clk_10m_det = '1' and rising_clk_10m = '1' else '0';
-- Extend sync at least 13 clk_ref_i ticks such that it can be
-- caught by the clk_10m_ext_i domain
cmp_extend_sync : gc_extend_pulse
generic map (
g_width => 13)
port map (
clk_i => clk_ref_i,
rst_n_i => rst_n_i,
pulse_i => sync,
extended_o => sync_ext);
-----------------------------------------------------------------------------
-- Generate pll_sync_o
-----------------------------------------------------------------------------
-- pll_sync_o minimal pusle width = 1 ms.
-- Note: need to use a free running clk (clk_10m_ext_i) since clk_ref_125m
-- is temporary lost due to sync!
-- 1 ms = 10000 clk_10m_ext_i ticks.
cmp_sync_ffs_sync: gc_sync_ffs
generic map (
g_sync_edge => "positive")
port map (
clk_i => clk_10m_ext_i,
rst_n_i => rst_n_i,
data_i => sync_ext,
ppulse_o => pll_sync);
U_Extend_pll_sync : gc_extend_pulse
generic map (
g_width => 10000)
-- g_width => 8)
port map (
clk_i => clk_10m_ext_i,
rst_n_i => rst_n_i,
pulse_i => pll_sync,
extended_o => pll_sync_ext);
cmp_sync_ffs_pll_sync_ext: gc_sync_ffs
generic map (
g_sync_edge => "positive")
port map (
clk_i => clk_10m_ext_i,
rst_n_i => rst_n_i,
data_i => pll_sync_ext,
npulse_o => done);
pll_sync_o <= pll_sync_ext;
-----------------------------------------------------------------------------
-- pll_sync sequence enable and done
-----------------------------------------------------------------------------
-- synchronize enable_sync_i (clk_sys_62m5_i domain) to clk_10m_ext_i
cmp_sync_ffs_enable_sync_i: gc_sync_ffs
generic map (
g_sync_edge => "positive")
port map (
clk_i => clk_10m_ext_i,
rst_n_i => rst_n_i,
data_i => enable_sync_i,
ppulse_o => enable_sync);
process (clk_10m_ext_i)
begin
if rst_n_i = '0' then
enable <= '0';
elsif rising_edge(clk_10m_ext_i) then
if enable_sync = '1' then
enable <= '1';
elsif done = '1' then
enable <= '0';
end if;
end if;
end process;
sync_done <= not enable;
-- synchronize sync_done (clk_10m_ext_i domain) to clk_sys_62m5_i domain
cmp_sync_ffs_sync_done: gc_sync_ffs
generic map (
g_sync_edge => "positive")
port map (
clk_i => clk_sys_62m5_i,
rst_n_i => rst_n_i,
data_i => sync_done,
synced_o => sync_done_o);
end architecture rtl;
-------------------------------------------------------------------------------
-- Title : 10MHz-1PPS even/odd 125 MHz reference clock phase detector
-- Project : WR PTP Core and EMPIR 17IND14 WRITE
-- URL : http://www.ohwr.org/projects/wr-cores/wiki/Wrpc_core
-- : http://empir.npl.co.uk/write/
-------------------------------------------------------------------------------
-- File : pps_even_odd_det.vhd
-- Author(s) : Peter Jansweijer <peterj@nikhef.nl>
-- Company : Nikhef
-- Created : 2020-08-11
-- Last update: 2020-08-11
-- Standard : VHDL'93
-------------------------------------------------------------------------------
-- Description: When a PLL is used to generate 125 MHz from 10 MHz then the PLL
-- can lock on the even or odd 10MHz phase w.r.t. the 1 PPS. This
-- module detects where (even/odd) the lock was achieved.
--
-------------------------------------------------------------------------------
-- Copyright (c) 2020 Nikhef
-------------------------------------------------------------------------------
-- GNU LESSER GENERAL PUBLIC LICENSE
--
-- This source file is free software; you can redistribute it
-- and/or modify it under the terms of the GNU Lesser General
-- Public License as published by the Free Software Foundation;
-- either version 2.1 of the License, or (at your option) any
-- later version.
--
-- This source is distributed in the hope that it will be
-- useful, but WITHOUT ANY WARRANTY; without even the implied
-- warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-- PURPOSE. See the GNU Lesser General Public License for more
-- details.
--
-- You should have received a copy of the GNU Lesser General
-- Public License along with this source; if not, download it
-- from http://www.gnu.org/licenses/lgpl-2.1.html
--
-------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
library work;
use work.gencores_pkg.all;
library unisim;
use unisim.vcomponents.all;
entity pps_even_odd_det is
port (
clk_ref_i : in std_logic;
rst_n_i : in std_logic;
pps_i : in std_logic;
enable_i : in std_logic;
even_odd_n_o : out std_logic;
sync_o : out std_logic
);
end entity pps_even_odd_det;
architecture rtl of pps_even_odd_det is
-----------------------------------------------------------------------------
-- Signals
-----------------------------------------------------------------------------
signal rst : std_logic;
signal pps_synced_pos : std_logic;
signal pps_synced_neg : std_logic;
signal pps_synced_pos_del : std_logic;
signal sync : std_logic;
begin -- architecture rtl
rst <= not rst_n_i;
cmp_iddr: IDDR
generic map (
DDR_CLK_EDGE => "SAME_EDGE")
port map (
Q1 => pps_synced_pos,
Q2 => pps_synced_neg,
C => clk_ref_i,
CE => '1',
D => pps_i,
R => rst,
S => '0');
-- If rising_edge pps_i is during clk_ref_i = '1' then
-- pps_synced_pos and pps_synced_neg are asserted at the same time
-- else pps_synced_pos is asserted before pps_synced_neg in.
process (clk_ref_i, rst_n_i)
begin
if (rst_n_i = '0') then
pps_synced_pos_del <= '0';
even_odd_n_o <= '0';
sync <= '0';
elsif rising_edge(clk_ref_i) then
pps_synced_pos_del <= pps_synced_pos;
-- detect a rising edge pps_synced_pos (always 1 clk_ref_i tick
-- after the clock tick in which ppsi had a rising edge).
if (pps_synced_pos_del = '0' and pps_synced_pos = '1') then
-- detect simultanious assertion of pps_synced_neg
if (pps_synced_neg = '1') then
even_odd_n_o <= '0';
else
even_odd_n_o <= '1';
end if;
sync <= '1';
else
sync <= '0';
end if;
end if;
if enable_i = '1' then
sync_o <= sync;
else
sync_o <= '0';
end if;
end process;
end architecture rtl;
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment