【问题标题】:VHDL code works in a simulation but not on FPGAVHDL 代码在仿真中工作,但在 FPGA 上不工作
【发布时间】:2016-11-05 08:00:10
【问题描述】:

我正在尝试使用缓冲区实现 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;

从模拟 bytes_rec 判断,在 UART 传输发生之前,它的起始值会转换为 x"FFFFFFFF"(miso 始终为高电平)。

Simulation Screenshot

但是,当我将生成的位文件上传到我的 FPGA(Mojo Board v3 上的 XC6SLX9)时,即使我将味噌连接到 3.3v 电源,我也只能通过 UART 收到零。我通过发送信号“字节”检查了我正在使用的 UART 实现,它工作得很好,所以我认为这不是罪魁祸首。

如果你不计算我复制的一些教程,这是我第一次编程 FPGA,所以我预计错误会归因于此。 但请指出它的可能来源。如果需要,我可以提供我的代码的其他部分。 先感谢您!

【问题讨论】:

    标签: vhdl fpga xilinx hdl modelsim


    【解决方案1】:

    这是相当不错的代码,总体而言,通过将其编写为具有正确敏感性列表的单个进程状态机,您已经躲过了很多潜在的问题。

    我会观察到,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 同步。

    因此,信号时序和同步设计的通常保证,如described here,不适用于它。

    因此,您希望从该语句中得到两个结果:要么什么都没有发生,要么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
    

    这个问题经常被错误地标记为“metastability”,但事实并非如此:这只是异步输入的不同用途的不同信号路径长度的结果。

    当异步输入到达(几乎)与时钟边沿完全相同的时刻(在飞秒内)时,就会发生亚稳态,因此寄存器看不到有效的“0”或“1”逻辑电平,并锁存该非等级。这就像在销钉上平衡一个滚珠轴承,滚珠迟早会掉下来。

    对于当前的 FPGA,它的可能性非常小,但如果您仍然担心,请在每个外部信号上添加第二阶段的同步。

    【讨论】:

    • 感谢您的回复和解释——我会相应地修改我的代码。也很抱歉,我没有明确说明 uartTXRdy 不是外部输入——它实际上是来自 UART 模块的信号。我正在使用的代码可在此处获得:github.com/Domipheus/UART 并且 txRdy 采用以下值:空闲时为 1',传输时为 '0'。
    • 如果这个模型的所有外部输入(不仅仅是 uartTxRdy)都是同步的......那么肯定有其他问题。检查综合报告是否有证据表明一些简单的错误让综合器完全排除了你的所有逻辑!
    • Brian,我试图通过仅使用 SPI 主模块和 FSM 模块来简化我的项目,但是当我合成它时 (pastebin.com/aWndX0eY),它给了我相当多的警告 (pastebin.com/DKMs4ind) ,这似乎引起了我的麻烦。您能否向我解释一下为什么它会削减我的一些逻辑以及我可以做些什么来避免这个问题?
    • 只看第一个警告。然后在记住该警告的情况下查看代码(在 Pastebin 链接中,它与上面发布的代码不同)。关于其中一个模块的第一个警告是正确的。结果,该模块显然什么都不做,删除它可能也允许修剪更多代码。
    • 我修复了第一个关于未使用 的警告。但它仍然会修剪 s_rx、ss、sclk 以及来自 SPI 模块的其他一些信号。
    猜你喜欢
    • 2018-02-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-10-10
    • 1970-01-01
    • 2017-04-11
    • 2012-12-01
    • 2015-11-06
    相关资源
    最近更新 更多