我正在尝试将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;
答案 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'
的周期。输出如下:
这意味着由于dout
中的值较高,'1'
仅在sum
进行一个时钟周期。这种情况随机发生,但大约每300个脉冲发生一次。
看起来像adc
添加了一个sum
的溢出。你有什么想法来自哪里?
此外,我还使用了PLL作为ADC时钟。我尝试了不同的相移(0°,90°,180°),但结果大致相同。
答案 2 :(得分:0)
对不起伙计们。问题是配置错误的Quartus项目错误