VHDL代码在合成后表现异常(I2C)

时间:2015-12-14 14:22:21

标签: vhdl i2c

首先,由于公司披露协议,我不允许发布我的代码,因此我将描述行为的症状,并希望它足够。

我正在使用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_cnti2c_ena以及其他信号,然后转到另一个案例写作类似于get_data

现状

  • 代码在模拟中执行良好,我打开和关闭i2c_busy,行为符合预期。
  • 没有关于灵敏度列表或任何锁存器的警告。我警告说5个时钟信号是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。

1 个答案:

答案 0 :(得分:1)

发布的代码段存在严重问题,如果它根据评论不再是时钟进程的一部分:

  

我:发布的代码仍然是时钟进程的一部分吗?

     

mmahdich:@Martin在我的代码中它不是,时钟进程只更新curr_state&lt; = next_state

如果我将code from the question嵌入到以下测试架构中,那么综合编译器XST(来自ISE 14.7)会报告有关信号busy_cntbusy_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为信号statebusy_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_cntbusy_prevdata