不同的时钟域VHDL



我正在制作一个自定义硬件ARINC 429 Core。目前,我已经描述了根据ARINC 429标准和FIFO传输中的模块(TX-FSM(,它从中获取数据并将其发送到外部。FIFO的工作频率为2MHz(clk2M(,而TX-FSM可以根据标准从2MHz产生100kb/s或12.5kb/s(clk429(的频率。

由于FIFO工作在较高的频率(2MHz(,而TX-FSM工作在较低的频率(100kb/s(,当TX-FSM通过升高";TX_ FIFO_;信号(FIFO上的"rd_en"(,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; 

谢谢你的帮助。

在2 MHzclk2M下运行两个FIFO,然后在需要FIFO读取数据传输时在TX_FIFO_rd上生成单周期启用指示。

因此,您可以从同步设计中获得好处,而无需处理多个时钟域。

此外,生成像clk429这样的内部时钟并不是好的(但实际上非常糟糕:-(同步设计实践,因为它会导致错误修剪设计和更复杂的静态时序分析(STA(时序闭合。相反,制作一个断言为单个周期的使能信号,在clk2M上运行设计,并且仅在使能信号为高时更新相关状态。

相关内容

  • 没有找到相关文章

最新更新