我正在尝试为uart发射器构建通用波特率发生器过程。
如果忽略波特率分频器并传入灵敏度列表中的clk信号,则变送器工作正常。但是如果我尝试实现分隔符,我会收到错误(在代码注释中描述)。我尝试了两种不同的方法,两者都给出了错误,或者没有预期的输出。是的,发布的确切代码不起作用,因为我分配两次fbaud,我评论一个测试。
也许我不明白波特率发生器应该如何工作。根据我的理解,fpga时钟以50mHz运行,这对于rs232通信来说是快速的。所以我们需要等待一定数量的时钟周期才能传输我们的角色。
在这种情况下,我们有一个可变的波特率,所以我们将波形发生器除以库存时钟,以获得我们需要等待的时钟周期数,然后再发送我们的' tick'发信号到发送状态机。
波特率分频器在测试台中设置为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 ;
答案 0 :(得分:1)
此代码存在一些潜在问题,但似乎导致您失败的原因是您将fbaud_counter
声明为整数,但没有指定范围限制,更关键的是,您&# 39;当它达到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,因为您的代码表明它应该是,将brd
设置为x"000008"
会给您一个非常慢的滴答速率(8 Hz,奇怪的是)。我将分子缩减到5000只是为了加快速度。
我也意识到我没有覆盖你的浮点异常(感谢你指出这一点)。
警告提示错误。 &#34;检测到元值,返回0&#34;。该警告表示to_integer
正在尝试将无法解析的值转换为1或0(例如'X'
或其他此类std_logic
值),当然您不能除以0.这很可能是一个初始化问题(注意你的致命错误是Time: 0 ns Iteration: 0
)。在您的测试平台中,brd
最初是如何驱动的?你能给它一个默认值吗?如果没有,你需要以其他方式防范这种情况。
答案 1 :(得分:0)
当你模拟它时,听起来你的brd
输入没有被初始化,所以U
s变成0
s并且你除以零 - 因此是例外。< / p>
此外,这将合成一个非常大的,资源方面的东西:
fbaud <= (50000000)/to_integer(signed(brd));
您要求每个时钟周期计算一次,这是硬件的一个大问题。
通常的方法是接受终端计数(您的fbaud
)作为输入,让控制软件找出值应该是什么。或者在编译时将其计算为常量,具体取决于您需要的灵活性。