From: Andreas Neiser Date: Mon, 22 Apr 2013 09:01:13 +0000 (+0200) Subject: Added trigger receiver for Mainz A2 X-Git-Url: https://jspc29.x-matter.uni-frankfurt.de/git/?a=commitdiff_plain;h=d9689fca3bc9edaa1fce8a7eb0a7438493465159;p=trb3.git Added trigger receiver for Mainz A2 --- diff --git a/base/code/mainz_a2_recv.vhd b/base/code/mainz_a2_recv.vhd new file mode 120000 index 0000000..f6b3be0 --- /dev/null +++ b/base/code/mainz_a2_recv.vhd @@ -0,0 +1 @@ +../../cts/source/mainz_a2_recv.vhd \ No newline at end of file diff --git a/cts/source/mainz_a2_recv.vhd b/cts/source/mainz_a2_recv.vhd new file mode 100644 index 0000000..caa05e0 --- /dev/null +++ b/cts/source/mainz_a2_recv.vhd @@ -0,0 +1,244 @@ +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +library work; +use work.trb_net_std.all; +use work.trb3_components.all; + + +entity mainz_a2_recv is + port( + CLK : in std_logic; -- must be 100 MHz! + RESET_IN : in std_logic; -- could be used after busy_release to make sure entity is in correct state + + --Module inputs + SERIAL_IN : in std_logic; -- serial raw in, externally clock'ed at 12.5 MHz + EXT_TRG_IN : in std_logic; -- external trigger in, ~10us later + -- the external trigger id is sent on SERIAL_IN + + --trigger outputs + TRG_ASYNC_OUT : out std_logic; -- asynchronous rising edge, length varying, here: approx. 110 ns + TRG_SYNC_OUT : out std_logic; -- sync. to CLK + + --data output for read-out + TRIGGER_IN : in std_logic; + DATA_OUT : out std_logic_vector(31 downto 0); + WRITE_OUT : out std_logic; + STATUSBIT_OUT : out std_logic_vector(31 downto 0); + FINISHED_OUT : out std_logic; + + --Registers / Debug + CONTROL_REG_IN : in std_logic_vector(31 downto 0); + STATUS_REG_OUT : out std_logic_vector(31 downto 0) := (others => '0'); + DEBUG : out std_logic_vector(31 downto 0) + ); +end entity; + +--A2 trigger format of SERIAL_IN +--Startbit : "1" +--Trig.nr. : 32bit (but only ~20bit used at the moment) +--Paritybit : "0" or "1" +--Stopbit/Controlbit: "1" +--Parity check over trig Nr and parity bit + +--Data Format of DATA_OUT (goes into DAQ stream) +-- Bit 30 - 0 : Trigger Number (Bit 32 is cut off and used for error flag) +-- Bit 31 : Error flag (either parity wrong or no stop/control bit seen) + +--statusbit 23 of STATUSBIT_OUT is equal to Bit 31 of DATA_OUT + +architecture arch1 of mainz_a2_recv is + + constant timeoutcnt_Max : integer := 2000000; -- x 10 ns = 20us maximum + -- time until trigger id can + -- be received; + signal timeoutcnt : integer range 0 to timeoutcnt_Max := timeoutcnt_Max; + + signal shift_reg : std_logic_vector(34 downto 0); + signal bitcnt : integer range 0 to shift_reg'length; + + + + --signal first_bits_fast : std_logic; + --signal first_bits_slow : std_logic; + signal reg_SERIAL_IN : std_logic; + signal done : std_logic; + --signal done_slow : std_logic; + + signal number_reg : std_logic_vector(30 downto 0); + --signal status_reg : std_logic_vector(1 downto 0); + signal error_reg : std_logic; + + signal trg_async : std_logic; + signal trg_sync : std_logic; + + type state_t is (IDLE, WAIT_FOR_STARTBIT, WAIT1, WAIT2, WAIT3, READ_BIT, + WAIT5, WAIT6, WAIT7, WAIT8, NO_TRG_ID_RECV, FINISH); + signal state : state_t := IDLE; + + type rdo_state_t is (RDO_IDLE, RDO_WAIT, RDO_WRITE, RDO_FINISH); + signal rdostate : rdo_state_t := RDO_IDLE; + + signal config_rdo_disable_i : std_logic; + +begin + + + reg_SERIAL_IN <= SERIAL_IN when rising_edge(CLK); + + --PROC_FIRST_BITS : process + --begin + -- wait until rising_edge(CLK_200); + -- if bitcnt > 32 and RESET_IN = '0' then + -- first_bits_fast <= '1'; + -- else + -- first_bits_fast <= '0'; + -- end if; + --end process; + + --first_bits_slow <= first_bits_fast when rising_edge(CLK); + + --trg_async <= (not MBS_IN or trg_async) when first_bits_fast = '1' else '0'; + --trg_sync <= (not reg_MBS_IN or trg_sync) and first_bits_slow when rising_edge(CLK); + trg_async <= EXT_TRG_IN; + trg_sync <= EXT_TRG_IN when rising_edge(CLK); -- do we need another register + -- here? + + TRG_ASYNC_OUT <= trg_async; + TRG_SYNC_OUT <= trg_sync when rising_edge(CLK); + + -- since CLK runs at 100MHz, we sample at 12.5MHz due to 8 WAIT states + PROC_FSM : process + begin + wait until rising_edge(CLK); + case state is + + when IDLE => + done <= '1'; + if trg_sync = '1' then + done <= '0'; + timeoutcnt <= timeoutcnt_Max; + state <= WAIT_FOR_STARTBIT; + end if; + + when WAIT_FOR_STARTBIT => + + if reg_SERIAL_IN = '1' then + bitcnt <= shift_reg'length; + state <= WAIT1; + elsif timeoutcnt = 0 then + state <= NO_TRG_ID_RECV; + else + timeoutcnt <= timeoutcnt-1; + end if; + + + when WAIT1 => + state <= WAIT2; + when WAIT2 => + state <= WAIT3; + when WAIT3 => + state <= READ_BIT; + + + when READ_BIT => -- actually WAIT4, but we read here, in the middle of + -- the serial line communication + bitcnt <= bitcnt - 1; + -- we fill the shift_reg LSB first since this way the trg id arrives + shift_reg <= reg_SERIAL_IN & shift_reg(shift_reg'high downto 1); + state <= WAIT5; + + when WAIT5 => + -- check if we're done reading + if bitcnt = 0 then + state <= FINISH; + else + state <= WAIT6; + end if; + + when WAIT6 => + state <= WAIT7; + when WAIT7 => + state <= WAIT8; + when WAIT8 => + state <= WAIT1; + + when NO_TRG_ID_RECV => + -- we received no id after a trigger within the timeout, so + -- set bogus trigger id and no control bit (forces error flag set!) + shift_reg <= b"00" & x"ffffffff" & b"1"; + state <= FINISH; + + when FINISH => + -- wait until serial line is idle again + if reg_SERIAL_IN = '0' then + state <= IDLE; + end if; + done <= '1'; + end case; + + if RESET_IN = '1' then + state <= IDLE; + done <= '0'; + end if; + end process; + + --done_slow <= done when rising_edge(CLK); + + PROC_REG_INFO : process + begin + wait until rising_edge(CLK); + if done = '1' then + -- here we cut off the highest bit of the received trigger id + -- so shift_reg(32) is discarded (but used for checksum) + number_reg <= shift_reg(31 downto 1); + --status_reg <= shift_reg(7 downto 6); + + -- check if start and control bit is 1 and parity is okay + if shift_reg(34) = '1' and shift_reg(0) = '1' + and xor_all(shift_reg(33 downto 1)) = '0' then + error_reg <= '0'; + else + error_reg <= '1'; + end if; + end if; + end process; + + + PROC_RDO : process + begin + wait until rising_edge(CLK); + WRITE_OUT <= '0'; + FINISHED_OUT <= config_rdo_disable_i; + STATUSBIT_OUT <= (23 => error_reg, others => '0'); + case rdostate is + when RDO_IDLE => + if TRIGGER_IN = '1' and config_rdo_disable_i = '0' then + if done = '0' then + rdostate <= RDO_WAIT; + else + rdostate <= RDO_WRITE; + end if; + end if; + when RDO_WAIT => + if done = '1' then + rdostate <= RDO_WRITE; + end if; + when RDO_WRITE => + rdostate <= RDO_FINISH; + DATA_OUT <= error_reg & number_reg; + WRITE_OUT <= '1'; + + when RDO_FINISH => + FINISHED_OUT <= '1'; + rdostate <= RDO_IDLE; + end case; + end process; + + config_rdo_disable_i <= CONTROL_REG_IN(0); + + STATUS_REG_OUT <= error_reg & std_logic_vector(to_unsigned(bitcnt, 6)) & number_reg(24 downto 0); + DEBUG <= x"00000000"; -- & done & '0' & shift_reg(13 downto 0); + +end architecture;