redpitaya-puzzlefw/fpga/rtl/acquisition_manager.vhd

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;