VHDL中的奇怪行为

时间:2018-05-27 20:19:42

标签: vhdl timing adc

我正在尝试将50位的ADC的14位信号进行积分(求和)。积分从信号“触发”的上升沿开始。如果积分达到定义的阈值(6000000),则应将数字信号(“dout”)设置为0(在“触发”变为1时变为1)。到目前为止,这是一项相当容易 虽然在硬件本身(Cyclone V)上我意识到了一种奇怪的行为。虽然我将ADC的电压电平保持恒定,但输出信号“dout”的脉冲宽度有时会波动(尽管对于ADC的恒定14位值,它应该保持几乎恒定,这具有低噪声)。脉冲宽度随着电压电平的升高而降低,因此集成本身工作正常。但它一直在波动。

这是我的代码:

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

entity integrator is
port(
  trigger:  in std_logic;
  adc:  in std_logic_vector(13 downto 0);
  clk:  in std_logic;
  dout: out std_logic);
end integrator ;

architecture rtl of integrator is
  signal sum : integer;
begin
  process(clk) is
  begin     
        if rising_edge(clk) then                
            if (trigger='1') and (sum<6000000) then
                sum<=sum+to_integer(unsigned(adc));
                dout<='1';
            else
                dout<='0';
                if (trigger='0') then
                    sum<=0;
                end if;
            end if;
        end if;
  end process;
end rtl;

我使用Quartus Prime的SignalTab II检查了信号。我意识到“和”的值正在上升,但并不完全正确(比较我手动计算的“adc”值的总和。

我使用PLL将50 Mhz时钟(“clk”)相移大约90度。产生的时钟用作ADC时钟的输入。我省略了PLL并且“sum”的值匹配。尽管如此,我还是看到了“dout”信号(示波器)的波动。

更奇怪的是:我将“sum”的类型改为unsigned,最后波动消失了。但只有不使用PLL!但是,在对代码进行调整后,波动又回来了。也许整数和无符号的总和导致了另一个时间?!?

现在的问题是: - 使用PLL时为什么“sum”的值不正确(虽然“相位移90度”时,“adc”的值应该在半个时钟周期内保持不变)? - 为什么我看到“dout”的波动?代码有问题吗?

EDIT1:添加测试平台

这是我的测试平台:

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

entity testbench is
end testbench; 

architecture tb of testbench is


component integrator is
port(
  trigger:  in std_logic;
  adc:  in std_logic_vector(13 downto 0);
  clk:  in std_logic;
  dout: out std_logic);
end component;


signal trigger_in, clk_in, dout_out: std_logic;
signal adc_in:  std_logic_vector(13 downto 0);
begin

  DUT: integrator port map(trigger_in, adc_in, clk_in, dout_out);

  process
  begin
    for I in 1 to 4500 loop
      clk_in <= '0';
      wait for 10 ns;
      clk_in <= '1';
      wait for 10 ns;
    end loop; 
    wait;
  end process;

  process
  begin
      trigger_in <= '0';
      wait for 10 us;
      trigger_in <= '1';
      wait for 30 us;
      trigger_in <= '0';
      wait for 10 us;
      trigger_in <= '1';
      wait for 30 us;
      trigger_in <= '0';
      wait for 10 us;
      wait;
  end process;

  process
  begin
      adc_in <= (others => '0');
      wait for 10 us;
      adc_in <= std_logic_vector(to_unsigned(6000, 14));
      wait for 30 us;
      adc_in <= (others => '0');
      wait for 10 us;
      adc_in <= std_logic_vector(to_unsigned(6000, 14));
      wait for 30 us;
      adc_in <= (others => '0');
      wait for 10 us;
      wait;
  end process;


end tb;

结果输出: Simultation output

3 个答案:

答案 0 :(得分:0)

我要求一个测试平台,因为你的代码看起来有点奇怪。就像user1155120一样,我注意到求和发生在任何可能导致溢出的条件之外。您没有看到溢出因为您没有在测试台中测试它。

我可以提出改变代码的建议,但问题在于规范:

  

如果积分达到定义的阈值(6000000),......

在这种情况下,您没有指定总和应该做什么。继续?保持? 如果你让它继续下去,它会在某些时候扭曲变成负面。

可能的解决方案是:

if sum<some_maximum_value_you_define then
   sum<=sum+to_integer(unsigned(adc));
end if;

可能的最大值是2 31 -2 14 -1。

另外,你必须确保trigger_in足够快,总和永远不会溢出。采用50MHz采样和14位ADC,意味着至少382Hz。

我会添加一些VHDL代码来检查ADC信号。例如看到的最大值和最小值。将这些与实际(或多或少恒定)输入值进行比较。这可能会让您了解采样的稳定性/可靠性。

答案 1 :(得分:0)

感谢所有回复。它帮助我进一步发展。我检查了ADC信号,但只有大约10(14位)的噪声,没有意外的值。此外,所有其他信号(没有逻辑尝试)都很好。

我还找到了不一致的sum行为的解决方案。我在计算之前把它保存在temp_adc中。我尝试了变量和信号,但我选择信号,因为我可以在SignalTap中看到它(当然现在有一个时钟周期的延迟):

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

entity integrator is
port(
  trigger:  in std_logic;
  adc:  in std_logic_vector(13 downto 0);
  clk:  in std_logic;
  dout: out std_logic);
end integrator ;

architecture rtl of integrator is
  signal sum : integer;
  signal temp_adc : unsigned(13 downto 0);
begin
  process(clk) is
  begin     
        temp_adc<=unsigned(adc);
        if rising_edge(clk) then                
            if (trigger='1') and (sum<6000000) then
                sum<=sum+to_integer(tem_adc);
                dout<='1';
            else
                dout<='0';
                if (trigger='0') then
                    sum<=0;
                end if;
            end if;
        end if;
  end process;
end rtl;

现在,在SignalTap中,它大部分时间都很合适(sum = sum + temp_adc)。回到问题:我在SignalTap中找到了一种触发意外事件的方法。我发现了一个非常奇怪的行为:

让t = 0成为trigger进入'1'的周期。输出如下:

simulation

这意味着由于dout中的值较高,'1'仅在sum进行一个时钟周期。这种情况随机发生,但大约每300个脉冲发生一次。 看起来像adc添加了一个sum的溢出。你有什么想法来自哪里?

此外,我还使用了PLL作为ADC时钟。我尝试了不同的相移(0°,90°,180°),但结果大致相同。

答案 2 :(得分:0)

对不起伙计们。问题是配置错误的Quartus项目错误