0

我一直在尝试实现一个 UART,以便在我的 Lattice MachXO3D 板和我的计算机之间进行通信。目前我正在尝试实现来自 FPGA 的传输。

在硬件上进行测试时,我遇到了一个非常奇怪的问题。如果运行正常,它会运行几秒钟,然后突然停止运行(连接到我的电脑的CH340会报告它正在接收包含0x0的消息)。但是,如果我通过 Lattice Diamond 软件将逻辑分析仪嵌入到 FPGA 中,并运行该分析仪,它将在很长一段时间内完美运行。

遗憾的是,我没有逻辑分析仪,因此嵌入式逻辑分析仪是我了解实际传输内容的唯一机会。

这些是与我的实现相关的文件:

波特根

LIBRARY IEEE; 
USE IEEE.std_logic_1164.ALL;
USE IEEE.numeric_std.ALL;
-- Generates 16 ticks per bit
ENTITY baud_gen IS
  GENERIC(divider: INTEGER := 13 -- 24M/115200*16
          );
  PORT(
    clk, reset: IN STD_LOGIC;
    s_tick: OUT STD_LOGIC
    );
END baud_gen;

ARCHITECTURE working OF baud_gen IS
  
BEGIN
  PROCESS(clk)
    VARIABLE counter: UNSIGNED(3 DOWNTO 0) := to_unsigned(0,4);
  BEGIN
    IF clk'EVENT AND clk='1' THEN
      IF reset='1' THEN
        s_tick <= '0';
        counter := to_unsigned(0,4);
      ELSIF counter=to_unsigned(divider-1,4) then
        s_tick <= '1';
        counter:= to_unsigned(0,4);
      ELSE
        s_tick <= '0';
        counter := counter + 1;
      END IF;
    END IF;
  END PROCESS;
END working;

rs232_tx

LIBRARY IEEE; 
USE IEEE.std_logic_1164.ALL;
USE IEEE.numeric_std.ALL;

ENTITY rs232_tx IS
  PORT(clk: IN std_logic;
       tx: OUT std_logic;
       rst: IN std_logic;
       fifo_empty: IN std_logic;
       fifo_RdEn, fifo_RdClock: OUT std_logic;
       fifo_data: IN STD_LOGIC_VECTOR(7 DOWNTO 0);
       Q: OUT STD_LOGIC_VECTOR(1 DOWNTO 0));
END rs232_tx;

ARCHITECTURE working OF rs232_tx IS
  TYPE state IS (idle,start,data);
  SIGNAL tx_pulse: STD_LOGIC := '1';
  SIGNAL s_tick: STD_LOGIC;
  SIGNAL pr_state, nx_state: state := idle;
  SIGNAL data_val: std_logic_vector(7 DOWNTO 0):=(others=>'0');
  SIGNAL data_count: unsigned(2 DOWNTO 0):=to_unsigned(0,3);
BEGIN
  process(s_tick, rst)
    VARIABLE count: unsigned(3 DOWNTO 0):= to_unsigned(0,4);
  BEGIN
    IF rising_edge(s_tick) THEN
      count := count + to_unsigned(1,4);

      IF count = to_unsigned(15,4) THEN
        tx_pulse <= '1';
      ELSE
        tx_pulse <='0';
      END IF; 
    END IF;
  END PROCESS;

  process(tx_pulse,rst)
  BEGIN
    IF rising_edge(tx_pulse) THEN
      IF rst='1' THEN
        pr_state <= idle;
        data_val <= (others=>'0');
        data_count <= to_unsigned(0,3);
      ELSE
        pr_state <= nx_state;
        CASE pr_state IS
          WHEN idle =>
            data_count <= to_unsigned(0,3);
          WHEN data =>
            data_count <= data_count + to_unsigned(1,3);
          WHEN start =>
            data_val <= fifo_data;
          WHEN OTHERS =>
        END case;
        
      END IF;
    END IF;
  END process;

  process(fifo_empty,rst,data_count,pr_state,data_count)
  BEGIN
    case pr_state is
      when idle =>
        Q <= ('1','1');
        fifo_RdEn <= '0';
        tx <= '1';
        IF fifo_empty='0' AND rst='0' THEN          
          nx_state <= start;
        ELSE          
          nx_state <= idle;
        END IF;
      WHEN start =>
        Q <= ('1','0');
        fifo_RdEn <= '1';
        tx <= '0';
        nx_state <= data;
      WHEN data =>
        Q <= ('0','1');
        fifo_RdEn <= '0';
        tx <= data_val(to_integer(data_count));
        if data_count=to_unsigned(7,3) then
          nx_state <= idle;
        ELSE
          nx_state <= data;
        end if;

    end case;
  END process;
  
  fifo_RdClock <= tx_pulse;
  baud_gen: ENTITY work.baud_gen
    PORT MAP(clk,reset=>'0',s_tick=>s_tick);
END working;

试验台

LIBRARY IEEE; 
USE IEEE.std_logic_1164.ALL;
USE IEEE.numeric_std.ALL;

ENTITY rs232_tx_test IS
  GENERIC(clk_period: TIME := 41666666.7 fs;
          baud_period: TIME := 8680.55556 ns);
END rs232_tx_test;

ARCHITECTURE working OF rs232_tx_test IS
  SIGNAL clk: STD_LOGIC := '0';
  SIGNAL tx, rst, fifo_empty, fifo_RdEn, fifo_RdClock: STD_LOGIC;
  SIGNAL fifo_data: STD_LOGIC_VECTOR(7 DOWNTO 0);
BEGIN
  clk <= NOT clk AFTER clk_period/2;
  rst <= '1', '0' AFTER 100 ns;
  PROCESS
  BEGIN
    fifo_empty <= '1';
    WAIT FOR baud_period;
    fifo_empty <= '0';
    WAIT FOR baud_period*16;
  END PROCESS;

  fifo_data <= ('1','1','0','0','1','0','1','1') WHEN fifo_RdEn='1' ELSE (others=>'0');
  dut: ENTITY work.rs232_tx
    PORT MAP(clk,tx,rst,fifo_empty,fifo_RdEn,fifo_RdClock,fifo_data);
END working;

编辑 我已经测试了我在网上找到的另一个 UART 设计@ 9600 bps,它以同样的方式失败。它可以向我计算机上的终端发送一个常量字符,在本例中为“a”,然后它突然停止发送任何内容。但是,如果我开始听我在 Lattice Diamond 中生成的软逻辑分析仪,它就可以正常工作并且不会失败。

4

1 回答 1

0

这听起来像是一个经典的时间问题。

在评论中,其他人已经解释了代码中可能间接导致这种情况的弱点。我将专注于正在发生的事情。

正如您所说,在模拟中,您的代码按预期工作。然而,这只是故事的一半。要创建 FPGA 比特流,构建工具会获取您的代码和其他几个文件、综合并进行布局布线。您的时间问题发生在 P&R 期间。这就是为什么您的模拟不会出现任何错误的原因,因为我假设它是 RTL(预布局和布线)模拟。

在 P&R 期间,工具以适合器件时序模型的最佳方式放置逻辑,因此所有路径都满足其时序要求。路径时序要求源自时序约束文件中的显式语句,并从您的代码中推断出来(这就是为什么您的编码风格很重要)。

一旦 P&R 完成,这些工具会将构建工件放入静态时序分析器 (STA) 工具,并报告构建是否未能满足时序要求。

这导致两个问题:

  1. 构建是否报告时序错误?
  2. 您是否有时间约束文件 - 如果您不确定,答案是否定的。

调试问题的方法是使用 Lattice Diamond 生成的 Timing Report 来查看故障所在。如果没有报告失败,则意味着您的时序模型是错误的,因为缺少适当的时序约束。至少,您需要约束设计中的所有 IO 并描述设计中的所有时钟。

这是一个可以帮助您的好文档: https ://www.latticesemi.com/-/media/LatticeSemi/Documents/UserManuals/RZ/Timing_Closure_Document.ashx?document_id=45588

当您使用嵌入式逻辑分析器时,您的设计能够正常工作的原因是在设计中放置了额外的逻辑,这会改变时序模型。P&R 工具对设计进行了不同的布局,幸运的是,设计的布局符合其真正的时序要求。

正如我经常对我的软件工程师同事说的那样,软件语言创建一组指令,HDL 创建一组建议。

于 2020-10-16T09:48:08.733 回答