【问题标题】:averaging 12 bit adc values using VHDL使用 VHDL 平均 12 位 adc 值
【发布时间】:2013-11-26 15:30:32
【问题描述】:

我有一个关于 ADC 值的连续平均的问题。我使用的方法是对示例 256 个样本进行连续平均。我在 GUI 上收到的 ''adc_a_out'' 值(如下面的代码所示)缓慢增加。例如,如果我期望值为 100mA,我的 GUI 会显示 4mA、8mA、15mA、......,最后 2 分钟后我得到稳定的 100mA 值。我想直接在我的 GUI 上从“adc_a_out”看到 100mA,而不是增加值并在一段时间后稳定下来。另一个问题是,我能否以某种方式加快此过程,以便我不必等待 3 分钟即可从 adc_a_out 接收稳定的 100 mA。下面数字设计中的时钟“clk”为 20 MHz。 FPGA板上接收ADC值的时钟为15KHz。

--adc_top_file.vhd

entity adc_block_1 is 
  port (
        clk      : in  std_logic;  
        reset    : in  std_logic;              

        data_in  : in  std_logic_vector (31 downto 0);
        req      : in  std_logic;
        adc_a_1    : inout std_logic_vector (11 downto 0);  
        adc_b_1    : inout 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 adc_block_1;

architecture adc_top_block of adc_block_1 is 

component adc is 
  port (
        clk      : in  std_logic;  
        reset    : in  std_logic;           

        data_in  : in  std_logic_vector (31 downto 0);
        req      : in  std_logic;
        adc_a_1    : inout std_logic_vector (11 downto 0);  
        adc_b_1    : inout std_logic_vector (11 downto 0);
        adc_a_1_temp: out signed(11 downto 0);
        adc_b_1_temp: out signed(11 downto 0);   
        slv_value1    : out std_logic_vector (11 downto 0);  
        slv_value2    : out std_logic_vector (11 downto 0);  

  );
end component;



component use_moving_average is

port (
        clock: in std_logic;
        reset: in std_logic;
        channel_1_sample: in signed(11 downto 0);
        channel_2_sample: in signed(11 downto 0);
        channel_1_average: inout signed(11 downto 0);
        channel_2_average: inout signed(11 downto 0);
        slv_value1    : out std_logic_vector (11 downto 0);  
        slv_value2    : out std_logic_vector (11 downto 0)
    );
end component;

  signal adc_a_1_temp   : std_logic_vector(11 downto 0);
  signal adc_b_1_temp   : std_logic_vector(11 downto 0);

  signal adc_a_1_out   : std_logic_vector(11 downto 0);
  signal adc_b_1_out   : std_logic_vector(11 downto 0);


begin

  inst_adc : adc 
  port map (
        clk      => clk,  
        reset    => reset,          

        req  => adc_req,
        adc_a_1    => adc_a_1_temp,
        adc_b_1    => adc_b_1_temp,
        adc_a_1_temp    => adc_a_1_temp,
        adc_b_1_temp    => adc_b_1_temp

  );

inst_moving_average : use_moving_average
    port map (
    clock  => clk,
        reset  => reset,
        channel_1_sample  => adc_a_1_temp,
        channel_2_sample  => adc_b_1_temp,
        channel_1_average => adc_a_1_out,
        channel_2_average => adc_b_1_out,
        slv_value1        => slv_value1,
        slv_value2        => slv_value2
    );

-- adc.vhd 文件如下:

     data_in  : in  std_logic_vector (31 downto 0);
     adc_a_1 : inout std_logic_vector (11 downto 0);  
     adc_b_1 : inout std_logic_vector (11 downto 0);
     adc_a_1_temp: out signed(11 downto 0);
     adc_b_1_temp: out signed(11 downto 0); 
     load   : out std_logic;  

    process (clk, reset)

    begin
        if (reset = '1') then 
        state<=idle;
        adc_out1=0;
        adc_out2 <= 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
        data_out <= addr0 & bits;
        adc_a_1 <= data_in(11 downto 0);
        adc_a_1_temp <= signed(adc_a_1);

        state <= out_2;
        endif;

    when out_2 =>
       if done='1' then
       adc_b_1 <= data_in(11 downto 0);
       adc_b_1_temp <= signed(adc_b_1);

       state <= done_st;

    when done_st =>
        ack <='1';
        --load <='1';
        state <= idle;

    when others =>
        state <= idle;
        end case;
        end if;
        end process;

load: process (clk, reset)
  begin
    if (reset = '1') then
      load <= '0';
    elsif (rising_edge(clk)) then
        max_cnt <= 5000000;
        load <= '0';
      else
        max_cnt <= max_cnt -1;
        load <= '1';
    end if;
  end process load;

你的代码修改如下:

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

entity use_moving_average is
    port (
        clock: in std_logic;
        reset: in std_logic;
        channel_1_sample: in signed(11 downto 0);
        channel_2_sample: in signed(11 downto 0);
        channel_1_average: inout signed(11 downto 0);
        channel_2_average: inout signed(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_moving_average is
    signal average_1, average_2: integer;
begin

    channel_1: entity work.moving_average
        port map(
            sample  => to_integer(channel_1_sample),
            average => average_1,
            clock   => clock,
            reset   => reset
        );

    channel_2: entity work.moving_average
        port map(
            sample  => channel_2_sample,
            average => average_2,
            clock   => clock,
            reset   => reset
        );

    channel_1_average <= to_signed(average_1, 12);
    slv_value1 <= std_logic_vector(channel_1_average);
    channel_2_average <= to_signed(average_2, 12);
    slv_value2 <= std_logic_vector(channel_2_average);
end;

我在 GUI 上查看的最终输出是“slv_value1”和“slv_value2”

谢谢!

【问题讨论】:

    标签: vhdl fpga xilinx hdl


    【解决方案1】:

    这个怎么样:在重置时(或在任何其他时间,如果您愿意),将data_in 值分配给stage 数组中的所有 元素。这应该立即将您的平均值设置为当前值:

    process (clk, reset) 
    begin
        if (reset = '1') then
            out_val <= 0;
            stage <= (others => data_in(11 downto 0));
            sum <= resize(255 * signed(data_in(11 downto 0)), sum'length);
        elsif rising_edge(clk) then
            ...
    

    下面的示例显示了移动平均线计算器的完整代码。我的建议是你研究它直到你理解它。然后,尝试在您的设计中使用它。最后,只有在基本电路工作后,您才能对其进行更改以满足您的设计约束(数据宽度、样本数、整数范围、signedinteger 的使用等)

    library ieee;
    use ieee.std_logic_1164.all;
    
    entity moving_average is
        generic(
            SAMPLES_COUNT: integer := 256
        );
        port (
            sample: in integer;
            average: out integer;
            clock: in std_logic;
            reset: in std_logic
        );
    end;
    
    architecture rtl of moving_average is
    
        signal samples_fifo: integer_vector(1 to SAMPLES_COUNT);
        signal sum: integer;
    
    begin
    
        process (clock, reset) begin
            if reset then
                samples_fifo <= (others => sample);
                sum <= SAMPLES_COUNT * sample;
            elsif rising_edge(clock) then
                samples_fifo <= sample & samples_fifo(1 to SAMPLES_COUNT-1);
                sum <= sum + sample - samples_fifo(SAMPLES_COUNT);
            end if;
        end process;
    
        average <= sum / SAMPLES_COUNT;
    end;
    

    最后,如果您想使用上面的代码为两个不同的信号保留两个单独的平均值,只需将平均实体实例化两次:

    library ieee;
    use ieee.std_logic_1164.all;
    use ieee.numeric_std.all;
    
    entity use_moving_average is
        port (
            clock: in std_logic;
            reset: in std_logic;
            channel_1_sample: in signed(11 downto 0);
            channel_2_sample: in signed(11 downto 0);
            channel_1_average: out signed(11 downto 0);
            channel_2_average: out signed(11 downto 0)
        );
    end;
    
    architecture rtl of use_moving_average is
        signal average_1, average_2: integer;
    begin
    
        channel_1: entity work.moving_average
            port map(
                sample  => to_integer(channel_1_sample),
                average => average_1,
                clock   => clock,
                reset   => reset
            );
    
        channel_2: entity work.moving_average
            port map(
                sample  => channel_2_sample,
                average => average_2,
                clock   => clock,
                reset   => reset
            );
    
        channel_1_average <= to_signed(average_1, 12);
        channel_2_average <= to_signed(average_2, 12);
    end;
    

    编辑:据我从您的 cmets 了解到,您可能需要额外的输入来将平均值立即设置为当前输入值。在这种情况下,您可以使用load 输入,如下所示:

    library ieee;
    use ieee.std_logic_1164.all;
    
    entity moving_average is
        generic(
            SAMPLES_COUNT: integer := 256
        );
        port (
            sample: in integer;
            average: out integer;
            clock: in std_logic;
            reset: in std_logic;
            load: in std_logic
        );
    end;
    
    architecture rtl of moving_average is
    
        signal samples_fifo: integer_vector(1 to SAMPLES_COUNT);
        signal sum: integer;
    
    begin
    
        process (clock, reset) begin
            if reset then
                samples_fifo <= (others => sample);
                sum <= SAMPLES_COUNT * sample;
            elsif rising_edge(clock) then
                if load then
                    samples_fifo <= (others => sample);
                    sum <= SAMPLES_COUNT * sample;
                else
                    samples_fifo <= sample & samples_fifo(1 to SAMPLES_COUNT-1);
                    sum <= sum + sample - samples_fifo(SAMPLES_COUNT);
                end if;
            end if;
        end process;
    
        average <= sum / SAMPLES_COUNT;
    end;
    

    【讨论】:

    • 我现在将在 fpga 上检查结果并告诉你。它也会加快这个过程吗?我的意思是,我会很快得到这个值吗,因为我使用上面的代码在 2 分钟后得到了稳定的值,比如 100mA。
    • 使用上面的代码,我得到以下错误:错误(10327):adc.vhd(103)处的VHDL错误:无法确定运算符“*”的定义——找到0个可能的定义
    • 您是否尝试包含use ieee.numeric_std.all;
    • 是的,我做到了,我得到了上述错误。我包括以下库:图书馆 ieee;使用 ieee.std_logic_1164.all;使用 ieee.std_logic_unsigned.all;使用 ieee.numeric_std.all;
    • 现在我得到另一个错误:Error (10344): VHDL expression error at adc.vhd(103): expression has 24 elements, but must have 20 elements 它正在谈论以下行:sum &lt;= 255 * signed(data_in(11 downto 0));
    猜你喜欢
    • 2021-11-20
    • 1970-01-01
    • 1970-01-01
    • 2020-07-07
    • 1970-01-01
    • 2018-06-20
    • 1970-01-01
    • 2015-12-10
    • 1970-01-01
    相关资源
    最近更新 更多