我试图用VHDL编写I2C总线主控器 - 并对其进行全面测试以确保其正常工作等。在这样做的过程中,我已经编写了模块和随后的测试平台来测试它不同的刺激 - 即在每个发送周期后(即忙碌变低时)改变地址和数据输入。
为此,我首先尝试使用此问题here中描述的技术递增数据总线中的值并递减地址总线中的值。但是,当我这样做时,而不是地址总线采用新值,它需要一个未初始化的值,并且赋值语句似乎不执行。
然后我尝试使用中间整数信号,但是这产生了相同的结果,但是这意味着地址&数据总线在第一个周期中采用正确的值 - 但随后不会增加,而是采取未知状态!最终我的问题是为什么会出现这些错误 - 我该如何修复/避免它们?
可以找到我的I2C主模块代码here,可以找到I2CBus(testbench)的代码here。我可以提供任何其他信息来帮助我们说吧!
非常感谢,
大卫
-----使用中间信号的代码------
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
USE ieee.numeric_std.ALL;
ENTITY I2CBus IS
END I2CBus;
ARCHITECTURE behavior OF I2CBus IS
COMPONENT IIC_Master
PORT(
CLOCK : IN std_logic;
RESET_N : IN std_logic;
ENA : IN std_logic;
ADR : IN std_logic_vector(6 downto 0);
RW : IN std_logic;
DAT_WR : IN std_logic_vector(7 downto 0);
DAT_RD : OUT std_logic_vector(7 downto 0);
BUSY : OUT std_logic;
SCL : INOUT std_logic;
SDA : INOUT std_logic;
ACK_ERR : BUFFER std_logic
);
END COMPONENT;
--Inputs
signal CLOCK : std_logic := '0';
signal RESET_N : std_logic; --active high
signal ENA : std_logic; --active high
signal ADR : std_logic_vector(6 downto 0);
signal RW : std_logic; --read high write low
signal DAT_WR : std_logic_vector(7 downto 0);
--BiDirs
signal SCL : std_logic;
signal SDA : std_logic;
--Outputs
signal DAT_RD : std_logic_vector(7 downto 0);
signal BUSY : std_logic;
signal ACK_ERR : std_logic;
-- Clock period definitions
constant CLOCK_period : time := 5 ns;
--Signals to vary
signal address : integer := 127;
signal input_data : integer := 0;
BEGIN
-- Instantiate the Unit Under Test (UUT)
uut : IIC_Master PORT MAP(
CLOCK => CLOCK,
RESET_N => RESET_N,
ENA => ENA,
ADR => ADR,
RW => RW,
DAT_WR => DAT_WR,
DAT_RD => DAT_RD,
BUSY => BUSY,
SCL => SCL,
SDA => SDA,
ACK_ERR => ACK_ERR
);
-- Clock process definitions
CLOCK_process : process
begin
CLOCK <= '0';
wait for CLOCK_period / 2;
CLOCK <= '1';
wait for CLOCK_period / 2;
end process;
-- Reset process
reset : process
begin
reset_n <= '0';
ADR <= "1111111"; --This doesn't seem to happen the first time?
DAT_WR <= "00000000"; --Nor does this?
RW <= '0';
wait for 50 ns;
reset_n <= '1';
ENA <= '1';
wait;
end process;
stim_proc : process
begin
DAT_WR <= std_logic_vector(to_unsigned(input_data, 8));
ADR <= std_logic_vector(to_unsigned(address, 7));
if input_data < 127 then
address <= address - 1;
input_data <= input_data + 1;
wait until BUSY = '0' and RESET_N = '1';
elsif unsigned(DAT_WR) > 126 then
wait;
end if;
end process;
end behavior;
------第一次刺激过程w / out中间信号
stim_proc : process
begin
if input_data < 127 then
wait until BUSY = '0' and RESET_N = '1';
ADR <= std_logic_vector(unsigned(ADR) + 1);
DAT_WR <= std_logic_vector(unsigned(DAT_WR) + 1);
elsif unsigned(DAT_WR) > 126 then
wait;
end if;
end process;
答案 0 :(得分:3)
通常的原因是在几个不同的过程中解决了ADR等信号的多个分配。用硬件术语来说。这相当于将几个不同IC的输出短路。 (没有特别小心,它不会工作,并且会破坏你的IC)。
因此,请检查您是否仅在一个流程中分配ADR和类似信号,如有必要,请重写以将这些流程合并为一个流程。
如果您需要将多个输出连接在一起,有两种方法可以成功运行,但我认为这不是正确的方法。
ADR <= (others -> 'L');
之类的分配永久地拉低,这可以被每个输出覆盖,驱动'Z'
为低或'1'
为高。这是有效的,因为多个输出可以一次安全地驱动信号。'Z'
或(others => 'Z')
置于同一信号上,表示他们处于非活动状态。答案 1 :(得分:2)
Brian Drummond的回答是正确的。我只是用魔杖在你的例子中解释。在时间0,reset
和stim_proc
进程分配相同的值:
reset : process
begin
...
ADR <= "1111111";
...
end process;
和
stim_proc : process
begin
ADR <= std_logic_vector(to_unsigned(address, 7)); -- with address = 127
...
end process;
因此,ADR
的结果是"1111111"
。但是在递减address
(使用中间版本的原始代码)之后,stim_proc
进程在重新开始后会分配不同的值(而不是reset
进程)。你在波形中看到了这一点。当地址变为126(即“1111110”)时,只有ADR
的最低位获得X
,因为只有此位与reset
进程中分配的“1111111”不同。
如果您只想初始化信号,请在信号声明中指定初始化值。 (我想,根据你的VHDL评论,这就是你想要的。)那就是:
signal ADR : std_logic_vector(6 downto 0) := (others => '1');
如果您(真的)只希望在"1111111"
进程的前50 ns秒内分配reset
,那么您必须分配(others => 'Z')
(三态),{{之后在此过程中1}}(弱下拉)或(others => 'Z')
(弱上拉)允许(others => 'H')
过程“覆盖”,例如:
stim_proc