Read digital input signals
This commit is contained in:
parent
81e5fe0eba
commit
5d00a2e792
|
@ -125,6 +125,7 @@ begin
|
|||
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';
|
||||
|
|
|
@ -0,0 +1,93 @@
|
|||
--
|
||||
-- Remove glitches from a digital signal.
|
||||
--
|
||||
-- Joris van Rantwijk 2024
|
||||
--
|
||||
|
||||
library ieee;
|
||||
use ieee.std_logic_1164.all;
|
||||
use ieee.numeric_std.all;
|
||||
|
||||
|
||||
entity deglitch is
|
||||
|
||||
generic (
|
||||
-- The output follows the input when the input is stable
|
||||
-- for "deglitch_cycles" clock cycles.
|
||||
--
|
||||
-- A glitch-free transition on the input, propagates to the output
|
||||
-- after a delay of "deglitch_cycles" clock cycles.
|
||||
--
|
||||
deglitch_cycles: integer range 2 to 16 := 4
|
||||
);
|
||||
|
||||
port (
|
||||
-- Main clock, active on rising edge.
|
||||
clk: in std_logic;
|
||||
|
||||
-- Input signal.
|
||||
din: in std_logic;
|
||||
|
||||
-- Deglitched output signal.
|
||||
dout: out std_logic
|
||||
);
|
||||
|
||||
end entity;
|
||||
|
||||
architecture arch of deglitch is
|
||||
|
||||
type regs_type is record
|
||||
cnt: integer range 0 to deglitch_cycles - 1;
|
||||
dout: std_logic;
|
||||
end record;
|
||||
|
||||
constant regs_init: regs_type := (
|
||||
cnt => 0,
|
||||
dout => '0'
|
||||
);
|
||||
|
||||
signal r: regs_type := regs_init;
|
||||
signal rnext: regs_type;
|
||||
|
||||
begin
|
||||
|
||||
-- Drive output.
|
||||
dout <= r.dout;
|
||||
|
||||
--
|
||||
-- Combinatorial process.
|
||||
--
|
||||
process (all) is
|
||||
variable v: regs_type;
|
||||
variable v_trig: std_logic;
|
||||
begin
|
||||
-- Load current register values.
|
||||
v := r;
|
||||
|
||||
if (din xor r.dout) = '1' then
|
||||
if r.cnt = deglitch_cycles - 1 then
|
||||
v.dout := din;
|
||||
v.cnt := 0;
|
||||
else
|
||||
v.cnt := r.cnt + 1;
|
||||
end if;
|
||||
else
|
||||
v.cnt := 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;
|
|
@ -75,8 +75,9 @@ package puzzlefw_pkg is
|
|||
constant reg_adc1_minmax: natural := 16#000294#;
|
||||
constant reg_adc2_minmax: natural := 16#000298#;
|
||||
constant reg_adc3_minmax: natural := 16#00029c#;
|
||||
constant reg_test_led: natural := 16#000404#;
|
||||
constant reg_test_divider: natural := 16#000408#;
|
||||
constant reg_dig_simulate: natural := 16#000330#;
|
||||
constant reg_dig_sample: natural := 16#000338#;
|
||||
constant reg_led_state: natural := 16#000404#;
|
||||
constant reg_dma_buf_addr: natural := 16#100000#;
|
||||
constant reg_dma_buf_size: natural := 16#100004#;
|
||||
|
||||
|
@ -98,8 +99,6 @@ package puzzlefw_pkg is
|
|||
-- Control registers: read/write access by processor, output signals to FPGA.
|
||||
type registers_control is record
|
||||
irq_enable: std_logic;
|
||||
test_led: std_logic_vector(7 downto 0);
|
||||
test_divider: std_logic_vector(15 downto 0);
|
||||
dma_en: std_logic;
|
||||
dma_clear: std_logic; -- single cycle
|
||||
timestamp_clear: std_logic; -- single cycle
|
||||
|
@ -125,6 +124,9 @@ package puzzlefw_pkg is
|
|||
trig_ext_falling: std_logic;
|
||||
trigger_delay: std_logic_vector(15 downto 0);
|
||||
adc_range_clear: std_logic;
|
||||
dig_simulate: std_logic;
|
||||
dig_sim_state: std_logic_vector(3 downto 0);
|
||||
led_state: std_logic_vector(7 downto 0);
|
||||
dma_buf_addr: std_logic_vector(31 downto 12);
|
||||
dma_buf_size: std_logic_vector(31 downto 12);
|
||||
end record;
|
||||
|
@ -144,12 +146,11 @@ package puzzlefw_pkg is
|
|||
adc_sample: adc_data_array(0 to 3);
|
||||
adc_min_value: adc_data_array(0 to 3);
|
||||
adc_max_value: adc_data_array(0 to 3);
|
||||
dig_sample: std_logic_vector(3 downto 0);
|
||||
end record;
|
||||
|
||||
constant registers_control_init: registers_control := (
|
||||
irq_enable => '0',
|
||||
test_led => (others => '0'),
|
||||
test_divider => (others => '0'),
|
||||
dma_en => '0',
|
||||
dma_clear => '0',
|
||||
timestamp_clear => '0',
|
||||
|
@ -175,6 +176,9 @@ package puzzlefw_pkg is
|
|||
trig_ext_falling => '0',
|
||||
trigger_delay => (others => '0'),
|
||||
adc_range_clear => '0',
|
||||
dig_simulate => '0',
|
||||
dig_sim_state => (others => '0'),
|
||||
led_state => (others => '0'),
|
||||
dma_buf_addr => (others => '0'),
|
||||
dma_buf_size => (others => '0')
|
||||
);
|
||||
|
|
|
@ -77,11 +77,11 @@ architecture arch of puzzlefw_top is
|
|||
-- Internal clock signal.
|
||||
signal s_adc_clk_ibuf: std_logic;
|
||||
|
||||
signal r_fclk_cnt: unsigned(26 downto 0);
|
||||
signal r_fclk_led: std_logic;
|
||||
signal r_adcclk_cnt: unsigned(26 downto 0);
|
||||
-- Blinking LED.
|
||||
signal r_adcclk_cnt: unsigned(25 downto 0);
|
||||
signal r_adcclk_led: std_logic;
|
||||
|
||||
-- APB bus for register access.
|
||||
signal s_apb_paddr: std_logic_vector(31 downto 0);
|
||||
signal s_apb_penable: std_logic;
|
||||
signal s_apb_prdata: std_logic_vector(31 downto 0);
|
||||
|
@ -91,6 +91,7 @@ architecture arch of puzzlefw_top is
|
|||
signal s_apb_pwdata: std_logic_vector(31 downto 0);
|
||||
signal s_apb_pwrite: std_logic;
|
||||
|
||||
-- AXI bus for DMA.
|
||||
signal s_axi_awid: std_logic_vector(5 downto 0);
|
||||
signal s_axi_awaddr: std_logic_vector(31 downto 0);
|
||||
signal s_axi_awlen: std_logic_vector(3 downto 0);
|
||||
|
@ -130,12 +131,15 @@ architecture arch of puzzlefw_top is
|
|||
signal s_axi_rvalid: std_logic;
|
||||
signal s_axi_rready: std_logic;
|
||||
|
||||
-- Interrupts.
|
||||
signal s_irq_pending: std_logic_vector(0 downto 0);
|
||||
signal s_irq_f2p: std_logic_vector(7 downto 0);
|
||||
|
||||
-- Registers.
|
||||
signal s_reg_control: registers_control;
|
||||
signal s_reg_status: registers_status;
|
||||
|
||||
-- DMA write channel control.
|
||||
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_valid: std_logic_vector(0 downto 0);
|
||||
|
@ -144,25 +148,26 @@ architecture arch of puzzlefw_top is
|
|||
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_timestamp: std_logic_vector(timestamp_bits - 1 downto 0);
|
||||
signal s_adc_data: adc_data_array(0 to 1);
|
||||
signal s_adc_sample: adc_data_array(0 to 1);
|
||||
|
||||
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_raddr: std_logic_vector(9 downto 0);
|
||||
signal r_test_waddr: std_logic_vector(9 downto 0);
|
||||
signal r_test_cnt: unsigned(15 downto 0);
|
||||
signal s_test_dout: std_logic_vector(63 downto 0);
|
||||
signal s_test_ren: std_logic;
|
||||
signal s_timestamp: std_logic_vector(timestamp_bits - 1 downto 0);
|
||||
signal s_adc_data: adc_data_array(0 to 1);
|
||||
signal s_adc_sample: adc_data_array(0 to 1);
|
||||
signal s_dig_in: std_logic_vector(3 downto 0);
|
||||
signal s_dig_sync: std_logic_vector(3 downto 0);
|
||||
signal s_dig_deglitch: std_logic_vector(3 downto 0);
|
||||
signal s_dig_sample: std_logic_vector(3 downto 0);
|
||||
|
||||
begin
|
||||
|
||||
led_o(7 downto 2) <= s_reg_control.test_led(7 downto 2);
|
||||
led_o(0) <= r_adcclk_led; -- blinking LED, 1 Hz
|
||||
led_o(1) <= s_reg_control.acquisition_en; -- acquisition enabled
|
||||
led_o(2) <= s_reg_status.trig_waiting; -- waiting for trigger
|
||||
-- led_o(3) <= timetagger_en
|
||||
led_o(7 downto 4) <= s_reg_control.led_state(7 downto 4);
|
||||
|
||||
-- Differential clock input for ADC clock.
|
||||
inst_ibuf_adc_clk: IBUFDS
|
||||
|
@ -179,18 +184,6 @@ begin
|
|||
O => clk_adc
|
||||
);
|
||||
|
||||
inst_obuf_led0: OBUF
|
||||
port map (
|
||||
I => r_fclk_led,
|
||||
O => led_o(0)
|
||||
);
|
||||
|
||||
inst_obuf_led1: OBUF
|
||||
port map (
|
||||
I => r_adcclk_led,
|
||||
O => led_o(1)
|
||||
);
|
||||
|
||||
-- ARM/PS block design.
|
||||
inst_blockdesign: entity work.puzzlefw_wrapper
|
||||
port map (
|
||||
|
@ -465,24 +458,64 @@ begin
|
|||
out_empty => s_acq_dma_empty,
|
||||
out_data => s_acq_dma_data );
|
||||
|
||||
-- Capture digital inputs.
|
||||
s_dig_in(0) <= exp_p_io(0);
|
||||
s_dig_in(1) <= exp_n_io(0);
|
||||
s_dig_in(2) <= exp_p_io(1);
|
||||
s_dig_in(3) <= exp_n_io(1);
|
||||
|
||||
inst_dig_capture_gen: for i in 0 to 3 generate
|
||||
|
||||
-- Use a 2-flipflop synchronizer to avoid metastability.
|
||||
inst_dig_sync: entity work.syncdff
|
||||
port map (
|
||||
clk => clk_adc,
|
||||
di => s_dig_in(i),
|
||||
do => s_dig_sync(i) );
|
||||
|
||||
-- Deglitch filter.
|
||||
inst_dig_deglitch: entity work.deglitch
|
||||
generic map (
|
||||
deglitch_cycles => 4 )
|
||||
port map (
|
||||
clk => clk_adc,
|
||||
din => s_dig_sync(i),
|
||||
dout => s_dig_deglitch(i) );
|
||||
|
||||
end generate;
|
||||
|
||||
-- Optionally generate simulated digital signals.
|
||||
process (clk_adc) is
|
||||
begin
|
||||
if rising_edge(clk_adc) then
|
||||
if s_reg_control.dig_simulate = '1' then
|
||||
s_dig_sample <= s_reg_control.dig_sim_state;
|
||||
else
|
||||
s_dig_sample <= s_dig_deglitch;
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
-- Monitor digital signal state.
|
||||
s_reg_status.dig_sample <= s_dig_sample;
|
||||
|
||||
-- TODO : time tagger
|
||||
|
||||
-- Collect interrupt signals from peripherals and generate interrupt to PS.
|
||||
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(7 downto 1) <= (others => '0');
|
||||
|
||||
process (clk_fclk) is
|
||||
begin
|
||||
if rising_edge(clk_fclk) then
|
||||
r_fclk_cnt <= r_fclk_cnt + 1;
|
||||
r_fclk_led <= r_fclk_cnt(r_fclk_cnt'high);
|
||||
end if;
|
||||
end process;
|
||||
|
||||
-- Blinking LED, 1 Hz.
|
||||
process (clk_adc) is
|
||||
begin
|
||||
if rising_edge(clk_adc) then
|
||||
r_adcclk_cnt <= r_adcclk_cnt + 1;
|
||||
r_adcclk_led <= r_adcclk_cnt(r_adcclk_cnt'high);
|
||||
if r_adcclk_cnt = 62499999 then
|
||||
r_adcclk_cnt <= (others => '0');
|
||||
r_adcclk_led <= not r_adcclk_led;
|
||||
else
|
||||
r_adcclk_cnt <= r_adcclk_cnt + 1;
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
|
|
|
@ -141,8 +141,11 @@ begin
|
|||
when reg_adc3_minmax =>
|
||||
v.prdata(adc_data_bits - 1 downto 0) := reg_status.adc_min_value(3);
|
||||
v.prdata(adc_data_bits + 15 downto 16) := reg_status.adc_max_value(3);
|
||||
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_dig_simulate =>
|
||||
v.prdata(8) := r.reg_control.dig_simulate;
|
||||
v.prdata(3 downto 0) := r.reg_control.dig_sim_state;
|
||||
when reg_dig_sample => v.prdata(3 downto 0) := reg_status.dig_sample;
|
||||
when reg_led_state => v.prdata(7 downto 0) := r.reg_control.led_state;
|
||||
when reg_dma_buf_addr => v.prdata(31 downto 12) := r.reg_control.dma_buf_addr;
|
||||
when reg_dma_buf_size => v.prdata(31 downto 12) := r.reg_control.dma_buf_size;
|
||||
when others => null;
|
||||
|
@ -182,8 +185,10 @@ begin
|
|||
v.reg_control.trig_force := apb_pwdata(8);
|
||||
when reg_trigger_delay => v.reg_control.trigger_delay := apb_pwdata(15 downto 0);
|
||||
when reg_adc_range_clear => v.reg_control.adc_range_clear := apb_pwdata(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_dig_simulate =>
|
||||
v.reg_control.dig_simulate := apb_pwdata(8);
|
||||
v.reg_control.dig_sim_state := apb_pwdata(3 downto 0);
|
||||
when reg_led_state => v.reg_control.led_state := apb_pwdata(7 downto 0);
|
||||
when reg_dma_buf_addr => v.reg_control.dma_buf_addr := apb_pwdata(31 downto 12);
|
||||
when reg_dma_buf_size => v.reg_control.dma_buf_size := apb_pwdata(31 downto 12);
|
||||
when others => null;
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
--
|
||||
-- Double flip-flop synchronizer.
|
||||
--
|
||||
|
||||
library ieee;
|
||||
use ieee.std_logic_1164.all;
|
||||
library xpm;
|
||||
use xpm.vcomponents.all;
|
||||
|
||||
entity syncdff is
|
||||
|
||||
port (
|
||||
-- Clock (destination domain).
|
||||
clk: in std_logic;
|
||||
|
||||
-- Input data (asynchronous).
|
||||
di: in std_logic;
|
||||
|
||||
-- Output data, synchronous to "clk".
|
||||
do: out std_logic
|
||||
);
|
||||
|
||||
end entity;
|
||||
|
||||
architecture rtl of syncdff is
|
||||
|
||||
begin
|
||||
|
||||
inst: xpm_cdc_single
|
||||
generic map (
|
||||
DEST_SYNC_FF => 2,
|
||||
SRC_INPUT_REG => 0 )
|
||||
port map (
|
||||
dest_clk => clk,
|
||||
dest_out => do,
|
||||
src_clk => '0',
|
||||
src_in => di );
|
||||
|
||||
end architecture;
|
|
@ -28,11 +28,13 @@ read_vhdl -vhdl2008 ../rtl/acquisition_stream.vhd
|
|||
read_vhdl -vhdl2008 ../rtl/adc_capture.vhd
|
||||
read_vhdl -vhdl2008 ../rtl/adc_range_monitor.vhd
|
||||
read_vhdl -vhdl2008 ../rtl/adc_sample_stream.vhd
|
||||
read_vhdl -vhdl2008 ../rtl/deglitch.vhd
|
||||
read_vhdl -vhdl2008 ../rtl/dma_axi_master.vhd
|
||||
read_vhdl -vhdl2008 ../rtl/dma_write_channel.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/syncdff.vhd
|
||||
read_vhdl -vhdl2008 ../rtl/simple_fifo.vhd
|
||||
read_vhdl -vhdl2008 ../rtl/timestamp_gen.vhd
|
||||
read_vhdl -vhdl2008 ../rtl/trigger_detector.vhd
|
||||
|
|
|
@ -59,6 +59,9 @@
|
|||
#define REG_ADC1_MINMAX 0x0294
|
||||
#define REG_ADC2_MINMAX 0x0298
|
||||
#define REG_ADC3_MINMAX 0x029c
|
||||
#define REG_DIG_SIMULATE 0x0330
|
||||
#define REG_DIG_SAMPLE 0x0338
|
||||
#define REG_LED_STATE 0x0404
|
||||
|
||||
|
||||
struct puzzlefw_context {
|
||||
|
@ -628,6 +631,10 @@ static void show_status(struct puzzlefw_context *ctx)
|
|||
(v >> 16) & 0xffff,
|
||||
adc_range & 0xffff,
|
||||
(adc_range >> 16) & 0xffff);
|
||||
|
||||
v = puzzlefw_read_reg(ctx, REG_DIG_SAMPLE);
|
||||
printf(" digital input = %d %d %d %d\n",
|
||||
(v >> 3) & 1, (v >> 2) & 1, (v >> 1) & 1, v & 1);
|
||||
}
|
||||
|
||||
|
||||
|
@ -1065,6 +1072,7 @@ int main(int argc, char **argv)
|
|||
int avgon = 0, avgoff = 0;
|
||||
int simon = 0, simoff = 0;
|
||||
int rangeclear = 0;
|
||||
int set_digsim = 0, digsim = 0;
|
||||
|
||||
if (argc == 2 && strcmp(argv[1], "show") == 0) {
|
||||
show = 1;
|
||||
|
@ -1114,6 +1122,13 @@ int main(int argc, char **argv)
|
|||
simoff = 1;
|
||||
} else if (argc == 2 && strcmp(argv[1], "rangeclear") == 0) {
|
||||
rangeclear = 1;
|
||||
} else if (argc == 3 && strcmp(argv[1], "digsim") == 0) {
|
||||
set_digsim = 1;
|
||||
if (strcmp(argv[2], "off") == 0) {
|
||||
digsim = -1;
|
||||
} else {
|
||||
digsim = atoi(argv[2]);
|
||||
}
|
||||
} else if (argc == 2 && strcmp(argv[1], "server") == 0) {
|
||||
server = 1;
|
||||
} else {
|
||||
|
@ -1185,6 +1200,9 @@ int main(int argc, char **argv)
|
|||
" testje rangeclear\n"
|
||||
" Clear min/max ADC sample monitor.\n"
|
||||
"\n"
|
||||
" testje digsim N/'off'\n"
|
||||
" Set simulated digital input.\n"
|
||||
"\n"
|
||||
" testje server\n"
|
||||
" Open TCP port 5001 to stream DMA data.\n"
|
||||
"\n");
|
||||
|
@ -1288,6 +1306,14 @@ int main(int argc, char **argv)
|
|||
puzzlefw_write_reg(&ctx, REG_ADC_RANGE_CLEAR, 1);
|
||||
}
|
||||
|
||||
if (set_digsim) {
|
||||
if (digsim < 0) {
|
||||
puzzlefw_write_reg(&ctx, REG_DIG_SIMULATE, 0);
|
||||
} else {
|
||||
puzzlefw_write_reg(&ctx, REG_DIG_SIMULATE, 0x100 + digsim);
|
||||
}
|
||||
}
|
||||
|
||||
if (server) {
|
||||
run_server(&ctx);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue