Revert "demo: add HPLL and serial_dac design files from White Rabbit r1344"

This reverts commit 1a2cb362.
parent 6553bd46
- integrator with anti-windup
- frequency error overflow checking/clamping (no recovery after loss-of-lock event)
- clock multiplexing: allow for UP0/UP1/local reference clock dynamic switching
#!/bin/bash
mkdir -p doc
wbgen2 -D ./doc/wrsw_helper_pll.html -V hpll_wb_slave.vhd -C ../../../software/include/hw/hpll_regs.h --cstyle defines --lang vhdl -K ../../sim/hpll_wb_regs.v hpll_wb.wb
\ No newline at end of file
This diff is collapsed.
This diff is collapsed.
-------------------------------------------------------------------------------
-- Title : DMTD Helper PLL (HPLL) - lock detection logic
-- Project : White Rabbit Switch
-------------------------------------------------------------------------------
-- File : hpll_controller.vhd
-- Author : Tomasz Wlostowski
-- Company : CERN BE-Co-HT
-- Created : 2010-06-14
-- Last update: 2010-08-23
-- Platform : FPGA-generic
-- Standard : VHDL'87
-------------------------------------------------------------------------------
-- Description:
-------------------------------------------------------------------------------
-- Copyright (c) 2010 Tomasz Wlostowski
-------------------------------------------------------------------------------
-- Revisions :
-- Date Version Author Description
-- 2010-06-14 1.0 twlostow Created
-------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity hpll_lock_detect is
port (
rst_n_sysclk_i : std_logic;
clk_sys_i : std_logic;
phase_err_i : in std_logic_vector(11 downto 0);
phase_err_stb_p_i : in std_logic;
freq_err_i : in std_logic_vector(11 downto 0);
freq_err_stb_p_i : in std_logic;
hpll_ldcr_ld_samp_i : in std_logic_vector(7 downto 0);
hpll_ldcr_ld_thr_i : in std_logic_vector(7 downto 0);
-- Flags: frequency lock
hpll_psr_freq_lk_o : out std_logic;
-- Flags: phase lock
hpll_psr_phase_lk_o : out std_logic;
-- Flags: loss-of-lock indicator
hpll_psr_lock_lost_i : in std_logic;
hpll_psr_lock_lost_o : out std_logic;
hpll_psr_lock_lost_load_i : in std_logic;
-- PI frequency/phase mode select
freq_mode_o : out std_logic
);
end hpll_lock_detect;
architecture syn of hpll_lock_detect is
type t_lock_detect_state is (LD_WAIT_FREQ_LOCK, LD_WAIT_PHASE_LOCK, LD_LOCKED);
signal ph_err_sign_d0 : std_logic;
signal ph_err_sign : std_logic;
signal ph_err_valid : std_logic;
signal ph_err_duty_cntr : unsigned(7 downto 0);
signal ph_err_lock_cntr : unsigned(7 downto 0);
signal f_err_lock_cntr : unsigned(7 downto 0);
signal phase_lock : std_logic;
signal freq_lock : std_logic;
signal state : t_lock_detect_state;
signal f_err_int : integer;
begin
ph_err_sign <= phase_err_i(phase_err_i'length-1);
lock_detect_phase : process (clk_sys_i, rst_n_sysclk_i)
begin
if rising_edge(clk_sys_i) then
if(rst_n_sysclk_i = '0') then
ph_err_valid <= '0';
ph_err_sign_d0 <= '0';
ph_err_valid <= '0';
ph_err_duty_cntr <= (others => '0');
ph_err_lock_cntr <= (others => '0');
phase_lock <= '0';
else
-- new phase error value arrived
if(phase_err_stb_p_i = '1') then
ph_err_sign_d0 <= ph_err_sign;
-- the sign of the phase error has changed, check how long it will
-- take to flip again
if(ph_err_sign /= ph_err_sign_d0) then
ph_err_duty_cntr <= (others => '0');
-- if the phase error has been changing its sign frequent enough
-- for a given number of samples, we assume the PLL is locked
if(std_logic_vector(ph_err_lock_cntr) = hpll_ldcr_ld_samp_i) then
phase_lock <= '1';
else
ph_err_lock_cntr <= ph_err_lock_cntr + 1;
phase_lock <= '0';
end if;
else
-- if the phase error remains positive or negative for too long,
-- we are out of lock
if(std_logic_vector(ph_err_duty_cntr) = hpll_ldcr_ld_thr_i) then
ph_err_lock_cntr <= (others => '0');
phase_lock <= '0';
else
ph_err_duty_cntr <= ph_err_duty_cntr + 1;
end if;
end if;
end if;
end if;
end if;
end process;
f_err_int <= to_integer(signed(freq_err_i));
lock_detect_freq : process(clk_sys_i, rst_n_sysclk_i)
begin
if rising_edge(clk_sys_i) then
if(rst_n_sysclk_i = '0') then
freq_lock <= '0';
f_err_lock_cntr <= (others => '0');
else
if(freq_err_stb_p_i = '1') then
if(f_err_int > -300 and f_err_int < 300) then
if(std_logic_vector(f_err_lock_cntr) = hpll_ldcr_ld_samp_i) then
freq_lock <= '1';
else
f_err_lock_cntr <= f_err_lock_cntr + 1;
freq_lock <= '0';
end if;
else
f_err_lock_cntr <= (others => '0');
freq_lock <= '0';
end if;
end if;
end if;
end if;
end process;
lock_fsm : process(clk_sys_i, rst_n_sysclk_i)
begin -- process
if rising_edge(clk_sys_i) then
if (rst_n_sysclk_i = '0') then
state <= LD_WAIT_FREQ_LOCK;
freq_mode_o <= '1';
hpll_psr_lock_lost_o <= '0';
else
if(hpll_psr_lock_lost_load_i = '1' and hpll_psr_lock_lost_i = '1') then
hpll_psr_lock_lost_o <= '0';
end if;
case state is
when LD_WAIT_FREQ_LOCK =>
if(freq_lock = '1') then
state <= LD_WAIT_PHASE_LOCK;
freq_mode_o <= '0';
else
freq_mode_o <= '1';
end if;
when LD_WAIT_PHASE_LOCK =>
if(phase_lock = '1') then
state <= LD_LOCKED;
end if;
when LD_LOCKED =>
if(phase_lock = '0' or freq_lock = '0') then
hpll_psr_lock_lost_o <= '1';
end if;
if(phase_lock = '0') then
state <= LD_WAIT_PHASE_LOCK;
elsif freq_lock = '0' then
state <= LD_WAIT_FREQ_LOCK;
end if;
when others => null;
end case;
end if;
end if;
end process;
hpll_psr_phase_lk_o <= phase_lock;
hpll_psr_freq_lk_o <= freq_lock;
end syn;
-------------------------------------------------------------------------------
-- Title : DMTD Helper PLL (HPLL) - linear frequency/period detector.
-- Project : White Rabbit Switch
-------------------------------------------------------------------------------
-- File : hpll_period_detect.vhd
-- Author : Tomasz Wlostowski
-- Company : CERN BE-Co-HT
-- Created : 2010-06-14
-- Last update: 2011-04-08
-- Platform : FPGA-generic
-- Standard : VHDL'87
-------------------------------------------------------------------------------
-- Description: Simple linear frequency detector with programmable error
-- setpoint and gating period. The measured clocks are: clk_ref_i and clk_fbck_i.
-- The error value is outputted every 2^(hpll_fbcr_fd_gate_i + 14) cycles on a
-- freq_err_o. A pulse is produced on freq_err_stb_p_o every time freq_err_o
-- is updated with a new value. freq_err_o value is:
-- - positive when clk_fbck_i is slower than selected frequency setpoint
-- - negative when clk_fbck_i is faster than selected frequency setpoint
-------------------------------------------------------------------------------
-- Copyright (c) 2010 Tomasz Wlostowski
-------------------------------------------------------------------------------
-- Revisions :
-- Date Version Author Description
-- 2010-06-14 1.0 twlostow Created
-------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.common_components.all;
entity hpll_period_detect is
generic(
g_freq_err_frac_bits: integer);
port (
-------------------------------------------------------------------------------
-- Clocks & resets
-------------------------------------------------------------------------------
-- reference clocks
clk_ref_i : in std_logic;
-- fed-back (VCO) clock
clk_fbck_i : in std_logic;
-- system clock (wishbone and I/O)
clk_sys_i : in std_logic;
-- reset signals (the same reset synced to different clocks)
rst_n_refclk_i : in std_logic;
rst_n_fbck_i : in std_logic;
rst_n_sysclk_i : in std_logic;
-------------------------------------------------------------------------------
-- Outputs
-------------------------------------------------------------------------------
-- frequency error value (signed)
freq_err_o : out std_logic_vector(11 downto 0);
-- frequency error valid pulse
freq_err_stb_p_o : out std_logic;
-------------------------------------------------------------------------------
-- Wishbone regs
-------------------------------------------------------------------------------
-- gating period:
hpll_fbcr_fd_gate_i : in std_logic_vector(2 downto 0);
-- frequency error setpoint:
hpll_fbcr_ferr_set_i : in std_logic_vector(11 downto 0)
);
end hpll_period_detect;
architecture rtl of hpll_period_detect is
-- derived from the maximum gating period (2 ^ 21 + 1 "safety" bit)
constant c_COUNTER_BITS : integer := 22;
-- number of fractional bits in the frequency error output
-- constant c_FREQ_ERR_FRAC_BITS : integer := 7;
-- frequency counters: feedback clock & gating counter
signal counter_fb : unsigned(c_COUNTER_BITS-1 downto 0);
signal counter_gate : unsigned(c_COUNTER_BITS-1 downto 0);
-- clock domain synchronization stuff...
signal gate_sreg : std_logic_vector(3 downto 0);
signal pstb_sreg : std_logic_vector(3 downto 0);
signal gate_p, period_p : std_logic;
signal gate_cntr_bitsel : std_logic;
signal desired_freq : unsigned(c_COUNTER_BITS-1 downto 0);
signal cur_freq : unsigned(c_COUNTER_BITS-1 downto 0);
signal delta_f: signed(11 downto 0);
begin -- rtl
-- decoding FD gating field from FBCR register:
decode_fd_gating : process(hpll_fbcr_fd_gate_i, counter_gate)
begin
case hpll_fbcr_fd_gate_i is
when "000" => gate_cntr_bitsel <= std_logic(counter_gate(14)); -- div: 16384
desired_freq <= to_unsigned(16384, desired_freq'length);
when "001" => gate_cntr_bitsel <= std_logic(counter_gate(15)); -- ....
desired_freq <= to_unsigned(32768, desired_freq'length);
when "010" => gate_cntr_bitsel <= std_logic(counter_gate(16));
desired_freq <= to_unsigned(65536, desired_freq'length);
when "011" => gate_cntr_bitsel <= std_logic(counter_gate(17));
desired_freq <= to_unsigned(131072, desired_freq'length);
when "100" => gate_cntr_bitsel <= std_logic(counter_gate(18));
desired_freq <= to_unsigned(262144, desired_freq'length);
when "101" => gate_cntr_bitsel <= std_logic(counter_gate(19));
desired_freq <= to_unsigned(524288, desired_freq'length);
when "110" => gate_cntr_bitsel <= std_logic(counter_gate(20)); -- ....
desired_freq <= to_unsigned(1048576, desired_freq'length);
when "111" => gate_cntr_bitsel <= std_logic(counter_gate(21)); -- div: 2097152
desired_freq <= to_unsigned(2097152, desired_freq'length);
when others => null;
end case;
end process;
-------------------------------------------------------------------------------
-- Gating counter: produces a gating pulse on gate_p (clk_fbck_i domain) with
-- period configured by FD_GATE field in FBCR register
-------------------------------------------------------------------------------
gating_counter : process(clk_ref_i, rst_n_refclk_i)
begin
if rising_edge(clk_ref_i) then
if(rst_n_refclk_i = '0') then
counter_gate <= to_unsigned(1, counter_gate'length);
gate_sreg <= (others => '0');
else
if(gate_cntr_bitsel = '1') then
-- counter bit selected by hpll_fbcr_fd_gate_i changed from 0 to 1?
-- reset the counter and generate the gating signal for feedback counter
counter_gate <= to_unsigned(1, counter_gate'length);
gate_sreg <= (others => '1');
else
-- advance the counter and generate a longer pulse on gating signal
-- using a shift register so the sync chain will always work regardless of
-- the clock frequency.
counter_gate <= counter_gate + 1;
gate_sreg <= '0' & gate_sreg(gate_sreg'length-1 downto 1);
end if;
end if;
end if;
end process;
-- sync logic for the gate_p pulse (from clk_ref_i to clk_fbck_i)
sync_gating_pulse : sync_ffs
generic map (
g_sync_edge => "positive")
port map (
clk_i => clk_fbck_i,
rst_n_i => rst_n_fbck_i,
data_i => gate_sreg(0),
synced_o => open,
npulse_o => open,
ppulse_o => gate_p);
-------------------------------------------------------------------------------
-- Main period/frequency measurement process: Takes a snapshot of the counter_fb
-- every time there's a pulse on gate_p. The capture of new frequency value
-- is indicated by pulsing period_p.
-------------------------------------------------------------------------------
period_detect : process(clk_fbck_i, rst_n_fbck_i)
begin
if rising_edge(clk_fbck_i) then
if rst_n_fbck_i = '0' then
counter_fb <= to_unsigned(1, counter_fb'length);
cur_freq <= (others => '0');
pstb_sreg <= (others => '0');
else
if(gate_p = '1') then
counter_fb <= to_unsigned(1, counter_fb'length);
cur_freq <= counter_fb;
pstb_sreg <= (others => '1');
else
counter_fb <= counter_fb + 1;
pstb_sreg <= '0' & pstb_sreg(pstb_sreg'length-1 downto 1);
end if;
end if;
end if;
end process;
-- synchronization logic for period_p (from clk_fbck_i to clk_sys_i)
sync_period_pulse : sync_ffs
generic map (
g_sync_edge => "positive")
port map (
clk_i => clk_sys_i,
rst_n_i => rst_n_sysclk_i,
data_i => pstb_sreg(0),
synced_o => open,
npulse_o => open,
ppulse_o => period_p);
-- calculate the frequency difference, padded by some fractional bits
delta_f <= resize(signed(desired_freq) - signed(cur_freq), delta_f'length-g_freq_err_frac_bits) & to_signed(0, g_freq_err_frac_bits);
-------------------------------------------------------------------------------
-- Calculates the phase error by taking the difference between reference and
-- measured frequency and subtracting the error setpoint from FERR_SET field
-- in FBCR register.
-------------------------------------------------------------------------------
freq_err_output : process(clk_sys_i, rst_n_sysclk_i)
begin
if rising_edge(clk_sys_i) then
if rst_n_sysclk_i = '0' then
freq_err_stb_p_o <= '0';
freq_err_o <= (others => '0');
else
if(period_p = '1') then
freq_err_o <= std_logic_vector(resize(delta_f - signed (hpll_fbcr_ferr_set_i), freq_err_o'length));
end if;
freq_err_stb_p_o <= period_p;
end if;
end if;
end process;
end rtl;
-- -*- Mode: LUA; tab-width: 2 -*-
peripheral
{
name = "DMTD Helper PLL";
description = "PLL controller for generating the DMTD offset clock.";
prefix = "HPLL";
hdl_entity = "hpll_wb_slave";
reg {
name = "HPLL Control Register";
description = "HPLL Control register";
prefix = "PCR";
field {
name = "PLL Enable";
description = "1: PLL is enabled \
0: PLL is disabled";
type = BIT;
prefix = "ENABLE";
access_bus = READ_WRITE;
access_dev = READ_ONLY;
};
field {
name = "PLL Force Freq mode";
type = BIT;
prefix = "FORCE_F";
access_bus = READ_WRITE;
access_dev = READ_ONLY;
};
field {
name = "DAC serial clock select";
description = "Selects the DAC serial clock frequency: \
0: f = refclk / 8 (~ 16 MHz) \
1: f = refclk / 16 (~ 8 MHz) \
2: f = refclk / 32 (~ 4 MHz) \
3: f = refclk / 64 (~ 2 MHz) \
4: f = refclk / 128 (~ 1 MHz) \
5: f = refclk / 256 (~ 500 kHz) \
6: f = refclk / 512 (~ 250 kHz) \
7: f = refclk / 1024 (~ 125 kHz)";
prefix = "DAC_CLKSEL";
align = 4;
type = SLV;
size = 3;
access_bus = READ_WRITE;
access_dev = READ_ONLY;
};
field {
name = "Phase detector gating period";
description = "Gating period for the phase detector: \
0: period = 1024 \
1: period = 2048 \
2: period = 4096 \
3: period = 8192 \
4: period = 16384 \
5: period = 32768 \
6: period = 65536 \
7: period = 131072";
prefix = "PD_GATE";
type = SLV;
size = 3;
align = 4;
access_bus = READ_WRITE;
access_dev = READ_ONLY;
};
field {
name = "Reference clock input select";
description = "00: local reference (from TCXO)\
01: uplink 0 recovered clock\
10: uplink 1 recovered clock";
size = 2;
type = SLV;
prefix = "REFSEL";
access_bus = READ_WRITE;
access_dev = READ_ONLY;
};
field {
name = "PLL Reset";
descritpion = "write 1: causes PLL reset\nwrite 0: no effect";
type = MONOSTABLE;
prefix = "SWRST";
access_bus = READ_WRITE;
access_dev = READ_ONLY;
align=31;
};
};
reg {
name = "HPLL Divider Register";
description = "Register controlling the frequency PLL frequency divider. The output frequency is f_ref * (DIV_FB / DIV_REF)";
prefix = "DIVR";
field {
name = "Reference divider";
prefix = "DIV_REF";
size = 16;
type = SLV;
access_bus = READ_WRITE;
access_dev = READ_ONLY;
};
field {
name = "Feedback divider";
prefix = "DIV_FB";
size = 16;
type = SLV;
access_bus = READ_WRITE;
access_dev = READ_ONLY;
};
};
reg {
name = "HPLL Frequency Branch Gain Register";
description = "Register containing the PI gain factors for the frequency branch.";
prefix = "FBGR";
field {
name = "Proportional gain (Kp)";
prefix = "F_KP";
size = 16;
type = SLV;
access_bus = READ_WRITE;
access_dev = READ_ONLY;
};
field {
name = "Integral gain (Ki)";
prefix = "F_KI";
size = 16;
type = SLV;
access_bus = READ_WRITE;
access_dev = READ_ONLY;
};
};
reg {
name = "HPLL Phase Branch Gain Register";
prefix = "PBGR";
field {
name = "Proportional gain (Kp)";
prefix = "P_KP";
size = 16;
type = SLV;
access_bus = READ_WRITE;
access_dev = READ_ONLY;
};
field {
name = "Integral gain (Ki)";
prefix = "P_KI";
size = 16;
type = SLV;
access_bus = READ_WRITE;
access_dev = READ_ONLY;
};
};
reg {
name = "HPLL Lock Detect Control Register";
prefix = "LDCR";
field {
name = "Phase Lock detect threshold";
prefix = "LD_THR";
description = "A maximum time between bang-bang PD phase error sign changes that keeps the PLL locked";
type = SLV;
size = 8;
align = 4;
access_bus = READ_WRITE;
access_dev = READ_ONLY;
};
field {
name = "Lock detect samples";
prefix = "LD_SAMP";
description = "Number of subsequent phase error samples smaller than LD_THR or frequency error samples in (-1, 1) after which the PLL assumes to be locked.";
type =SLV;
size = 8;
align = 8;
access_bus = READ_WRITE;
access_dev = READ_ONLY;
};
};
reg {
name = "HPLL Frequency branch control register";
prefix = "FBCR";
field {
name = "Frequency detector gating period";
description = "Gating period for the frequency detector: \
0: period = 16384 \
1: period = 32768 \
2: period = 65536 \
3: period = 131072 \
4: period = 262144 \
5: period = 524288 \
6: period = 1048576 \
7: period = 2097152";
prefix = "FD_GATE";
type = SLV;
size = 3;
access_bus = READ_WRITE;
access_dev = READ_ONLY;
align =4;
};
field {
name = "Frequency error setpoint";
description = "Value of desired frequency error in the lock state. Computed as: f_err = FD_GATE[real value] * (1 - (N / (N+DELTA)))";
prefix = "FERR_SET";
align = 4;
size = 12;
type = SLV;
access_bus = READ_WRITE;
access_dev = READ_ONLY;
};
};
reg {
name = "HPLL Status Register";
description = "Register containing the current status of the PLL";
prefix = "PSR";
field {
name = "Frequency lock";
type = BIT;
prefix = "FREQ_LK";
access_bus = READ_ONLY;
access_dev = WRITE_ONLY;
};
field {
name = "Phase lock";
type = BIT;
prefix = "PHASE_LK";
access_bus = READ_ONLY;
access_dev = WRITE_ONLY;
};
field {
name = "Loss-of-lock indicator";
description = "read 0: PLL is locked\
read 1: PLL has lost the lock since the last poll of this bit\
write 0: no effect\
write 1: clears the field";
type = BIT;
prefix = "LOCK_LOST";
access_bus = READ_WRITE;
access_dev = READ_WRITE;
load = LOAD_EXT;
};
};
fifo_reg {
name = "HPLL Phase/Output record FIFO";
description = "A FIFO recording the phase/freq error, the DAC output and other PLL parameters for debugging/optimization purposes";
prefix = "RFIFO";
direction = CORE_TO_BUS;
size = 1024;
flags_bus = {FIFO_EMPTY};
flags_dev = {FIFO_FULL};
field {
name = "Freq/phase error";