[英]VHDL code works in a simulation but not on FPGA
我正在尝试使用缓冲区实现SPI主模块。 我使用此FSM模块进行测试,并通过UART将接收到的数据传输到我的串行控制台。
library IEEE;
USE ieee.std_logic_1164.all;
USE ieee.std_logic_arith.all;
USE ieee.std_logic_unsigned.all;
entity FSM_SPI_buf is
Port ( clk: in STD_LOGIC;
increase: in STD_LOGIC;
reset: in STD_LOGIC;
busy : in STD_LOGIC;
tx : out STD_LOGIC_VECTOR (7 downto 0);
rx : in STD_LOGIC_VECTOR (7 downto 0);
transmit : out STD_LOGIC;
loadFromRXBuf : out STD_LOGIC;
loadToTxBuf : out STD_LOGIC;
rxBufEmpty : in STD_LOGIC;
rxBufFull : in STD_LOGIC;
txBufEmpty : in STD_LOGIC;
txBufFull : in STD_LOGIC;
led: out STD_LOGIC_VECTOR (7 downto 0);
uartTXData: out STD_LOGIC_VECTOR(7 downto 0);
uartRXData: in STD_LOGIC_VECTOR(7 downto 0);
uartTXSig: out STD_LOGIC;
uartTXRdy: in STD_LOGIC ;
uartRXCont: out STD_LOGIC;
uartRXSig: in STD_LOGIC;
uartRXFrameError: in STD_LOGIC
);
end FSM_SPI_buf;
architecture Behavioral of FSM_SPI_buf is
type statex is (start,updateTX, closeTX, send,openRX, receive, closeRX,
sendUART,closeUART, stop);
signal state: statex:=start;
signal counter: integer range 0 to 5 := 0;
signal bytes:STD_LOGIC_VECTOR(31 downto 0) := x"030001FF";
signal bytes_rec:STD_LOGIC_VECTOR(31 downto 0):=x"03040506";
begin
process(clk, reset) begin
if(clk'event and clk = '1') then
case state is
when start =>
if(increase = '0') then
state <= updateTX;
counter <= 0;
uartrxCont <= '1';
else
state <= start;
end if;
when updateTX =>
if(counter < 4) then
loadToTxBuf <= '1';
tx<=bytes(31 - counter * 8 downto 32 - (counter+1) * 8);
counter <= counter + 1;
state <= closeTX;
else
state <= send;
end if;
when closeTX =>
loadToTxBuf <= '0';
state <= updateTX;
when send =>
transmit <= '1';
counter <= 0;
if (rxbuffull = '1') then
state <=openRX;
end if;
when openRX =>
transmit <= '0';
if(counter < 4) then
loadFromRxBuf <= '1';
state <=closeRX;
else
counter <= 0;
state <= sendUART;
end if;
when closeRX =>
loadFromRXBuf <= '0';
state <= receive;
when receive =>
bytes_rec(31 - (counter) * 8 downto 32 - (counter+1) * 8)<=rx;
counter <= counter + 1;
state <= openRX;
when sendUART =>
if(counter < 4) then
if uarttxRdy = '1' then
uarttxData <=bytes_rec(31 - (counter) * 8 downto 32 - (counter+1) * 8);
uarttxSig <= '1';
counter <= counter + 1;
state <= closeUART;
end if;
else
state <= stop;
end if;
when closeUART =>
if (uarttxRdy= '0') then
uarttxSig <= '0';
state <= sendUART;
else
state <= closeUART;
end if;
when stop =>
if (uarttxRdy= '0') then
uarttxSig <= '0';
end if;
if(increase = '1') then
state <= start;
else
state <= stop;
end if;
end case;
elsif(reset = '1') then
counter <= 0;
state <= updateTX;
end if;
end process;
end Behavioral;
这是SPI模块的摘录,其中我移出了接收的字节
if(rx_upd <='0' and loadFromRxBuf ='1') then
rx_upd <='1';
rx <= rx_buffer(d_width*buffer_size-1 downto d_width*(buffer_size-1));
rx_buffer<= rx_buffer(d_width*(buffer_size-1)-1 downto 0) & x"00";
elsif(rx_upd ='1' and loadFromRxBuf ='0') then
rx_upd <='0';
end if;
通过仿真判断,在发生UART发送之前,bytes_rec从其初始值转换为x“ FFFFFFFF”(miso始终为高)。
但是,当我将生成的位文件上传到我的FPGA(Mojo Board v3上的XC6SLX9)时,即使我将味o与3.3v信号源相连,我也只能通过UART接收零。 我已经通过通过它发送信号“字节”来检查我正在使用的UART实现,并且它工作得很好,所以我认为这不应该受到指责。
如果您不计算我复制的一些教程,这是我第一次编程FPGA,因此我希望将错误归因于此。 但是,请向我指出它的可能来源。 如果需要,我可以提供代码的其他部分。 先感谢您!
总体而言,这是非常好的代码,通过将其编写为具有正确敏感性列表的单个过程状态机,您已经躲开了很多潜在的麻烦。
我会观察到,UART的发送器和接收器半部通常在单独的进程中是单独的状态机,以允许全双工通信。 但是我不清楚这是否实际上是状态名称所暗示的UART或SPI(同步)接口,因此观察可能无关紧要。
但是,存在一个关键错误,至少适用于increase, rxBufFull, uarttxRdy
,可能还有其他错误。
让我们看一下closeUart
状态。
if uarttxRdy = '0' then
uarttxSig <= '0';
state <= sendUART;
-- else
-- state <= closeUART;
end if;
(不是重点,但是我注释掉了多余的行,因为否则会保留state
的当前值-不必要的代码通常不是一个好主意,即使只是增加了冗长和混乱。我也清理了布尔表达式周围的C样式线噪声)
这里的错误是uarttxRdy
显然是FPGA的外部输入,未同步到clk
。
因此, 此处所述的信号时序和同步设计的常规保证不适用于此 。
因此,您可以从此语句中得到两个结果:要么什么都不做,要么清除uarttxRdy
并开始发送。
但是,请想象一下,合成过程进行了相当合法的转换(以合并逻辑并保存门或缩短关键信号路径),从而:
if uarttxRdy= '0' then
uarttxSig <= '0';
end if;
if uarttxRdy= '0' then
state <= sendUART;
end if;
而且从您的输入引脚到每个比较的信号延迟都不同。
我认为您可以看到现在有四种可能的结果,包括开始发送而不清除uarttxSig
或清除它并保持此状态至少一个时钟周期。 这些都可以皇家破坏您的状态机。
因此很明显,异步输入需要特殊处理,才能将它们带入同步域。
只需在时钟沿复制它们,然后使用同步复制。 您可以在单独的同步过程中执行此操作,但是在状态机中的Case语句之前添加“默认操作”也是一种完全安全和正常的做法。 例如:
if rising_edge(clk) then
-- default actions : synch external inputs
uarttxRdy_s <= uarttxRdy;
-- state machine
case state is
when closeUART =>
if uarttxRdy_s = '0' then
这个问题通常被错误地标记为“ 亚稳 ”,但并非如此:这仅仅是由于异步输入的不同用途而导致的信号路径长度不同的结果。
当异步输入(几乎)恰好在时钟沿的同一时刻(在飞秒内)到达时,就会发生亚稳态,因此寄存器看不到有效的“ 0”或“ 1”逻辑电平,并锁存该非电平。 这就像使滚珠保持在销点上一样,球迟早会掉落。
对于当前的FPGA,这种可能性很小,但是如果您仍然担心的话,请在每个外部信号上添加第二级同步。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.