Test analog acquisition chain
This commit is contained in:
parent
131fe91c67
commit
716d16e6a3
|
@ -0,0 +1,210 @@
|
||||||
|
--
|
||||||
|
-- Analog acquisition chain.
|
||||||
|
--
|
||||||
|
-- Joris van Rantwijk 2024
|
||||||
|
--
|
||||||
|
|
||||||
|
library ieee;
|
||||||
|
use ieee.std_logic_1164.all;
|
||||||
|
use ieee.numeric_std.all;
|
||||||
|
|
||||||
|
use work.puzzlefw_pkg.all;
|
||||||
|
|
||||||
|
|
||||||
|
entity acquisition_chain is
|
||||||
|
|
||||||
|
generic (
|
||||||
|
-- Number of analog input channels. It should be either 2 or 4.
|
||||||
|
-- If num_channels == 2, the acquisition always runs in 2-channel mode.
|
||||||
|
-- IF num_channels == 4, the acquisition can run in 2-channel mode
|
||||||
|
-- or 4-channel mode.
|
||||||
|
num_channels: integer range 2 to 4
|
||||||
|
);
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
-- Number of right-shift steps to apply to ADC data.
|
||||||
|
-- When set to zero, the least significant ADC sample bit aligns
|
||||||
|
-- with the least significant decimated sample bit.
|
||||||
|
shift_steps: in std_logic_vector(3 downto 0);
|
||||||
|
|
||||||
|
-- High to enable 4-channel mode.
|
||||||
|
-- Ignored if num_channels == 2.
|
||||||
|
ch4_mode: in std_logic;
|
||||||
|
|
||||||
|
-- High to use simulated samples in place of real ADC samples.
|
||||||
|
simulate_adc: in std_logic;
|
||||||
|
|
||||||
|
-- High to enable automatic (continuous) triggering.
|
||||||
|
trig_auto_en: in std_logic;
|
||||||
|
|
||||||
|
-- High to enable external triggering.
|
||||||
|
trig_ext_en: in std_logic;
|
||||||
|
|
||||||
|
-- High to force a trigger event (if the acquisition chain is ready).
|
||||||
|
trig_force: in std_logic;
|
||||||
|
|
||||||
|
-- Select external input signal to use as trigger.
|
||||||
|
trig_ext_select: in std_logic_vector(1 downto 0);
|
||||||
|
|
||||||
|
-- High to trigger on falling edge, low to trigger on rising edge.
|
||||||
|
trig_ext_falling: in std_logic;
|
||||||
|
|
||||||
|
-- Global timestamp counter.
|
||||||
|
timestamp_in: in std_logic_vector(timestamp_bits - 1 downto 0);
|
||||||
|
|
||||||
|
-- ADC input data.
|
||||||
|
adc_data_in: in adc_data_array(0 to num_channels - 1);
|
||||||
|
|
||||||
|
-- External trigger signals, already synchronized and de-glitched.
|
||||||
|
trig_ext_in: in std_logic_vector(3 downto 0);
|
||||||
|
|
||||||
|
-- High if the acquisition chain is waiting for a trigger.
|
||||||
|
trig_waiting: out std_logic;
|
||||||
|
|
||||||
|
-- Output data stream.
|
||||||
|
out_valid: out std_logic;
|
||||||
|
out_ready: in std_logic;
|
||||||
|
out_empty: in std_logic;
|
||||||
|
out_data: out dma_data_type
|
||||||
|
);
|
||||||
|
|
||||||
|
end entity;
|
||||||
|
|
||||||
|
architecture arch of acquisition_chain is
|
||||||
|
|
||||||
|
-- Number of data bits for accumulating ADC samples when averaging.
|
||||||
|
constant accum_data_bits: natural := 32;
|
||||||
|
|
||||||
|
subtype accum_data_type is std_logic_vector(accum_data_bits - 1 downto 0);
|
||||||
|
type accum_data_array is array(natural range <>) of accum_data_type;
|
||||||
|
|
||||||
|
signal s_trigger: std_logic;
|
||||||
|
signal s_trig_ack: std_logic;
|
||||||
|
signal s_sample_start: std_logic;
|
||||||
|
signal s_sample_integrate: std_logic;
|
||||||
|
signal s_sample_done: std_logic;
|
||||||
|
signal s_adc_sample: adc_data_array(0 to num_channels - 1);
|
||||||
|
signal s_adc_shifted: accum_data_array(0 to num_channels - 1);
|
||||||
|
signal s_sample_decimated: sample_data_array(0 to num_channels - 1);
|
||||||
|
|
||||||
|
begin
|
||||||
|
|
||||||
|
-- External trigger detector.
|
||||||
|
inst_trigger_detector: entity work.trigger_detector
|
||||||
|
port map (
|
||||||
|
clk => clk,
|
||||||
|
reset => reset,
|
||||||
|
trig_auto_en => trig_auto_en,
|
||||||
|
trig_ext_en => trig_ext_en,
|
||||||
|
trig_force => trig_force,
|
||||||
|
trig_select => trig_ext_select,
|
||||||
|
trig_falling => trig_ext_falling,
|
||||||
|
trig_ext_in => trig_ext_in,
|
||||||
|
trig_out => s_trigger );
|
||||||
|
|
||||||
|
-- Timing of sampling and decimation.
|
||||||
|
inst_acquisition_manager: entity work.acquisition_manager
|
||||||
|
port map (
|
||||||
|
clk => clk,
|
||||||
|
reset => reset,
|
||||||
|
acquisition_en => acquisition_en,
|
||||||
|
trigger_delay => trigger_delay,
|
||||||
|
record_length => record_length,
|
||||||
|
decimation_factor => decimation_factor,
|
||||||
|
averaging => averaging,
|
||||||
|
trig_in => s_trigger,
|
||||||
|
trig_waiting => trig_waiting,
|
||||||
|
trig_ack => s_trig_ack,
|
||||||
|
sample_start => s_sample_start,
|
||||||
|
sample_integrate => s_sample_integrate,
|
||||||
|
sample_done => s_sample_done );
|
||||||
|
|
||||||
|
-- Optionally generate simulated ADC data.
|
||||||
|
inst_adc_sample_stream: entity work.adc_sample_stream
|
||||||
|
port map (
|
||||||
|
clk => clk,
|
||||||
|
reset => reset,
|
||||||
|
simulate => simulate_adc,
|
||||||
|
in_data => adc_data_in(0 to 1),
|
||||||
|
out_data => s_adc_sample(0 to 1) );
|
||||||
|
|
||||||
|
inst_adc_sample_stream_gen: if num_channels > 2 generate
|
||||||
|
inst_adc_sample_stream2: entity work.adc_sample_stream
|
||||||
|
port map (
|
||||||
|
clk => clk,
|
||||||
|
reset => reset,
|
||||||
|
simulate => simulate_adc,
|
||||||
|
in_data => adc_data_in(2 to 3),
|
||||||
|
out_data => s_adc_sample(2 to 3) );
|
||||||
|
end generate;
|
||||||
|
|
||||||
|
-- Shift and decimation chains for each ADC channel.
|
||||||
|
inst_channels: for i in 0 to num_channels - 1 generate
|
||||||
|
|
||||||
|
inst_shift: entity work.shift_engine
|
||||||
|
generic map (
|
||||||
|
input_data_bits => adc_data_bits,
|
||||||
|
output_data_bits => accum_data_bits,
|
||||||
|
pre_shift_left => accum_data_bits - sample_data_bits,
|
||||||
|
signed_data => false )
|
||||||
|
port map (
|
||||||
|
clk => clk,
|
||||||
|
in_data => s_adc_sample(i),
|
||||||
|
in_shift => shift_steps,
|
||||||
|
out_data => s_adc_shifted(i) );
|
||||||
|
|
||||||
|
inst_decimation: entity work.sample_decimation
|
||||||
|
generic map (
|
||||||
|
input_data_bits => accum_data_bits,
|
||||||
|
output_data_bits => sample_data_bits )
|
||||||
|
port map (
|
||||||
|
clk => clk,
|
||||||
|
reset => reset,
|
||||||
|
start => s_sample_start,
|
||||||
|
integrate => s_sample_integrate,
|
||||||
|
in_data => s_adc_shifted(i),
|
||||||
|
out_data => s_sample_decimated(i) );
|
||||||
|
|
||||||
|
end generate;
|
||||||
|
|
||||||
|
-- Format sample data stream and insert trigger timestamps.
|
||||||
|
inst_stream: entity work.acquisition_stream
|
||||||
|
generic map (
|
||||||
|
num_channels => num_channels )
|
||||||
|
port map (
|
||||||
|
clk => clk,
|
||||||
|
reset => reset,
|
||||||
|
ch4_mode => ch4_mode,
|
||||||
|
timestamp_in => timestamp_in,
|
||||||
|
trig_ack => s_trig_ack,
|
||||||
|
sample_valid => s_sample_done,
|
||||||
|
sample_data => s_sample_decimated,
|
||||||
|
out_valid => out_valid,
|
||||||
|
out_ready => out_ready,
|
||||||
|
out_empty => out_empty,
|
||||||
|
out_data => out_data );
|
||||||
|
|
||||||
|
end architecture;
|
|
@ -0,0 +1,201 @@
|
||||||
|
--
|
||||||
|
-- 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;
|
|
@ -0,0 +1,201 @@
|
||||||
|
--
|
||||||
|
-- Format analog acquisition data into a stream of 64-bit words.
|
||||||
|
--
|
||||||
|
-- Joris van Rantwijk 2024
|
||||||
|
--
|
||||||
|
|
||||||
|
library ieee;
|
||||||
|
use ieee.std_logic_1164.all;
|
||||||
|
use ieee.numeric_std.all;
|
||||||
|
|
||||||
|
use work.puzzlefw_pkg.all;
|
||||||
|
|
||||||
|
|
||||||
|
entity acquisition_stream is
|
||||||
|
|
||||||
|
generic (
|
||||||
|
-- Number of analog input channels. It should be either 2 or 4.
|
||||||
|
num_channels: integer range 2 to 4
|
||||||
|
);
|
||||||
|
|
||||||
|
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 4-channel mode.
|
||||||
|
-- Ignored if num_channels == 2.
|
||||||
|
ch4_mode: in std_logic;
|
||||||
|
|
||||||
|
-- Global timestamp counter.
|
||||||
|
timestamp_in: in std_logic_vector(timestamp_bits - 1 downto 0);
|
||||||
|
|
||||||
|
-- High for one cycle when a trigger occurs.
|
||||||
|
trig_ack: in std_logic;
|
||||||
|
|
||||||
|
-- Decimated sample stream.
|
||||||
|
sample_valid: in std_logic;
|
||||||
|
sample_data: in sample_data_array(0 to num_channels - 1);
|
||||||
|
|
||||||
|
-- Output data stream.
|
||||||
|
out_valid: out std_logic;
|
||||||
|
out_ready: in std_logic;
|
||||||
|
out_empty: in std_logic;
|
||||||
|
out_data: out dma_data_type
|
||||||
|
);
|
||||||
|
|
||||||
|
end entity;
|
||||||
|
|
||||||
|
architecture arch of acquisition_stream is
|
||||||
|
|
||||||
|
type regs_type is record
|
||||||
|
overflow: std_logic;
|
||||||
|
trig_pending: std_logic;
|
||||||
|
trig_timestamp: std_logic_vector(timestamp_bits - 1 downto 0);
|
||||||
|
sample_pending: std_logic;
|
||||||
|
sample_data: sample_data_array(0 to num_channels - 3);
|
||||||
|
out_valid: std_logic;
|
||||||
|
out_data: dma_data_type;
|
||||||
|
end record;
|
||||||
|
|
||||||
|
constant regs_init: regs_type := (
|
||||||
|
overflow => '0',
|
||||||
|
trig_pending => '0',
|
||||||
|
trig_timestamp => (others => '0'),
|
||||||
|
sample_pending => '0',
|
||||||
|
sample_data => (others => (others => '0')),
|
||||||
|
out_valid => '0',
|
||||||
|
out_data => (others => '0')
|
||||||
|
);
|
||||||
|
|
||||||
|
signal r: regs_type := regs_init;
|
||||||
|
signal rnext: regs_type;
|
||||||
|
|
||||||
|
begin
|
||||||
|
|
||||||
|
-- Drive output ports.
|
||||||
|
out_valid <= r.out_valid;
|
||||||
|
out_data <= r.out_data;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Combinatorial process.
|
||||||
|
--
|
||||||
|
process (all) is
|
||||||
|
variable v: regs_type;
|
||||||
|
begin
|
||||||
|
-- Load current register values.
|
||||||
|
v := r;
|
||||||
|
|
||||||
|
-- By default, do not emit data.
|
||||||
|
v.out_valid := '0';
|
||||||
|
|
||||||
|
if sample_valid = '1' then
|
||||||
|
|
||||||
|
-- Emit first sample data word.
|
||||||
|
v.out_valid := '1';
|
||||||
|
v.out_data(63 downto 56) := msg_adc_data;
|
||||||
|
v.out_data(55 downto 48) := x"10";
|
||||||
|
v.out_data(23 downto 0) := sample_data(0);
|
||||||
|
v.out_data(47 downto 24) := sample_data(1);
|
||||||
|
|
||||||
|
-- Detect internal overflow.
|
||||||
|
if (r.sample_pending = '1') or (r.trig_pending = '1') then
|
||||||
|
v.overflow := '1';
|
||||||
|
end if;
|
||||||
|
|
||||||
|
elsif r.sample_pending = '1' then
|
||||||
|
|
||||||
|
-- Emit second sample data word.
|
||||||
|
v.sample_pending := '0';
|
||||||
|
v.out_valid := '1';
|
||||||
|
v.out_data(63 downto 56) := msg_adc_data;
|
||||||
|
v.out_data(55 downto 48) := x"32";
|
||||||
|
v.out_data(47 downto 0) := (others => '0');
|
||||||
|
if num_channels > 2 then
|
||||||
|
v.out_data(23 downto 0) := r.sample_data(0);
|
||||||
|
end if;
|
||||||
|
if num_channels > 3 then
|
||||||
|
v.out_data(47 downto 24) := r.sample_data(1);
|
||||||
|
end if;
|
||||||
|
|
||||||
|
elsif r.trig_pending = '1' then
|
||||||
|
|
||||||
|
-- Emit pending trigger record.
|
||||||
|
v.trig_pending := '0';
|
||||||
|
v.out_valid := '1';
|
||||||
|
v.out_data(63 downto 56) := msg_trigger;
|
||||||
|
v.out_data(55 downto 48) := x"00";
|
||||||
|
v.out_data(47 downto 0) := r.trig_timestamp;
|
||||||
|
|
||||||
|
elsif trig_ack = '1' then
|
||||||
|
|
||||||
|
-- Emit trigger record.
|
||||||
|
v.out_valid := '1';
|
||||||
|
v.out_data(63 downto 56) := msg_trigger;
|
||||||
|
v.out_data(55 downto 48) := x"00";
|
||||||
|
v.out_data(47 downto 0) := timestamp_in;
|
||||||
|
|
||||||
|
end if;
|
||||||
|
|
||||||
|
-- Latch second sample data word.
|
||||||
|
if (num_channels > 2) and (sample_valid = '1') then
|
||||||
|
v.sample_pending := '1';
|
||||||
|
v.sample_data := sample_data(2 to num_channels - 1);
|
||||||
|
end if;
|
||||||
|
|
||||||
|
-- Latch timestamp when a trigger occurs.
|
||||||
|
if trig_ack = '1' then
|
||||||
|
v.trig_timestamp := timestamp_in;
|
||||||
|
if (sample_valid = '1') or (r.sample_pending = '1') then
|
||||||
|
v.trig_pending := '1';
|
||||||
|
end if;
|
||||||
|
|
||||||
|
-- Detect internal overflow.
|
||||||
|
if r.trig_pending = '1' then
|
||||||
|
v.overflow := '1';
|
||||||
|
end if;
|
||||||
|
end if;
|
||||||
|
|
||||||
|
-- Detect overflow of external data buffer.
|
||||||
|
if (r.out_valid = '1') and (out_ready = '0') then
|
||||||
|
v.overflow := '1';
|
||||||
|
end if;
|
||||||
|
|
||||||
|
-- If there is a pending overflow, discard data until the buffer
|
||||||
|
-- is empty, then emit an overflow record.
|
||||||
|
if r.overflow = '1' then
|
||||||
|
v.sample_pending := '0';
|
||||||
|
v.trig_pending := '0';
|
||||||
|
v.out_valid := '0';
|
||||||
|
v.out_data(63 downto 56) := msg_overflow;
|
||||||
|
v.out_data(55 downto 0) := (others => '0');
|
||||||
|
|
||||||
|
if out_empty = '1' then
|
||||||
|
v.out_valid := '1';
|
||||||
|
v.overflow := '0';
|
||||||
|
end if;
|
||||||
|
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;
|
|
@ -0,0 +1,61 @@
|
||||||
|
--
|
||||||
|
-- Capture ADC sample data from FPGA input ports.
|
||||||
|
--
|
||||||
|
-- Input signals are captured on the rising edge of CLK.
|
||||||
|
-- This entity adds 2 clock cycles delay.
|
||||||
|
--
|
||||||
|
-- Joris van Rantwijk 2024
|
||||||
|
--
|
||||||
|
|
||||||
|
library ieee;
|
||||||
|
use ieee.std_logic_1164.all;
|
||||||
|
use ieee.numeric_std.all;
|
||||||
|
|
||||||
|
use work.puzzlefw_pkg.all;
|
||||||
|
|
||||||
|
|
||||||
|
entity adc_capture is
|
||||||
|
|
||||||
|
port (
|
||||||
|
-- Main clock, active on rising edge.
|
||||||
|
clk: in std_logic;
|
||||||
|
|
||||||
|
-- Input signals.
|
||||||
|
in_data: in std_logic_vector(adc_data_bits - 1 downto 0);
|
||||||
|
|
||||||
|
-- Output sample stream.
|
||||||
|
-- Produces one new ADC sample per clock cycle.
|
||||||
|
out_data: out adc_data_type
|
||||||
|
);
|
||||||
|
|
||||||
|
end entity;
|
||||||
|
|
||||||
|
architecture arch of adc_capture is
|
||||||
|
|
||||||
|
signal r_stage1: std_logic_vector(adc_data_bits - 1 downto 0);
|
||||||
|
signal r_stage2: std_logic_vector(adc_data_bits - 1 downto 0);
|
||||||
|
|
||||||
|
begin
|
||||||
|
|
||||||
|
-- Drive output ports.
|
||||||
|
out_data <= r_stage2;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Synchronous process.
|
||||||
|
--
|
||||||
|
process (clk) is
|
||||||
|
begin
|
||||||
|
if rising_edge(clk) then
|
||||||
|
|
||||||
|
-- Capture input signals into registers.
|
||||||
|
-- These registers will be placed in IO flipflops through IOB constraints.
|
||||||
|
r_stage1 <= in_data;
|
||||||
|
|
||||||
|
-- Second register stage.
|
||||||
|
-- These can be placed anywhere in the FPGA to optimize timing.
|
||||||
|
r_stage2 <= r_stage1;
|
||||||
|
|
||||||
|
end if;
|
||||||
|
end process;
|
||||||
|
|
||||||
|
end architecture;
|
|
@ -0,0 +1,80 @@
|
||||||
|
--
|
||||||
|
-- Manage the ADC sample stream.
|
||||||
|
--
|
||||||
|
-- Optionally generates simulated samples in place of real ADC data.
|
||||||
|
-- The simulated sample stream works as follows:
|
||||||
|
-- - Both simulated channels output a simple increasing ramp.
|
||||||
|
-- - The output of channel 0 increments at a rate of 1 per clock cycle.
|
||||||
|
-- - The output of channel 1 increments by 1 whenever channel 0 wraps around.
|
||||||
|
--
|
||||||
|
-- This entity adds 1 clock cycle delay in the ADC sample stream.
|
||||||
|
--
|
||||||
|
-- Joris van Rantwijk 2024
|
||||||
|
--
|
||||||
|
|
||||||
|
library ieee;
|
||||||
|
use ieee.std_logic_1164.all;
|
||||||
|
use ieee.numeric_std.all;
|
||||||
|
|
||||||
|
use work.puzzlefw_pkg.all;
|
||||||
|
|
||||||
|
|
||||||
|
entity adc_sample_stream 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 select simulated samples in place of ADC data.
|
||||||
|
simulate: in std_logic;
|
||||||
|
|
||||||
|
-- Input sample stream from ADC.
|
||||||
|
in_data: in adc_data_array(0 to 1);
|
||||||
|
|
||||||
|
-- Output sample stream.
|
||||||
|
out_data: out adc_data_array(0 to 1)
|
||||||
|
);
|
||||||
|
|
||||||
|
end entity;
|
||||||
|
|
||||||
|
architecture arch of adc_sample_stream is
|
||||||
|
|
||||||
|
signal r_counter: unsigned(2 * adc_data_bits - 1 downto 0);
|
||||||
|
signal r_out_data: adc_data_array(0 to 1);
|
||||||
|
|
||||||
|
begin
|
||||||
|
|
||||||
|
-- Drive output ports.
|
||||||
|
out_data <= r_out_data;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Synchronous process.
|
||||||
|
--
|
||||||
|
process (clk) is
|
||||||
|
begin
|
||||||
|
if rising_edge(clk) then
|
||||||
|
|
||||||
|
-- Select ADC sample or simulated sample.
|
||||||
|
if simulate = '1' then
|
||||||
|
-- Output simulated sample.
|
||||||
|
r_out_data(0) <= std_logic_vector(r_counter(adc_data_bits - 1 downto 0));
|
||||||
|
r_out_data(1) <= std_logic_vector(r_counter(2 * adc_data_bits - 1 downto adc_data_bits));
|
||||||
|
else
|
||||||
|
-- Output real ADC sample.
|
||||||
|
r_out_data <= in_data;
|
||||||
|
end if;
|
||||||
|
|
||||||
|
-- Update simulated sample stream.
|
||||||
|
if reset = '1' then
|
||||||
|
r_counter <= (others => '0');
|
||||||
|
else
|
||||||
|
r_counter <= r_counter + 1;
|
||||||
|
end if;
|
||||||
|
|
||||||
|
end if;
|
||||||
|
end process;
|
||||||
|
|
||||||
|
end architecture;
|
|
@ -83,6 +83,7 @@ entity dma_write_channel is
|
||||||
-- Input data stream to the channel.
|
-- Input data stream to the channel.
|
||||||
in_valid: in std_logic;
|
in_valid: in std_logic;
|
||||||
in_ready: out std_logic;
|
in_ready: out std_logic;
|
||||||
|
in_empty: out std_logic;
|
||||||
in_data: in dma_data_type;
|
in_data: in dma_data_type;
|
||||||
|
|
||||||
-- Signals to AXI master.
|
-- Signals to AXI master.
|
||||||
|
@ -173,6 +174,7 @@ begin
|
||||||
channel_busy <= r.channel_busy;
|
channel_busy <= r.channel_busy;
|
||||||
addr_pointer <= r.addr_pointer;
|
addr_pointer <= r.addr_pointer;
|
||||||
intr_out <= r.intr_out;
|
intr_out <= r.intr_out;
|
||||||
|
in_empty <= not s_fifo_valid;
|
||||||
write_cmd_addr <= r.cmd_addr;
|
write_cmd_addr <= r.cmd_addr;
|
||||||
write_cmd_length <= "0000" when (r.cmd_full_burst = '0') else
|
write_cmd_length <= "0000" when (r.cmd_full_burst = '0') else
|
||||||
std_logic_vector(to_unsigned(transfer_size - 1, 4));
|
std_logic_vector(to_unsigned(transfer_size - 1, 4));
|
||||||
|
@ -226,7 +228,6 @@ begin
|
||||||
|
|
||||||
v.cmd_valid := '1';
|
v.cmd_valid := '1';
|
||||||
v.channel_busy := '1';
|
v.channel_busy := '1';
|
||||||
v.pending_beats := to_unsigned(0, v.pending_beats'length);
|
|
||||||
v.state := STATE_SINGLE_START;
|
v.state := STATE_SINGLE_START;
|
||||||
|
|
||||||
end if;
|
end if;
|
||||||
|
@ -260,7 +261,7 @@ begin
|
||||||
when STATE_SINGLE_DATA =>
|
when STATE_SINGLE_DATA =>
|
||||||
|
|
||||||
-- Wait until data accepted.
|
-- Wait until data accepted.
|
||||||
if (write_data_ready = '1') and (r.pending_beats = 0) then
|
if write_data_ready = '1' then
|
||||||
v.state := STATE_SINGLE_IDLE;
|
v.state := STATE_SINGLE_IDLE;
|
||||||
end if;
|
end if;
|
||||||
|
|
||||||
|
|
|
@ -36,6 +36,9 @@ package puzzlefw_pkg is
|
||||||
-- 48-bit timestamp.
|
-- 48-bit timestamp.
|
||||||
constant timestamp_bits: integer := 48;
|
constant timestamp_bits: integer := 48;
|
||||||
|
|
||||||
|
-- ADC input port type.
|
||||||
|
type adc_data_input_type is array(0 to 1) of std_logic_vector(15 downto 0);
|
||||||
|
|
||||||
-- Register addresses.
|
-- Register addresses.
|
||||||
constant reg_addr_mask: std_logic_vector(31 downto 0) := x"0010fffc";
|
constant reg_addr_mask: std_logic_vector(31 downto 0) := x"0010fffc";
|
||||||
constant reg_info: natural := 16#000000#;
|
constant reg_info: natural := 16#000000#;
|
||||||
|
@ -44,6 +47,9 @@ package puzzlefw_pkg is
|
||||||
constant reg_dma_en: natural := 16#000100#;
|
constant reg_dma_en: natural := 16#000100#;
|
||||||
constant reg_dma_status: natural := 16#000104#;
|
constant reg_dma_status: natural := 16#000104#;
|
||||||
constant reg_dma_clear: natural := 16#000108#;
|
constant reg_dma_clear: natural := 16#000108#;
|
||||||
|
constant reg_timestamp_lo: natural := 16#000180#;
|
||||||
|
constant reg_timestamp_hi: natural := 16#000184#;
|
||||||
|
constant reg_timestamp_clear: natural := 16#000188#;
|
||||||
constant reg_acq_addr_start: natural := 16#000200#;
|
constant reg_acq_addr_start: natural := 16#000200#;
|
||||||
constant reg_acq_addr_end: natural := 16#000204#;
|
constant reg_acq_addr_end: natural := 16#000204#;
|
||||||
constant reg_acq_addr_limit: natural := 16#000208#;
|
constant reg_acq_addr_limit: natural := 16#000208#;
|
||||||
|
@ -51,6 +57,16 @@ package puzzlefw_pkg is
|
||||||
constant reg_acq_addr_ptr: natural := 16#000210#;
|
constant reg_acq_addr_ptr: natural := 16#000210#;
|
||||||
constant reg_acq_channel_ctrl: natural := 16#000214#;
|
constant reg_acq_channel_ctrl: natural := 16#000214#;
|
||||||
constant reg_acq_intr_ctrl: natural := 16#000218#;
|
constant reg_acq_intr_ctrl: natural := 16#000218#;
|
||||||
|
constant reg_acquisition_en: natural := 16#000220#;
|
||||||
|
constant reg_record_length: natural := 16#000224#;
|
||||||
|
constant reg_decimation_factor: natural := 16#000228#;
|
||||||
|
constant reg_shift_steps: natural := 16#00022c#;
|
||||||
|
constant reg_averaging_en: natural := 16#000230#;
|
||||||
|
constant reg_ch4_mode: natural := 16#000234#;
|
||||||
|
constant reg_simulate_adc: natural := 16#000238#;
|
||||||
|
constant reg_trigger_mode: natural := 16#000240#;
|
||||||
|
constant reg_trigger_delay: natural := 16#000244#;
|
||||||
|
constant reg_trigger_status: natural := 16#000248#;
|
||||||
constant reg_test_led: natural := 16#000404#;
|
constant reg_test_led: natural := 16#000404#;
|
||||||
constant reg_test_divider: natural := 16#000408#;
|
constant reg_test_divider: natural := 16#000408#;
|
||||||
constant reg_dma_buf_addr: natural := 16#100000#;
|
constant reg_dma_buf_addr: natural := 16#100000#;
|
||||||
|
@ -71,21 +87,35 @@ package puzzlefw_pkg is
|
||||||
constant msg_trigger: std_logic_vector(7 downto 0) := x"02";
|
constant msg_trigger: std_logic_vector(7 downto 0) := x"02";
|
||||||
constant msg_overflow: std_logic_vector(7 downto 0) := x"10";
|
constant msg_overflow: std_logic_vector(7 downto 0) := x"10";
|
||||||
|
|
||||||
-- ADC input port type.
|
|
||||||
type adc_data_input_type is array(0 to 1) of std_logic_vector(15 downto 0);
|
|
||||||
|
|
||||||
-- Control registers: read/write access by processor, output signals to FPGA.
|
-- Control registers: read/write access by processor, output signals to FPGA.
|
||||||
type registers_control is record
|
type registers_control is record
|
||||||
irq_enable: std_logic;
|
irq_enable: std_logic;
|
||||||
test_led: std_logic_vector(7 downto 0);
|
test_led: std_logic_vector(7 downto 0);
|
||||||
test_divider: std_logic_vector(15 downto 0);
|
test_divider: std_logic_vector(15 downto 0);
|
||||||
dma_en: std_logic;
|
dma_en: std_logic;
|
||||||
|
dma_clear: std_logic; -- single cycle
|
||||||
|
timestamp_clear: std_logic; -- single cycle
|
||||||
acq_addr_start: std_logic_vector(31 downto 7);
|
acq_addr_start: std_logic_vector(31 downto 7);
|
||||||
acq_addr_end: std_logic_vector(31 downto 7);
|
acq_addr_end: std_logic_vector(31 downto 7);
|
||||||
acq_addr_limit: std_logic_vector(31 downto 7);
|
acq_addr_limit: std_logic_vector(31 downto 7);
|
||||||
acq_addr_intr: std_logic_vector(31 downto 3);
|
acq_addr_intr: std_logic_vector(31 downto 3);
|
||||||
acq_channel_en: std_logic;
|
acq_channel_en: std_logic;
|
||||||
|
acq_channel_init: std_logic; -- single cycle
|
||||||
acq_intr_en: std_logic;
|
acq_intr_en: std_logic;
|
||||||
|
acq_intr_clear: std_logic; -- single cycle
|
||||||
|
acquisition_en: std_logic;
|
||||||
|
record_length: std_logic_vector(15 downto 0);
|
||||||
|
decimation_factor: std_logic_vector(17 downto 0);
|
||||||
|
shift_steps: std_logic_vector(3 downto 0);
|
||||||
|
averaging_en: std_logic;
|
||||||
|
ch4_mode: std_logic;
|
||||||
|
simulate_adc: std_logic;
|
||||||
|
trig_auto_en: std_logic;
|
||||||
|
trig_ext_en: std_logic;
|
||||||
|
trig_force: std_logic; -- single cycle
|
||||||
|
trig_ext_select: std_logic_vector(1 downto 0);
|
||||||
|
trig_ext_falling: std_logic;
|
||||||
|
trigger_delay: std_logic_vector(15 downto 0);
|
||||||
dma_buf_addr: std_logic_vector(31 downto 12);
|
dma_buf_addr: std_logic_vector(31 downto 12);
|
||||||
dma_buf_size: std_logic_vector(31 downto 12);
|
dma_buf_size: std_logic_vector(31 downto 12);
|
||||||
end record;
|
end record;
|
||||||
|
@ -98,15 +128,10 @@ package puzzlefw_pkg is
|
||||||
dma_err_write: std_logic;
|
dma_err_write: std_logic;
|
||||||
dma_err_address: std_logic;
|
dma_err_address: std_logic;
|
||||||
dma_err_any: std_logic;
|
dma_err_any: std_logic;
|
||||||
|
timestamp: std_logic_vector(timestamp_bits - 1 downto 0);
|
||||||
acq_addr_ptr: std_logic_vector(31 downto 3);
|
acq_addr_ptr: std_logic_vector(31 downto 3);
|
||||||
acq_channel_busy: std_logic;
|
acq_channel_busy: std_logic;
|
||||||
end record;
|
trig_waiting: std_logic;
|
||||||
|
|
||||||
-- Trigger registers: write-only access by processor, single-cycle pulse signals to FPGA.
|
|
||||||
type registers_trigger is record
|
|
||||||
dma_clear: std_logic;
|
|
||||||
acq_channel_init: std_logic;
|
|
||||||
acq_intr_clear: std_logic;
|
|
||||||
end record;
|
end record;
|
||||||
|
|
||||||
constant registers_control_init: registers_control := (
|
constant registers_control_init: registers_control := (
|
||||||
|
@ -114,20 +139,31 @@ package puzzlefw_pkg is
|
||||||
test_led => (others => '0'),
|
test_led => (others => '0'),
|
||||||
test_divider => (others => '0'),
|
test_divider => (others => '0'),
|
||||||
dma_en => '0',
|
dma_en => '0',
|
||||||
|
dma_clear => '0',
|
||||||
|
timestamp_clear => '0',
|
||||||
acq_addr_start => (others => '0'),
|
acq_addr_start => (others => '0'),
|
||||||
acq_addr_end => (others => '0'),
|
acq_addr_end => (others => '0'),
|
||||||
acq_addr_limit => (others => '0'),
|
acq_addr_limit => (others => '0'),
|
||||||
acq_addr_intr => (others => '0'),
|
acq_addr_intr => (others => '0'),
|
||||||
acq_channel_en => '0',
|
acq_channel_en => '0',
|
||||||
|
acq_channel_init => '0',
|
||||||
acq_intr_en => '0',
|
acq_intr_en => '0',
|
||||||
|
acq_intr_clear => '0',
|
||||||
|
acquisition_en => '0',
|
||||||
|
record_length => (others => '0'),
|
||||||
|
decimation_factor => (others => '0'),
|
||||||
|
shift_steps => (others => '0'),
|
||||||
|
averaging_en => '0',
|
||||||
|
ch4_mode => '0',
|
||||||
|
simulate_adc => '0',
|
||||||
|
trig_auto_en => '0',
|
||||||
|
trig_ext_en => '0',
|
||||||
|
trig_force => '0',
|
||||||
|
trig_ext_select => (others => '0'),
|
||||||
|
trig_ext_falling => '0',
|
||||||
|
trigger_delay => (others => '0'),
|
||||||
dma_buf_addr => (others => '0'),
|
dma_buf_addr => (others => '0'),
|
||||||
dma_buf_size => (others => '0')
|
dma_buf_size => (others => '0')
|
||||||
);
|
);
|
||||||
|
|
||||||
constant registers_trigger_init: registers_trigger := (
|
|
||||||
dma_clear => '0',
|
|
||||||
acq_channel_init => '0',
|
|
||||||
acq_intr_clear => '0'
|
|
||||||
);
|
|
||||||
|
|
||||||
end package;
|
end package;
|
||||||
|
|
|
@ -74,7 +74,9 @@ architecture arch of puzzlefw_top is
|
||||||
-- Main reset signal, derived from FCLK_RESET0, active high, synchronous to clk_adc.
|
-- Main reset signal, derived from FCLK_RESET0, active high, synchronous to clk_adc.
|
||||||
signal s_reset: std_logic;
|
signal s_reset: std_logic;
|
||||||
|
|
||||||
|
-- Internal clock signal.
|
||||||
signal s_adc_clk_ibuf: std_logic;
|
signal s_adc_clk_ibuf: std_logic;
|
||||||
|
|
||||||
signal r_fclk_cnt: unsigned(26 downto 0);
|
signal r_fclk_cnt: unsigned(26 downto 0);
|
||||||
signal r_fclk_led: std_logic;
|
signal r_fclk_led: std_logic;
|
||||||
signal r_adcclk_cnt: unsigned(26 downto 0);
|
signal r_adcclk_cnt: unsigned(26 downto 0);
|
||||||
|
@ -128,13 +130,11 @@ architecture arch of puzzlefw_top is
|
||||||
signal s_axi_rvalid: std_logic;
|
signal s_axi_rvalid: std_logic;
|
||||||
signal s_axi_rready: std_logic;
|
signal s_axi_rready: std_logic;
|
||||||
|
|
||||||
signal s_dma_interrupt: std_logic;
|
|
||||||
signal s_irq_pending: std_logic_vector(0 downto 0);
|
signal s_irq_pending: std_logic_vector(0 downto 0);
|
||||||
signal s_irq_f2p: std_logic_vector(7 downto 0);
|
signal s_irq_f2p: std_logic_vector(7 downto 0);
|
||||||
|
|
||||||
signal s_reg_control: registers_control;
|
signal s_reg_control: registers_control;
|
||||||
signal s_reg_status: registers_status;
|
signal s_reg_status: registers_status;
|
||||||
signal s_reg_trigger: registers_trigger;
|
|
||||||
|
|
||||||
signal s_dma_write_cmd_addr: dma_address_array(0 downto 0);
|
signal s_dma_write_cmd_addr: dma_address_array(0 downto 0);
|
||||||
signal s_dma_write_cmd_length: dma_burst_length_array(0 to 0);
|
signal s_dma_write_cmd_length: dma_burst_length_array(0 to 0);
|
||||||
|
@ -144,9 +144,13 @@ architecture arch of puzzlefw_top is
|
||||||
signal s_dma_write_data_ready: std_logic_vector(0 downto 0);
|
signal s_dma_write_data_ready: std_logic_vector(0 downto 0);
|
||||||
signal s_dma_write_finished: std_logic_vector(0 downto 0);
|
signal s_dma_write_finished: std_logic_vector(0 downto 0);
|
||||||
|
|
||||||
signal s_dma_in_valid: std_logic;
|
signal s_timestamp: std_logic_vector(timestamp_bits - 1 downto 0);
|
||||||
signal s_dma_in_ready: std_logic;
|
signal s_adc_data: adc_data_array(0 to 1);
|
||||||
signal s_dma_in_data: std_logic_vector(63 downto 0);
|
|
||||||
|
signal s_acq_dma_valid: std_logic;
|
||||||
|
signal s_acq_dma_ready: std_logic;
|
||||||
|
signal s_acq_dma_empty: std_logic;
|
||||||
|
signal s_acq_dma_data: dma_data_type;
|
||||||
|
|
||||||
signal r_test_prefetch: std_logic;
|
signal r_test_prefetch: std_logic;
|
||||||
signal r_test_raddr: std_logic_vector(9 downto 0);
|
signal r_test_raddr: std_logic_vector(9 downto 0);
|
||||||
|
@ -276,8 +280,7 @@ begin
|
||||||
apb_pslverr => s_apb_pslverr,
|
apb_pslverr => s_apb_pslverr,
|
||||||
apb_prdata => s_apb_prdata,
|
apb_prdata => s_apb_prdata,
|
||||||
reg_control => s_reg_control,
|
reg_control => s_reg_control,
|
||||||
reg_status => s_reg_status,
|
reg_status => s_reg_status
|
||||||
reg_trigger => s_reg_trigger
|
|
||||||
);
|
);
|
||||||
|
|
||||||
-- AXI master.
|
-- AXI master.
|
||||||
|
@ -296,7 +299,7 @@ begin
|
||||||
err_write => s_reg_status.dma_err_write,
|
err_write => s_reg_status.dma_err_write,
|
||||||
err_address => s_reg_status.dma_err_address,
|
err_address => s_reg_status.dma_err_address,
|
||||||
err_any => s_reg_status.dma_err_any,
|
err_any => s_reg_status.dma_err_any,
|
||||||
clear_errors => s_reg_trigger.dma_clear,
|
clear_errors => s_reg_control.dma_clear,
|
||||||
read_cmd_addr => (others => (others => '0')),
|
read_cmd_addr => (others => (others => '0')),
|
||||||
read_cmd_length => (others => (others => '0')),
|
read_cmd_length => (others => (others => '0')),
|
||||||
read_cmd_valid => (others => '0'),
|
read_cmd_valid => (others => '0'),
|
||||||
|
@ -361,18 +364,19 @@ begin
|
||||||
reset => s_reset,
|
reset => s_reset,
|
||||||
channel_en => s_reg_control.acq_channel_en,
|
channel_en => s_reg_control.acq_channel_en,
|
||||||
channel_busy => s_reg_status.acq_channel_busy,
|
channel_busy => s_reg_status.acq_channel_busy,
|
||||||
channel_init => s_reg_trigger.acq_channel_init,
|
channel_init => s_reg_control.acq_channel_init,
|
||||||
addr_start => s_reg_control.acq_addr_start,
|
addr_start => s_reg_control.acq_addr_start,
|
||||||
addr_end => s_reg_control.acq_addr_end,
|
addr_end => s_reg_control.acq_addr_end,
|
||||||
addr_limit => s_reg_control.acq_addr_limit,
|
addr_limit => s_reg_control.acq_addr_limit,
|
||||||
addr_interrupt => s_reg_control.acq_addr_intr,
|
addr_interrupt => s_reg_control.acq_addr_intr,
|
||||||
addr_pointer => s_reg_status.acq_addr_ptr,
|
addr_pointer => s_reg_status.acq_addr_ptr,
|
||||||
intr_en => s_reg_control.acq_intr_en,
|
intr_en => s_reg_control.acq_intr_en,
|
||||||
intr_clear => s_reg_trigger.acq_intr_clear,
|
intr_clear => s_reg_control.acq_intr_clear,
|
||||||
intr_out => s_dma_interrupt,
|
intr_out => s_irq_pending(0),
|
||||||
in_valid => s_dma_in_valid,
|
in_valid => s_acq_dma_valid,
|
||||||
in_ready => s_dma_in_ready,
|
in_ready => s_acq_dma_ready,
|
||||||
in_data => s_dma_in_data,
|
in_empty => s_acq_dma_empty,
|
||||||
|
in_data => s_acq_dma_data,
|
||||||
write_cmd_addr => s_dma_write_cmd_addr(0),
|
write_cmd_addr => s_dma_write_cmd_addr(0),
|
||||||
write_cmd_length => s_dma_write_cmd_length(0),
|
write_cmd_length => s_dma_write_cmd_length(0),
|
||||||
write_cmd_valid => s_dma_write_cmd_valid(0),
|
write_cmd_valid => s_dma_write_cmd_valid(0),
|
||||||
|
@ -381,39 +385,64 @@ begin
|
||||||
write_data_ready => s_dma_write_data_ready(0),
|
write_data_ready => s_dma_write_data_ready(0),
|
||||||
write_finished => s_dma_write_finished(0) );
|
write_finished => s_dma_write_finished(0) );
|
||||||
|
|
||||||
|
-- Timestamp generator.
|
||||||
|
inst_timestamp_gen: entity work.timestamp_gen
|
||||||
|
port map (
|
||||||
|
clk => clk_adc,
|
||||||
|
reset => s_reset,
|
||||||
|
clear => s_reg_control.timestamp_clear,
|
||||||
|
timestamp => s_timestamp );
|
||||||
|
|
||||||
|
s_reg_status.timestamp <= s_timestamp;
|
||||||
|
|
||||||
|
-- Capture ADC data.
|
||||||
|
-- Ignore the 2 LSB bits which are not-connected on the ADC side.
|
||||||
|
inst_adc_capture1: entity work.adc_capture
|
||||||
|
port map (
|
||||||
|
clk => clk_adc,
|
||||||
|
in_data => adc_dat_i(0)(15 downto 2),
|
||||||
|
out_data => s_adc_data(0) );
|
||||||
|
|
||||||
|
inst_adc_capture2: entity work.adc_capture
|
||||||
|
port map (
|
||||||
|
clk => clk_adc,
|
||||||
|
in_data => adc_dat_i(1)(15 downto 2),
|
||||||
|
out_data => s_adc_data(1) );
|
||||||
|
|
||||||
|
-- Analog acquisition data chain.
|
||||||
|
inst_acquisition_chain: entity work.acquisition_chain
|
||||||
|
generic map (
|
||||||
|
num_channels => 2 )
|
||||||
|
port map (
|
||||||
|
clk => clk_adc,
|
||||||
|
reset => s_reset,
|
||||||
|
acquisition_en => s_reg_control.acquisition_en,
|
||||||
|
trigger_delay => s_reg_control.trigger_delay,
|
||||||
|
record_length => s_reg_control.record_length,
|
||||||
|
decimation_factor => s_reg_control.decimation_factor,
|
||||||
|
averaging => s_reg_control.averaging_en,
|
||||||
|
shift_steps => s_reg_control.shift_steps,
|
||||||
|
ch4_mode => s_reg_control.ch4_mode,
|
||||||
|
simulate_adc => s_reg_control.simulate_adc,
|
||||||
|
trig_auto_en => s_reg_control.trig_auto_en,
|
||||||
|
trig_ext_en => s_reg_control.trig_ext_en,
|
||||||
|
trig_force => s_reg_control.trig_force,
|
||||||
|
trig_ext_select => s_reg_control.trig_ext_select,
|
||||||
|
trig_ext_falling => s_reg_control.trig_ext_falling,
|
||||||
|
timestamp_in => s_timestamp,
|
||||||
|
adc_data_in => s_adc_data,
|
||||||
|
trig_ext_in => "0000", -- TODO
|
||||||
|
trig_waiting => s_reg_status.trig_waiting,
|
||||||
|
out_valid => s_acq_dma_valid,
|
||||||
|
out_ready => s_acq_dma_ready,
|
||||||
|
out_empty => s_acq_dma_empty,
|
||||||
|
out_data => s_acq_dma_data );
|
||||||
|
|
||||||
-- Collect interrupt signals from peripherals and generate interrupt to PS.
|
-- Collect interrupt signals from peripherals and generate interrupt to PS.
|
||||||
s_irq_pending(0) <= s_dma_interrupt;
|
|
||||||
s_reg_status.irq_pending <= s_irq_pending;
|
s_reg_status.irq_pending <= s_irq_pending;
|
||||||
s_irq_f2p(0) <= s_reg_control.irq_enable and or_reduce(s_irq_pending);
|
s_irq_f2p(0) <= s_reg_control.irq_enable and or_reduce(s_irq_pending);
|
||||||
s_irq_f2p(7 downto 1) <= (others => '0');
|
s_irq_f2p(7 downto 1) <= (others => '0');
|
||||||
|
|
||||||
-- little test machine for DMA
|
|
||||||
process (clk_adc) is
|
|
||||||
begin
|
|
||||||
if rising_edge(clk_adc) then
|
|
||||||
if s_reg_control.test_divider = x"ffff" then
|
|
||||||
s_dma_in_valid <= '1';
|
|
||||||
if s_dma_in_ready = '1' then
|
|
||||||
s_dma_in_data(47 downto 0) <= std_logic_vector(unsigned(s_dma_in_data(47 downto 0)) + 1);
|
|
||||||
s_dma_in_data(63 downto 48) <= (others => '0');
|
|
||||||
end if;
|
|
||||||
else
|
|
||||||
if s_dma_in_ready = '1' then
|
|
||||||
s_dma_in_valid <= '0';
|
|
||||||
end if;
|
|
||||||
if r_test_cnt >= unsigned(s_reg_control.test_divider) then
|
|
||||||
r_test_cnt <= (others => '0');
|
|
||||||
s_dma_in_valid <= '1';
|
|
||||||
s_dma_in_data(47 downto 0) <= std_logic_vector(unsigned(s_dma_in_data(47 downto 0)) + 1);
|
|
||||||
s_dma_in_data(63 downto 48) <= (others => '0');
|
|
||||||
else
|
|
||||||
r_test_cnt <= r_test_cnt + 1;
|
|
||||||
end if;
|
|
||||||
end if;
|
|
||||||
end if;
|
|
||||||
end process;
|
|
||||||
-- END test
|
|
||||||
|
|
||||||
process (clk_fclk) is
|
process (clk_fclk) is
|
||||||
begin
|
begin
|
||||||
if rising_edge(clk_fclk) then
|
if rising_edge(clk_fclk) then
|
||||||
|
|
|
@ -32,8 +32,7 @@ entity registers is
|
||||||
|
|
||||||
-- FPGA interface.
|
-- FPGA interface.
|
||||||
reg_control: out registers_control;
|
reg_control: out registers_control;
|
||||||
reg_status: in registers_status;
|
reg_status: in registers_status
|
||||||
reg_trigger: out registers_trigger
|
|
||||||
);
|
);
|
||||||
|
|
||||||
end entity;
|
end entity;
|
||||||
|
@ -44,14 +43,12 @@ architecture arch of registers is
|
||||||
pready: std_logic;
|
pready: std_logic;
|
||||||
prdata: std_logic_vector(31 downto 0);
|
prdata: std_logic_vector(31 downto 0);
|
||||||
reg_control: registers_control;
|
reg_control: registers_control;
|
||||||
reg_trigger: registers_trigger;
|
|
||||||
end record;
|
end record;
|
||||||
|
|
||||||
constant regs_init: regs_type := (
|
constant regs_init: regs_type := (
|
||||||
pready => '0',
|
pready => '0',
|
||||||
prdata => (others => '0'),
|
prdata => (others => '0'),
|
||||||
reg_control => registers_control_init,
|
reg_control => registers_control_init
|
||||||
reg_trigger => registers_trigger_init
|
|
||||||
);
|
);
|
||||||
|
|
||||||
signal r: regs_type := regs_init;
|
signal r: regs_type := regs_init;
|
||||||
|
@ -63,9 +60,7 @@ begin
|
||||||
apb_pready <= r.pready;
|
apb_pready <= r.pready;
|
||||||
apb_pslverr <= '0'; -- never signal errors
|
apb_pslverr <= '0'; -- never signal errors
|
||||||
apb_prdata <= r.prdata;
|
apb_prdata <= r.prdata;
|
||||||
|
|
||||||
reg_control <= r.reg_control;
|
reg_control <= r.reg_control;
|
||||||
reg_trigger <= r.reg_trigger;
|
|
||||||
|
|
||||||
-- Combinatorial process.
|
-- Combinatorial process.
|
||||||
process (all) is
|
process (all) is
|
||||||
|
@ -75,7 +70,11 @@ begin
|
||||||
v := r;
|
v := r;
|
||||||
|
|
||||||
-- Clear single-cycle trigger pulses.
|
-- Clear single-cycle trigger pulses.
|
||||||
v.reg_trigger := registers_trigger_init;
|
v.reg_control.dma_clear := '0';
|
||||||
|
v.reg_control.timestamp_clear := '0';
|
||||||
|
v.reg_control.acq_channel_init := '0';
|
||||||
|
v.reg_control.acq_intr_clear := '0';
|
||||||
|
v.reg_control.trig_force := '0';
|
||||||
|
|
||||||
-- Respond to each APB access on the next clock cycle (no wait states).
|
-- Respond to each APB access on the next clock cycle (no wait states).
|
||||||
v.pready := apb_psel and (not apb_penable);
|
v.pready := apb_psel and (not apb_penable);
|
||||||
|
@ -98,6 +97,8 @@ begin
|
||||||
v.prdata(2) := reg_status.dma_err_write;
|
v.prdata(2) := reg_status.dma_err_write;
|
||||||
v.prdata(3) := reg_status.dma_err_address;
|
v.prdata(3) := reg_status.dma_err_address;
|
||||||
v.prdata(4) := reg_status.dma_err_any;
|
v.prdata(4) := reg_status.dma_err_any;
|
||||||
|
when reg_timestamp_lo => v.prdata := reg_status.timestamp(31 downto 0);
|
||||||
|
when reg_timestamp_hi => v.prdata(15 downto 0) := reg_status.timestamp(47 downto 32);
|
||||||
when reg_acq_addr_start => v.prdata(31 downto 7) := r.reg_control.acq_addr_start;
|
when reg_acq_addr_start => v.prdata(31 downto 7) := r.reg_control.acq_addr_start;
|
||||||
when reg_acq_addr_end => v.prdata(31 downto 7) := r.reg_control.acq_addr_end;
|
when reg_acq_addr_end => v.prdata(31 downto 7) := r.reg_control.acq_addr_end;
|
||||||
when reg_acq_addr_limit => v.prdata(31 downto 7) := r.reg_control.acq_addr_limit;
|
when reg_acq_addr_limit => v.prdata(31 downto 7) := r.reg_control.acq_addr_limit;
|
||||||
|
@ -107,6 +108,20 @@ begin
|
||||||
v.prdata(0) := r.reg_control.acq_channel_en;
|
v.prdata(0) := r.reg_control.acq_channel_en;
|
||||||
v.prdata(8) := reg_status.acq_channel_busy;
|
v.prdata(8) := reg_status.acq_channel_busy;
|
||||||
when reg_acq_intr_ctrl => v.prdata(0) := r.reg_control.acq_intr_en;
|
when reg_acq_intr_ctrl => v.prdata(0) := r.reg_control.acq_intr_en;
|
||||||
|
when reg_acquisition_en => v.prdata(0) := r.reg_control.acquisition_en;
|
||||||
|
when reg_record_length => v.prdata(15 downto 0) := r.reg_control.record_length;
|
||||||
|
when reg_decimation_factor => v.prdata(17 downto 0) := r.reg_control.decimation_factor;
|
||||||
|
when reg_shift_steps => v.prdata(3 downto 0) := r.reg_control.shift_steps;
|
||||||
|
when reg_averaging_en => v.prdata(0) := r.reg_control.averaging_en;
|
||||||
|
when reg_ch4_mode => v.prdata(0) := r.reg_control.ch4_mode;
|
||||||
|
when reg_simulate_adc => v.prdata(0) := r.reg_control.simulate_adc;
|
||||||
|
when reg_trigger_mode =>
|
||||||
|
v.prdata(0) := r.reg_control.trig_auto_en;
|
||||||
|
v.prdata(1) := r.reg_control.trig_ext_en;
|
||||||
|
v.prdata(5 downto 4) := r.reg_control.trig_ext_select;
|
||||||
|
v.prdata(7) := r.reg_control.trig_ext_falling;
|
||||||
|
when reg_trigger_delay => v.prdata(15 downto 0) := r.reg_control.trigger_delay;
|
||||||
|
when reg_trigger_status => v.prdata(0) := reg_status.trig_waiting;
|
||||||
when reg_test_led => v.prdata(7 downto 0) := r.reg_control.test_led;
|
when reg_test_led => v.prdata(7 downto 0) := r.reg_control.test_led;
|
||||||
when reg_test_divider => v.prdata(15 downto 0) := r.reg_control.test_divider;
|
when reg_test_divider => v.prdata(15 downto 0) := r.reg_control.test_divider;
|
||||||
when reg_dma_buf_addr => v.prdata(31 downto 12) := r.reg_control.dma_buf_addr;
|
when reg_dma_buf_addr => v.prdata(31 downto 12) := r.reg_control.dma_buf_addr;
|
||||||
|
@ -121,17 +136,32 @@ begin
|
||||||
case to_integer(unsigned(apb_paddr and reg_addr_mask)) is
|
case to_integer(unsigned(apb_paddr and reg_addr_mask)) is
|
||||||
when reg_irq_enable => v.reg_control.irq_enable := apb_pwdata(0);
|
when reg_irq_enable => v.reg_control.irq_enable := apb_pwdata(0);
|
||||||
when reg_dma_en => v.reg_control.dma_en := apb_pwdata(0);
|
when reg_dma_en => v.reg_control.dma_en := apb_pwdata(0);
|
||||||
when reg_dma_clear => v.reg_trigger.dma_clear := apb_pwdata(0);
|
when reg_dma_clear => v.reg_control.dma_clear := apb_pwdata(0);
|
||||||
|
when reg_timestamp_clear => v.reg_control.timestamp_clear := apb_pwdata(0);
|
||||||
when reg_acq_addr_start => v.reg_control.acq_addr_start := apb_pwdata(31 downto 7);
|
when reg_acq_addr_start => v.reg_control.acq_addr_start := apb_pwdata(31 downto 7);
|
||||||
when reg_acq_addr_end => v.reg_control.acq_addr_end := apb_pwdata(31 downto 7);
|
when reg_acq_addr_end => v.reg_control.acq_addr_end := apb_pwdata(31 downto 7);
|
||||||
when reg_acq_addr_limit => v.reg_control.acq_addr_limit := apb_pwdata(31 downto 7);
|
when reg_acq_addr_limit => v.reg_control.acq_addr_limit := apb_pwdata(31 downto 7);
|
||||||
when reg_acq_addr_intr => v.reg_control.acq_addr_intr := apb_pwdata(31 downto 3);
|
when reg_acq_addr_intr => v.reg_control.acq_addr_intr := apb_pwdata(31 downto 3);
|
||||||
when reg_acq_channel_ctrl =>
|
when reg_acq_channel_ctrl =>
|
||||||
v.reg_control.acq_channel_en := apb_pwdata(0);
|
v.reg_control.acq_channel_en := apb_pwdata(0);
|
||||||
v.reg_trigger.acq_channel_init := apb_pwdata(1);
|
v.reg_control.acq_channel_init := apb_pwdata(1);
|
||||||
when reg_acq_intr_ctrl =>
|
when reg_acq_intr_ctrl =>
|
||||||
v.reg_control.acq_intr_en := apb_pwdata(0);
|
v.reg_control.acq_intr_en := apb_pwdata(0);
|
||||||
v.reg_trigger.acq_intr_clear := apb_pwdata(1);
|
v.reg_control.acq_intr_clear := apb_pwdata(1);
|
||||||
|
when reg_acquisition_en => v.reg_control.acquisition_en := apb_pwdata(0);
|
||||||
|
when reg_record_length => v.reg_control.record_length := apb_pwdata(15 downto 0);
|
||||||
|
when reg_decimation_factor => v.reg_control.decimation_factor := apb_pwdata(17 downto 0);
|
||||||
|
when reg_shift_steps => v.reg_control.shift_steps := apb_pwdata(3 downto 0);
|
||||||
|
when reg_averaging_en => v.reg_control.averaging_en := apb_pwdata(0);
|
||||||
|
when reg_ch4_mode => v.reg_control.ch4_mode := apb_pwdata(0);
|
||||||
|
when reg_simulate_adc => v.reg_control.simulate_adc := apb_pwdata(0);
|
||||||
|
when reg_trigger_mode =>
|
||||||
|
v.reg_control.trig_auto_en := apb_pwdata(0);
|
||||||
|
v.reg_control.trig_ext_en := apb_pwdata(1);
|
||||||
|
v.reg_control.trig_ext_select := apb_pwdata(5 downto 4);
|
||||||
|
v.reg_control.trig_ext_falling := apb_pwdata(7);
|
||||||
|
v.reg_control.trig_force := apb_pwdata(8);
|
||||||
|
when reg_trigger_delay => v.reg_control.trigger_delay := apb_pwdata(15 downto 0);
|
||||||
when reg_test_led => v.reg_control.test_led := apb_pwdata(7 downto 0);
|
when reg_test_led => v.reg_control.test_led := apb_pwdata(7 downto 0);
|
||||||
when reg_test_divider => v.reg_control.test_divider := apb_pwdata(15 downto 0);
|
when reg_test_divider => v.reg_control.test_divider := apb_pwdata(15 downto 0);
|
||||||
when reg_dma_buf_addr => v.reg_control.dma_buf_addr := apb_pwdata(31 downto 12);
|
when reg_dma_buf_addr => v.reg_control.dma_buf_addr := apb_pwdata(31 downto 12);
|
||||||
|
|
|
@ -0,0 +1,124 @@
|
||||||
|
--
|
||||||
|
-- Decimation or averaging of ADC samples.
|
||||||
|
--
|
||||||
|
-- Joris van Rantwijk 2024
|
||||||
|
--
|
||||||
|
|
||||||
|
library ieee;
|
||||||
|
use ieee.std_logic_1164.all;
|
||||||
|
use ieee.numeric_std.all;
|
||||||
|
|
||||||
|
|
||||||
|
entity sample_decimation is
|
||||||
|
|
||||||
|
generic (
|
||||||
|
-- Input word length.
|
||||||
|
-- This is also the word length of the internal accumulator.
|
||||||
|
input_data_bits: integer range 4 to 64;
|
||||||
|
|
||||||
|
-- Output word length.
|
||||||
|
-- If the output has fewer bits than the input, it represents the
|
||||||
|
-- most significant bits of the accumulator, rounded to the
|
||||||
|
-- nearest integer.
|
||||||
|
output_data_bits: integer range 4 to 64
|
||||||
|
);
|
||||||
|
|
||||||
|
port (
|
||||||
|
-- Main clock, active on rising edge.
|
||||||
|
clk: in std_logic;
|
||||||
|
|
||||||
|
-- Reset, active high, synchronous to main clock.
|
||||||
|
reset: in std_logic;
|
||||||
|
|
||||||
|
-- High to initialize the accumulator to the input word plus rounding bias.
|
||||||
|
start: in std_logic;
|
||||||
|
|
||||||
|
-- High to add the input word to the accumulator.
|
||||||
|
integrate: in std_logic;
|
||||||
|
|
||||||
|
-- Input data word.
|
||||||
|
in_data: in std_logic_vector(input_data_bits - 1 downto 0);
|
||||||
|
|
||||||
|
-- Output data word.
|
||||||
|
-- Results from input signals appear on the output after 1 clock cycle.
|
||||||
|
out_data: out std_logic_vector(output_data_bits - 1 downto 0)
|
||||||
|
);
|
||||||
|
|
||||||
|
end entity;
|
||||||
|
|
||||||
|
architecture arch of sample_decimation is
|
||||||
|
|
||||||
|
-- Return the rounding bias to add to the accumulator before truncating
|
||||||
|
-- the least significant bits.
|
||||||
|
function rounding_bias return unsigned
|
||||||
|
is begin
|
||||||
|
if output_data_bits < input_data_bits then
|
||||||
|
-- Set the most significant truncated bit to '1'.
|
||||||
|
return shift_left(to_unsigned(1, input_data_bits),
|
||||||
|
input_data_bits - output_data_bits - 1);
|
||||||
|
else
|
||||||
|
-- No truncation.
|
||||||
|
return to_unsigned(0, input_data_bits);
|
||||||
|
end if;
|
||||||
|
end function;
|
||||||
|
|
||||||
|
type regs_type is record
|
||||||
|
accumulator: std_logic_vector(input_data_bits - 1 downto 0);
|
||||||
|
end record;
|
||||||
|
|
||||||
|
constant regs_init: regs_type := (
|
||||||
|
accumulator => (others => '0')
|
||||||
|
);
|
||||||
|
|
||||||
|
signal r: regs_type := regs_init;
|
||||||
|
signal rnext: regs_type;
|
||||||
|
|
||||||
|
begin
|
||||||
|
|
||||||
|
-- Drive output from accumulator.
|
||||||
|
out_data <= r.accumulator(input_data_bits - 1 downto input_data_bits - output_data_bits)
|
||||||
|
when (output_data_bits <= input_data_bits)
|
||||||
|
else r.accumulator & std_logic_vector(to_unsigned(0, output_data_bits - input_data_bits));
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Combinatorial process.
|
||||||
|
--
|
||||||
|
process (all) is
|
||||||
|
variable v: regs_type;
|
||||||
|
begin
|
||||||
|
-- Load current register values.
|
||||||
|
v := r;
|
||||||
|
|
||||||
|
if start = '1' then
|
||||||
|
|
||||||
|
-- Initialize accumulator and add input word.
|
||||||
|
v.accumulator := std_logic_vector(rounding_bias + unsigned(in_data));
|
||||||
|
|
||||||
|
elsif integrate = '1' then
|
||||||
|
|
||||||
|
-- Add input word to the accumulator.
|
||||||
|
v.accumulator := std_logic_vector(unsigned(r.accumulator) + unsigned(in_data));
|
||||||
|
|
||||||
|
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;
|
|
@ -0,0 +1,90 @@
|
||||||
|
--
|
||||||
|
-- Signed or unsigned variable right-shift.
|
||||||
|
--
|
||||||
|
-- Joris van Rantwijk 2024
|
||||||
|
--
|
||||||
|
|
||||||
|
library ieee;
|
||||||
|
use ieee.std_logic_1164.all;
|
||||||
|
use ieee.numeric_std.all;
|
||||||
|
|
||||||
|
|
||||||
|
entity shift_engine is
|
||||||
|
|
||||||
|
generic (
|
||||||
|
-- Input word length.
|
||||||
|
input_data_bits: integer range 4 to 64;
|
||||||
|
|
||||||
|
-- Output word length.
|
||||||
|
output_data_bits: integer range 4 to 64;
|
||||||
|
|
||||||
|
-- Number of bit positions to pre-shift left before shifting right.
|
||||||
|
pre_shift_left: integer range 0 to 16;
|
||||||
|
|
||||||
|
-- True to apply sign extension when shifting.
|
||||||
|
-- False to apply zero extension.
|
||||||
|
signed_data: boolean
|
||||||
|
);
|
||||||
|
|
||||||
|
port (
|
||||||
|
-- Main clock, active on rising edge.
|
||||||
|
clk: in std_logic;
|
||||||
|
|
||||||
|
-- Data input operand.
|
||||||
|
-- A new input word is accepted on every clock cycle.
|
||||||
|
in_data: in std_logic_vector(input_data_bits - 1 downto 0);
|
||||||
|
|
||||||
|
-- Shift input operand.
|
||||||
|
-- It indicates the number of bit positions to shift right, expressed
|
||||||
|
-- as an unsigned integer in range 0 to 15.
|
||||||
|
-- A new input word is accepted on every clock cycle.
|
||||||
|
in_shift: in std_logic_vector(3 downto 0);
|
||||||
|
|
||||||
|
-- Shifted output data.
|
||||||
|
-- The output corresponds to the input delayed by 1 clock cycle.
|
||||||
|
out_data: out std_logic_vector(output_data_bits - 1 downto 0)
|
||||||
|
);
|
||||||
|
|
||||||
|
end entity;
|
||||||
|
|
||||||
|
architecture arch of shift_engine is
|
||||||
|
|
||||||
|
-- Output register.
|
||||||
|
signal r_data: std_logic_vector(output_data_bits - 1 downto 0);
|
||||||
|
|
||||||
|
begin
|
||||||
|
|
||||||
|
-- Drive output.
|
||||||
|
out_data <= r_data;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Synchronous process.
|
||||||
|
--
|
||||||
|
process (clk) is
|
||||||
|
begin
|
||||||
|
if rising_edge(clk) then
|
||||||
|
|
||||||
|
if signed_data then
|
||||||
|
|
||||||
|
r_data <= std_logic_vector(
|
||||||
|
shift_right(
|
||||||
|
shift_left(
|
||||||
|
resize(signed(in_data), output_data_bits),
|
||||||
|
pre_shift_left),
|
||||||
|
to_integer(unsigned(in_shift))));
|
||||||
|
|
||||||
|
else
|
||||||
|
|
||||||
|
r_data <= std_logic_vector(
|
||||||
|
shift_right(
|
||||||
|
shift_left(
|
||||||
|
resize(unsigned(in_data), output_data_bits),
|
||||||
|
pre_shift_left),
|
||||||
|
to_integer(unsigned(in_shift))));
|
||||||
|
|
||||||
|
end if;
|
||||||
|
|
||||||
|
end if;
|
||||||
|
end process;
|
||||||
|
|
||||||
|
end architecture;
|
|
@ -0,0 +1,57 @@
|
||||||
|
--
|
||||||
|
-- Generate timestamps.
|
||||||
|
--
|
||||||
|
-- Joris van Rantwijk 2024
|
||||||
|
--
|
||||||
|
|
||||||
|
library ieee;
|
||||||
|
use ieee.std_logic_1164.all;
|
||||||
|
use ieee.numeric_std.all;
|
||||||
|
|
||||||
|
use work.puzzlefw_pkg.all;
|
||||||
|
|
||||||
|
|
||||||
|
entity timestamp_gen 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 reset the timestamp counter to 0.
|
||||||
|
clear: in std_logic;
|
||||||
|
|
||||||
|
-- Timestamp.
|
||||||
|
timestamp: out std_logic_vector(timestamp_bits - 1 downto 0)
|
||||||
|
);
|
||||||
|
|
||||||
|
end entity;
|
||||||
|
|
||||||
|
architecture arch of timestamp_gen is
|
||||||
|
|
||||||
|
signal r_counter: unsigned(timestamp_bits - 1 downto 0);
|
||||||
|
|
||||||
|
begin
|
||||||
|
|
||||||
|
-- Drive output.
|
||||||
|
timestamp <= std_logic_vector(r_counter);
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Synchronous process.
|
||||||
|
--
|
||||||
|
process (clk) is
|
||||||
|
begin
|
||||||
|
if rising_edge(clk) then
|
||||||
|
|
||||||
|
if (reset = '1') or (clear = '1') then
|
||||||
|
r_counter <= (others => '0');
|
||||||
|
else
|
||||||
|
r_counter <= r_counter + 1;
|
||||||
|
end if;
|
||||||
|
|
||||||
|
end if;
|
||||||
|
end process;
|
||||||
|
|
||||||
|
end architecture;
|
|
@ -0,0 +1,112 @@
|
||||||
|
--
|
||||||
|
-- Detect external triggers.
|
||||||
|
--
|
||||||
|
-- Joris van Rantwijk 2024
|
||||||
|
--
|
||||||
|
|
||||||
|
library ieee;
|
||||||
|
use ieee.std_logic_1164.all;
|
||||||
|
use ieee.numeric_std.all;
|
||||||
|
|
||||||
|
use work.puzzlefw_pkg.all;
|
||||||
|
|
||||||
|
|
||||||
|
entity trigger_detector 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 automatic (continuous) triggering.
|
||||||
|
trig_auto_en: in std_logic;
|
||||||
|
|
||||||
|
-- High to enable external triggering.
|
||||||
|
trig_ext_en: in std_logic;
|
||||||
|
|
||||||
|
-- High to force a trigger event (if the acquisition chain is ready).
|
||||||
|
trig_force: in std_logic;
|
||||||
|
|
||||||
|
-- Select external input signal to use as trigger.
|
||||||
|
trig_select: in std_logic_vector(1 downto 0);
|
||||||
|
|
||||||
|
-- High to trigger on falling edge, low to trigger on rising edge.
|
||||||
|
trig_falling: in std_logic;
|
||||||
|
|
||||||
|
-- Digital input signals.
|
||||||
|
trig_ext_in: in std_logic_vector(3 downto 0);
|
||||||
|
|
||||||
|
-- High in the clock cycle following the occurrence of a trigger.
|
||||||
|
trig_out: out std_logic
|
||||||
|
);
|
||||||
|
|
||||||
|
end entity;
|
||||||
|
|
||||||
|
architecture arch of trigger_detector is
|
||||||
|
|
||||||
|
type regs_type is record
|
||||||
|
prev_level: std_logic;
|
||||||
|
ext_trig: std_logic;
|
||||||
|
trig_out: std_logic;
|
||||||
|
end record;
|
||||||
|
|
||||||
|
constant regs_init: regs_type := (
|
||||||
|
prev_level => '0',
|
||||||
|
ext_trig => '0',
|
||||||
|
trig_out => '0'
|
||||||
|
);
|
||||||
|
|
||||||
|
signal r: regs_type := regs_init;
|
||||||
|
signal rnext: regs_type;
|
||||||
|
|
||||||
|
begin
|
||||||
|
|
||||||
|
-- Drive output.
|
||||||
|
trig_out <= r.trig_out;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Combinatorial process.
|
||||||
|
--
|
||||||
|
process (all) is
|
||||||
|
variable v: regs_type;
|
||||||
|
variable v_trig: std_logic;
|
||||||
|
begin
|
||||||
|
-- Load current register values.
|
||||||
|
v := r;
|
||||||
|
|
||||||
|
-- Select external input signal.
|
||||||
|
v.prev_level := trig_ext_in(to_integer(unsigned(trig_select)));
|
||||||
|
|
||||||
|
-- Detect active edge.
|
||||||
|
v.ext_trig := (not (r.prev_level xor trig_falling)) and
|
||||||
|
(v.prev_level xor trig_falling);
|
||||||
|
|
||||||
|
-- Combine trigger sources.
|
||||||
|
v.trig_out := trig_auto_en or
|
||||||
|
(trig_ext_en and r.ext_trig) or
|
||||||
|
trig_force;
|
||||||
|
|
||||||
|
-- Synchronous reset.
|
||||||
|
if reset = '1' then
|
||||||
|
v.ext_trig := '0';
|
||||||
|
v.trig_out := '0';
|
||||||
|
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;
|
|
@ -19,10 +19,19 @@ set_property target_language VHDL [current_project]
|
||||||
|
|
||||||
# Load VHDL files.
|
# Load VHDL files.
|
||||||
read_vhdl -vhdl2008 ../rtl/puzzlefw_pkg.vhd
|
read_vhdl -vhdl2008 ../rtl/puzzlefw_pkg.vhd
|
||||||
read_vhdl -vhdl2008 ../rtl/simple_fifo.vhd
|
read_vhdl -vhdl2008 ../rtl/acquisition_chain.vhd
|
||||||
|
read_vhdl -vhdl2008 ../rtl/acquisition_manager.vhd
|
||||||
|
read_vhdl -vhdl2008 ../rtl/acquisition_stream.vhd
|
||||||
|
read_vhdl -vhdl2008 ../rtl/adc_capture.vhd
|
||||||
|
read_vhdl -vhdl2008 ../rtl/adc_sample_stream.vhd
|
||||||
read_vhdl -vhdl2008 ../rtl/dma_axi_master.vhd
|
read_vhdl -vhdl2008 ../rtl/dma_axi_master.vhd
|
||||||
read_vhdl -vhdl2008 ../rtl/dma_write_channel.vhd
|
read_vhdl -vhdl2008 ../rtl/dma_write_channel.vhd
|
||||||
read_vhdl -vhdl2008 ../rtl/registers.vhd
|
read_vhdl -vhdl2008 ../rtl/registers.vhd
|
||||||
|
read_vhdl -vhdl2008 ../rtl/sample_decimation.vhd
|
||||||
|
read_vhdl -vhdl2008 ../rtl/shift_engine.vhd
|
||||||
|
read_vhdl -vhdl2008 ../rtl/simple_fifo.vhd
|
||||||
|
read_vhdl -vhdl2008 ../rtl/timestamp_gen.vhd
|
||||||
|
read_vhdl -vhdl2008 ../rtl/trigger_detector.vhd
|
||||||
read_vhdl -vhdl2008 ../rtl/puzzlefw_top.vhd
|
read_vhdl -vhdl2008 ../rtl/puzzlefw_top.vhd
|
||||||
|
|
||||||
# Load Zynq block design.
|
# Load Zynq block design.
|
||||||
|
|
|
@ -31,14 +31,26 @@
|
||||||
#define REG_DMA_EN 0x0100
|
#define REG_DMA_EN 0x0100
|
||||||
#define REG_DMA_STATUS 0x0104
|
#define REG_DMA_STATUS 0x0104
|
||||||
#define REG_DMA_CLEAR 0x0108
|
#define REG_DMA_CLEAR 0x0108
|
||||||
#define REG_DMA_ADDR_START 0x0200
|
#define REG_TIMESTAMP_LO 0x0180
|
||||||
#define REG_DMA_ADDR_END 0x0204
|
#define REG_TIMESTAMP_HI 0x0184
|
||||||
#define REG_DMA_ADDR_LIMIT 0x0208
|
#define REG_TIMESTAMP_CLEAR 0x0188
|
||||||
#define REG_DMA_ADDR_INTR 0x020c
|
#define REG_ACQ_ADDR_START 0x0200
|
||||||
#define REG_DMA_ADDR_PTR 0x0210
|
#define REG_ACQ_ADDR_END 0x0204
|
||||||
#define REG_DMA_CHANNEL_CTRL 0x0214
|
#define REG_ACQ_ADDR_LIMIT 0x0208
|
||||||
#define REG_DMA_INTR_CTRL 0x0218
|
#define REG_ACQ_ADDR_INTR 0x020c
|
||||||
#define REG_TEST_DIVIDER 0x0408
|
#define REG_ACQ_ADDR_PTR 0x0210
|
||||||
|
#define REG_ACQ_CHANNEL_CTRL 0x0214
|
||||||
|
#define REG_ACQ_INTR_CTRL 0x0218
|
||||||
|
#define REG_ACQUISITION_EN 0x0220
|
||||||
|
#define REG_RECORD_LENGTH 0x0224
|
||||||
|
#define REG_DECIMATION_FACTOR 0x0228
|
||||||
|
#define REG_SHIFT_STEPS 0x022c
|
||||||
|
#define REG_AVERAGING_EN 0x0230
|
||||||
|
#define REG_CH4_MODE 0x0234
|
||||||
|
#define REG_SIMULATE_ADC 0x0238
|
||||||
|
#define REG_TRIGGER_MODE 0x0240
|
||||||
|
#define REG_TRIGGER_DELAY 0x0244
|
||||||
|
#define REG_TRIGGER_STATUS 0x0248
|
||||||
|
|
||||||
|
|
||||||
struct puzzlefw_context {
|
struct puzzlefw_context {
|
||||||
|
@ -51,6 +63,12 @@ struct puzzlefw_context {
|
||||||
char uio_path[128];
|
char uio_path[128];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum puzzlefw_trigger_mode {
|
||||||
|
TRIG_NONE = 0,
|
||||||
|
TRIG_AUTO = 1,
|
||||||
|
TRIG_EXTERNAL = 2
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Find PuzzleFW device in /sys filesystem.
|
* Find PuzzleFW device in /sys filesystem.
|
||||||
|
@ -395,6 +413,123 @@ void puzzlefw_copy_from_dma(void *dst, volatile void *src, size_t len)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Return the current value of the timestamp counter.
|
||||||
|
*/
|
||||||
|
uint64_t puzzlefw_get_timestamp(struct puzzlefw_context *ctx)
|
||||||
|
{
|
||||||
|
uint32_t vhi0, vlo, vhi;
|
||||||
|
vhi0 = puzzlefw_read_reg(ctx, REG_TIMESTAMP_HI);
|
||||||
|
vlo = puzzlefw_read_reg(ctx, REG_TIMESTAMP_LO);
|
||||||
|
vhi = puzzlefw_read_reg(ctx, REG_TIMESTAMP_HI);
|
||||||
|
if (vhi != vhi0) {
|
||||||
|
vlo = puzzlefw_read_reg(ctx, REG_TIMESTAMP_LO);
|
||||||
|
}
|
||||||
|
return (((uint64_t)vhi) << 32) | vlo;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Clear the timestamp counter.
|
||||||
|
*/
|
||||||
|
void puzzlefw_clear_timestamp(struct puzzlefw_context *ctx)
|
||||||
|
{
|
||||||
|
puzzlefw_write_reg(ctx, REG_TIMESTAMP_CLEAR, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Return the current trigger mode.
|
||||||
|
*/
|
||||||
|
enum puzzlefw_trigger_mode puzzlefw_get_trigger_mode(
|
||||||
|
struct puzzlefw_context *ctx)
|
||||||
|
{
|
||||||
|
uint32_t v = puzzlefw_read_reg(ctx, REG_TRIGGER_MODE);
|
||||||
|
if ((v & 0x01) != 0) {
|
||||||
|
return TRIG_AUTO;
|
||||||
|
}
|
||||||
|
if ((v & 0x02) != 0) {
|
||||||
|
return TRIG_EXTERNAL;
|
||||||
|
}
|
||||||
|
return TRIG_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set trigger mode.
|
||||||
|
*/
|
||||||
|
void puzzlefw_set_trigger_mode(
|
||||||
|
struct puzzlefw_context *ctx,
|
||||||
|
enum puzzlefw_trigger_mode mode)
|
||||||
|
{
|
||||||
|
uint32_t v = puzzlefw_read_reg(ctx, REG_TRIGGER_MODE);
|
||||||
|
v &= 0xfc;
|
||||||
|
if (mode == TRIG_AUTO) {
|
||||||
|
v |= 0x01;
|
||||||
|
}
|
||||||
|
if (mode == TRIG_EXTERNAL) {
|
||||||
|
v |= 0x02;
|
||||||
|
}
|
||||||
|
puzzlefw_write_reg(ctx, REG_TRIGGER_MODE, v);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Return selected external trigger channel.
|
||||||
|
*/
|
||||||
|
int puzzlefw_get_trigger_ext_channel(struct puzzlefw_context *ctx)
|
||||||
|
{
|
||||||
|
uint32_t v = puzzlefw_read_reg(ctx, REG_TRIGGER_MODE);
|
||||||
|
return ((v >> 4) & 7);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Select external trigger channel.
|
||||||
|
*/
|
||||||
|
void puzzlefw_set_trigger_ext_channel(struct puzzlefw_context *ctx, int channel)
|
||||||
|
{
|
||||||
|
uint32_t v = puzzlefw_read_reg(ctx, REG_TRIGGER_MODE);
|
||||||
|
v &= 0x8f;
|
||||||
|
v |= (channel << 4);
|
||||||
|
puzzlefw_write_reg(ctx, REG_TRIGGER_MODE, v);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Return external trigger polarity.
|
||||||
|
*/
|
||||||
|
int puzzlefw_get_trigger_ext_falling(struct puzzlefw_context *ctx)
|
||||||
|
{
|
||||||
|
uint32_t v = puzzlefw_read_reg(ctx, REG_TRIGGER_MODE);
|
||||||
|
return ((v & 0x80) != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Select external trigger polarity.
|
||||||
|
*/
|
||||||
|
void puzzlefw_set_trigger_ext_falling(struct puzzlefw_context *ctx, int falling)
|
||||||
|
{
|
||||||
|
uint32_t v = puzzlefw_read_reg(ctx, REG_TRIGGER_MODE);
|
||||||
|
v &= 0x7f;
|
||||||
|
if (falling) {
|
||||||
|
v |= 0x80;
|
||||||
|
}
|
||||||
|
puzzlefw_write_reg(ctx, REG_TRIGGER_MODE, v);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Force a single trigger event.
|
||||||
|
*/
|
||||||
|
void puzzlefw_trigger_force(struct puzzlefw_context *ctx)
|
||||||
|
{
|
||||||
|
uint32_t v = puzzlefw_read_reg(ctx, REG_TRIGGER_MODE);
|
||||||
|
puzzlefw_write_reg(ctx, REG_TRIGGER_MODE, v | 0x100);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static void show_status(struct puzzlefw_context *ctx)
|
static void show_status(struct puzzlefw_context *ctx)
|
||||||
{
|
{
|
||||||
uint32_t v;
|
uint32_t v;
|
||||||
|
@ -415,29 +550,57 @@ static void show_status(struct puzzlefw_context *ctx)
|
||||||
v = puzzlefw_read_reg(ctx, REG_DMA_STATUS);
|
v = puzzlefw_read_reg(ctx, REG_DMA_STATUS);
|
||||||
printf(" dma_status = 0x%08x\n", v);
|
printf(" dma_status = 0x%08x\n", v);
|
||||||
|
|
||||||
v = puzzlefw_read_reg(ctx, REG_DMA_ADDR_START);
|
uint64_t ts = puzzlefw_get_timestamp(ctx);
|
||||||
printf(" dma_addr_start = 0x%08x\n", v);
|
printf(" timestamp = %llu\n", (unsigned long long)ts);
|
||||||
|
|
||||||
v = puzzlefw_read_reg(ctx, REG_DMA_ADDR_END);
|
v = puzzlefw_read_reg(ctx, REG_ACQ_ADDR_START);
|
||||||
printf(" dma_addr_end = 0x%08x\n", v);
|
printf(" acq_addr_start = 0x%08x\n", v);
|
||||||
|
|
||||||
v = puzzlefw_read_reg(ctx, REG_DMA_ADDR_LIMIT);
|
v = puzzlefw_read_reg(ctx, REG_ACQ_ADDR_END);
|
||||||
printf(" dma_addr_limit = 0x%08x\n", v);
|
printf(" acq_addr_end = 0x%08x\n", v);
|
||||||
|
|
||||||
v = puzzlefw_read_reg(ctx, REG_DMA_ADDR_INTR);
|
v = puzzlefw_read_reg(ctx, REG_ACQ_ADDR_LIMIT);
|
||||||
printf(" dma_addr_intr = 0x%08x\n", v);
|
printf(" acq_addr_limit = 0x%08x\n", v);
|
||||||
|
|
||||||
v = puzzlefw_read_reg(ctx, REG_DMA_ADDR_PTR);
|
v = puzzlefw_read_reg(ctx, REG_ACQ_ADDR_INTR);
|
||||||
printf(" dma_addr_ptr = 0x%08x\n", v);
|
printf(" acq_addr_intr = 0x%08x\n", v);
|
||||||
|
|
||||||
v = puzzlefw_read_reg(ctx, REG_DMA_CHANNEL_CTRL);
|
v = puzzlefw_read_reg(ctx, REG_ACQ_ADDR_PTR);
|
||||||
printf(" dma_channel_ctrl = 0x%08x\n", v);
|
printf(" acq_addr_ptr = 0x%08x\n", v);
|
||||||
|
|
||||||
v = puzzlefw_read_reg(ctx, REG_DMA_INTR_CTRL);
|
v = puzzlefw_read_reg(ctx, REG_ACQ_CHANNEL_CTRL);
|
||||||
printf(" dma_intr_ctrl = 0x%08x\n", v);
|
printf(" acq_channel_ctrl = 0x%08x\n", v);
|
||||||
|
|
||||||
v = puzzlefw_read_reg(ctx, REG_TEST_DIVIDER);
|
v = puzzlefw_read_reg(ctx, REG_ACQ_INTR_CTRL);
|
||||||
printf(" test_divider = 0x%08x\n", v);
|
printf(" acq_intr_ctrl = 0x%08x\n", v);
|
||||||
|
|
||||||
|
v = puzzlefw_read_reg(ctx, REG_SIMULATE_ADC);
|
||||||
|
printf(" simulate_adc = 0x%08x\n", v);
|
||||||
|
|
||||||
|
enum puzzlefw_trigger_mode trigger_mode = puzzlefw_get_trigger_mode(ctx);
|
||||||
|
int trigger_channel = puzzlefw_get_trigger_ext_channel(ctx);
|
||||||
|
int trigger_falling = puzzlefw_get_trigger_ext_falling(ctx);
|
||||||
|
printf(" trigger mode = %s, channel=%d, falling=%d\n",
|
||||||
|
(trigger_mode == TRIG_AUTO) ? "auto" :
|
||||||
|
(trigger_mode == TRIG_EXTERNAL) ?"external" :
|
||||||
|
"none",
|
||||||
|
trigger_channel,
|
||||||
|
trigger_falling);
|
||||||
|
|
||||||
|
v = puzzlefw_read_reg(ctx, REG_TRIGGER_DELAY);
|
||||||
|
printf(" trigger_delay = 0x%08x\n", v);
|
||||||
|
|
||||||
|
v = puzzlefw_read_reg(ctx, REG_RECORD_LENGTH);
|
||||||
|
printf(" record_length = 0x%08x\n", v);
|
||||||
|
|
||||||
|
v = puzzlefw_read_reg(ctx, REG_DECIMATION_FACTOR);
|
||||||
|
printf(" decimation_fac = 0x%08x\n", v);
|
||||||
|
|
||||||
|
v = puzzlefw_read_reg(ctx, REG_SHIFT_STEPS);
|
||||||
|
printf(" shift_steps = 0x%08x\n", v);
|
||||||
|
|
||||||
|
v = puzzlefw_read_reg(ctx, REG_AVERAGING_EN);
|
||||||
|
printf(" averaging_en = 0x%08x\n", v);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -489,20 +652,20 @@ static void blast_dma(struct puzzlefw_context *ctx)
|
||||||
printf("Starting DMA blaster ...\n");
|
printf("Starting DMA blaster ...\n");
|
||||||
|
|
||||||
// Disable DMA writer.
|
// Disable DMA writer.
|
||||||
puzzlefw_write_reg(ctx, REG_DMA_CHANNEL_CTRL, 0);
|
puzzlefw_write_reg(ctx, REG_ACQ_CHANNEL_CTRL, 0);
|
||||||
|
|
||||||
// Setup DMA buffer.
|
// Setup DMA buffer.
|
||||||
puzzlefw_write_reg(ctx, REG_DMA_ADDR_START, 0);
|
puzzlefw_write_reg(ctx, REG_ACQ_ADDR_START, 0);
|
||||||
puzzlefw_write_reg(ctx, REG_DMA_ADDR_END, ctx->dma_buf_size);
|
puzzlefw_write_reg(ctx, REG_ACQ_ADDR_END, ctx->dma_buf_size);
|
||||||
|
|
||||||
// Set invalid limit to keep the writer blasting.
|
// Set invalid limit to keep the writer blasting.
|
||||||
puzzlefw_write_reg(ctx, REG_DMA_ADDR_LIMIT, 0xffffffff);
|
puzzlefw_write_reg(ctx, REG_ACQ_ADDR_LIMIT, 0xffffffff);
|
||||||
|
|
||||||
// Initialize DMA writer.
|
// Initialize DMA writer.
|
||||||
puzzlefw_write_reg(ctx, REG_DMA_CHANNEL_CTRL, 2);
|
puzzlefw_write_reg(ctx, REG_ACQ_CHANNEL_CTRL, 2);
|
||||||
|
|
||||||
// Enable DMA writer.
|
// Enable DMA writer.
|
||||||
puzzlefw_write_reg(ctx, REG_DMA_CHANNEL_CTRL, 1);
|
puzzlefw_write_reg(ctx, REG_ACQ_CHANNEL_CTRL, 1);
|
||||||
|
|
||||||
struct timespec tp;
|
struct timespec tp;
|
||||||
tp.tv_sec = 10;
|
tp.tv_sec = 10;
|
||||||
|
@ -510,7 +673,7 @@ static void blast_dma(struct puzzlefw_context *ctx)
|
||||||
clock_nanosleep(CLOCK_MONOTONIC, 0, &tp, NULL);
|
clock_nanosleep(CLOCK_MONOTONIC, 0, &tp, NULL);
|
||||||
|
|
||||||
// Disable DMA writer.
|
// Disable DMA writer.
|
||||||
puzzlefw_write_reg(ctx, REG_DMA_CHANNEL_CTRL, 0);
|
puzzlefw_write_reg(ctx, REG_ACQ_CHANNEL_CTRL, 0);
|
||||||
|
|
||||||
printf("Stopped DMA blaster\n");
|
printf("Stopped DMA blaster\n");
|
||||||
}
|
}
|
||||||
|
@ -590,20 +753,20 @@ static int wait_dma_data(
|
||||||
if (addr_intr >= ctx->dma_buf_size) {
|
if (addr_intr >= ctx->dma_buf_size) {
|
||||||
addr_intr -= ctx->dma_buf_size;
|
addr_intr -= ctx->dma_buf_size;
|
||||||
}
|
}
|
||||||
puzzlefw_write_reg(ctx, REG_DMA_ADDR_INTR, addr_intr);
|
puzzlefw_write_reg(ctx, REG_ACQ_ADDR_INTR, addr_intr);
|
||||||
puzzlefw_write_reg(ctx, REG_DMA_INTR_CTRL, 3);
|
puzzlefw_write_reg(ctx, REG_ACQ_INTR_CTRL, 3);
|
||||||
|
|
||||||
// Check if data are already available.
|
// Check if data are already available.
|
||||||
// This is necessary to prevent a race condition when data becomes
|
// This is necessary to prevent a race condition when data becomes
|
||||||
// available just before the interrupt is enabled.
|
// available just before the interrupt is enabled.
|
||||||
uint32_t write_pointer = puzzlefw_read_reg(ctx, REG_DMA_ADDR_PTR);
|
uint32_t write_pointer = puzzlefw_read_reg(ctx, REG_ACQ_ADDR_PTR);
|
||||||
uint32_t navail =
|
uint32_t navail =
|
||||||
(write_pointer >= read_pointer) ?
|
(write_pointer >= read_pointer) ?
|
||||||
(write_pointer - read_pointer) :
|
(write_pointer - read_pointer) :
|
||||||
(ctx->dma_buf_size + write_pointer - read_pointer);
|
(ctx->dma_buf_size + write_pointer - read_pointer);
|
||||||
if (navail >= wait_avail) {
|
if (navail >= wait_avail) {
|
||||||
// Data already available; disable DMA writer interrupts.
|
// Data already available; disable DMA writer interrupts.
|
||||||
puzzlefw_write_reg(ctx, REG_DMA_INTR_CTRL, 2);
|
puzzlefw_write_reg(ctx, REG_ACQ_INTR_CTRL, 2);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -615,7 +778,7 @@ static int wait_dma_data(
|
||||||
fds[0].fd = ctx->uio_fd;
|
fds[0].fd = ctx->uio_fd;
|
||||||
fds[0].events = POLLIN;
|
fds[0].events = POLLIN;
|
||||||
fds[1].fd = conn;
|
fds[1].fd = conn;
|
||||||
fds[1].events = 0;
|
fds[1].events = POLLIN;
|
||||||
|
|
||||||
int ret = poll(fds, 2, timeout_ms);
|
int ret = poll(fds, 2, timeout_ms);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
|
@ -624,7 +787,7 @@ static int wait_dma_data(
|
||||||
}
|
}
|
||||||
|
|
||||||
// Disable DMA writer interrupt and clear pending interrupt.
|
// Disable DMA writer interrupt and clear pending interrupt.
|
||||||
puzzlefw_write_reg(ctx, REG_DMA_INTR_CTRL, 2);
|
puzzlefw_write_reg(ctx, REG_ACQ_INTR_CTRL, 2);
|
||||||
|
|
||||||
if ((fds[0].revents & POLLIN) != 0) {
|
if ((fds[0].revents & POLLIN) != 0) {
|
||||||
// Interrupt occurred.
|
// Interrupt occurred.
|
||||||
|
@ -633,8 +796,10 @@ static int wait_dma_data(
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((fds[1].revents & POLLHUP) != 0) {
|
if ((fds[1].revents & (POLLHUP | POLLIN)) != 0) {
|
||||||
// Connection closed.
|
// Connection closed, or client sent unexpected data.
|
||||||
|
// POLLHUP does not happen on Linux as long as our side of the
|
||||||
|
// connection remains open, but check it anyway to be sure.
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -671,16 +836,16 @@ int transmit_dma_data(struct puzzlefw_context *ctx, int conn)
|
||||||
puzzlefw_write_reg(ctx, REG_DMA_EN, 0);
|
puzzlefw_write_reg(ctx, REG_DMA_EN, 0);
|
||||||
|
|
||||||
// Disable DMA write channel.
|
// Disable DMA write channel.
|
||||||
puzzlefw_write_reg(ctx, REG_DMA_CHANNEL_CTRL, 0);
|
puzzlefw_write_reg(ctx, REG_ACQ_CHANNEL_CTRL, 0);
|
||||||
|
|
||||||
// Initialize DMA write buffer.
|
// Initialize DMA write buffer.
|
||||||
puzzlefw_write_reg(ctx, REG_DMA_ADDR_START, 0);
|
puzzlefw_write_reg(ctx, REG_ACQ_ADDR_START, 0);
|
||||||
puzzlefw_write_reg(ctx, REG_DMA_ADDR_END, ctx->dma_buf_size);
|
puzzlefw_write_reg(ctx, REG_ACQ_ADDR_END, ctx->dma_buf_size);
|
||||||
puzzlefw_write_reg(ctx, REG_DMA_ADDR_LIMIT,
|
puzzlefw_write_reg(ctx, REG_ACQ_ADDR_LIMIT,
|
||||||
ctx->dma_buf_size - pointer_margin);
|
ctx->dma_buf_size - pointer_margin);
|
||||||
|
|
||||||
// Disable DMA writer interrupts; clear interrupt status.
|
// Disable DMA writer interrupts; clear interrupt status.
|
||||||
puzzlefw_write_reg(ctx, REG_DMA_INTR_CTRL, 2);
|
puzzlefw_write_reg(ctx, REG_ACQ_INTR_CTRL, 2);
|
||||||
|
|
||||||
// Clear AXI DMA state.
|
// Clear AXI DMA state.
|
||||||
puzzlefw_write_reg(ctx, REG_DMA_CLEAR, 1);
|
puzzlefw_write_reg(ctx, REG_DMA_CLEAR, 1);
|
||||||
|
@ -689,10 +854,10 @@ int transmit_dma_data(struct puzzlefw_context *ctx, int conn)
|
||||||
puzzlefw_write_reg(ctx, REG_DMA_EN, 1);
|
puzzlefw_write_reg(ctx, REG_DMA_EN, 1);
|
||||||
|
|
||||||
// Initialize DMA writer.
|
// Initialize DMA writer.
|
||||||
puzzlefw_write_reg(ctx, REG_DMA_CHANNEL_CTRL, 2);
|
puzzlefw_write_reg(ctx, REG_ACQ_CHANNEL_CTRL, 2);
|
||||||
|
|
||||||
// Enable DMA writer.
|
// Enable DMA writer.
|
||||||
puzzlefw_write_reg(ctx, REG_DMA_CHANNEL_CTRL, 1);
|
puzzlefw_write_reg(ctx, REG_ACQ_CHANNEL_CTRL, 1);
|
||||||
|
|
||||||
uint32_t read_pointer = 0;
|
uint32_t read_pointer = 0;
|
||||||
int ret;
|
int ret;
|
||||||
|
@ -709,7 +874,7 @@ int transmit_dma_data(struct puzzlefw_context *ctx, int conn)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Determine number of bytes available.
|
// Determine number of bytes available.
|
||||||
uint32_t write_pointer = puzzlefw_read_reg(ctx, REG_DMA_ADDR_PTR);
|
uint32_t write_pointer = puzzlefw_read_reg(ctx, REG_ACQ_ADDR_PTR);
|
||||||
uint32_t navail = (write_pointer >= read_pointer) ?
|
uint32_t navail = (write_pointer >= read_pointer) ?
|
||||||
(write_pointer - read_pointer) :
|
(write_pointer - read_pointer) :
|
||||||
(ctx->dma_buf_size + write_pointer - read_pointer);
|
(ctx->dma_buf_size + write_pointer - read_pointer);
|
||||||
|
@ -729,7 +894,7 @@ int transmit_dma_data(struct puzzlefw_context *ctx, int conn)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
write_pointer = puzzlefw_read_reg(ctx, REG_DMA_ADDR_PTR);
|
write_pointer = puzzlefw_read_reg(ctx, REG_ACQ_ADDR_PTR);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Determine number of bytes available.
|
// Determine number of bytes available.
|
||||||
|
@ -759,7 +924,7 @@ int transmit_dma_data(struct puzzlefw_context *ctx, int conn)
|
||||||
// Update read pointer and update DMA writer limit.
|
// Update read pointer and update DMA writer limit.
|
||||||
read_pointer += block_size;
|
read_pointer += block_size;
|
||||||
if (read_pointer > pointer_margin) {
|
if (read_pointer > pointer_margin) {
|
||||||
puzzlefw_write_reg(ctx, REG_DMA_ADDR_LIMIT,
|
puzzlefw_write_reg(ctx, REG_ACQ_ADDR_LIMIT,
|
||||||
read_pointer - pointer_margin);
|
read_pointer - pointer_margin);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -786,10 +951,10 @@ int transmit_dma_data(struct puzzlefw_context *ctx, int conn)
|
||||||
puzzlefw_write_reg(ctx, REG_DMA_EN, 0);
|
puzzlefw_write_reg(ctx, REG_DMA_EN, 0);
|
||||||
|
|
||||||
// Disable DMA write channel.
|
// Disable DMA write channel.
|
||||||
puzzlefw_write_reg(ctx, REG_DMA_CHANNEL_CTRL, 0);
|
puzzlefw_write_reg(ctx, REG_ACQ_CHANNEL_CTRL, 0);
|
||||||
|
|
||||||
// Disable DMA writer interrupts; clear interrupt status.
|
// Disable DMA writer interrupts; clear interrupt status.
|
||||||
puzzlefw_write_reg(ctx, REG_DMA_INTR_CTRL, 2);
|
puzzlefw_write_reg(ctx, REG_ACQ_INTR_CTRL, 2);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -860,8 +1025,18 @@ int main(int argc, char **argv)
|
||||||
int dmaclear = 0;
|
int dmaclear = 0;
|
||||||
int blastdma = 0;
|
int blastdma = 0;
|
||||||
int server = 0;
|
int server = 0;
|
||||||
int set_divider = 0;
|
int tsclear = 0;
|
||||||
int divider;
|
int acqon = 0;
|
||||||
|
int acqoff = 0;
|
||||||
|
int trigger = 0;
|
||||||
|
int trigauto = 0;
|
||||||
|
int trignone = 0;
|
||||||
|
int set_trigdelay = 0, trigdelay = 0;
|
||||||
|
int set_reclen = 0, reclen = 0;
|
||||||
|
int set_decimate = 0, decimate = 0;
|
||||||
|
int set_shift = 0, shift_steps = 0;
|
||||||
|
int avgon = 0, avgoff = 0;
|
||||||
|
int simon = 0, simoff = 0;
|
||||||
|
|
||||||
if (argc == 2 && strcmp(argv[1], "show") == 0) {
|
if (argc == 2 && strcmp(argv[1], "show") == 0) {
|
||||||
show = 1;
|
show = 1;
|
||||||
|
@ -877,9 +1052,38 @@ int main(int argc, char **argv)
|
||||||
dmaclear = 1;
|
dmaclear = 1;
|
||||||
} else if (argc == 2 && strcmp(argv[1], "blastdma") == 0) {
|
} else if (argc == 2 && strcmp(argv[1], "blastdma") == 0) {
|
||||||
blastdma = 1;
|
blastdma = 1;
|
||||||
} else if (argc == 3 && strcmp(argv[1], "divider") == 0) {
|
} else if (argc == 2 && strcmp(argv[1], "tsclear") == 0) {
|
||||||
set_divider = 1;
|
tsclear = 1;
|
||||||
divider = atoi(argv[2]);
|
} else if (argc == 2 && strcmp(argv[1], "acqon") == 0) {
|
||||||
|
acqon = 1;
|
||||||
|
} else if (argc == 2 && strcmp(argv[1], "acqoff") == 0) {
|
||||||
|
acqoff = 1;
|
||||||
|
} else if (argc == 2 && strcmp(argv[1], "trigger") == 0) {
|
||||||
|
trigger = 1;
|
||||||
|
} else if (argc == 2 && strcmp(argv[1], "trigauto") == 0) {
|
||||||
|
trigauto = 1;
|
||||||
|
} else if (argc == 2 && strcmp(argv[1], "trignone") == 0) {
|
||||||
|
trignone = 1;
|
||||||
|
} else if (argc == 3 && strcmp(argv[1], "trigdelay") == 0) {
|
||||||
|
set_trigdelay = 1;
|
||||||
|
trigdelay = atoi(argv[2]);
|
||||||
|
} else if (argc == 3 && strcmp(argv[1], "reclen") == 0) {
|
||||||
|
set_reclen = 1;
|
||||||
|
reclen = atoi(argv[2]);
|
||||||
|
} else if (argc == 3 && strcmp(argv[1], "decimate") == 0) {
|
||||||
|
set_decimate = 1;
|
||||||
|
decimate = atoi(argv[2]);
|
||||||
|
} else if (argc == 3 && strcmp(argv[1], "shift") == 0) {
|
||||||
|
set_shift = 1;
|
||||||
|
shift_steps = atoi(argv[2]);
|
||||||
|
} else if (argc == 2 && strcmp(argv[1], "avgon") == 0) {
|
||||||
|
avgon = 1;
|
||||||
|
} else if (argc == 2 && strcmp(argv[1], "avgoff") == 0) {
|
||||||
|
avgoff = 1;
|
||||||
|
} else if (argc == 2 && strcmp(argv[1], "simon") == 0) {
|
||||||
|
simon = 1;
|
||||||
|
} else if (argc == 2 && strcmp(argv[1], "simoff") == 0) {
|
||||||
|
simoff = 1;
|
||||||
} else if (argc == 2 && strcmp(argv[1], "server") == 0) {
|
} else if (argc == 2 && strcmp(argv[1], "server") == 0) {
|
||||||
server = 1;
|
server = 1;
|
||||||
} else {
|
} else {
|
||||||
|
@ -906,6 +1110,48 @@ int main(int argc, char **argv)
|
||||||
" testje blastdma\n"
|
" testje blastdma\n"
|
||||||
" Run unlimited DMA into buffer for 10 seconds.\n"
|
" Run unlimited DMA into buffer for 10 seconds.\n"
|
||||||
"\n"
|
"\n"
|
||||||
|
" testje tsclear\n"
|
||||||
|
" Clear timestamp counter.\n"
|
||||||
|
"\n"
|
||||||
|
" testje acqon\n"
|
||||||
|
" Enable acquisition.\n"
|
||||||
|
"\n"
|
||||||
|
" testje acqoff\n"
|
||||||
|
" Disable acquisition.\n"
|
||||||
|
"\n"
|
||||||
|
" testje trigger\n"
|
||||||
|
" Trigger once.\n"
|
||||||
|
"\n"
|
||||||
|
" testje trigauto\n"
|
||||||
|
" Enable continuous triggering.\n"
|
||||||
|
"\n"
|
||||||
|
" testje trignone\n"
|
||||||
|
" Disable triggering.\n"
|
||||||
|
"\n"
|
||||||
|
" testje trigdelay N\n"
|
||||||
|
" Set trigger delay N cycles.\n"
|
||||||
|
"\n"
|
||||||
|
" testje reclen N\n"
|
||||||
|
" Set record length N + 1.\n"
|
||||||
|
"\n"
|
||||||
|
" testje decimate N\n"
|
||||||
|
" Set decimation factor N + 1.\n"
|
||||||
|
"\n"
|
||||||
|
" testje shift N\n"
|
||||||
|
" Set shift-right by N.\n"
|
||||||
|
"\n"
|
||||||
|
" testje avgon\n"
|
||||||
|
" Enable averaging.\n"
|
||||||
|
"\n"
|
||||||
|
" testje avgoff\n"
|
||||||
|
" Disable averaging.\n"
|
||||||
|
"\n"
|
||||||
|
" testje simon\n"
|
||||||
|
" Use simulated ADC data.\n"
|
||||||
|
"\n"
|
||||||
|
" testje simoff\n"
|
||||||
|
" Use real ADC data.\n"
|
||||||
|
"\n"
|
||||||
" testje server\n"
|
" testje server\n"
|
||||||
" Open TCP port 5001 to stream DMA data.\n"
|
" Open TCP port 5001 to stream DMA data.\n"
|
||||||
"\n");
|
"\n");
|
||||||
|
@ -949,8 +1195,60 @@ int main(int argc, char **argv)
|
||||||
blast_dma(&ctx);
|
blast_dma(&ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (set_divider) {
|
if (tsclear) {
|
||||||
puzzlefw_write_reg(&ctx, REG_TEST_DIVIDER, divider);
|
puzzlefw_clear_timestamp(&ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (acqon) {
|
||||||
|
puzzlefw_write_reg(&ctx, REG_ACQUISITION_EN, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (acqoff) {
|
||||||
|
puzzlefw_write_reg(&ctx, REG_ACQUISITION_EN, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (trigger) {
|
||||||
|
puzzlefw_trigger_force(&ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (trigauto) {
|
||||||
|
puzzlefw_set_trigger_mode(&ctx, TRIG_AUTO);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (trignone) {
|
||||||
|
puzzlefw_set_trigger_mode(&ctx, TRIG_NONE);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (set_trigdelay) {
|
||||||
|
puzzlefw_write_reg(&ctx, REG_TRIGGER_DELAY, trigdelay);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (set_reclen) {
|
||||||
|
puzzlefw_write_reg(&ctx, REG_RECORD_LENGTH, reclen);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (set_decimate) {
|
||||||
|
puzzlefw_write_reg(&ctx, REG_DECIMATION_FACTOR, decimate);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (set_shift) {
|
||||||
|
puzzlefw_write_reg(&ctx, REG_SHIFT_STEPS, shift_steps);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (avgon) {
|
||||||
|
puzzlefw_write_reg(&ctx, REG_AVERAGING_EN, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (avgoff) {
|
||||||
|
puzzlefw_write_reg(&ctx, REG_AVERAGING_EN, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (simon) {
|
||||||
|
puzzlefw_write_reg(&ctx, REG_SIMULATE_ADC, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (simoff) {
|
||||||
|
puzzlefw_write_reg(&ctx, REG_SIMULATE_ADC, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (server) {
|
if (server) {
|
||||||
|
|
Loading…
Reference in New Issue