嘿,我是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上发布图片,而是将它们上传到我的网站上)
此屏幕截图显示了使用逻辑分析仪实际测量的莱迪思CPLD信号。 在这种情况下,我们可以看到状态没有变化,o_ws和o_newdata也没有变化。 eliaselectronics.com/wp-content/uploads/2014/08/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的
答案 0 :(得分:2)
对于连续的i_dataready
:
其中显示o_newdata
无法进入状态s_OPC_DATA
的测试平台。暂时搁置一个i_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将更改状态。
您可以将问题添加为启用其他答案的最佳方式。