202 lines
6.2 KiB
VHDL
202 lines
6.2 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
|
||
|
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;
|