-1

I'm making a custom hardware ARINC 429 Core. For now I have described the module in transmission (TX-FSM), according to the ARINC 429 standard and a FIFO in transmission from which it takes the data and sends them to the outside. The FIFO works at a frequency of 2MHz (clk2M), while TX-FSM can generate a frequency of 100kb / s or 12.5kb / s (clk429) from 2MHz as per standard.

Since the FIFO works at a higher frequency (2 MHz), and the TX-FSM works at a lower frequency (100 kb/s), when the TX-FSM requests a data from the FIFO by raising the "TX_FIFO_rd" signal ("rd_en" on FIFO ), the FIFO supplies all the data contained within it, since in the FIFO clock domain the "rd_en" signal remains high for several cycles.

The FIFO should only provide one data at a time. Once the data has been transmitted, the TX-FSM will request the next data.

How can I make the FIFO and TX-FSM work in sync using a single clock?

FIFO VHDL code:

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 code

-- 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; 

Thanks for your help.

KemKing
  • 11
  • 3

1 Answers1

0

Run both FIFOs at the 2 MHz clk2M, and then generate a single cycle enable indication on TX_FIFO_rd when FIFO read data transfer is required.

Thereby you can get the benefit from synchronous design, without the hazzle of handling multiple clock domains.

Also, it is not good (but actually very bad :-) synchronous design practice to generate internal clock like the clk429, since it results in error prune design and more complex timing closure with Static Timing Analysis (STA). Instead make an enable signal that is asserted a single cycle, run the design on the clk2M, and the only update the relevant state when the enable signal is high.

Morten Zilmer
  • 15,586
  • 3
  • 30
  • 49