203 lines
		
	
	
		
			6.3 KiB
		
	
	
	
		
			VHDL
		
	
	
	
			
		
		
	
	
			203 lines
		
	
	
		
			6.3 KiB
		
	
	
	
		
			VHDL
		
	
	
	
--
 | 
						|
--  Handle sample acquisition and triggering.
 | 
						|
--
 | 
						|
--  Joris van Rantwijk 2024
 | 
						|
--
 | 
						|
 | 
						|
library ieee;
 | 
						|
use ieee.std_logic_1164.all;
 | 
						|
use ieee.numeric_std.all;
 | 
						|
 | 
						|
 | 
						|
entity acquisition_manager is
 | 
						|
 | 
						|
    port (
 | 
						|
        -- Main clock, active on rising edge.
 | 
						|
        clk:                in  std_logic;
 | 
						|
 | 
						|
        -- Reset, active high, synchronous to main clock.
 | 
						|
        reset:              in  std_logic;
 | 
						|
 | 
						|
        -- High to enable data acquisition.
 | 
						|
        -- Low to disable data acquisition, ignore triggers, stop emitting
 | 
						|
        -- samples and clear the trigger status.
 | 
						|
        acquisition_en:     in  std_logic;
 | 
						|
 | 
						|
        -- Trigger delay in clock cycles.
 | 
						|
        trigger_delay:      in  std_logic_vector(15 downto 0);
 | 
						|
 | 
						|
        -- Number of decimated samples per trigger minus 1.
 | 
						|
        record_length:      in  std_logic_vector(15 downto 0);
 | 
						|
 | 
						|
        -- Decimation factor minus 1.
 | 
						|
        decimation_factor:  in  std_logic_vector(17 downto 0);
 | 
						|
 | 
						|
        -- High to sum input samples; low to select single samples.
 | 
						|
        averaging:          in  std_logic;
 | 
						|
 | 
						|
        -- High when a trigger condition occurs.
 | 
						|
        trig_in:            in  std_logic;
 | 
						|
 | 
						|
        -- High if the acquisition chain is waiting for a trigger.
 | 
						|
        -- This not a handshake signal. It does not accurately predict
 | 
						|
        -- whether a trigger will be accepted or ignored.
 | 
						|
        trig_waiting:       out std_logic;
 | 
						|
 | 
						|
        -- High for one cycle when a trigger occurs, after the configured
 | 
						|
        -- trigger delay has passed. This indicates that a trigger timestamp
 | 
						|
        -- record must be generated.
 | 
						|
        trig_ack:           out std_logic;
 | 
						|
 | 
						|
        -- High to initiate the capture of a new decimated sample.
 | 
						|
        sample_start:       out std_logic;
 | 
						|
 | 
						|
        -- High to accumulate additional raw samples into a decimated sample.
 | 
						|
        sample_integrate:   out std_logic;
 | 
						|
 | 
						|
        -- High to emit a decimated sample.
 | 
						|
        sample_done:        out std_logic
 | 
						|
    );
 | 
						|
 | 
						|
end entity;
 | 
						|
 | 
						|
architecture arch of acquisition_manager is
 | 
						|
 | 
						|
    type state_type is (STATE_IDLE, STATE_DELAY, STATE_CAPTURE);
 | 
						|
 | 
						|
    type regs_type is record
 | 
						|
        state:              state_type;
 | 
						|
        delay_cnt:          unsigned(15 downto 0);
 | 
						|
        record_cnt:         unsigned(15 downto 0);
 | 
						|
        decimation_cnt:     unsigned(17 downto 0);
 | 
						|
        trig_waiting:       std_logic;
 | 
						|
        trig_ack:           std_logic;
 | 
						|
        sample_start:       std_logic;
 | 
						|
        sample_integrate:   std_logic;
 | 
						|
        sample_done:        std_logic;
 | 
						|
    end record;
 | 
						|
 | 
						|
    constant regs_init: regs_type := (
 | 
						|
        state               => STATE_IDLE,
 | 
						|
        delay_cnt           => (others => '0'),
 | 
						|
        record_cnt          => (others => '0'),
 | 
						|
        decimation_cnt      => (others => '0'),
 | 
						|
        trig_waiting        => '0',
 | 
						|
        trig_ack            => '0',
 | 
						|
        sample_start        => '0',
 | 
						|
        sample_integrate    => '0',
 | 
						|
        sample_done         => '0'
 | 
						|
    );
 | 
						|
 | 
						|
    signal r: regs_type := regs_init;
 | 
						|
    signal rnext: regs_type;
 | 
						|
 | 
						|
begin
 | 
						|
 | 
						|
    -- Drive output ports.
 | 
						|
    trig_waiting        <= r.trig_waiting;
 | 
						|
    trig_ack            <= r.trig_ack;
 | 
						|
    sample_start        <= r.sample_start;
 | 
						|
    sample_integrate    <= r.sample_integrate;
 | 
						|
    sample_done         <= r.sample_done;
 | 
						|
 | 
						|
    --
 | 
						|
    -- Combinatorial process.
 | 
						|
    --
 | 
						|
    process (all) is
 | 
						|
        variable v: regs_type;
 | 
						|
    begin
 | 
						|
        -- Load current register values.
 | 
						|
        v := r;
 | 
						|
 | 
						|
        -- Default assignments.
 | 
						|
        v.trig_ack := '0';
 | 
						|
        v.sample_start := '0';
 | 
						|
        v.sample_integrate := '0';
 | 
						|
        v.sample_done := '0';
 | 
						|
 | 
						|
        -- State machine.
 | 
						|
        case r.state is
 | 
						|
 | 
						|
            when STATE_IDLE =>
 | 
						|
                -- Waiting for trigger.
 | 
						|
                v.delay_cnt := unsigned(trigger_delay);
 | 
						|
                v.record_cnt := unsigned(record_length);
 | 
						|
                v.decimation_cnt := unsigned(decimation_factor);
 | 
						|
                v.trig_waiting := acquisition_en;
 | 
						|
                if acquisition_en = '1' and trig_in = '1' then
 | 
						|
                    v.trig_waiting := '0';
 | 
						|
                    if unsigned(trigger_delay) = 0 then
 | 
						|
                        v.trig_ack := '1';
 | 
						|
                        v.sample_start := '1';
 | 
						|
                        v.state := STATE_CAPTURE;
 | 
						|
                    else
 | 
						|
                        v.state := STATE_DELAY;
 | 
						|
                    end if;
 | 
						|
                end if;
 | 
						|
 | 
						|
            when STATE_DELAY =>
 | 
						|
                -- Wait for end of trigger delay.
 | 
						|
                v.delay_cnt := r.delay_cnt - 1;
 | 
						|
                if r.delay_cnt = 1 then
 | 
						|
                    v.trig_ack := '1';
 | 
						|
                    v.sample_start := '1';
 | 
						|
                    v.state := STATE_CAPTURE;
 | 
						|
                end if;
 | 
						|
 | 
						|
            when STATE_CAPTURE =>
 | 
						|
                -- Capture samples.
 | 
						|
                v.delay_cnt := unsigned(trigger_delay);
 | 
						|
                v.decimation_cnt := r.decimation_cnt - 1;
 | 
						|
                if r.decimation_cnt = 0 then
 | 
						|
                    v.sample_done := '1';
 | 
						|
                    v.record_cnt := r.record_cnt - 1;
 | 
						|
                    v.decimation_cnt := unsigned(decimation_factor);
 | 
						|
                    if r.record_cnt = 0 then
 | 
						|
                        v.record_cnt := unsigned(record_length);
 | 
						|
                        if trig_in = '1' then
 | 
						|
                            if unsigned(trigger_delay) = 0 then
 | 
						|
                                v.trig_ack := '1';
 | 
						|
                                v.sample_start := '1';
 | 
						|
                                v.state := STATE_CAPTURE;
 | 
						|
                            else
 | 
						|
                                v.state := STATE_DELAY;
 | 
						|
                            end if;
 | 
						|
                        else
 | 
						|
                            v.state := STATE_IDLE;
 | 
						|
                        end if;
 | 
						|
                    else
 | 
						|
                        v.sample_start := '1';
 | 
						|
                    end if;
 | 
						|
                else
 | 
						|
                    v.sample_integrate := averaging;
 | 
						|
                end if;
 | 
						|
 | 
						|
        end case;
 | 
						|
 | 
						|
        -- Stop acquisition immediately when disabled.
 | 
						|
        if acquisition_en = '0' then
 | 
						|
            v.state := STATE_IDLE;
 | 
						|
        end if;
 | 
						|
 | 
						|
        -- Synchronous reset.
 | 
						|
        if reset = '1' then
 | 
						|
            v := regs_init;
 | 
						|
        end if;
 | 
						|
 | 
						|
        -- Drive new register values to synchronous process.
 | 
						|
        rnext <= v;
 | 
						|
    
 | 
						|
    end process;
 | 
						|
 | 
						|
    --
 | 
						|
    -- Synchronous process.
 | 
						|
    --
 | 
						|
    process (clk) is
 | 
						|
    begin
 | 
						|
        if rising_edge(clk) then
 | 
						|
            r <= rnext;
 | 
						|
        end if;
 | 
						|
    end process;
 | 
						|
 | 
						|
end architecture;
 |