-1

I'm trying to integrate (sum) a 14-bit signal of ADC at 50 Mhz. The integration starts with rising edge of signal "trigger". If the integral reaches a defined threshold (6000000), a digital signal ("dout") should be set to 0 (which became 1 with "trigger" becoming 1). So far a quite easy task. Though on the hardware itself (Cyclone V) I realized a strange behaviour. Although I kept the voltage level at the ADC constant, the pulse width of the output signal "dout" is sometimes fluctuating (although it should stay nearly constant for a constant 14-bit value at the ADC, which has a low noise). The pulse width is decreasing with rising voltage level, so the integration itself works fine. But it keeps fluctuating.

Here is my code:

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;

I checked the signals using SignalTab II of Quartus Prime. I realized that the value of "sum" was rising, but not perfectly correct (compared the sum I calculated manually of the values of "adc".

I used a PLL to phase shift the 50 Mhz clock ("clk") about 90 degrees. The resulting clock served as input for the ADC clock. I left out the PLL and the value of "sum" matched. Nonetheless I see fluctuations in the "dout" signal (oscilloscope).

Even more strange: I changed the type of "sum" to unsigned and finally the fluctuations disappeared. But only without using the PLL! But while making adaptations to the code below the fluctuations came back. Maybe the sum of integer and unsigned leaded to another timing?!?

The questions are now: - Why the value of "sum" is incorrect when using PLL (I though the value of "adc" should stay constant for half a clock cycle when phase shifting of 90 degrees)? - Why I see the fluctuations in "dout"? Is there something wrong with the code?

EDIT1: Add testbench

Here is my testbench:

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;

And the resulting output: Simultation output

JHBonarius
  • 10,824
  • 3
  • 22
  • 41
j0hn
  • 1
  • 3
  • What does your test-bench show you when you give the module a constant input? – Oldfart May 27 '18 at 21:08
  • 'fluctuations' is imprecise. You're counting on `trigger = '0'` to reset sum to 0. Without setting it to '0' sum will rollover (in hardware, simulation will fail), ` dout` will remain '1' until `sum` goes negative (it's an integer, 32 bits). What generates `trigger`? Any fluctuations might be accounted for either in `trigger` control or `adc` value (for very small 'fluctuations'). Provide a [mcve]. –  May 27 '18 at 23:08
  • I added a testbench for more details. As you can see the code is working. Regarding the fluctuations: The resulting pulsewidth is 30 µs. Sometimes its around 25 - 28 µs without the ADC signal changing. The 32-Bits should be engough, because the "trigger" signal is 40 µs pulses with a frequency of 1 kHz (i simplified this to pulses each 50 µs in the testbench). – j0hn May 28 '18 at 07:46
  • Your last edit is not a 'minor change': it changes the behavior of the code quite significantly. It renders the current answer partially invalid. You're making a lot of assumptions on the accuracy of your ADC. Furthermore, are you properly synchronizing the connections between the ADC and the FPGA? – JHBonarius May 28 '18 at 13:58
  • Sorry for that, my fault. Like I said the PLL is phase shifting the 50 MHz clock serving as an input for the ADC trigger. For testing I changed the PLL output to 5 MHz and in Signal Tab I can see that only every 10th value there is a change to "adc". Independent of that I wonder why the values in Signal Tab are slightly varing. I directly watched for the internal signals of the integrator component. I initially tought that the values should be totally consistent (sum=adc1+adc2...) which is not the case. I'm not sure if there is a timing issue. But 50 MHz is not that high frequency ... – j0hn May 29 '18 at 21:39

3 Answers3

0

I asked for a test-bench because your code looks a bit strange. Just as user1155120 I noticed that the summation takes place outside any condition which can cause overflow. You do not see that overflow because you do not test for it in your test bench.

I can make a suggestion to change your code but the problem, lies in the specification:

If the integral reaches a defined threshold (6000000),...

You do not specify what the sum should do in that case. Continue? Hold? If you let it continue it will at some point warp around and become negative.

A possible solution would be:

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

A possible maximum value would be 231-214-1.

Alternative you must make sure the the trigger_in comes fast enough that a the sum never overflows. With 50MHz sampling and a 14 bit ADC that means at least 382Hz.


I would add some VHDL code to check the ADC signal. e.g. maximum and minimum values seen. Compare those against the actual (more or less constant) input value. That might give you an idea about the stability/reliability of the sampling.

Oldfart
  • 6,104
  • 2
  • 13
  • 15
  • Hello again. Sorry, I forgot to mention that I already tried to put the code for the sum inside the if-statement. So an overflow should not occur. I will change the code above. – j0hn May 28 '18 at 08:44
  • Do you also have an idea why SignalTab is not showing a proper sum if using a PLL? I used MegaWizard for creating the PLL and used 50 Mhz in, 50 Mhz out and 90 degree phase shift (normal mode). BTW: I use the ADA-HSMC daughter card of Terasic. – j0hn May 28 '18 at 09:24
0

thanks for all the responses. It helped my to get a bit further. I checked the ADC signal, but there is only noise of around 10 (of 14-Bit) and no unexpected values. Furthermore all the other signals (tried without logic) are fine.

I also found a solution for the inconsistent sum behaviour. I just saved it in temp_adc before the calculations. I tried variable and signal but I go with signal, because i can visualize it in SignalTap (of course there is a delay of one clock cycle now):

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;

In SignalTap now it's fitting well (sum=sum+temp_adc) most of the time. Coming back to the problem: I found a way in SignalTap to trigger unexpected events. I found one very strange behaviour:

Lets t=0 be the cycle in which trigger goes '1'. The output looks like this:

simulation

This means dout just goes '1' for a single clock cycle due to the high value in sum. This happens random but with around every 300th pulse. Looks like there is something like an overflow with a single adc added to sum. Do you have any ideas where this comes from?

Additionally I played around with the PLL for the ADC clock. I tried different phase shifts (0°, 90°, 180°) but the result is more or less the same.

JHBonarius
  • 10,824
  • 3
  • 22
  • 41
j0hn
  • 1
  • 3
  • StackOverflow does not support HTML table formatting. Please fix. And don't ask questions in an answer. Open a new question. – JHBonarius Jun 05 '18 at 10:37
  • Your code is invalid. You cannot assign a signal using `:=`. `temp_adc` seems redundant anyhow. Just use `to_integer(unsigned(adc))`. P.s. unconstrained integers are usually synthesized as 32-bit. – JHBonarius Jun 05 '18 at 10:39
  • Sorry I fixed it all up. I just wanted to give a detailed overview of my findings, without opening a new redundant question to link it to my original question. Should I just include the post in my initial question? – j0hn Jun 05 '18 at 13:40
  • usually new question. – JHBonarius Jun 05 '18 at 18:29
0

Sorry guys. The problem was a misconfigured Quartus project with wrong

j0hn
  • 1
  • 3