Read digital input signals

This commit is contained in:
Joris van Rantwijk 2024-08-27 23:48:12 +02:00
parent 81e5fe0eba
commit 5d00a2e792
8 changed files with 249 additions and 46 deletions

View File

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

93
fpga/rtl/deglitch.vhd Normal file
View File

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

View File

@ -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')
);

View File

@ -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
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;
r_adcclk_led <= r_adcclk_cnt(r_adcclk_cnt'high);
end if;
end if;
end process;

View File

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

39
fpga/rtl/syncdff.vhd Normal file
View File

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

View File

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

View File

@ -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);
}