Другой часовой домен VHDL

Я делаю собственное оборудование ARINC 429 Core. Сейчас я описал модуль передачи (TX-FSM) в соответствии со стандартом ARINC 429 и FIFO при передаче, из которого он берет данные и отправляет их наружу. FIFO работает на частоте 2 МГц (clk2M), а TX-FSM может генерировать частоту 100 кбит/с или 12,5 кбит/с (clk429) из 2 МГц по стандарту.

Поскольку FIFO работает на более высокой частоте (2 МГц), а TX-FSM работает на более низкой частоте (100 кбит/с), когда TX-FSM запрашивает данные из FIFO путем поднятия сигнала "TX_FIFO_rd" (" rd_en" в FIFO), FIFO поставляет все данные, содержащиеся в нем, поскольку в тактовой области FIFO сигнал "rd_en" остается высоким в течение нескольких циклов.

FIFO должен предоставлять только одни данные за раз. Как только данные будут переданы, TX-FSM запросит следующие данные.

Как заставить FIFO и TX-FSM работать синхронно, используя одни часы?

Код FIFO VHDL:

      library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
 
entity FIFO is
  generic (
    FIFO_WIDTH          : natural := 32;
    FIFO_DEPTH          : integer := 10;
    ALMOST_FULL_LEVEL   : integer := 8;
    ALMOST_EMPTY_LEVEL  : integer := 2
    );
  port (
    reset    : in std_logic;
    clk      : in std_logic;        
 
    -- FIFO Write Interface
    wr_en           : in  std_logic;
    wr_data         : in  std_logic_vector(FIFO_WIDTH-1 downto 0);
    ALMOST_FULL     : out std_logic;
    FULL            : out std_logic;
 
    -- FIFO Read Interface
    rd_en           : in  std_logic;
    rd_data         : out std_logic_vector(FIFO_WIDTH-1 downto 0);
    ALMOST_EMPTY    : out std_logic;
    EMPTY           : out std_logic
    );
    
end FIFO;

architecture rtl of FIFO is
 
  type t_FIFO_DATA is array (0 to FIFO_DEPTH) of std_logic_vector(FIFO_WIDTH-1 downto 0);
  signal r_FIFO_DATA : t_FIFO_DATA := (others => (others => '0'));
 
  signal r_WR_INDEX   : integer range 0 to FIFO_DEPTH -1 := 0;
  signal r_RD_INDEX   : integer range 0 to FIFO_DEPTH -1 := 0;
 
  -- # Words in FIFO, has extra range to allow for assert conditions
  signal r_FIFO_COUNT : integer range -1 to FIFO_DEPTH+1 := 0;
 
  signal w_FULL  : std_logic;
  signal w_EMPTY : std_logic;
  
   
begin

-- FIFO process
-------------------------------------------------------------------
-------------------------------------------------------------------

 WRITE_INDEX : process(clk)
  begin
    if rising_edge(clk) then
      if reset = '1' then
        r_WR_INDEX <= 1;
      else
        if (wr_en = '1' and w_FULL = '0') then
          if r_WR_INDEX = FIFO_DEPTH-1 then
            r_WR_INDEX <= 1;
          else
            r_WR_INDEX <= r_WR_INDEX + 1;
          end if;
        end if;
      end if;
    end if;
  end process;
 
 READ_INDEX : process(clk)
  begin
    if rising_edge(clk) then
      if reset = '1' then
        r_RD_INDEX <= 0;
      else      
         if (rd_en = '1' and w_EMPTY = '0') then
            if r_RD_INDEX = FIFO_DEPTH-1 then
                r_RD_INDEX <= 0;
            else
                r_RD_INDEX <= r_RD_INDEX + 1;
            end if;
         end if;
      end if;
    end if;
  end process;
  
 COUNT_INDEX : process(clk)
  begin
    if rising_edge(clk) then
      if reset = '1' then
        r_FIFO_COUNT <= 0;
      else
        if (wr_en = '1' and rd_en = '0') then
          r_FIFO_COUNT <= r_FIFO_COUNT + 1;
        elsif (wr_en = '0' and rd_en = '1') then
            if r_FIFO_COUNT > 0 then
                r_FIFO_COUNT <= r_FIFO_COUNT - 1;
            end if;
        end if;
      end if;
    end if;
  end process;

  Write_Data : process (clk) is
    begin
        if rising_edge(clk) then
            if wr_en = '1' then
                r_FIFO_DATA(r_WR_INDEX) <= wr_data;
            end if;
        end if;                          
  end process;
 
   
  rd_data <= r_FIFO_DATA(r_RD_INDEX);
 
  w_FULL  <= '1' when r_FIFO_COUNT = FIFO_DEPTH else '0';
  w_EMPTY <= '1' when r_FIFO_COUNT = 0       else '0';
 
  ALMOST_FULL <= '1' when r_FIFO_COUNT > ALMOST_FULL_LEVEL else '0';
  ALMOST_EMPTY <= '1' when r_FIFO_COUNT < ALMOST_EMPTY_LEVEL else '0';
   
  FULL  <= w_FULL;
  EMPTY <= w_EMPTY;
   
end rtl;

TX-FSM-код

      -- Arinc 429 trasmitter interface

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity Tx is
    port 
        (
            --INPUT
            clk2M        : in std_logic;                        -- clock signal
            reset        : in std_logic;                        -- reset signal
            enable       : in std_logic;                        -- enable signal
            en_parity    : in std_logic;                        -- enable parity bit
            parity       : in std_logic;                        -- odd/even parity
            speed        : in std_logic;                        -- speed 100kbps or 12.5kbps    
            gap          : in std_logic;                        -- gap between two messages: 4 or 64 bit of gap
            TX_FIFO_ep   : in std_logic;                        -- TX FIFO EMPTY
            a429TX_in    : in std_logic_vector (31 downto 0);   -- data in
            
            --OUTPUT
            a429TX_outA  : out std_logic;                       -- positive out
            a429TX_outB  : out std_logic;                       -- negative out
            TX_FIFO_rd   : out std_logic                        -- TX FIFO READ
        );
        
end entity;

architecture RTL_A429TX of Tx is

-- FSM state name
type state_type is (IDLE,START, PAR,TRANSMITTING,WAITING);
signal state                : state_type;   
-- FSM register
signal shift_reg            : std_logic_vector (31 downto 0);   
signal shift_counter        : std_logic_vector (4 downto 0);
signal gap_counter          : std_logic_vector (6 downto 0);
-- speed clock register
signal clk429            : std_logic;
signal clk429_counter    : integer;
signal clk429_max_count  : integer;
signal clk429_half_count : integer;


begin
-- speed clock process
-------------------------------------------------------------------
-------------------------------------------------------------------
-- select speed process
process (speed)
    begin
        if (speed = '1') then
            clk429_max_count <= 19;         -- 100kbs/s
            clk429_half_count <= 10;
        else
            clk429_max_count <= 159;        -- 12.5kbs/s
            clk429_half_count <= 80;
        end if;
end process;

-- clock429 generate speed process          
process (clk2M, reset)
    begin
            if (reset = '1') then   
                clk429 <= '0';
            elsif rising_edge(clk2M) then
                    if (clk429_counter <= clk429_half_count ) then
                        clk429 <= '1';
                    else
                        clk429 <= '0';
                   end if;
            end if;
end process;

-- counter activity process
process (clk2M, reset)
    begin
        if (reset = '1') then   
            clk429_counter <= 0;
        elsif rising_edge(clk2M) then
                if (clk429_counter >= clk429_max_count) then
                    clk429_counter <= 0;
                else
                    clk429_counter <= clk429_counter + 1;
                end if;
        end if;
end process;
-------------------------------------------------------------------
-------------------------------------------------------------------

-- a429TX interface process
process (clk429, reset)
    variable p : std_logic;
    begin
        if reset = '1' then
            state           <= IDLE;
            shift_reg       <= (others => '0');
            shift_counter   <= (others => '0');
            gap_counter     <= (others => '0');
            a429TX_outA     <= '0';
            a429TX_outB     <= '0';
            TX_FIFO_rd      <= '0';
        elsif rising_edge(clk429) then
                case state is
                    when IDLE           =>  -- idle state
                                                if (enable = '1') then
                                                    if (gap = '1') then 
                                                        gap_counter <= "0000100"; -- 4 
                                                    else
                                                        gap_counter <= "1000000"; -- 64
                                                    end if;
                                                    if TX_FIFO_ep = '0' then
                                                        TX_FIFO_rd <= '1';
                                                        state <= START;
                                                    else
                                                        state <= IDLE;
                                                    end if;
                                                else
                                                    state <= IDLE;
                                                end if;     
                    when START          =>
                                                -- data formatting 
                                                TX_FIFO_rd <= '0';
                                                shift_reg <= a429TX_in(31 downto 8)& a429TX_in(0) & a429TX_in(1) & a429TX_in(2) & a429TX_in(3) & a429TX_in(4) & a429TX_in(5) & a429TX_in(6) & a429TX_in(7);
                                                shift_counter <= "11111";
                                                if ( en_parity = '1') then
                                                    state <= PAR;
                                                else
                                                    state <= TRANSMITTING;
                                                end if;
                                                    
                    when PAR            =>  -- parity state
                                                --TX_FIFO_rd <= '0';
                                                p := '0';
                                                for I in 31 downto 0 loop
                                                    p := p xor shift_reg(I);
                                                end loop;
                                                if (parity = '1') then
                                                    shift_reg(31) <= p;      -- odd
                                                else
                                                    shift_reg(31) <= not p;  -- even
                                                end if;
                                                state <= TRANSMITTING;
                                                
                    when TRANSMITTING   =>  -- transmission state
                                                --TX_FIFO_rd <= '0';
                                                a429TX_outA <= shift_reg(0);
                                                a429TX_outB <= not shift_reg(0);
                                                shift_reg <= shift_reg(0) & shift_reg(31 downto 1);
                                                if (shift_counter = "00000") then
                                                    state <= WAITING;
                                                else
                                                    shift_counter <= shift_counter -1;
                                                    state <= TRANSMITTING;
                                                end if;
                        
                    when WAITING        =>  -- wait state. generate gap
                                                a429TX_outA <= '0';
                                                a429TX_outB <= '0';
                                                if (gap_counter > 0) then
                                                    gap_counter <= gap_counter - 1;
                                                    state <= WAITING;
                                                else
                                                    state <= IDLE;
                                                end if;
                                                                                
                    when others         =>  -- default
                                                state <= IDLE;
                    end case;
        elsif falling_edge (clk429) then
            a429TX_outA <= '0';
            a429TX_outB <= '0';
        end if;
    end process;
    
    clk429 <= clk429;
end architecture; 

Спасибо за вашу помощь.

1 ответ

Запустите оба FIFO на частоте 2 МГц, а затем сгенерируйте индикацию включения одного цикла на TX_FIFO_rd, когда требуется передача данных чтения FIFO.

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

Кроме того, нехорошо (но на самом деле очень плохо :-) практика синхронного проектирования генерировать внутренние часы, такие как clk429, так как это приводит к сокращению ошибок и более сложному закрытию времени с помощью статического анализа времени (STA). Вместо этого сделайте сигнал включения, который выдается за один цикл, запустите проект на clk2M, и обновлять соответствующее состояние только при высоком уровне разрешающего сигнала.

Другие вопросы по тегам