0

我正在尝试为 uart 发送器构建通用波特率生成器过程。

如果我忽略波特率分频器并在灵敏度列表中传递 clk 信号,则发射器工作正常。但是如果我尝试实现分隔符,我会得到错误(在代码注释中描述)。我尝试了两种不同的方法,要么都给出了错误,要么没有预期的输出。是的,发布的确切代码将不起作用,因为我分配了两次 fbaud,我将其中一个注释掉以进行测试。

也许我不明白波特发生器应该如何工作。据我了解,fpga 时钟以 50mHz 运行,这对于 rs232 通信来说是快速的。所以我们需要等待一定数量的时钟周期才能传输我们的字符。

在这种情况下,我们有一个可变波特率,因此我们将备用时钟除以波特率发生器,以获得在将“滴答”信号发送到发送状态机之前需要等待的时钟周期数。

波特率分频器在测试台中设置为 x"000008"。


-- Universal Asynch Receiver Transmitter
---------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity eds_uart is
   generic (width : positive := 16);
   port ( clk,reset: in std_logic ;
     din_wen: in std_logic; -- state machine sets value thus buffer needed
     brd : in std_logic_vector(23 downto 0); -- buad rate dividor
     din : in std_logic_vector(7 downto 0); -- input value
     txd: out std_logic; -- sent data bit
     tx_busy : buffer std_logic -- sent data bit active
     );
end entity eds_uart;

architecture behaviour of eds_uart is
    type state_type is (idle_s, wait_s, transmit_s);  -- three possible states of uat
    signal current_s: state_type; 
    signal tick: std_logic := '0'; -- baud rate clock
    signal count: integer := 0; -- count number of characters sent
    signal shift: std_logic_vector(9 downto 0); -- intermediate vector to be shifted
    signal fbaud: integer := 0;
    signal fbaud_counter: integer := 0;

begin
   --- process that is causing the issue. 
   process(clk, brd) begin
      fbaud <= (50000000)/to_integer(signed(brd)); -- 50,000,000 is the default clock Hz
      ------ error message  ------
      --# ** Warning: NUMERIC_STD.TO_INTEGER: metavalue detected, returning 0
      -- # Time: 0 ns  Iteration: 0  Instance: /eds_uart_tb/inst_uart
      -- # ** Fatal: (SIGFPE) Floating point exception.
      --#    Time: 0 ns  Iteration: 0  Process: /eds_uart_tb/inst_uart/line__29 File: 

      fbaud <= 50000;
      --- error ---
      -- this command simply does not work, it compiles and runs though
      -- I don't get any transitions in my output wave
      -- I don't think it is entering the transmit stage based on a clock signal

      if (rising_edge(clk)) then
         if (fbaud_counter = fbaud) then -- tick when proper number of counts have appeared
             tick <= '1';
         elsif (fbaud_counter < fbaud) then
             tick <= '0';
             fbaud_counter <= fbaud_counter + 1;
         end if;
      end if;
   end process; 

   process(tick, reset, din) begin 
       if (reset = '1') then
           current_s <= idle_s; -- default state
           count <= 0; -- reset character counter
           txd <= '1'; 
           tx_busy <= '0'; 
       elsif (current_s = idle_s and din_wen = '1') then -- transition when write enable is high
           current_s <= wait_s; -- transition
           tx_busy <= '1';  
           shift <= '1' & din & '0'; -- init shift value
       end if;
       if(rising_edge(tick)) then
          if (current_s = wait_s) then -- transition on clock signal
               current_s <= transmit_s;
          elsif (current_s = transmit_s) then -- transition on clock signal
               if (count < 9) then
                   txd <= shift(0); -- output value
                   shift <= '0' & shift(9 downto 1); -- shift to next value
                   count <= count + 1; -- increment counter
                   current_s <= transmit_s; -- dont change state
               elsif (count = 9) then 
                   txd <= shift(0); -- send last element
                   count <= 0;
                   tx_busy <= '0'; -- reset busy signal
                   current_s <= idle_s; -- start process again
              end if;
          end if;
      end if;
   end process;
end architecture behaviour ;
4

2 回答 2

1

此代码存在一些潜在问题,但似乎导致您失败的原因是您声明fbaud_counter为整数但未指定范围限制,更关键的是,当它达到您的fbaud计数值时您没有清除它. 由于在达到计数后您从未重置该值,因此它将继续计数所有 2^32 值,然后再回绕并fbaud再次匹配。无论如何,范围限制可能是一个好主意,但无论哪种方式,如果您不重置它,您的波特率将不正确。例如:

if (rising_edge(clk)) then
  if (fbaud_counter = fbaud - 1) then
    tick <= '1';
    fbaud_counter <= 0;   
  else
    tick <= '0';
    fbaud_counter <= fbaud_counter + 1;
  end if;
end if;

请注意,那里确实不需要elsif条件,因为确实没有您不想设置或tick增加'0'计数的条件。请注意,我也数到fbaud - 1- 如果您从 0 开始,一直数到fbaud可能会稍微降低您的费率。

编辑

我用我建议的过程更改模拟了上述内容,并且得到了响应txd(以及稳定的tick)。你确定你模拟的时间足够长吗?假设您的时钟设置为 50 MHz,正如您的代码所指示的那样,设置brdx"000008"会给您一个非常慢的滴答率(8 Hz,很奇怪)。我将分子减少到 5000 只是为了加快速度。

我也意识到我没有涵盖您的浮点异常(感谢您指出这一点)。

警告是对错误的提示。“检测到元值,返回 0”。警告表明to_integer正在尝试将无法解析的值转换为 1 或 0(例如'X'或其他此类std_logic值),当然您不能除以 0。这很可能是初始化问题(请注意你的致命错误说Time: 0 ns Iteration: 0)。在您的测试平台中,brd最初是如何驱动的?你能给它一个默认值吗?如果没有,您将需要以其他方式防范这种情况。

于 2014-07-11T14:51:08.427 回答
0

当你模拟它时,听起来你的brd输入没有被初始化,所以Us 变成了0s 并且你被零除 - 因此是例外。

此外,这将综合到非常大的资源方面:

fbaud <= (50000000)/to_integer(signed(brd));

您要求在每个时钟周期进行计算,这对硬件来说是一个很大的要求。

通常的方法是接受一个终端计数(你的fbaud)作为输入,让控制软件找出应该是什么值。或者在编译时将其计算为常数,具体取决于您需要的灵活性。

于 2014-07-16T13:20:42.453 回答