VHDL读入输入端口会破坏输出信号

时间:2017-03-12 08:12:48

标签: vhdl fpga intel-fpga quartus

我通过 inout 行触发传感器。之后,我正在等待传感器将 inout 线拉高,但是我在查看 inout 信号时遇到了麻烦,而没有损坏我的输出信号。写作有效,不读。

每当行

elsif state = sensor_answer_0 AND trigger_sensor = '1' then 

ouput_signal 设置为' X'。

但是当我评论 trigger_sensor 时:

elsif state = sensor_answer_0 then 

output_signal 实际上获取分配给它的值。

我已经尝试过使用内部缓冲信号,该信号在单独的过程中读取,但结果相同。

在下面的代码中我也使用 output_signal 进行调试,我在每个状态下设置它以查看实际执行的状态。 我检查了我的测试平台,似乎没有与 output_signal 的写 - 写冲突。但是,我正在设置 trigger_sensor 。但只有在 trigger_sensor 已经设置为' Z'在我的主要代码中。

为什么我会看到这种奇怪的行为?我不能只读 inout 信号吗?

我正在使用' Quartus II 15.0'和模拟的ModelSim

ibrary ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity sensor_read is port(
    clk_50: in std_logic;
    enable : in std_logic;              -- enable sensor read
    trigger_sensor: inout std_logic;    -- 1. trigger sensor, 2. read sensor value
    output_sensor : out std_logic_vector(7 downto 0) 
);
end sensor_read;


architecture behavior of sensor_read is
--  
    type state_type is (init, trigger_0, trigger_1, sensor_answer_0 );

    signal state : state_type := init;
    signal icnt : std_logic_vector( 18 downto 0 ) := ( others => '0' );  -- counter

----------------------------------------------------------------------  
--- wait for enable
--- trigger sensor
--- wait for sensor to pull trigger line HIGH and assign output
----------------------------------------------------------------------  
begin
    process (clk_50 )
    begin
        if rising_edge( clk_50 ) then
            -- start here
            if state = init AND unsigned( icnt ) = 0 then
                icnt <= ( others => '0' );
                if enable = '1' then                            -- start trigger process
                    state <= trigger_0;
                    trigger_sensor <= '0';
                else
                    state <= init;
                    trigger_sensor <= 'Z';  
                end if; 

            -- TRIGGER SENSOR
            elsif state = trigger_0 AND unsigned( icnt ) = 50 then      
                state <= trigger_1;
                trigger_sensor <= '1';
                output_sensor <= "00000001";    -- debug                                

            elsif state = trigger_1 AND unsigned( icnt ) = 550 then     -- 500 clk cycle
                state <= sensor_answer_0;                   
                icnt <= ( others => '0' );
                trigger_sensor <= 'Z';        -- set trigger to high impedance to let sensor drive line
                output_sensor <= "00001111";  -- debug

            -- WAIT FOR SENSOR TO PULL TRIGGER=HIGH
            -- ERROR HERE -> when trigger_sensor is used in if statement output_sensor becomes xxx
            --               when trigger_sensor = not('1') is commented out, output_sensor is set correctly to "00011111"
            elsif state = sensor_answer_0 AND trigger_sensor = '1' then 
                state <= init;                              
                icnt <= ( others => '0' );                          
                output_sensor <= "00011111";        -- assign final output
            else    
                icnt <= std_logic_vector ( unsigned( icnt ) + 1 );
            end if;
        end if; 
    end process;
end behavior;

编辑:根据要求添加测试平台

-- clock generation
process
begin
  clk_50 <= '1';
  wait for 10 ns;
  clk_50 <= '0';
  wait for 10 ns;
end process;

-- input data
process
begin
    enable <= '0'; 
    trigger_sensor <= 'Z';
    wait for 1 ms;

    -- start the meassurement
    enable <= '1';

    -- wait for the trigger signal to be over
    while trigger_sensor /= '1' loop wait for 1 us; end loop;
    while trigger_sensor = '1' loop wait for 1 us; end loop;

    -- now send response
    wait for 100 us;
    trigger_sensor <= '1';
    wait for 1 ms;
    trigger_sensor <= '0';
    wait for 10 us;
    trigger_sensor <= 'Z';

    wait;
end process;

1 个答案:

答案 0 :(得分:0)

完成测试平台的Minimal Complete and Verifiable example后:

library ieee;
use ieee.std_logic_1164.all;

entity sensor_read_tb is
end entity;

architecture foo of sensor_read_tb is
    signal clk_50:          std_logic;
    signal enable:          std_logic;
    signal trigger_sensor:  std_logic;
    signal output_sensor:   std_logic_vector (7 downto 0);

    --added for visual markers:
    signal waitfor100us:    bit;
    signal waitfor1ms:      bit;
    signal waitfor10us:     bit;
begin
    DUT:
    entity work.sensor_read
        port map (
            clk_50 => clk_50,
            enable => enable,
            trigger_sensor => trigger_sensor,
            output_sensor => output_sensor

        );
    -- clock generation
    process
    begin
      clk_50 <= '1';
      wait for 10 ns;
      clk_50 <= '0';
      wait for 10 ns;
      if now > 2.2 ms then
          wait;
      end if;
    end process;

    -- input data
    process
    begin
        enable <= '0';
        trigger_sensor <= 'Z';
        wait for 1 ms;

        -- start the meassurement
        enable <= '1';

        -- wait for the trigger signal to be over
        while trigger_sensor /= '1' loop wait for 1 us; end loop;
        while trigger_sensor = '1' loop wait for 1 us; end loop;

        -- now send response
        waitfor100us <= '1';
        wait for 100 us;
        waitfor100us <= '0';
        trigger_sensor <= '1';
        waitfor1ms <= '1';
        wait for 1 ms;
        waitfor1ms <= '0';
        trigger_sensor <= '0';
        waitfor10us <= '1';
        wait for 10 us;
        waitfor10us <= '0';
        trigger_sensor <= 'Z';

        wait;
    end process;
end architecture;

我们看到了问题:

enter sensor_read_tb.png

在测试平台中添加了几个信号以标记您的延迟。它们很容易丢弃。使用的模拟器不会将输出变量输出到波形。 您没有正确操作双向传感器信号。

那该怎么办呢?

在前十几个谷歌的热门歌曲中,最初的Single line multiplexing system for sensors and actuators专利出现了,1982年被授予美国专利4,311,986。

虽然该专利已经过期,但它已经教授了这项专利。发明。

还有MAX6575L/H数据表告诉我们,您希望在FPGA下降trigger_sensor之前操作计数器,直到传感器再次触发触发传感器为止。

这种方式的工作原理是FPGA会在一个固定的时间间隔内丢失trigger_sensor,从而发出单线总线上任何传感器或执行器的信号。多达8个设备可以使用乘法器共享总线,根据两个输入引脚缩放时间,具有两个延迟系列(H和L后缀)。

对于单个传感器,它将通过再次丢弃触发传感器在一段固定时间内响应其时间窗口,该固定周期用信号通知脉冲宽度调制编码值(通常用于温度)。

执行器将由主机端操作(在这种情况下是FPGA,通过丢弃触发传感器线再次向执行器发送脉冲宽度编码数据值。

当没有传感器应答重新开始采样间隔时,计数器可以大到足以重新启动。 我们这里的VHDL模型只读取传感器。

回到双向信号的错误。

它应该被建模为具有两个驱动器和上拉的开放式收集器。对于单个传感器,状态机可能有点过度,但可以使其工作。

这里的诀窍是,两端都不会驱动一个&#39; 1&#39;在电线上,只有一个&#39; 0&#39; 0或者是&#39; Z&#39; (高阻抗)。上拉将是一个&#39; Z&#39;到了&#39; H&#39;并代表一个电阻器(数据表显示一个10K欧姆的电阻器)。

要阅读一个需要过滤到&#39; 0&#39;或者&#39; 1&#39;值和std_logic_1164包有一个函数TO_01来做到这一点,添加了一个输入,其默认值将元值映射到&#39; 0&#39;。对于使用开放收集器模型的我们的目的,我们希望函数将元值映射到&#39; 1&#39;。

对于您未使用TO-01的情况,这些情况在std_logic_1164软件包的早期版本中不可用,但它已被包含在内。对您的VHDL源所做的所有更改都已注释:

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity sensor_read is
    port (
        clk_50:         in  std_logic;
        enable:         in  std_logic;      -- enable sensor read
        trigger_sensor: inout std_logic;    -- 1. trigger sensor, 2. read sensor value
        output_sensor:  out std_logic_vector(7 downto 0)
    );
end entity sensor_read;


architecture behavior of sensor_read is

    type state_type is (init, trigger_0, trigger_1, sensor_answer_0);
    signal state:  state_type := init;
    signal icnt:  std_logic_vector( 18 downto 0) := (others => '0');
    -- for VHDL revisions prior to -2008:
    function TO_01 (s: STD_ULOGIC; xmap: std_ulogic := '0') return std_ulogic is
    begin
        case s is
            when '0' | 'L' => 
                return '0';
            when '1' | 'H' => 
                return '1';
            when others    => 
                return xmap;
        end case;
    end function TO_01;
begin
    process (clk_50)
    begin
        if rising_edge(clk_50) then
            if state = init AND unsigned(icnt) = 0 then
                icnt <= ( others => '0' );
                if enable = '1' then
                    state <= trigger_0;
                    trigger_sensor <= '0';
                else
                    state <= init;
                    trigger_sensor <= 'Z';
                end if;
            elsif state = trigger_0 AND unsigned(icnt) = 50 then
                state <= trigger_1;
                trigger_sensor <= 'Z'; -- WAS '1';
                output_sensor <= "00000001";

            elsif state = trigger_1 AND unsigned(icnt) = 550 then
                state <= sensor_answer_0;
                icnt <= (others => '0');
                trigger_sensor <= 'Z';
                output_sensor <= "00001111";
            elsif state = sensor_answer_0 AND 
                   TO_01(trigger_sensor, xmap => '1') = '1' then -- CHANGED
                state <= init;
                icnt <= ( others => '0' );
                output_sensor <= "00011111";
            else
                icnt <= std_logic_vector (unsigned(icnt) + 1);
            end if;
        end if;
    end process;
end architecture behavior;

library ieee;
use ieee.std_logic_1164.all;

entity sensor_read_tb is
end entity;

architecture foo of sensor_read_tb is
    signal clk_50:          std_logic;
    signal enable:          std_logic;
    signal trigger_sensor:  std_logic;
    signal output_sensor:   std_logic_vector (7 downto 0);

    --added for visual markers:
    signal waitfor100us:    bit;
    signal waitfor1ms:      bit;
    signal waitfor10us:     bit;
    -- for VHDL revisions prior to -2008:
    function TO_01 (s: STD_ULOGIC; xmap: std_ulogic := '0') return std_ulogic is
    begin
        case s is
            when '0' | 'L' => 
                return '0';
            when '1' | 'H' => 
                return '1';
            when others    => 
                return xmap;
        end case;
    end function TO_01;
begin
    DUT:
    entity work.sensor_read
        port map (
            clk_50 => clk_50,
            enable => enable,
            trigger_sensor => trigger_sensor,
            output_sensor => output_sensor

        );
    -- clock generation
    process
    begin
      clk_50 <= '1';
      wait for 10 ns;
      clk_50 <= '0';
      wait for 10 ns;
      if now > 2.2 ms then
          wait;
      end if;
    end process;

    -- input data
    process
    begin
        enable <= '0';
        trigger_sensor <= 'Z';
        wait for 1 ms;

        -- start the meassurement
        enable <= '1';

        -- wait for the trigger signal to be over
        while TO_01(trigger_sensor, '1') /= '1' loop wait for 1 us; end loop;
        while TO_01(trigger_sensor, '1')  = '1' loop wait for 1 us; end loop;

        -- now send response
        waitfor100us <= '1';
        wait for 100 us;
        waitfor100us <= '0';
        -- trigger_sensor <= '1';
        trigger_sensor <= 'Z';  -- WAS '1';
        waitfor1ms <= '1';
        wait for 1 ms;
        waitfor1ms <= '0';
        trigger_sensor <= '0';
        waitfor10us <= '1';
        wait for 10 us;
        waitfor10us <= '0';
        trigger_sensor <= 'Z';

        wait;
    end process;
PULLUP:                       -- ADDED
    trigger_sensor <= 'H';    -- PULLUP
end architecture;

这为我们提供了有效的信号波形:

sensor_read1.png

因为驱动trigger_sensor的传感器是异步的,你可以考虑在trigger_sensor上对状态机进行元稳定性过滤。

如果在显示waitfor10us脉冲的时间之后检查显示的波形,您将看到测试平台与sensor_read设计单元的计数间隔不匹配。可能需要一些修修补补。另请注意,在测试台发出一个值后,计数器正在运行。这里需要进行一些修改。