- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I have a question related to VHDL programming. I want to calculate the continuous average. My example code is:
process (clk, reset)
begin
if (reset = '1') then
state<=idle;
out-val=0;
elsif(rising_edge(clk)) then
case state is
when idle =>
if req='1' then
state= out-1;
end if;
when out-1 =>
if done='1' then
out-val<=data-in (11 downto 0)
state <= done-st;
endif;
when done-st =>
ack <='1';
state <= idle;
when others =>
state <= idle;
end case;
end if;
end process;
On every positive edge of clock, the value of "out-val" changes. I want to continuously take the average of "out-val". I want to take average of 32 values continuously. Is there a way where I can take average of 32 values continuously till the clock is running. Kindly let me know how can I do that. You can modify the above code as well. Many Thanks,
Link Copied
90 Replies
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
--- Quote Start --- "I have two ADCs, each ADC has 12 bit inputs (you mean outputs)" "two outputs from first ADC..."??? what is the sample width of your current ADC? is it 12 bits or 24 bits? --- Quote End --- Yes I mean two 12 bit outputs Its 12 bits.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
is it possible to know the ADC device you are using just to make up my mind why it is 12 bits and 24 bits.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
--- Quote Start --- is it possible to know the ADC device you are using just to make up my mind why it is 12 bits and 24 bits. --- Quote End --- Yes. I am using ADC122S021
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
This device has figures for Fsclk & Fs separately.
I understand that min Fs is 50Ksps and max Fs is 200Ksps. The Fsclk has then to be fast enough for 12 bits (in fact 16 times as Fs) i.e. Fsclk(min) = .8MHz and 3.2MHz(max). Yet you are using Fsclk of 15KHz i.e. Fs = 15KHz/16 = .9KHz appart from violating device spec. Am I right?- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
--- Quote Start --- This device has figures for Fsclk & Fs separately. I understand that min Fs is 50Ksps and max Fs is 200Ksps. The Fsclk has then to be fast enough for 12 bits (in fact 16 times as Fs) i.e. Fsclk(min) = .8MHz and 3.2MHz(max). Yet you are using Fsclk of 15KHz i.e. Fs = 15KHz/16 = .9KHz appart from violating device spec. Am I right? --- Quote End --- The FSclk is 312KHz which means Fs= 312/16=19.5 KHz
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
--- Quote Start --- The FSclk is 312KHz which means Fs= 312/16=19.5 KHz --- Quote End --- OK assuming 19.5Ksps is not violating spec then I don't see why you shouldn't get the mean quickly. Your accumulator will settle after 256 samples i.e. within msec(you have 19.5Ksps) You better check in signaltap or simulation what is causing this delay. It should be easy as you can check sum and avg all the way through. your accummulator bitwidth of 20 bits is just right (12 bits + 8bits = 20bits) so there is no overflow.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
--- Quote Start --- OK assuming 19.5Ksps is not violating spec then I don't see why you shouldn't get the mean quickly. Your accumulator will settle after 256 samples i.e. within msec(you have 19.5Ksps) You better check in signaltap or simulation what is causing this delay. It should be easy as you can check sum and avg all the way through. your accummulator bitwidth of 20 bits is just right (12 bits + 8bits = 20bits) so there is no overflow. --- Quote End --- Ok. I will check in the simulation what is causing the delay. But one thing I am confused is about those slowly incrementing values. I don't know why I see like 4mA, 8 mA, 16mA,,..... finally stable value of 100mA. I don't know why it is not just showing me 100mA directly.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
--- Quote Start --- Ok. I will check in the simulation what is causing the delay. But one thing I am confused is about those slowly incrementing values. I don't know why I see like 4mA, 8 mA, 16mA,,..... finally stable value of 100mA. I don't know why it is not just showing me 100mA directly. --- Quote End --- If your adc data is a constant (or so) then your accumulator (plus division by 256) will build up from zero gradually then settle at the constant value when sample 255 arrives from stage 255 i.e. it should be within msec not second. during this initial time there is subtraction from zero and so the summed up total divided by 2^8 will be less than constant until all 256 samples are added and divided by 2^8 to equal the constant. Thereafter any new sample arrival is added but last one subtracted leading to same constant.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
--- Quote Start --- If your adc data is a constant (or so) then your accumulator (plus division by 256) will build up from zero gradually then settle at the constant value when sample 255 arrives from stage 255 i.e. it should be within msec not second. during this initial time there is subtraction from zero and so the summed up total divided by 2^8 will be less than constant until all 256 samples are added and divided by 2^8 to equal the constant. Thereafter any new sample arrival is added but last one subtracted leading to same constant. --- Quote End --- @kaz I don't see anything stupid in the simulation. No idea why I am getting this delay now.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
--- Quote Start --- @kaz I don't see anything stupid in the simulation. No idea why I am getting this delay now. --- Quote End --- I take it that there is no such delay in simulation but in hardware. Did you see sum building up soon and avg taking values. In that case revise your design and use signaltap. Check your clocking scheme. Your adc samples should be sampled into filter at 19.5KHz. since your clock is 312KHz I therefore assume your done = '1' is enabling clock at 19.5KHz.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
@kaz
Yes I can see the sum building up soon and avg taking values. One observation during hardware testing is when I increase the number of samples from 128 to 256, I receive the ADC current values slowly. The less the number of samples, the faster I get the averaged values on GUI. But the values I receive is always like 4mA, 8mA, 15mA, 25mA....., 100mA, 101mA, 102mA, 100mA, 99mA... I want to recieve only in the small range of 10mA eg.. between 95mA and 105mA. Is there a way that I can discard values such as 4mA, 8mA,.....90mA and recieve the value when it comes in range between 95mA and 105mA. How can I use signaltap in my code?- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
--- Quote Start --- @kaz Yes I can see the sum building up soon and avg taking values. One observation during hardware testing is when I increase the number of samples from 128 to 256, I receive the ADC current values slowly. The less the number of samples, the faster I get the averaged values on GUI. But the values I receive is always like 4mA, 8mA, 15mA, 25mA....., 100mA, 101mA, 102mA, 100mA, 99mA... I want to recieve only in the small range of 10mA eg.. between 95mA and 105mA. Is there a way that I can discard values such as 4mA, 8mA,.....90mA and recieve the value when it comes in range between 95mA and 105mA. How can I use signaltap in my code? --- Quote End --- For the issue of not receiving initial build up values until it settles, yes you can do that readily: with avg and avg_final starting at zero(at reset) if avg > 95 then avg_final <= avg; -- update end if; signaltap does not require code change but is a tool that you need to learn and capture data from any node for display or saving into files. It is added to project through the quartus before compilation. I assume your adc signal is a constant value but remember that adc signal may start with +/- values due to noise or step response and thus may average slowly up
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
--- Quote Start --- For the issue of not receiving initial build up values until it settles, yes you can do that readily: with avg and avg_final starting at zero(at reset) if avg > 95 then avg_final <= avg; -- update end if; signaltap does not require code change but is a tool that you need to learn and capture data from any node for display or saving into files. It is added to project through the quartus before compilation. I assume your adc signal is a constant value but remember that adc signal may start with +/- values due to noise or step response and thus may average slowly up --- Quote End --- @kaz I don't want to write specific value 95 because the range is not always 95mA to 105mA. It should be generalized because 95mA to 105mA is for specific voltage that I set in DAC. How can make it generalized? Also, I am using the code in a different way and I am getting the values quickly but the values coming out are wrong. I am using the code as follows:
--use_average.vhdl file
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity use_average is
port (
clock: in std_logic;
reset: in std_logic;
channel_1_sample: in std_logic_vector(11 downto 0);
channel_2_sample: in std_logic_vector(11 downto 0);
slv_value1 : out std_logic_vector (11 downto 0);
slv_value2 : out std_logic_vector (11 downto 0)
);
end;
architecture rtl of use_average is
signal average_1, average_2: std_logic_vector(11 downto 0);
begin
channel_1: entity work.average
port map(
sample => channel_1_sample,
average => average_1,
clock => clock,
reset => reset
);
channel_2: entity work.average
port map(
sample => channel_2_sample,
average => average_2,
clock => clock,
reset => reset
);
slv_value1 <= average_1;
slv_value2 <= average_2;
end;
The average block is as follows: --average.vhd
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity average is
port (
sample: in std_logic_vector(11 downto 0);
average: out std_logic_vector(11 downto 0);
clock: in std_logic;
reset: in std_logic
);
end;
architecture rtl of average is
type type1 is array (1 to 255) of std_logic_vector(11 downto 0);
signal stage: type1 := (others => (others => '0'));
signal sub_result: signed(12 downto 0) := (others => '0');
signal sum: signed(19 downto 0) := (others => '0');
begin
process (clock, reset) begin
if (reset = '1') then
average <= (others => '0');
elsif (rising_edge(clock)) then
stage(1) <= sample(11 downto 0);
for i in 2 to 255 loop
stage(i) <= stage(i-1);
end loop;
sub_result <= resize(signed(sample),13) - signed(stage(255));
sum <= sum + sub_result;
average <= std_logic_vector(sum(19 downto 8));
end if;
end process;
end;
In the adc top level block, the use_average block is used as follows: component use_average is
port (
clock: in std_logic;
reset: in std_logic;
channel_1_sample: in std_logic_vector(11 downto 0);
channel_2_sample: in std_logic_vector(11 downto 0);
slv_value1 : out std_logic_vector (11 downto 0);
slv_value2 : out std_logic_vector (11 downto 0)
);
end component;
inst_average : use_average
port map (
clock => clk,
reset => reset,
channel_1_sample => adc_a_1_temp,
channel_2_sample => adc_b_1_temp,
slv_value1 => slv_value1,
slv_value2 => slv_value2
);
adc_a_1_temp and adc_b_1_temp are the output signals coming from the adc block i-e: data_in : in std_logic_vector (31 downto 0);
process (clk, reset)
begin
if (reset = '1') then
out_val=0;
adc_a_1_temp = 0;
adc_b_1_temp = 0;
elsif(rising_edge(clk)) then
case state is
when out_1 =>
if done='1' then
data_out <= addr0 & bits;
adc_a_1_temp <= data_in(11 downto 0);
state <= out_2;
when out_2 =>
adc_b_1_temp <= data_in(11 downto 0);
state <= idle;
endif;
end process
Is it okay If I use the code in the above way? Kindly let me know. Thanks
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
It looks ok to me.
Can you do describe what wrong is? do you have a model to check against or do you do that manually. above all is your adc data correctly entering the filters. here is a model for running average
%(n) stage running average, implementation model
%delay input n stages,
%subtract last stage from current input
%accumulate result and discard LSBs
clear all;
v = 2^16; %vector length
n = 256; %filter stages
data = round(2^10*randn(1,v));
data2 = data - ;
data3 = cumsum();
result = floor(data3/n);
%test it using direct computation of mean of every n samples
data = ;
avg = zeros(1,v);
for i = 1:v
avg(i) = floor(mean(data(i:i+n-1)));
end
figure;hold;
plot(result);
plot(avg,'r--');
figure; plot(result(1:end-1) - avg);
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
--- Quote Start --- It looks ok to me. Can you do describe what wrong is? do you have a model to check against or do you do that manually. above all is your adc data correctly entering the filters. here is a model for running average
%(n) stage running average, implementation model
%delay input n stages,
%subtract last stage from current input
%accumulate result and discard LSBs
clear all;
v = 2^16; %vector length
n = 256; %filter stages
data = round(2^10*randn(1,v));
data2 = data - ;
data3 = cumsum();
result = floor(data3/n);
%test it using direct computation of mean of every n samples
data = ;
avg = zeros(1,v);
for i = 1:v
avg(i) = floor(mean(data(i:i+n-1)));
end
figure;hold;
plot(result);
plot(avg,'r--');
figure; plot(result(1:end-1) - avg);
--- Quote End --- Sorry, I was making small mistake in wiring the signals. But now I get the correct values with the above approach. Now the issue comes in the variation. Now I get the values eg. 95mA, 100mA, 105mA,... then all of a sudden it jumps to higher value like 140mA and then all of a sudden it comes to 80mA. I am receiving the values quickly now with the approach I wrote earlier, but the variation is a lot. Is there a way I can decrease the variation?
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Are you waiting long enough for the A/D converter to settle/convert before reading the value?
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
--- Quote Start --- Sorry, I was making small mistake in wiring the signals. But now I get the correct values with the above approach. Now the issue comes in the variation. Now I get the values eg. 95mA, 100mA, 105mA,... then all of a sudden it jumps to higher value like 140mA and then all of a sudden it comes to 80mA. I am receiving the values quickly now with the approach I wrote earlier, but the variation is a lot. Is there a way I can decrease the variation? --- Quote End --- either your adc signal is like that or your wiring is wrong or your conversion to mA is wrong. If adc signal is like that then your filter is doing the job. you can reduce variation by using higher order than 256.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
--- Quote Start --- Are you waiting long enough for the A/D converter to settle/convert before reading the value? --- Quote End --- Yes I am. I am sending the opcode for getting ADC value after every 2 seconds.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
--- Quote Start --- either your adc signal is like that or your wiring is wrong or your conversion to mA is wrong. If adc signal is like that then your filter is doing the job. you can reduce variation by using higher order than 256. --- Quote End --- I showed you in my above code how my signals are wired. Do you think they are wrong?
slv_value1 => slv_value1,
slv_value2 => slv_value2
The concatenation of above signals are the outputs that I get on the GUI. Also I changed 256 to 512 but still there is variation. There is not much difference. adc_a_1_temp and adc_b_1_temp are going into the average block in my code.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
--- Quote Start --- I showed you in my above code how my signals are wired. Do you think they are wrong?
slv_value1 => slv_value1,
slv_value2 => slv_value2
The concatenation of above signals are the outputs that I get on the GUI. Also I changed 256 to 512 but still there is variation. There is not much difference. adc_a_1_temp and adc_b_1_temp are going into the average block in my code. --- Quote End --- I sense something wrong with your interpretation of that concatenation. Reading back your previous posts you talk about two adcs one for voltage(does not need filter) and one for current(needs filter) yet you are filtering two adcs and there seems to be four adcs in total. each adc is 12 bits then you talk about concatenating two 12 bits into 24 bits for GUI. Do you have one adc for current(not voltage) or do you have two adcs for current(not voltage). If so why do you concatenate them. Is it just for passing purpose and that GUI will read ech 12 bits value separately or will it read the 24 bits as one value? I think you need to clear this confusion.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
--- Quote Start --- I sense something wrong with your interpretation of that concatenation. Reading back your previous posts you talk about two adcs one for voltage(does not need filter) and one for current(needs filter) yet you are filtering two adcs and there seems to be four adcs in total. each adc is 12 bits then you talk about concatenating two 12 bits into 24 bits for GUI. Do you have one adc for current(not voltage) or do you have two adcs for current(not voltage). If so why do you concatenate them. Is it just for passing purpose and that GUI will read ech 12 bits value separately or will it read the 24 bits as one value? I think you need to clear this confusion. --- Quote End --- @kaz, I have figured it out that my average block was not running at all because I was running it at 20MHz and the done signal coming from SPI block is running on 78KHz which means I get the next data_in after every 78KHz. I am now running my average block on CS (78kHz) coming from spi master instead of normal clock of 20MHz. Now I am getting the result like before i-e 10mA, 20mA, 40mA,......100mA and the value gets stable after that. I am not sure but I think I need to further divide down the CS to 39KHz to get the 100mA directly. Am I right?
Reply
Topic Options
- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page