VHDL FSM不改变状态

时间:2014-08-09 19:45:48

标签: vhdl fsm

嘿,我是VHDL的初学者,目前我正在尝试为开放像素控制(OPC)协议编写协议解码器:http://openpixelcontrol.org/

我已经在VHDL中实现了一个FSM,通过从串行/ RS232接收器读取字节来解码OPC消息。 RX模块将接收到的字节作为std_logic_vector输出,并创建一个gclk周期长的数据就绪脉冲。

在我的顶级实体中,我已将RX和解码器模块连接到相同的全局时钟网络。来自RX模块的数据就绪脉冲直接连接到相关FSM的i_dataready输入。

虽然我在过去几天内多次检查过此FSM的代码,并且搜索了一下,但我无法找出为什么我的FSM不会改变状态。

让我感到困惑的是,另外两个模块,一个串行TX和另一个模块在接收到来自RX模块的数据就绪信号后改变状态就好了,只是这个FSM不起作用。

这是我写的代码:

编辑:好的我已经对我的完整顶级实体进行了更多模拟: 该系统目前运行频率为2MHz(我知道速度很慢,但我现在只能做它)。

根据Active-HDL中的模拟,系统按预期工作。

这是我的顶级实体:

library IEEE;
use IEEE.STD_LOGIC_1164.all;

entity serial_test is 
    port(
        i_gclk: in std_logic;
        i_rx: in std_logic;
        o_tx: out std_logic;
        o_go: out std_logic;
        o_newdata: out std_logic;
        o_ws: out std_logic;
        o_leds: out std_logic_vector(2 downto 0)
    );
end serial_test;

architecture rtl of serial_test is

    signal txact, txdone: std_logic;

    signal rxdata: std_logic_vector(7 downto 0);
    signal rgbdata: std_logic_vector(7 downto 0);
    signal opc_chan: std_logic_vector(7 downto 0);
    signal go: std_logic;
    signal opc_state: std_logic_vector(2 downto 0);
    signal newrgb: std_logic;

begin

    opcdec_inst: entity work.opc_decoder
        port map(i_gclk => i_gclk, i_dataready => go, i_rawdata => rxdata, o_channel => opc_chan, o_rgbdata => rgbdata, o_state => opc_state, o_newdata => newrgb);

    urx_inst: entity work.uart_rx    
        port map(i_clk => i_gclk, i_rx_serial => i_rx, o_rx_dv => go, o_rx_byte => rxdata);

    utx_inst: entity work.uart_tx    
        port map(i_clk => i_gclk, i_tx_dv => go, i_tx_byte => rxdata, o_tx_active => txact, o_tx_serial => o_tx, o_tx_done => txdone);

    wsdrv_inst: entity work.ws2812_driver
        port map(i_gclk => i_gclk, i_rgbdata => rgbdata, i_newdata => newrgb, o_serial => o_ws);

    -- output FSM state to LEDs 
    o_leds <= opc_state;

    -- output go signal for signal analyzer
    o_go <= go;
    o_newdata <= newrgb;

end rtl;

我的顶级实体的测试平台

LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
USE ieee.numeric_std.ALL;

ENTITY testbench IS
END testbench;

ARCHITECTURE behavior OF testbench IS 

    COMPONENT serial_test
    PORT(
        i_gclk : IN std_logic;
        i_rx : IN std_logic;
        o_tx: OUT std_logic;
        o_go : OUT std_logic;
        o_newdata : OUT std_logic;
        o_ws : OUT std_logic;
        o_leds : OUT std_logic_vector(2 downto 0)
        );
    END COMPONENT;

    SIGNAL i_gclk :  std_logic := '1';
    SIGNAL i_rx :  std_logic := '1';    
    SIGNAL o_tx : std_logic;
    SIGNAL o_go :  std_logic;
    SIGNAL o_newdata :  std_logic;
    SIGNAL o_ws :  std_logic;
    SIGNAL o_leds :  std_logic_vector(2 downto 0);

BEGIN

-- Please check and add your generic clause manually
    uut: serial_test PORT MAP(
        i_gclk => i_gclk,
        i_rx => i_rx,    
        o_tx => o_tx,
        o_go => o_go,
        o_newdata => o_newdata,
        o_ws => o_ws,
        o_leds => o_leds
    );

    p_GCLK: process
    begin
        i_gclk <= not i_gclk;
        wait for 250ns;
    end process p_GCLK;

    p_RX: process
    begin  
        --wait for 375ns;
        wait for 1ms;
        -- first byte: 0x01  (CHANNEL)
        i_rx <= '0';
        wait for 104us;
        i_rx <= '1';
        wait for 104us;
        i_rx <= '0';
        wait for 104us;
        i_rx <= '0';
        wait for 104us;
        i_rx <= '0';
        wait for 104us;
        i_rx <= '0';
        wait for 104us;
        i_rx <= '0';
        wait for 104us;
        i_rx <= '0';
        wait for 104us;
        i_rx <= '0';
        wait for 104us;
        i_rx <= '1';
        wait for 104us;

        -- second byte: 0x00  (COMMAND)
        i_rx <= '0';
        wait for 104us;
        i_rx <= '0';
        wait for 104us;
        i_rx <= '0';
        wait for 104us;
        i_rx <= '0';
        wait for 104us;
        i_rx <= '0';
        wait for 104us;
        i_rx <= '0';
        wait for 104us;
        i_rx <= '0';
        wait for 104us;
        i_rx <= '0';
        wait for 104us;
        i_rx <= '0';
        wait for 104us;
        i_rx <= '1';
        wait for 104us;

        -- third byte 0x00(LENGTH MSB)
        i_rx <= '0';
        wait for 104us;
        i_rx <= '0';
        wait for 104us;
        i_rx <= '0';
        wait for 104us;
        i_rx <= '0';
        wait for 104us;
        i_rx <= '0';
        wait for 104us;
        i_rx <= '0';
        wait for 104us;
        i_rx <= '0';
        wait for 104us;
        i_rx <= '0';
        wait for 104us;
        i_rx <= '0';
        wait for 104us;
        i_rx <= '1';
        wait for 104us;

        -- fourth byte 0x03 (LENGTH LSB)
        i_rx <= '0';
        wait for 104us;
        i_rx <= '1';
        wait for 104us;
        i_rx <= '1';
        wait for 104us;
        i_rx <= '0';
        wait for 104us;
        i_rx <= '0';
        wait for 104us;
        i_rx <= '0';
        wait for 104us;
        i_rx <= '0';
        wait for 104us;
        i_rx <= '0';
        wait for 104us;
        i_rx <= '0';
        wait for 104us;
        i_rx <= '1';
        wait for 104us;

        -- fifth byte 0xCD
        i_rx <= '0';
        wait for 104us;

        i_rx <= '1';
        wait for 104us;
        i_rx <= '0';
        wait for 104us;
        i_rx <= '1';
        wait for 104us;
        i_rx <= '1';
        wait for 104us;
        i_rx <= '0';
        wait for 104us;
        i_rx <= '0';
        wait for 104us;
        i_rx <= '1';
        wait for 104us;
        i_rx <= '1';
        wait for 104us;

        i_rx <= '1';
        wait for 104us;

        -- sixth byte 0xBA
        i_rx <= '0';
        wait for 104us;

        i_rx <= '0';
        wait for 104us;
        i_rx <= '1';
        wait for 104us;
        i_rx <= '0';
        wait for 104us;
        i_rx <= '1';
        wait for 104us;
        i_rx <= '1';
        wait for 104us;
        i_rx <= '1';
        wait for 104us;
        i_rx <= '0';
        wait for 104us;
        i_rx <= '1';
        wait for 104us;

        i_rx <= '1';
        wait for 104us;

        -- seventh byte 0xFE
        i_rx <= '0';
        wait for 104us;

        i_rx <= '0';
        wait for 104us;
        i_rx <= '1';
        wait for 104us;
        i_rx <= '1';
        wait for 104us;
        i_rx <= '1';
        wait for 104us;
        i_rx <= '1';
        wait for 104us;
        i_rx <= '1';
        wait for 104us;
        i_rx <= '1';
        wait for 104us;
        i_rx <= '1';
        wait for 104us;

        i_rx <= '1';
        wait for 104us;

        wait for 10ms;

    end process p_RX;

END;

在这里您可以看到模拟器产生的波形。它清楚地表明,至少在模拟中,FSM确实改变了状态,甚至o_newdata也按预期工作。 eliaselectronics.com/wp-content/uploads/2014/08/opc_dec_simulation.jpg (抱歉,我还不能在StackOverflow上发布图片,而是将它们上传到我的网站上)

opc_dec_simulation.jpg

此屏幕截图显示了使用逻辑分析仪实际测量的莱迪思CPLD信号。 在这种情况下,我们可以看到状态没有变化,o_ws和o_newdata也没有变化。 eliaselectronics.com/wp-content/uploads/2014/08/opc_dec_measured.png

opc_dec_measured.png

现在知道我的FSM代码应该没问题,我认为这与实际合成到硬件有关,可能是过度传播延迟或时钟偏差等。有没有办法以某种方式解决这个问题?

这是有问题的FSM代码

library IEEE;
use IEEE.STD_LOGIC_1164.all;
use IEEE.NUMERIC_STD.all;

entity opc_decoder is 
    port(
        i_gclk: in std_logic;                           -- global system clock
        i_dataready: in std_logic;                      -- data ready signal from previous block (length: 1 gclk cycle)
        i_rawdata: in std_logic_vector(7 downto 0);     -- raw byte received by previous block
        o_channel: out std_logic_vector(7 downto 0);    -- output channel address for output MUX
        o_rgbdata: out std_logic_vector(7 downto 0);    -- decoded OPC data byte (R|G|B)
        o_state: out std_logic_vector(2 downto 0); 
        o_newdata: out std_logic                        -- data synchronization signal for next block
    );
end opc_decoder;

architecture rtl of opc_decoder is

    type t_OPC_SM is (s_IDLE, s_OPC_CMD, s_OPC_LEN_HI, s_OPC_LEN_LO, s_OPC_DATA);

    signal r_OPC_SM: t_OPC_SM := s_IDLE;

    signal r_OPC_CHANNEL: std_logic_vector(7 downto 0); -- decoded channel number/address
    signal r_OPC_COUNT: unsigned(15 downto 0);  -- number of actual RGB data bytes to be received

begin

    p_OPC_SM: process(i_gclk) is
    begin   
        if(rising_edge(i_gclk)) then
            o_newdata <= '0';

            case r_OPC_SM is

                when s_IDLE =>

                    r_OPC_CHANNEL <= (others=>'0');
                    r_OPC_COUNT <= (others=>'0');

                    if(i_dataready = '1') then
                        r_OPC_CHANNEL <= i_rawdata;
                        r_OPC_SM <= s_OPC_CMD;
                    else
                        r_OPC_SM <= s_IDLE;
                    end if;

                when s_OPC_CMD =>

                    if(i_dataready = '1') then
                        r_OPC_SM <= s_OPC_LEN_HI;
                    else
                        r_OPC_SM <= s_OPC_CMD;
                    end if;

                when s_OPC_LEN_HI =>

                    if(i_dataready = '1') then
                        r_OPC_COUNT <= unsigned(i_rawdata) & r_OPC_COUNT(7 downto 0);
                        r_OPC_SM <= s_OPC_LEN_LO;
                    else
                        r_OPC_SM <= s_OPC_LEN_HI;
                    end if;

                when s_OPC_LEN_LO =>
                    if(i_dataready = '1') then
                        r_OPC_COUNT <= r_OPC_COUNT(15 downto 8) & unsigned(i_rawdata);
                        r_OPC_SM <= s_OPC_DATA;
                    else
                        r_OPC_SM <= s_OPC_LEN_LO;
                    end if;

                when s_OPC_DATA =>

                    if(i_dataready = '1') then
                        if (r_OPC_COUNT > 0) then
                            o_rgbdata <= i_rawdata;
                            o_newdata <= '1';
                            r_OPC_COUNT <= r_OPC_COUNT - 1;
                            r_OPC_SM <= s_OPC_DATA;
                        else
                            r_OPC_SM <= s_IDLE;
                        end if;
                    else
                        r_OPC_SM <= s_OPC_DATA;
                    end if;

                when others =>
                    r_OPC_SM <= s_IDLE;

            end case;
        end if;
    end process p_OPC_SM;

    -- output state information 
    with r_OPC_SM select
        o_state <= "001" when s_IDLE,
                   "010" when s_OPC_CMD,
                   "011" when s_OPC_LEN_HI,
                   "100" when s_OPC_LEN_LO,
                   "101" when s_OPC_DATA,
                   "000" when others;

    o_channel <= r_OPC_CHANNEL;

end rtl;

非常感谢, Elia的

1 个答案:

答案 0 :(得分:2)

好吧,我会咬人的。我写了一个测试工作台,虽然状态机的执行有错误,但它会改变状态。

对于连续的i_dataready

opc_decoder continuous dataready

其中显示o_newdata无法进入状态s_OPC_DATA的测试平台。暂时搁置一个i_dataready

opc_decoder single dataready

其中显示opc_decoder将状态从s_IDLE更改为s_OPC_CMD,这是我对您的流程语句的期望。

这告诉我们你没有提供足够的关于你看到的错误指示的信息,这可能就像opc_decoder没有被绑定一样简单,因为它是在例如实例化的块语句之后进行分析的。

我想到的另一件事是你正在操纵i_dataready的长度,因此长度小于一个时钟并且由于使用时钟的某些实体之间的delta延迟不同而导致它被丢失。 / p>

用于生成这些波形的测试平台(注意到STIMULUS过程目前仅将i_dataready置于'1'一个时钟):

library ieee;
use ieee.std_logic_1164.all;

entity opc_decoder_tb is
end entity;

architecture foo of opc_decoder_tb is
    signal i_gclk:      std_logic := '0';  -- global system clock

    signal i_dataready: std_logic;         -- data ready signal from previous   
                                           -- block (length: 1 gclk cycle)

    signal i_rawdata: std_logic_vector(7 downto 0) := (others => '0');     
           -- raw byte received by previous block

    signal o_channel: std_logic_vector(7 downto 0);   -- output channel address 
                                                      -- for output MUX

    signal o_rgbdata: std_logic_vector(7 downto 0);  -- decoded OPC data byte 
                                                     -- (R|G|B)
    signal o_state: std_logic_vector(2 downto 0);   
    signal o_newdata: std_logic ; 
begin

DUT:
    entity work.opc_decoder
        port map (
            i_gclk => i_gclk,
            i_dataready => i_dataready,
            i_rawdata => i_rawdata,
            o_channel => o_channel,
            o_rgbdata => o_rgbdata,
            o_newdata => o_newdata
        );

CLOCK:  -- picked the clock period out of a hat
    process
    begin
        wait for 50 ns;
        i_gclk <= not i_gclk;  -- which is why it was initialized to '0'
        if Now > 500 ns then     -- bound he simulation time, stop simulation
            wait;
        end if;
    end process;

STIMULUS:
    process
    begin
        wait for 20 ns;
        i_dataready <= '0';  -- demo 'U'
        wait for 30 ns;
        i_dataready <= '1';
        wait for 100 ns;  -- clock period
        i_dataready <= '0';
        wait;
    end process;
end architecture;

您所描述的问题(“为什么我的FSM不会改变状态”)不会对您显示的代码负责,并且可能存在于尚未公开的方法中。

根据您提供的信息,FSM将更改状态。

您可以将问题添加为启用其他答案的最佳方式。

相关问题