-- -- 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 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;