diff --git a/firmware/src/tjmonopix2_core.v b/firmware/src/tjmonopix2_core.v index 1ebfeb5..f9bd8b3 100644 --- a/firmware/src/tjmonopix2_core.v +++ b/firmware/src/tjmonopix2_core.v @@ -176,8 +176,8 @@ localparam GPIO_DAQ_CONTROL_HIGHADDR = 32'h0600 - 1; localparam TLU_BASEADDR = 32'h0600; localparam TLU_HIGHADDR = 32'h0700 - 1; -localparam TDC_BASEADDR = 32'h0700; -localparam TDC_HIGHADDR = 32'h0800 - 1; +localparam TDC_LVDS_BASEADDR = 32'h0700; +localparam TDC_LVDS_HIGHADDR = 32'h0800 - 1; localparam PULSER_VETO_BASEADDR = 32'h0800; localparam PULSER_VETO_HIGHADDR = 32'h0900-1; @@ -194,6 +194,9 @@ localparam PULSER_VETO_HIGHADDR = 32'h0900-1; localparam PULSE_CMD_START_LOOP_BASEADDR = 32'h0C00; localparam PULSE_CMD_START_LOOP_HIGHADDR = 32'h0D00 - 1; +localparam TDC_CMOS_BASEADDR = 32'h0D00; +localparam TDC_CMOS_HIGHADDR = 32'h0E00 - 1; + localparam I2C_BASEADDR = 32'h3000; localparam I2C_HIGHADDR = 32'h4000 - 1; @@ -514,12 +517,12 @@ wire [31:0] TLU_FIFO_DATA; wire TLU_FIFO_PREEMPT_REQ; // TDC -wire TDC_FIFO_READ, TDC_FIFO_EMPTY; -wire [31:0] TDC_FIFO_DATA; +wire TDC_LVDS_FIFO_READ, TDC_LVDS_FIFO_EMPTY, TDC_CMOS_FIFO_READ, TDC_CMOS_FIFO_EMPTY; +wire [31:0] TDC_LVDS_FIFO_DATA, TDC_CMOS_FIFO_DATA; rrp_arbiter #( - .WIDTH(3) + .WIDTH(4) ) rrp_arbiter ( .RST(BUS_RST), .CLK(BUS_CLK), @@ -527,17 +530,21 @@ rrp_arbiter .WRITE_REQ({ ~RX_FIFO_EMPTY, ~TLU_FIFO_EMPTY, - ~TDC_FIFO_EMPTY + ~TDC_LVDS_FIFO_EMPTY, + ~TDC_CMOS_FIFO_EMPTY }), - .HOLD_REQ({1'b0, TLU_FIFO_PREEMPT_REQ, 1'b0}), + .HOLD_REQ({1'b0, TLU_FIFO_PREEMPT_REQ, 1'b0, 1'b0}), .DATA_IN({ RX_FIFO_DATA, TLU_FIFO_DATA, - TDC_FIFO_DATA}), + TDC_LVDS_FIFO_DATA, + TDC_CMOS_FIFO_DATA + }), .READ_GRANT({ RX_FIFO_READ, TLU_FIFO_READ, - TDC_FIFO_READ + TDC_LVDS_FIFO_READ, + TDC_CMOS_FIFO_READ }), .READY_OUT(ARB_READY_OUT), .WRITE_OUT(ARB_WRITE_OUT), @@ -617,30 +624,69 @@ wire [CLKDV * 4 - 1:0] FAST_TRIGGER_OUT; // wire HITOR_FROM_TDC; tdc_s3 #( - .BASEADDR(TDC_BASEADDR), - .HIGHADDR(TDC_HIGHADDR), + .BASEADDR(TDC_LVDS_BASEADDR), + .HIGHADDR(TDC_LVDS_HIGHADDR), .ABUSWIDTH(ABUSWIDTH), .CLKDV(CLKDV), .DATA_IDENTIFIER(4'b0010), .FAST_TDC(1), .FAST_TRIGGER(1), - .BROADCAST(0) // generate for first TDC module the 640MHz sampled trigger signal and share it with other modules using TRIGGER input -) i_tdc ( + .BROADCAST(0) // generate for LVDS TDC module the 640MHz sampled trigger signal and share it with other modules using TRIGGER input +) i_tdc_lvds ( .CLK320(CLK320), // 320 MHz .CLK160(CLK160), // 160 MHz .DV_CLK(CLK40), // 40 MHz - .TDC_IN(LVDS_HITOR), // HITOR + .TDC_IN(LVDS_HITOR), // LVDS HITOR (DP) .TDC_OUT(), .TRIG_IN(LEMO_RX[0]), .TRIG_OUT(), // input/output trigger signals for broadcasting mode .FAST_TRIGGER_IN(16'b0), + .FAST_TRIGGER_OUT(FAST_TRIGGER_OUT), // collect 640 MHz sampled trigger signal to pass it to other modules + + .FIFO_READ(TDC_LVDS_FIFO_READ), + .FIFO_EMPTY(TDC_LVDS_FIFO_EMPTY), + .FIFO_DATA(TDC_LVDS_FIFO_DATA), + + .BUS_CLK(BUS_CLK), + .BUS_RST(BUS_RST), + .BUS_ADD(BUS_ADD), + .BUS_DATA(BUS_DATA), + .BUS_RD(BUS_RD), + .BUS_WR(BUS_WR), + + .ARM_TDC(1'b0), + .EXT_EN(1'b0), + + .TIMESTAMP(TIMESTAMP[15:0]) +); + +tdc_s3 #( + .BASEADDR(TDC_LVDS_BASEADDR), + .HIGHADDR(TDC_LVDS_HIGHADDR), + .ABUSWIDTH(ABUSWIDTH), + .CLKDV(CLKDV), + .DATA_IDENTIFIER(4'b0001), + .FAST_TDC(1), + .FAST_TRIGGER(1), + .BROADCAST(1) // generate FAST_TRIGGER signal for LVDS TDC module and receive here +) i_tdc_cmos ( + .CLK320(CLK320), // 320 MHz + .CLK160(CLK160), // 160 MHz + .DV_CLK(CLK40), // 40 MHz + .TDC_IN(LEMO_RX[1]), // CMOS HITOR (LEMO) + .TDC_OUT(), + .TRIG_IN(1'b0), + .TRIG_OUT(), + + // input/output trigger signals for broadcasting mode + .FAST_TRIGGER_IN(FAST_TRIGGER_OUT), // looped through tdc_lvds instance .FAST_TRIGGER_OUT(), // collect 640 MHz sampled trigger signal to pass it to other modules - .FIFO_READ(TDC_FIFO_READ), - .FIFO_EMPTY(TDC_FIFO_EMPTY), - .FIFO_DATA(TDC_FIFO_DATA), + .FIFO_READ(TDC_CMOS_FIFO_READ), + .FIFO_EMPTY(TDC_CMOS_FIFO_EMPTY), + .FIFO_DATA(TDC_CMOS_FIFO_DATA), .BUS_CLK(BUS_CLK), .BUS_RST(BUS_RST), diff --git a/tjmonopix2/analysis/analysis.py b/tjmonopix2/analysis/analysis.py index f850776..666b26f 100644 --- a/tjmonopix2/analysis/analysis.py +++ b/tjmonopix2/analysis/analysis.py @@ -360,13 +360,13 @@ def analyze_data(self): pbar.update(upd) pbar.close() - hist_occ, hist_tot, hist_tdc = interpreter.get_histograms() + hist_occ, hist_tot, hist_tdc_lvds, hist_tdc_lvds_dist, hist_tdc_cmos, hist_tdc_cmos_dist = interpreter.get_histograms() - self._create_additional_hit_data(hist_occ, hist_tot) + self._create_additional_hit_data(hist_occ, hist_tot, hist_tdc_lvds, hist_tdc_lvds_dist, hist_tdc_cmos, hist_tdc_cmos_dist) if self.cluster_hits: self._create_additional_cluster_data(hist_cs_size, hist_cs_tot, hist_cs_shape) - def _create_additional_hit_data(self, hist_occ, hist_tot): + def _create_additional_hit_data(self, hist_occ, hist_tot, hist_tdc_lvds, hist_tdc_lvds_dist, hist_tdc_cmos, hist_tdc_cmos_dist): with tb.open_file(self.analyzed_data_file, 'r+') as out_file: scan_id = self.run_config['scan_id'] @@ -384,6 +384,38 @@ def _create_additional_hit_data(self, hist_occ, hist_tot): filters=tb.Filters(complib='blosc', complevel=5, fletcher32=False)) + + out_file.create_carray(out_file.root, + name='HistTdcLvds', + title='TDC Histogram', + obj=hist_tdc_lvds, + filters=tb.Filters(complib='blosc', + complevel=5, + fletcher32=False)) + + out_file.create_carray(out_file.root, + name='HistTdcLvdsDist', + title='TDC Dist Histogram', + obj=hist_tdc_lvds_dist, + filters=tb.Filters(complib='blosc', + complevel=5, + fletcher32=False)) + + out_file.create_carray(out_file.root, + name='HistTdcCmos', + title='TDC Histogram', + obj=hist_tdc_cmos, + filters=tb.Filters(complib='blosc', + complevel=5, + fletcher32=False)) + + out_file.create_carray(out_file.root, + name='HistTdcCmosDist', + title='TDC Dist Histogram', + obj=hist_tdc_cmos_dist, + filters=tb.Filters(complib='blosc', + complevel=5, + fletcher32=False)) # if self.analyze_tdc: # Only store if TDC analysis is used. # out_file.create_carray(out_file.root, diff --git a/tjmonopix2/analysis/interpreter.py b/tjmonopix2/analysis/interpreter.py index eafcf75..4007b59 100644 --- a/tjmonopix2/analysis/interpreter.py +++ b/tjmonopix2/analysis/interpreter.py @@ -17,7 +17,10 @@ ('hist_occ', numba.uint32[:, :, :]), ('hist_tot', numba.uint16[:, :, :, :]), - ('hist_tdc', numba.uint32[:]), + ('hist_tdc_lvds', numba.uint32[:]), + ('hist_tdc_lvds_dist', numba.uint32[:]), + ('hist_tdc_cmos', numba.uint32[:]), + ('hist_tdc_cmos_dist', numba.uint32[:]), ('n_triggers', numba.int64), ('n_tdc', numba.int64), ] @@ -34,10 +37,15 @@ def is_tlu(word): @numba.njit -def is_tdc(word): +def is_tdc_lvds(word): return word & 0xF0000000 == 0x20000000 +@numba.njit +def is_tdc_cmos(word): + return word & 0xF0000000 == 0x10000000 + + @numba.njit def is_tjmono_timestamp_msb(word): return (word & 0xFC000000) == 0x4C000000 @@ -59,10 +67,15 @@ def get_tlu_word(word, trigger_data_format): @numba.njit -def get_tdc_value(word): +def get_tdc_value(word, enable_write_timestamp=1, enable_trigger_dist=1): return word & 0xFFF +@numba.njit +def get_tdc_dist(word): + return (word & 0x0FF00000) >> 20 + + @numba.experimental.jitclass(class_spec) class RawDataInterpreter(object): def __init__(self, n_scan_params=1, trigger_data_format=1): @@ -164,22 +177,46 @@ def interpret(self, raw_data, hit_data, scan_param_id=0): # Prepare for next data block. Increase hit index hit_index += 1 - ############################## - # Part 3: interpret TDC word # - ############################## - elif is_tdc(raw_data_word): + ################################### + # Part 3: interpret TDC LVDS word # + ################################### + elif is_tdc_lvds(raw_data_word): + tdc_value = get_tdc_value(raw_data_word) + trigger_dist = get_tdc_dist(raw_data_word) + + hit_data[hit_index]["col"] = 0x3FE # 1022 as TDC LVDS identifier + hit_data[hit_index]["row"] = 0 + hit_data[hit_index]["le"] = 0 + hit_data[hit_index]["te"] = 0 + hit_data[hit_index]["token_id"] = tdc_value + hit_data[hit_index]["timestamp"] = trigger_dist + hit_data[hit_index]["scan_param_id"] = scan_param_id + self.n_tdc += 1 + + self.hist_tdc_lvds[tdc_value] += 1 + self.hist_tdc_lvds_dist[trigger_dist] += 1 + + # Prepare for next data block. Increase hit index + hit_index += 1 + + ################################### + # Part 4: interpret TDC CMOS word # + ################################### + elif is_tdc_cmos(raw_data_word): tdc_value = get_tdc_value(raw_data_word) + trigger_dist = get_tdc_dist(raw_data_word) - hit_data[hit_index]["col"] = 0x3FE # 1022 as TDC identifier + hit_data[hit_index]["col"] = 0x3FD # 1021 as TDC CMOS identifier hit_data[hit_index]["row"] = 0 hit_data[hit_index]["le"] = 0 hit_data[hit_index]["te"] = 0 hit_data[hit_index]["token_id"] = tdc_value - hit_data[hit_index]["timestamp"] = 0 + hit_data[hit_index]["timestamp"] = trigger_dist hit_data[hit_index]["scan_param_id"] = scan_param_id self.n_tdc += 1 - self.hist_tdc[tdc_value] += 1 + self.hist_tdc_cmos[tdc_value] += 1 + self.hist_tdc_cmos_dist[trigger_dist] += 1 # Prepare for next data block. Increase hit index hit_index += 1 @@ -189,7 +226,7 @@ def interpret(self, raw_data, hit_data, scan_param_id=0): return hit_data def get_histograms(self): - return self.hist_occ, self.hist_tot, self.hist_tdc + return self.hist_occ, self.hist_tot, self.hist_tdc_lvds, self.hist_tdc_lvds_dist, self.hist_tdc_cmos, self.hist_tdc_cmos_dist def get_n_triggers(self): return self.n_triggers @@ -200,7 +237,10 @@ def get_n_tdc(self): def reset(self): self.hist_occ = np.zeros((512, 512, self.n_scan_params), dtype=numba.uint32) self.hist_tot = np.zeros((512, 512, self.n_scan_params, 128), dtype=numba.uint16) - self.hist_tdc = np.zeros(4096, dtype=numba.uint32) + self.hist_tdc_lvds = np.zeros(4096, dtype=numba.uint32) + self.hist_tdc_lvds_dist = np.zeros(256, dtype=numba.uint32) + self.hist_tdc_cmos = np.zeros(4096, dtype=numba.uint32) + self.hist_tdc_cmos_dist = np.zeros(256, dtype=numba.uint32) self.n_triggers = 0 self.n_tdc = 0 diff --git a/tjmonopix2/system/bdaq53.py b/tjmonopix2/system/bdaq53.py index 1b6aeea..1f983c2 100644 --- a/tjmonopix2/system/bdaq53.py +++ b/tjmonopix2/system/bdaq53.py @@ -241,19 +241,53 @@ def set_chip_type(self): # '''Disables automatic sending of sync commands''' # self['cmd'].set_auto_sync(0) - def configure_tdc_module(self): + def _set_tdc_registers(self, tdc_module="tdc_lvds"): + self[tdc_module].EN_WRITE_TIMESTAMP = self.configuration['TDC'].get('EN_WRITE_TIMESTAMP', 1) + self[tdc_module].EN_TRIGGER_DIST = self.configuration['TDC'].get('EN_TRIGGER_DIST', 1) + self[tdc_module].EN_NO_WRITE_TRIG_ERR = self.configuration['TDC'].get('EN_NO_WRITE_TRIG_ERR', 1) + self[tdc_module].EN_INVERT_TDC = self.configuration['TDC'].get('EN_INVERT_TDC', 0) + self[tdc_module].EN_INVERT_TRIGGER = self.configuration['TDC'].get('EN_INVERT_TRIGGER', 0) + + def _set_tdc_enable(self, tdc_module='tdc_lvds', enable=True): + self[tdc_module].ENABLE = enable + + def configure_tdc_module(self, input="lvds"): + """Configuration of TDC module(s) for different kinds of inputs: + - single ended CMOS at LEMO RX1 (LEMO on chip carrier PCB) + - differential LVDS at DP_SL1 (DP2 on chip carrier PCB) + + Args: + input (str, optional): Type of TDC input. Supports "lvds" (DP_SL1), "cmos" (LEMO RX1) or None (both). Defaults to "lvds". + + Raises: + ValueError: Invalid type of TDC input choice + """ self.log.info('Configuring TDC module') - self['tdc'].EN_WRITE_TIMESTAMP = self.configuration['TDC'].get('EN_WRITE_TIMESTAMP', 1) - self['tdc'].EN_TRIGGER_DIST = self.configuration['TDC'].get('EN_TRIGGER_DIST', 1) - self['tdc'].EN_NO_WRITE_TRIG_ERR = self.configuration['TDC'].get('EN_NO_WRITE_TRIG_ERR', 1) - self['tdc'].EN_INVERT_TDC = self.configuration['TDC'].get('EN_INVERT_TDC', 0) - self['tdc'].EN_INVERT_TRIGGER = self.configuration['TDC'].get('EN_INVERT_TRIGGER', 0) - - def enable_tdc_module(self): - self['tdc'].ENABLE = 1 - - def disable_tdc_module(self): - self['tdc'].ENABLE = 0 + if input not in ['lvds', 'cmos', None]: + raise ValueError("Unsupported TDC input") + if input is None: + for tdc_module in ['lvds', 'cmos']: + self._set_tdc_registers(tdc_module=tdc_module) + else: + self._set_tdc_registers(tdc_module='tdc_{}'.format(input.lower())) + + def enable_tdc_module(self, input="lvds"): + if input not in ['lvds', 'cmos', None]: + raise ValueError("Unsupported TDC input") + if input is None: + for tdc_module in ['lvds', 'cmos']: + self._set_tdc_enable(tdc_module=tdc_module, enable=True) + else: + self._set_tdc_enable(tdc_module='tdc_{}'.format(input.lower()), enable=True) + + def disable_tdc_module(self, input="lvds"): + if input not in ['lvds', 'cmos', None]: + raise ValueError("Unsupported TDC input") + if input is None: + for tdc_module in ['lvds', 'cmos']: + self._set_tdc_enable(tdc_module=tdc_module, enable=False) + else: + self._set_tdc_enable(tdc_module='tdc_{}'.format(input.lower()), enable=False) def enable_tlu_module(self): self['tlu']['TRIGGER_ENABLE'] = True diff --git a/tjmonopix2/system/bdaq53.yaml b/tjmonopix2/system/bdaq53.yaml index c63f041..09b63e2 100755 --- a/tjmonopix2/system/bdaq53.yaml +++ b/tjmonopix2/system/bdaq53.yaml @@ -63,11 +63,16 @@ hw_drivers: interface : intf base_addr : 0x0600 - - name : tdc + - name : tdc_lvds type : tdc_s3 interface : intf base_addr : 0x0700 + - name : tdc_cmos + type : tdc_s3 + interface : intf + base_addr : 0x0D00 + - name : tlu_veto type : pulse_gen interface : intf diff --git a/tjmonopix2/testbench.yaml b/tjmonopix2/testbench.yaml index 595fc40..a4a1548 100644 --- a/tjmonopix2/testbench.yaml +++ b/tjmonopix2/testbench.yaml @@ -28,10 +28,10 @@ TLU: TDC: EN_WRITE_TIMESTAMP: 1 # Writing trigger timestamp - EN_TRIGGER_DIST: 0 # Measuring trigger to TDC delay with 640MHz clock + EN_TRIGGER_DIST: 1 # Measuring trigger to TDC delay with 640MHz clock EN_NO_WRITE_TRIG_ERR: 1 # Writing TDC word only if valid trigger occurred EN_INVERT_TDC: 0 # Inverting TDC input - EN_INVERT_TRIGGER: 0 # Inverting trigger input, e.g. for using Test output from EUDET TLU + EN_INVERT_TRIGGER: 1 # Inverting trigger input, e.g. for using Test output from EUDET TLU hardware: # Setup-specific hardware settings enable_NTC: False # Only enable if you know you have the correct resistors mounted on the BDAQ board!