首页 文章

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

提问于
浏览
0

我通过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'之后 .

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

我使用'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

    完成测试平台的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,以指示单线总线上的任何传感器或 Actuator 启动 . 多达8个设备可以使用乘法器共享总线,根据两个输入引脚缩放时间,具有两个延迟系列(H和L后缀) .

    对于单个传感器,它将在其时间窗口中通过再次丢弃触发传感器来响应一段固定时间,从而发出脉冲宽度调制编码值(通常用于温度) .

    Actuator 将由主机端操作(在这种情况下,FPGA通过丢弃触发传感器线再次将脉冲宽度编码数据值发送到致动器 .

    只要没有传感器应答重新开始采样间隔,计数器就足够大,可以通过翻转来重新启动 . 我们这里的VHDL模型只读取传感器 .

    那么回到双向信号有什么问题 .

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

    这里的诀窍是,两端都不会在线上驱动'1',只有'0'或'Z'(高阻抗) . 上拉将'Z'变为'H'并代表电阻(数据表显示10K欧姆电阻) .

    要读取一个,需要过滤为'0'或'1'值,并且std_logic_1164包有一个函数TO_01来执行该操作,添加的输入具有将元值映射为'0'的默认值 . 对于我们使用开放收集器模型的目的,我们希望函数将元值映射为“1” .

    对于您没有使用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设计单元的计数间隔不匹配 . 可能需要一些修修补补 . 另请注意,在测试台发出一个值后,计数器正在运行 . 这里需要进行一些修修补补 .

相关问题