SERDES symbol locking

From Hamsterworks Wiki!

Jump to: navigation, search

This FPGA Project was completed in July 2015.

One thing that I found challenging about using the ISERDESE2 is how to dynamically control and bitslipping settings to automatically tune the for incoming DVI-D/HDMI bit stream. Here's my initial working solution....


How it works

1. A 24 bit counter starts 'signal_quality' at about 4,194,304 (0x400000). Each time an invalid symbol is is seen, about million is added (actually 0x100000). Each time a valid symbol is seen, the counter is decremented by one.

2. When this counter reaches 0x0FFFFF, we have seen enough valid symbols to declare it is in sync by asserting 'symbol_sync'

3. Should the counter reach 0xF00000 (11 errors in quick succession) then then it flags that sync is lost by deasserting 'symbol_sync', and actions are taken to find a better settings.

The actions are:

1. Increase the delay tap setting for the IDELAY.

2. Should the tap setting wrap from 31 back down to 0, then also assert the bit-slip signal for one cycle.

3. The 24-bit counter 'signal_quality' is set back to 4,194,304

When actions are taken, the 'holdoff' counter starts taking down, to give a short delay for the new settings to apply before invalid symbols are acted on.

Assuming that when settings are not optimal the symbol error rate is one in 1000, the time to attempt to lock at every different bitslip/delay setting is as follows:

 Delay_taps * bitslip_options * (12*symbols_per_error + holdoff_per_change) + cycles_to_lock_when_optimal
 32 * 10 * (12*1,000 + 1,024) + 3,145,728 = 7,313,408 cycles

At 148.5MHz (the symbol rate for 1080p@60Hz) this could take about 50ms, at 25MHz (used by 640x480) it will take about 6 times longer - about 1/3rd of a second. This is fine for video, but would be a bit too slow for data communication. It would be relatively easy to adjust the length of 'signal_quality' and 'holdoff' to reduce this period - however almost half this time is in the 3.1M cycles required to be sure that the error rate is under 1 in a million.

Why I designed it this way

  • The only input it needs is an invalid symbol signal for each channel being monitored
  • All the testing is performed on the top four bits off the 24-bit counter, minimizing the logic needed
  • Because high levels of symbols errors are acted on so quickly (about a dozen errors in quick succession are is enough) it quickly moves on from invalid settings
  • Sync is kept as the error rate is less than one in 1,048,576, which seemed a reasonable value to me
  • It will find the first delay setting where the the error rate is less than one in a million, and should increase the delay tap to a better setting


  • There is a small chance that if the error rate is exactly one in 1,048,576 then the signal will never assert the 'symbol_sync' status output, even though an acceptable signal might

just be one change of tap setting away.

  • Maybe once it finds the first acceptable delay setting maybe the delay setting should be incremented by one, hopefully to move the sampling point further into the signal's eye


Unlike other projects, this will just be code fragments.

Signals used

    -- Signals for controlling the bitslip 
    -- and delay so we can sync symbols
    signal count          : unsigned(19 downto 0)        := (others => '0');
    signal signal_quality : unsigned(23 downto 0)        := (others => '0');
    signal holdoff        : unsigned(9 downto 0)         := (others => '0');
    signal bitslip        : std_logic := '0';
    signal error_seen     : std_logic                    := '0';
    signal idelay_ce      : std_logic                    := '0';
    signal idelay_count   : std_logic_vector(4 downto 0) := (others => '0');

    signal reset_sr       : std_logic_vector(3 downto 0) := (others => '1');

Process for finding a working phase alignment/bitslip

detect_alignment_proc: process(clk_pixel)
        -- If there are a dozen or so symbol errors in at a rate of 
        -- greater than 1 in a million then advance the delay and
        -- if that wraps then assert the bitslip signal
        if rising_edge(clk_pixel) then
            -- See if an error has been seen
            -- Holdoff gives a few cycles for 
            -- bitslips and delay changes to 
            -- take effect.
            error_seen <= '0';
            if holdoff = 0 then
                if ch0_invalid_symbol = '1' or ch1_invalid_symbol = '1' or ch2_invalid_symbol = '1' then
                    error_seen <= '1';
                end if;
                holdoff <= holdoff-1;
            end if;

            -- Keep track of valid symbol count vs errors
            -- Each error increase the count by a million, 
            -- each valid sysmbol decreases the count by 
            -- one. So after 12 errors it will cause us to
            -- change bitslip or delay settings, but it will
            -- take 7 million cycles until the high four 
            -- bits are zeros (and the link considered OK)
            bitslip <= '0';
            idelay_ce <= '0';
            if error_seen = '1' then
                if signal_quality(23 downto 20) = x"F" then
                    -- Enough errors to cause us to loose sync 
                    -- (if we had it!) 
                    symbol_sync         <= '0';

                    -- Hold off acting on any more errors
                    -- while we adjust the delay or bitslip
                    holdoff <= (others => '1');
                    -- Bitslip if required
                    if unsigned(idelay_count) = 31 then   
                        bitslip <= '1';
                    end if;
                    -- And adjust the delay setting (will wrap to 0 when bitslipping)
                    idelay_count  <= std_logic_vector(unsigned(idelay_count)+1);
                    idelay_ce <= '1';
                    -- It will need 4M good symbols to avoid adjusting the timing again 
                    signal_quality(23 downto 20) <= x"4";
                    signal_quality <= signal_quality + x"10000";   -- add a million if there is a symbol error
                end if;
                -- Count down by one, as we are one symbol 
                -- closer to having a valid stream
                if signal_quality(23 downto 20) > 0 then
                    signal_quality <= signal_quality - 1;   -- one symbol closer to a valid stream
                end if;        
            end if;

            -- if we have counted down about 3M
            -- symbols without any symbol errors
            -- being seen then we are in sync
            if signal_quality(23 downto 20) = "0000" then 
                symbol_sync <= '1';
            end if;
        end if;        
    end process;

Personal tools