首先,由于公司披露协议,我不允许发布我的代码,因此我将描述行为的症状,并希望它足够。
我正在使用Scott Larson on eewiki提供的IP for I2C master,我在页面提供的示例中使用它。不同之处在于我有几个程序,如示例
中所述WHEN get_data => --state for conducting this transaction
busy_prev <= i2c_busy; --capture the value of the previous i2c busy signal
IF(busy_prev = '0' AND i2c_busy = '1') THEN --i2c busy just went high
busy_cnt := busy_cnt + 1; --counts the times busy has gone from low to high during transaction
END IF;
CASE busy_cnt IS --busy_cnt keeps track of which command we are on
WHEN 0 => --no command latched in yet
i2c_ena <= '1'; --initiate the transaction
i2c_addr <= slave_addr; --set the address of the slave
i2c_rw <= '0'; --command 1 is a write
i2c_data_wr <= data_to_write; --data to be written
WHEN 1 => --1st busy high: command 1 latched, okay to issue command 2
i2c_rw <= '1'; --command 2 is a read (addr stays the same)
WHEN 2 => --2nd busy high: command 2 latched, okay to issue command 3
i2c_rw <= '0'; --command 3 is a write
i2c_data_wr <= new_data_to_write; --data to be written
IF(i2c_busy = '0') THEN --indicates data read in command 2 is ready
data(15 DOWNTO 8) <= i2c_data_rd; --retrieve data from command 2
END IF;
WHEN 3 => --3rd busy high: command 3 latched, okay to issue command 4
i2c_rw <= '1'; --command 4 is read (addr stays the same)
WHEN 4 => --4th busy high: command 4 latched, ready to stop
i2c_ena <= '0'; --deassert enable to stop transaction after command 4
IF(i2c_busy = '0') THEN --indicates data read in command 4 is ready
data(7 DOWNTO 0) <= i2c_data_rd; --retrieve data from command 4
busy_cnt := 0; --reset busy_cnt for next transaction
state <= home; --transaction complete, go to next state in design
END IF;
WHEN OTHERS => NULL;
END CASE;
例如最后,如果get_data
而不是home
,我会转到初始化案例,重置busy_cnt
和i2c_ena
以及其他信号,然后转到另一个案例写作类似于get_data
。
现状
i2c_busy
,行为符合预期。routed using generic routing resource and might suffer from excessive delay and/or skew
问题
正如我之前提到的,在上面的示例中,代码被分为几个类似于get_data
的情况,并且当执行它时,它们被卡在其中一个中的无限循环中。当我改变某些情况时会发生某种情况,这种情况会在行为不端之前陷入另一种情况并陷入无限循环。在一种情况下,即使更改一个与算法无关的简单信号(用于调试的LED输出),也可能会导致它出现错误行为。
无限循环行为也很奇怪,并且在案例结束时未显示状态。
请注意,我在示例中没有使用相同的方式更新状态,而是使用单独的Process进行状态更新(curr_state <= next_state;
),而next_state
是更新的。
我的猜测 我认为问题可能是因为我必须在每种情况下设置每个输出。但即使设置完毕,我的行为也是如此。
为了完成:开发环境是Lattice Diamond,FPGA是MachXO2。
答案 0 :(得分:1)
发布的代码段存在严重问题,如果它根据评论不再是时钟进程的一部分:
我:发布的代码仍然是时钟进程的一部分吗?
mmahdich:@Martin在我的代码中它不是,时钟进程只更新curr_state&lt; = next_state
如果我将code from the question嵌入到以下测试架构中,那么综合编译器XST(来自ISE 14.7)会报告有关信号busy_cnt
,busy_prev
和{{1的锁存器的警告}}。 OP观察到没有锁存警告的原因可能是由于未公开的代码部分的进一步优化或干扰。 (我手头没有Lattice Diamond。)
data
首先,下一个状态的信号似乎被命名为library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity i2c_test is
port (
clk : in std_logic;
i2c_busy : in std_logic;
slave_addr : in std_logic;
data_to_write : in std_logic_vector(7 downto 0);
new_data_to_write : in std_logic_vector(7 downto 0);
i2c_data_rd : in std_logic_vector(7 downto 0);
i2c_ena : out std_logic;
i2c_addr : out std_logic;
i2c_rw : out std_logic;
i2c_data_wr : out std_logic_vector(7 downto 0);
data : out std_logic_vector(15 downto 0));
end i2c_test;
architecture rtl of i2c_test is
type state_t is (get_data, home);
signal curr_state : state_t := home;
signal state : state_t; -- next state is named "state" in OP code
signal busy_prev : std_logic;
begin -- rtl
process (clk)
begin -- process
if rising_edge(clk) then
curr_state <= state;
end if;
end process;
process(curr_state, busy_prev, i2c_busy, slave_addr, data_to_write, new_data_to_write, i2c_data_rd)
variable busy_cnt : integer range 0 to 4 := 0;
begin
state <= curr_state; -- next state is named "state" in OP code
i2c_ena <= '0';
i2c_addr <= '-';
i2c_rw <= '-';
i2c_data_wr <= (others => '-');
-- no default assignments for busy_prev and data here, because the usage
-- below indicates that a register was intended
case curr_state is
when home => state <= get_data;
---------------------------------------------------------------
-- Add code from question here
---------------------------------------------------------------
end case;
end process;
end rtl;
。
然后,XST为信号state
和busy_prev
找到了锁存器。我没有在组合过程中为这些信号添加默认分配,因为OP代码中的以下分配表明寄存器是预期的:
data
最后,如果没有时钟进程,就不能(轻松)实现这个等待计数器:
busy_prev <= i2c_busy; --capture the value of the previous i2c busy signal
data(15 DOWNTO 8) <= i2c_data_rd; --retrieve data from command 2
data(7 DOWNTO 0) <= i2c_data_rd; --retrieve data from command 4
修改强>
合成上述内容将需要WHEN get_data => --state for conducting this transaction
IF(busy_prev = '0' AND i2c_busy = '1') THEN --i2c busy just went high
busy_cnt := busy_cnt + 1; --counts the times busy has gone from low to high during transaction
END IF;
的触发器,该触发器由过程灵敏度列表中列出的所有信号触发。当然,只有当条件busy_cnt
为真时,才会将新状态加载到触发器中。例如,XST为此合成一个锁存器,当条件为真时启用该锁存器。但是,(curr_state = get_data and busy_prev = '0' and i2c_busy = '1')
在启用的锁存器期间形成组合循环。此合成行为与VHDL描述不匹配。
解决方案是在计时过程中实现寄存器busy_cnt
,busy_prev
和data
。