VHDL average of Array through for loop

1.6k views Asked by At

I have an Array of X Integer values in VHDL declared as a variable inside a process. I would like to calculate the average of all Values in a for loop. If I write it out for 3 Values manually everything works fine (tested on hardware):

entity MyEntity is
Port(
    Enable   : IN STD_LOGIC ;
    CLK      : IN STD_LOGIC;
    SpeedOut : OUT INTEGER
);
end MyEntity;

Average : process
  type      SampleArray         is Array (2 downto 0) of INTEGER;
  variable  SpeedSamples        : SampleArray;

  begin
  wait until rising_edge(CLK);
  if ENABLE = '1' then
     SpeedOut <=  ( SpeedSamples(0)+ SpeedSamples(1)+SpeedSamples(2) ) / 3;
  end if;
end process Average;

If i use a for loop to do the same SpeedOut is constant 0:

entity MyEntity is
Port(
    Enable   : IN STD_LOGIC ;
    CLK      : IN STD_LOGIC;
    SpeedOut : Out INTEGER
);
end MyEntity;

Average : process
  type      SampleArray         is Array (2 downto 0) of INTEGER;
  variable  SpeedSamples        : SampleArray;
  variable  tempVar             : Integer;
  begin
  wait until rising_edge(CLK);
  if ENABLE = '1' then
     for i in 0 to 2 loop
       tempVar := tempVar +  SpeedSamples(i);           
     end loop;
     SpeedOut <=  tempVar / 3;
  end if;
end process Average;

I am aware this will need a lot of resources if the Array is bigger but i think there is something fundamentally wrong with my code.

Is there a proven method of calculating a moving average in VHDL?

1

There are 1 answers

0
scary_jeff On BEST ANSWER

It's not that efficient to add up a large number of samples each clock period like that; an adder with n inputs will consume a lot of logic resource as n starts to increase.

My suggestion is to implement a memory buffer for the samples, which will have as many locations as you want samples in your rolling average. This will have one new sample written to it each clock cycle; you will also add this same sample to your total on the following clock edge.

Using dual-port memory, you can simultaneously read out the 'oldest' sample in the memory from the same location (provided you have the memory in read-before-write mode). Subtract this from your total, then perform the divide. I expect by far the most efficient divisor will be a power of two, so that your divide does not consume any logic resource. Other types of divider use relatively lots of logic.

So the design would boil down to a memory buffer, a 3-input adder, a counter for use as a pointer to the sample buffer, and a wire-shift divider. If performance was an issue, you could pipeline the add/subtract phases so that you only ever needed 2-input adders.

As for the actual coding question about creating a multi-input adder using a loop, on top of suggestions made in the comments, I would say it's really up to your synthesis tool as to whether it would be able to identify this as a multi-input adder. Have you looked in the synthesis report for any messages relating to this segment of code?