Перейти к содержанию
    

можно было и по переднему фронту. Так времянке даже легче будет, на распространение сигнала будет 1 такт, а не половина. Сигнал так же попадет под анализ синтезатора.

Второй триггер в цепочке синхронизации нужен для защиты от мета-стабильности.

 

Один триггер который щелкает входной сигнал может быть в состоянии 0, 1, или Х - это если неудачно попал фронт. Это состояние рано или поздно свалиться к 1 или 0. И беда что остальные участники схемы смотрят на это состояние и по разному его видят, кто-то может его принять за 0, а кто-то за 1. Поэтому ставят второй триггер, чтобы он принял какое-то решение единолично, а остальные уже работали от него.

 

Вероятность поймать мета-стабильность сильно меньше чем вероятность поймать гонку в исходном примере, поэтому все и заработало. Но природу не обманешь, когда-то и это стрельнет, так что лучше все же 2 триггера.

Ну это даже я понимаю :)

 

Просто хотелось посмотреть, насколько кардинально поменяет ситуацию такое минимальное изменение.

 

Кстати, вроде бы дошло, почему гонки возникали так часто. Мне с самого начала было очень подозрительно, что проблема повторяется крайне регулярно, вроде статистически при моих частотах это должно происходить НАМНОГО реже. А сейчас сообразил, что у меня формирование StartCmd нельзя назвать по настоящему асинхронным по отношению к тактовому сигналу FSM - все тактовые начинаются от одного выхода PLL. Потом ветки этих тактовых сигналов расходятся, формируются по разному и т.д., но все равно их фронты более-менее совпадают каждый шестой (вроде бы, если правильно прикинул) раз, т.е. условия для гонки присутствуют постоянно.

Мне даже стало интересно взять старую схему, но использовать 2 независимые PLL, чтобы посмотреть, уйдет ли такая регулярность проблемы...

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Ну это даже я понимаю :)

 

Просто хотелось посмотреть, насколько кардинально поменяет ситуацию такое минимальное изменение.

 

Кстати, вроде бы дошло, почему гонки возникали так часто. Мне с самого начала было очень подозрительно, что проблема повторяется крайне регулярно, вроде статистически при моих частотах это должно происходить НАМНОГО реже. А сейчас сообразил, что у меня формирование StartCmd нельзя назвать по настоящему асинхронным по отношению к тактовому сигналу FSM - все тактовые начинаются от одного выхода PLL. Потом ветки этих тактовых сигналов расходятся, формируются по разному и т.д., но все равно их фронты более-менее совпадают каждый шестой (вроде бы, если правильно прикинул) раз, т.е. условия для гонки присутствуют постоянно.

Мне даже стало интересно взять старую схему, но использовать 2 независимые PLL, чтобы посмотреть, уйдет ли такая регулярность проблемы...

А не проще сразу делать правильно - обрабатывать асинхронный сигнал по идеологии пересечения клоковых доменов ? Зачем жалеть 2 несчастных регистра ?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

 

Синхронизация цепочка

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity synchronizer is
    generic ( stages : natural := 3 );
    Port ( clk : in STD_LOGIC;
           i : in STD_LOGIC;
           o : out STD_LOGIC);
end synchronizer;

architecture Behavioral of synchronizer is
    signal flipflops : std_logic_vector(stages-1 downto 0):= (others => '0');
    attribute ASYNC_REG : string;
    attribute ASYNC_REG of flipflops: signal is "true";
begin

    o <= flipflops(flipflops'high);

clk_proc: process(clk)
    begin
        if rising_edge(clk) then
            flipflops <= flipflops(flipflops'high-1 downto 0) & i;
        end if;
    end process;

end Behavioral;

 

Возможно применение двуклокового FIFO для передачи принятых данных, возможно применение синхронизирующей цепочки для строба-готовности данных - что данные приняты и записаны в FIFO

Дальше автомат отсчитывает например N стробов-готовности данных и производит вычитку из FIFO этих данных, производя их обработку...

Можно учесть синхронизацию при описании SPI slave и работать на 1 частоте, если описать например так

 

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;

-- THE SPI SLAVE MODULE SUPPORT ONLY SPI MODE 0 (CPOL=0, CPHA=0)!!!

entity SPI_SLAVE is
    Port (
        CLK      : in  std_logic; -- system clock
        RST      : in  std_logic; -- high active synchronous reset
        -- SPI SLAVE INTERFACE
        SCLK     : in  std_logic;
        CS_N     : in  std_logic;
        MOSI     : in  std_logic;
        MISO     : out std_logic;
        -- USER INTERFACE
        READY    : out std_logic; -- when READY = 1, SPI slave is ready to accept input data
        DIN      : in  std_logic_vector(7 downto 0); -- input data for master
        DIN_VLD  : in  std_logic; -- when DIN_VLD = 1, input data are valid and can be accept
        DOUT     : out std_logic_vector(7 downto 0); -- output data from master
        DOUT_VLD : out std_logic  -- when DOUT_VLD = 1, output data are valid
    );
end SPI_SLAVE;

architecture RTL of SPI_SLAVE is

    signal spi_clk_reg        : std_logic;
    signal spi_clk_redge_en   : std_logic;
    signal spi_clk_fedge_en   : std_logic;
    signal load_data          : std_logic;
    signal data_shreg         : std_logic_vector(7 downto 0);
    signal bit_cnt            : unsigned(2 downto 0);
    signal last_bit_en        : std_logic;
    signal slave_ready        : std_logic;
    signal data_busy_reg      : std_logic;
    signal rx_data_vld        : std_logic;

begin

    load_data <= slave_ready and DIN_VLD;
    READY     <= slave_ready;
    DOUT      <= data_shreg;

    -- -------------------------------------------------------------------------
    --  SPI CLOCK REGISTER
    -- -------------------------------------------------------------------------

    spi_clk_reg_p : process (CLK)
    begin
        if (rising_edge(CLK)) then
            if (RST = '1') then
                spi_clk_reg <= '0';
            else
                spi_clk_reg <= SCLK;
            end if;
        end if;
    end process;

    -- -------------------------------------------------------------------------
    --  SPI CLOCK EDGES FLAGS
    -- -------------------------------------------------------------------------

    spi_clk_fedge_en <= not SCLK and spi_clk_reg;
    spi_clk_redge_en <= SCLK and not spi_clk_reg;

    -- -------------------------------------------------------------------------
    --  DATA BUSY REGISTER
    -- -------------------------------------------------------------------------

    data_busy_reg_p : process (CLK)
    begin
        if (rising_edge(CLK)) then
            if (RST = '1') then
                data_busy_reg <= '0';
            else
                if (DIN_VLD = '1' and CS_N = '1') then
                    data_busy_reg <= '1';
                elsif (rx_data_vld = '1') then
                    data_busy_reg <= '0';
                else
                    data_busy_reg <= data_busy_reg;
                end if;
            end if;
        end if;
    end process;

    slave_ready <= CS_N and not data_busy_reg;

    -- -------------------------------------------------------------------------
    --  MISO REGISTER
    -- -------------------------------------------------------------------------

    miso_p : process (CLK)
    begin
        if (rising_edge(CLK)) then
            if (load_data = '1') then
                MISO <= DIN(7);
            elsif (spi_clk_fedge_en = '1' and CS_N = '0') then
                MISO <= data_shreg(7);
            end if;
        end if;
    end process;

    -- -------------------------------------------------------------------------
    --  DATA SHIFT REGISTER
    -- -------------------------------------------------------------------------

    data_shreg_p : process (CLK)
    begin
        if (rising_edge(CLK)) then
            if (load_data = '1') then
                data_shreg <= DIN;
            elsif (spi_clk_redge_en = '1' and CS_N = '0') then
                data_shreg <= data_shreg(6 downto 0) & MOSI;
            end if;
        end if;
    end process;

    -- -------------------------------------------------------------------------
    --  DATA OUT VALID FLAG REGISTER
    -- -------------------------------------------------------------------------

    rx_data_vld <= spi_clk_fedge_en and last_bit_en;

    dout_vld_reg_p : process (CLK)
    begin
        if (rising_edge(CLK)) then
            if (RST = '1') then
                DOUT_VLD <= '0';
            else
                DOUT_VLD <= rx_data_vld;
            end if;
        end if;
    end process;

    -- -------------------------------------------------------------------------
    --  BIT COUNTER
    -- -------------------------------------------------------------------------

    bit_cnt_p : process (CLK)
    begin
        if (rising_edge(CLK)) then
            if (RST = '1') then
                bit_cnt <= (others => '0');
            elsif (spi_clk_fedge_en = '1' and CS_N = '0') then
                if (bit_cnt = "111") then
                    bit_cnt <= (others => '0');
                else
                    bit_cnt <= bit_cnt + 1;
                end if;
            end if;
        end if;
    end process;

    -- -------------------------------------------------------------------------
    --  LAST BIT FLAG REGISTER
    -- -------------------------------------------------------------------------

    last_bit_en_p : process (CLK)
    begin
        if (rising_edge(CLK)) then
            if (RST = '1') then
                last_bit_en <= '0';
            else
                if (bit_cnt = "111") then
                    last_bit_en <= '1';
                else
                    last_bit_en <= '0';
                end if;
            end if;
        end if;
    end process;

end RTL;

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

А сейчас сообразил, что у меня формирование StartCmd нельзя назвать по настоящему асинхронным по отношению к тактовому сигналу FSM - все тактовые начинаются от одного выхода PLL. Потом ветки этих тактовых сигналов расходятся, формируются по разному и т.д., но все равно их фронты более-менее совпадают каждый шестой (вроде бы, если правильно прикинул) раз, т.е. условия для гонки присутствуют постоянно.

 

Хм, так они если от одного PLL то должны были попасть автоматом под анализ. Другое дело если частоты не кратные, то конечно развести не удастся, но об этом должен сказать синтезатор. Вы варнинги и ероры тайм анализа не читали? По идее там должно быть написано что ничего не получилось....

 

А насчет проверять - это конечно дело ваше, но мировая практика все это уже проверила 100500 раз, нам можно верить, и мета-стабильности и гонки сигналов в реальном мире существуют... :)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Вы варнинги и ероры тайм анализа не читали? По идее там должно быть написано что ничего не получилось....

Признаюсь честно - я по подобным сообщениям делаю supress message, практически не читая... Наверное, в настоящее время time analysis - первоочередное, что мне нужно еще освоить. Брался за него пару раз, но становилось скучно :(

Мои игрушки работают на частотах меньше 20МГц, поэтому в большинстве случаев проблем с быстродействием не возникает. Другое дело, что понимание основ могло бы выявить проблемы, аналогичные описанной в этой теме, на раннем этапе...

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...