Skip to content

Commit

Permalink
ENH: Add TDC module for CMOS (LEMO_RX1)
Browse files Browse the repository at this point in the history
  • Loading branch information
cbespin committed Mar 29, 2023
1 parent 5f6c2ba commit 12f48e8
Show file tree
Hide file tree
Showing 6 changed files with 204 additions and 47 deletions.
80 changes: 63 additions & 17 deletions firmware/src/tjmonopix2_core.v
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;

Expand Down Expand Up @@ -514,30 +517,34 @@ 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),

.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),
Expand Down Expand Up @@ -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),

This comment has been minimized.

Copy link
@lschall

lschall Mar 29, 2023

Member

This needs to be TDC_CMOS_BASEADDR, firmware crashed because of LVDS_BASEADDR is used twice and tdc_cmos module of bdaq53.yaml is not found. @cbespin

This comment has been minimized.

Copy link
@cbespin

cbespin Mar 30, 2023

Author Collaborator

Thanks, solved with 7c28bc7

.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),
Expand Down
38 changes: 35 additions & 3 deletions tjmonopix2/analysis/analysis.py
Original file line number Diff line number Diff line change
Expand Up @@ -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']

Expand All @@ -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,
Expand Down
64 changes: 52 additions & 12 deletions tjmonopix2/analysis/interpreter.py
Original file line number Diff line number Diff line change
Expand Up @@ -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),
]
Expand All @@ -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
Expand All @@ -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):
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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

Expand Down
58 changes: 46 additions & 12 deletions tjmonopix2/system/bdaq53.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Loading

0 comments on commit 12f48e8

Please sign in to comment.