From 92c6872b22b133b9221c6fa2dfd889339a95c03f Mon Sep 17 00:00:00 2001 From: Diego Lopez Gutierrez <dlopezgu@bu.edu> Date: Wed, 26 Apr 2023 13:52:32 -0400 Subject: [PATCH 1/4] Include all ETROC2 in-pixel and peripheral configuration and status registers in new format --- address_table/ETROC2_example.yaml | 1640 ++++++++++++++++++++++++++++- 1 file changed, 1612 insertions(+), 28 deletions(-) diff --git a/address_table/ETROC2_example.yaml b/address_table/ETROC2_example.yaml index fa8077f..d9776e4 100644 --- a/address_table/ETROC2_example.yaml +++ b/address_table/ETROC2_example.yaml @@ -1,10 +1,15 @@ +############################################ +##### In-Pixel Configuration Registers ##### +############################################ + CLSel: - doc: "Select of load capacitance of the preamp first stage. - 2‘b00: 0 fC; - 2‘b01–> 80 fC; - 2‘b10–> 80 fC; - 2‘b01–> 160 fC. - Debugging use only." + doc: |- + Select of load capacitance of the preamp first stage. + 2‘b00: 0 fC; + 2‘b01: 80 fC; + 2‘b10: 80 fC; + 2‘b01: 160 fC. + Debugging use only. address: - 0 mask: @@ -13,8 +18,158 @@ CLSel: stat: 0 default: 0x0 +IBSel: + doc: |- + Bias current selection of the input transistor in the preamp. + 3'b000: I1; + 3'b001, 3'b010, 3'b100: I2; + 3'b011, 3'b110, 3'b101: I3; + 3'b111: I4 + I1 > I2 > I3 > I4. + address: + - 0 + mask: + - 0x1C + pixel: 1 + stat: 0 + default: 0x7 + +RfSel: + doc: |- + Feedback resistance selection. + 2'b00: 20 kOHm + 2'b01: 10 kOHm + 2'b10: 5.7 kOHm + 2'b11: 4.4 kOHm + address: + - 0 + mask: + - 0x60 + pixel: 1 + stat: 0 + default: 0x2 + +HysSel: + doc: |- + Hysteresis voltage selection. + 4'b0000: Vhys1 + 4'b0001: Vhys2 + 4'b0011: Vhys3 + 4'b0111: Vhys4 + 4'b1111: Vhys5 + Vhys1 > Vhys2 > Vhys3 > Vhys4 = Vhys5 = 0 + address: + - 2 + mask: + - 0xF + pixel: 1 + stat: 0 + default: 0xF + +PD_DACDiscri: + doc: |- + Power down the DAC and the discriminator in pixels. + When PD_DACDiscri is 1, the DAC and the discriminator are powered down. + address: + - 2 + mask: + - 0x10 + pixel: 1 + stat: 0 + default: 0x0 + +QSel: + doc: "Select injected charge, from 1 fC (5'b00000) to 32 fC (5'b11111)." + address: + - 1 + mask: + - 0x1F + pixel: 1 + stat: 0 + default: 0x6 + +QInjEn: + doc: "Enable the charge injection of the specified pixel. Active high." + address: + - 1 + mask: + - 0x20 + pixel: 1 + stat: 0 + default: 0x0 + +autoReset_TDC: + doc: "TDC automatically reset controller for every clock period." + address: + - 6 + mask: + - 0x20 + pixel: 1 + stat: 0 + default: 0x0 + +enable_TDC: + doc: |- + TDC enable. + 1'b1: enable TDC conversion + 1'b0: disable TDC conversion + address: + - 6 + mask: + - 0x80 + pixel: 1 + stat: 0 + default: 0x1 + +level_TDC: + doc: "The bit width of bubble tolerant in TDC encode. It is up to 3'b011" + address: + - 6 + mask: + - 0xE + pixel: 1 + stat: 0 + default: 0x1 + +resetn_TDC: + doc: "Reset TDC encoder, active low." + address: + - 6 + mask: + - 0x40 + pixel: 1 + stat: 0 + default: 0x1 + +testMode_TDC: + doc: |- + Test mode enable of TDC, active high. In test mode, TDC generates + a fixed test pulse as input signal for test for every 25 ns. + address: + - 6 + mask: + - 0x10 + pixel: 1 + stat: 0 + default: 0x0 + +Bypass_THCal: + doc: |- + Bypass control of the in-pixel threshold calibration block. + 1: Bypassing the in-pixel threshold calibration block. DAC is applied to TH. + Users can control the threshold voltage through DAC. + 0: Calibrated threshold is applied to TH. + TH = BL + TH_offset. + address: + - 3 + mask: + - 0x4 + pixel: 1 + stat: 0 + default: 0x1 + DAC: - doc: "threshold" + doc: "When THCal_Bypass==1'b1, TH = DAC." address: - 4 - 5 @@ -26,7 +181,7 @@ DAC: default: 0x0 TH_offset: - doc: "Threshold offset for the calibrated baseline. + doc: "Threshold offset for the calibrated baseline. TH = BL + TH_offset" address: - 5 @@ -36,8 +191,203 @@ TH_offset: stat: 0 default: 0xa +RSTn_THCal: + doc: "Reset of threshold calibration block, active low." + address: + - 3 + mask: + - 0x1 + pixel: 1 + stat: 0 + default: 0x1 + +ScanStart_THCal: + doc: "A rising edge of ScanStart_THCal initializes the threshold calibration." + address: + - 3 + mask: + - 0x10 + pixel: 1 + stat: 0 + default: 0x0 + +BufEn_THCal: + doc: |- + Threshold calibration buffer enable. + 1: enabling the buffer between discriminator output and the TH_Ctrl. + 0: disabling the buffer between discriminator output and the TH_Ctrl. + address: + - 3 + mask: + - 0x2 + pixel: 1 + stat: 0 + default: 0x0 + +CLKEn_THCal: + doc: |- + This register is only used when the threshold calibration clock is bypassed. + 1: enabling the clock for measuring average discriminator output. + 0: disabling the clock. Measurement of the average discriminator output is not available. + address: + - 3 + mask: + - 0x8 + pixel: 1 + stat: 0 + default: 0x0 + +workMode: + doc: |- + Readout work mode selection. + 2'b00: normal, + 2'b01: self test, periodic trigger fixed TDC data, + 2'b10: self test, random TDC data, + 2'b11: reservered. + address: + - 7 + mask: + - 0x18 + pixel: 1 + stat: 0 + default: 0x0 + +L1Adelay: + doc: "L1A latency" + address: + - 8 + - 9 + mask: + - 0x80 + - 0xFF + pixel: 1 + stat: 0 + default: 0x1F5 + +disDataReadout: + doc: |- + Disable signal of the TDC data readout. + 1: disabling the TDC data readout of the current pixel. + 0: enabling the TDC data readout fo the current pixel. + address: + - 7 + mask: + - 0x2 + pixel: 1 + stat: 0 + default: 0x0 + +disTrigPath: + doc: |- + Disable signal of the trigger readout. + 1: disabling the trigger readout of the current pixel. + 0: enabling the trigger readout of the current pixel. + address: + - 7 + mask: + - 0x4 + pixel: 1 + stat: 0 + default: 0x0 + +upperTOATrig: + doc: "TOA upper threshold for the trigger readout" + address: + - 21 + - 22 + mask: + - 0xFF + - 0x3 + pixel: 1 + stat: 0 + default: 0x200 + +lowerTOATrig: + doc: "TOA lower threshold for the trigger readout" + address: + - 19 + - 20 + mask: + - 0xC0 + - 0xFF + pixel: 1 + stat: 0 + default: 0x20 + +upperTOTTrig: + doc: "TOT upper threshold for the trigger readout" # Potential mismatch between register table default (p.62) and address register table default (p. 63) in Users Manual. + address: + - 23 + - 24 + mask: + - 0xF8 + - 0xF + pixel: 1 + stat: 0 + default: 0x40 + +lowerTOTTrig: + doc: "TOT lower threshold for the trigger readout" + address: + - 22 + - 23 + mask: + - 0xFC + - 0x7 + pixel: 1 + stat: 0 + default: 0x10 + +upperCalTrig: + doc: "Cal upper threshold for the trigger readout" + address: + - 18 + - 19 + mask: + - 0xF0 + - 0x3F + pixel: 1 + stat: 0 + default: 0x200 + +lowerCalTrig: + doc: "Cal lower threshold for the trigger readout" + address: + - 17 + - 18 + mask: + - 0xFC + - 0xF + pixel: 1 + stat: 0 + default: 0x10 + +upperTOA: + doc: "TOA upper threshold for the TDC data readout" + address: + - 13 + - 14 + mask: + - 0xC0 + - 0xFF + pixel: 1 + stat: 0 + default: 0x200 + +lowerTOA: + doc: "TOA lower threshold for the TDC data readout" + address: + - 12 + - 13 + mask: + - 0xF0 + - 0x3F + pixel: 1 + stat: 0 + default: 0x20 + upperTOT: - doc: "please add doc" + doc: "TOT upper threshold for the TDC data readout" address: - 16 - 17 @@ -46,40 +396,1274 @@ upperTOT: - 0x3 pixel: 1 stat: 0 - default: 0x0 + default: 0x100 -disScrambler: - doc: "Disable scrambler. - 0: enable scrambler - 1: disable scrambler" +lowerTOT: + doc: "TOT lower threshold for the TDC data readout" address: - - 19 + - 15 + - 16 mask: + - 0xFF - 0x1 - pixel: 0 + pixel: 1 + stat: 0 + default: 0x10 + +upperCal: + doc: "Cal upper threshold for the TDC data readout" + address: + - 11 + - 12 + mask: + - 0xFC + - 0xF + pixel: 1 + stat: 0 + default: 0x200 + +lowerCal: + doc: "Cal lower threshold for the TDC data readout" # Potential mismatch between register table default (p.62) and address register table default (p. 63) in Users Manual. + address: + - 10 + - 11 + mask: + - 0xFF + - 0x3 + pixel: 1 + stat: 0 + default: 0x10 + +addrOffset: + doc: |- + Enabling of the circular buffer (CB) write address offset + by the pixel ID, active high. + 1: enabling of the CB write address offset. + 0: disabling of the CB write address offset. + address: + - 7 + mask: + - 0x1 + pixel: 1 stat: 0 default: 0x1 -singlePort: - doc: "enable single port or both ports. - 0: use both left and right serial ports. - 1: use right serial port only" +selfTestOccupancy: + doc: |- + Self-test data occupancy is selfTestOccupancy[6:0]/128. + For example: + 1: 1/1.28% + 2: 2/1.28% + 5: 5/1.28% + 10: 10/1.28% address: - - 19 + - 8 mask: - - 0x40 - pixel: 0 + - 0x7F + pixel: 1 stat: 0 default: 0x1 -mergeTriggerData: - doc: "merge trigger and data in a port - 0: trigger and data in separate port, only valid when single port is false. - 1: trigger and data are merged in serial port" +############################################ +######### In-Pixel Status Registers ######## +############################################ + +ACC: + doc: "Accumulator of the threshold calibration." address: - - 20 + - 5 + - 6 + mask: + - 0xFF + - 0xFF + pixel: 1 + stat: 1 + +ScanDone: + doc: "Scan done signal of the threshold calibration." + address: + - 1 mask: - 0x1 + pixel: 1 + stat: 1 + +BL: + doc: "Baseline obtained from threshold calibration." + address: + - 2 + - 3 + mask: + - 0xFF + - 0x3 + pixel: 1 + stat: 1 + +NW: + doc: "Noise width from threshold calibration. Expect less than 10." + address: + - 1 + mask: + - 0x1E + pixel: 1 + stat: 1 + +TH: + doc: "10-bit threshold applied to the DAC input." + address: + - 3 + - 4 + mask: + - 0xC0 + - 0xFF + pixel: 1 + stat: 1 + +THState: + doc: "Threshold calibration state machine output." + address: + - 1 + mask: + - 0xE0 + pixel: 1 + stat: 1 + +PixelID: + doc: "Col[3:0], Row[3:0]" + address: + - 0 + mask: + - 0xFF + pixel: 1 + stat: 1 + +############################################ +#### Peripheral Configuration Registers #### +############################################ + +readoutClockDelayPixel: + doc: "phase delay of pixel readout clock, 780 ps a step." + address: + - 13 + mask: + - 0x1F + pixel: 0 + stat: 0 + default: 0x0 + +readoutClockWidthPixel: + doc: "Positive pulse width of pixel clock, 780 ps a step." + address: + - 14 + mask: + - 0x1F + pixel: 0 + stat: 0 + default: 0x20 + +readoutClockDelayGlobal: + doc: "Phase delay of global readout clock, 780 ps a step." + address: + - 15 + mask: + - 0x1F pixel: 0 stat: 0 default: 0x0 + +readoutClockWidthGlobal: + doc: "Positive pulse width of global readout clock, 780 ps a step." + address: + - 16 + mask: + - 0x1F + pixel: 0 + stat: 0 + default: 0x20 + +serRateRight: + doc: |- + Data rate selection of the right data port. + 2'b00: 320 Mbps; + 2'b01: 640 Mbps; + 2'b10: 1280 Mbps. + address: + - 19 + mask: + - 0x30 + pixel: 0 + stat: 0 + default: 0x1 + +serRateLeft: + doc: |- + Data rate selection of the right data port. + 2'b00: 320 Mbps; + 2'b01: 640 Mbps; + 2'b10: 1280 Mbps. + address: + - 19 + mask: + - 0xC + pixel: 0 + stat: 0 + default: 0x1 + +linkResetTestPattern: + doc: |- + Link reset test pattern selection. + 1'b0: PRBS; + 1'b1: Fixed pattern. + address: + - 19 + mask: + - 0x2 + pixel: 0 + stat: 0 + default: 0x1 + +linkResetFixedPattern: + doc: "User-specified pattern to be sent during link reset, LSB first." + address: + - 26 + - 27 + - 28 + - 29 + mask: + - 0xFF + - 0xFF + - 0xFF + - 0xFF + pixel: 0 + stat: 0 + default: 0xACC78CC5 + +emptySlotBCID: + doc: "Empty BCID slot for synchronization." + address: + - 11 + - 12 + mask: + - 0xF0 + - 0xFF + pixel: 0 + stat: 0 + default: 0x7 + +triggerGranularity: + doc: |- + The trigger data size varies from 0, 1, 2, 4, 8, 16. + 0/6/7: trigger data size is 0. + 1: trigger data size is 1. + 2: trigger data size is 2. + 3: trigger data size is 4. + 4: trigger data size is 8. + 5: trigger data size is 16. + address: + - 20 + mask: + - 0xE + pixel: 0 + stat: 0 + default: 0x0 + +disScrambler: + doc: |- + Disable scrambler. + 0: enable scrambler + 1: disable scrambler + address: + - 19 + mask: + - 0x1 + pixel: 0 + stat: 0 + default: 0x1 + +mergeTriggerData: + doc: |- + Merge trigger and data in a port + 0: trigger and data in separate port, only valid when single port is false. + 1: trigger and data are merged in serial port + address: + - 20 + mask: + - 0x1 + pixel: 0 + stat: 0 + default: 0x0 + +singlePort: + doc: |- + Enable single port or both ports. + 0: use both left and right serial ports. + 1: use right serial port only + address: + - 19 + mask: + - 0x40 + pixel: 0 + stat: 0 + default: 0x1 + +onChipL1AConf: + doc: |- + On-chip L1A mode + 2'b0x: on-chip L1A disable; + 2'b10: periodic L1A; + 2'b11: random L1A. + address: + - 18 + mask: + - 0x60 + pixel: 0 + stat: 0 + default: 0x0 + +BCIDoffset: + doc: "BCID when BCID is reset" + address: + - 10 + - 11 + mask: + - 0xFF + - 0xF + pixel: 0 + stat: 0 + default: 0x0 + +fcSelfAlignEn: + doc: |- + Fast command decoder self-alignment mode enable. + 1: self-alignment mode enabled; + 0: manual alignment mode enabled. + address: + - 18 + mask: + - 0x4 + pixel: 0 + stat: 0 + default: 0x0 + +fcClkDelayEn: + doc: "Enable clock delay in fast command manual alignment mode" + address: + - 18 + mask: + - 0x8 + pixel: 0 + stat: 0 + default: 0x0 + +fcDataDelayEn: + doc: "Enable data delay in fast command manual alignment mode, active high." + address: + - 18 + mask: + - 0x10 + pixel: 0 + stat: 0 + default: 0x0 + +chargeInjectionDelay: + doc: |- + The charge injection delay to the 40 MHz clcok rising + edge. Start from the rising edge of 40 MHz clock, + each step 781 ps. The pulse width is fixed of 50 ns. + address: + - 17 + mask: + - 0x1F + pixel: 0 + stat: 0 + default: 0x18 + +RefStrSel: + doc: "TDC reference strobe selection." + address: + - 6 + mask: + - 0xFF + pixel: 0 + stat: 0 + default: 0x3 + +PLL_BIASGEN_CONFIG: + doc: "Charge pump bias current selection, [0:8:120] uA. Debugging use only." # Potential name mismatch of registers between page 55 and page 60 of Users manual + address: + - 1 + mask: + - 0xF + pixel: 0 + stat: 0 + default: 0x8 + +PLL_CONFIG_I_PLL: + doc: "Bias current selection of the I-filter unit cell in PLL mode [0:1.1:8] uA. Debugging use only." + address: + - 1 + mask: + - 0xF0 + pixel: 0 + stat: 0 + default: 0x9 + +PLL_CONFIG_P_PLL: + doc: "Bias current selection of the P-filter unit cell in PLL mode [0:5.46:82] uA. Debugging use only." + address: + - 2 + mask: + - 0xF + pixel: 0 + stat: 0 + default: 0x9 + +PLL_R_CONFIG: + doc: "Resistor selection of the P-path in PLL mode [R=1/2*79.8k/CONFIG] Ohm. Debugging use only." # Potential name mismatch of registers between page 55 and page 60 of Users manual + address: + - 2 + mask: + - 0xF0 + pixel: 0 + stat: 0 + default: 0x2 + +PLL_vcoDAC: + doc: "Bias current selection of the VCO core [0:0.470:7.1] mA. Debugging use only." + address: + - 3 + mask: + - 0xF + pixel: 0 + stat: 0 + default: 0x8 + +PLL_vcoRailMode: + doc: |- + Output rail-to-rail mode selection of the VCO, active low. + 1'b0: rail-to-rail output. + 1'b1: CML output. + Debugging use only. + address: + - 3 + mask: + - 0x10 + pixel: 0 + stat: 0 + default: 0x1 + +PLL_ENABLEPLL: + doc: "Enable PLL mode, active high. Debugging use only." + address: + - 3 + mask: + - 0x20 + pixel: 0 + stat: 0 + default: 0x0 + +PLL_FBDiv_skip: + doc: |- + Adjusting the phase of the output clk1G28 of freqPrescaler + in the feedback divider (N=64) by one skip from low to high. + Debugging use only. + address: + - 0 + mask: + - 0x80 + pixel: 0 + stat: 0 + default: 0x0 + +PLL_FBDiv_clkTreeDisable: + doc: |- + Disable the feedback divider, active high. + 1'b0: all output clocks with different frequencies (40MHz - 2.56GHz) are enabled. + 1'b1: The input clk2G56 from the prescaler and all output clocks are disabled. + Debugging use only. + address: + - 0 + mask: + - 0x40 + pixel: 0 + stat: 0 + default: 0x0 + +PLLclkgen_disSER: + doc: |- # Potential name mismatch of registers between page 56 and page 60 of Users manual + Disable output clocks for serializer, active high. + When PLLclkgen_disSER is high, the following clocks are disabled: + clk2g56S, clk2g56SN, clk5g12S, clk5g12SN. + Debuggin use only. + address: + - 0 + mask: + - 0x8 + pixel: 0 + stat: 0 + default: 0x1 + +PLLclkgen_disVCO: + doc: |- # Potential name mismatch of registers between page 56 and page 60 of Users manual + Disable VCO output buffer (associated with clk5g12lshp, clk5g12lshn), active high. + clk5g12lsh is the output clock of the first input buffer in prescaler, and the source + clock for all output clocks. Once disabled, all output clocks are disabled. + Debugging use only. + address: + - 0 + mask: + - 0x10 + pixel: 0 + stat: 0 + default: 0x0 + +PLLclkgen_disEOM: + doc: |- # Potential name mismatch of registers between page 56 and page 60 of Users manual + Disable output clocks for EOM, active high. When PLLclkgen_disEOM is high, the following + clocks are disabled: clk5g12EOMp, clk5g12EOMn. + Debugging use only. + address: + - 0 + mask: + - 0x4 + pixel: 0 + stat: 0 + default: 0x1 + +PLLclkgen_disCLK: + doc: |- # Potential name mismatch of registers between page 56 and page 60 of Users manual + Disable the internal clock buffers and 1/2 clock divider in prescaler, active high. When + PLLclkgen_disCLK is high, all output clocks are disabled. + Debugging use only. + address: + - 0 + mask: + - 0x1 + pixel: 0 + stat: 0 + default: 0x0 + +PLLclkgen_disDES: + doc: |- # Potential name mismatch of registers between page 56 and page 60 of Users manual + Disable output clocks for deserializer, active high. When PLLclkgen_disDES is high, the + following clocks are disabled: clk2g56Qp, clk2g56Qn, clk2g56lp, clk2g56ln. clk2g56Q is + the 2.56 GHz clock for test in ETROC_PLL. clk2g56Q is used as WS clock in ETROC2. + Debugging use only. + address: + - 0 + mask: + - 0x2 + pixel: 0 + stat: 0 + default: 0x0 + +CLKSel: + doc: |- + Selecting PLL clock or off-chip clock for TDC and readout. + 1'b0: using off-chip clocks for TDC and readout; + 1'b1: using PLL clocks for TDC and readout. + Debugging use only. + address: + - 0 + mask: + - 0x20 + pixel: 0 + stat: 0 + default: 0x1 + +PS_CPCurrent: + doc: "Charge pump current control bits, range from 0 to 15uA for charge and discharge. Debugging use only." + address: + - 4 + mask: + - 0xF + pixel: 0 + stat: 0 + default: 0x1 + +PS_CapRst: + doc: "Reset the control voltage of DLL to power supply, active high. Debugging use only." + address: + - 4 + mask: + - 0x10 + pixel: 0 + stat: 0 + default: 0x0 + +PS_Enable: + doc: "Enabling DLL, active high. Debugging use only." + address: + - 4 + mask: + - 0x20 + pixel: 0 + stat: 0 + default: 0x1 + +PS_ForceDown: + doc: "Force to pull down the output of the phase detector, active high. Debugging use only." + address: + - 4 + mask: + - 0x40 + pixel: 0 + stat: 0 + default: 0x0 + +PS_PhaseAdj: + doc: "Phase selecting control bits, PS_PhaseAdj[7:3] for coarse, PS_PhaseAdj[2:0] for fine." + address: + - 5 + mask: + - 0xFF + pixel: 0 + stat: 0 + default: 0x0 + +CLK40_EnRx: + doc: "Enable the Rx for the 40 MHz reference clock, active high. Debugging use only." + address: + - 7 + mask: + - 0x1 + pixel: 0 + stat: 0 + default: 0x1 + +CLK40_EnTer: + doc: "Enable internal termination of the Rx for the 40 MHz reference clock, active high. Debugging use only." + address: + - 7 + mask: + - 0x2 + pixel: 0 + stat: 0 + default: 0x1 + +CLK40_Equ: + doc: |- + Equalization strength of the Rx for the 40 MHz reference clock. + 2'b00: equalization is turned off; + 2'b11: maximal equalization. + Debugging use only. + address: + - 7 + mask: + - 0xC + pixel: 0 + stat: 0 + default: 0x0 + +CLK40_InvData: + doc: "Inverting data of the Rx for the 40 MHz reference clock, active high. Debugging use only." + address: + - 7 + mask: + - 0x10 + pixel: 0 + stat: 0 + default: 0x0 + +CLK40_SetCM: + doc: "Set common voltage of the Rx for the 40 MHz reference clock to 1/2 vdd, active high. Debugging use only." + address: + - 7 + mask: + - 0x20 + pixel: 0 + stat: 0 + default: 0x1 + +CLK1280_EnRx: + doc: "Enable the Rx for the 1.28 GHz clock, active high. Debugging use only." + address: + - 8 + mask: + - 0x1 + pixel: 0 + stat: 0 + default: 0x1 + +CLK1280_EnTer: + doc: "Enable the internal termination of the Rx for the 1.28 GHz clock, active high. Debugging use only." + address: + - 8 + mask: + - 0x2 + pixel: 0 + stat: 0 + default: 0x1 + +CLK1280_Equ: + doc: |- + Equalization strength of the Rx for the 1.28 GHz clock. + 2'b00: equalization is turned off; + 2'b11: maximal equalization. + Debugging use only. + address: + - 8 + mask: + - 0xC + pixel: 0 + stat: 0 + default: 0x0 + +CLK1280_InvData: + doc: "Inverting data of the Rx for the 1.28 GHz clock, active high. Debugging use only." + address: + - 8 + mask: + - 0x10 + pixel: 0 + stat: 0 + default: 0x0 + +CLK1280_SetCM: + doc: "Set common voltage of the Rx for the 1.28 GHz clock to 1/2 vdd, active high. Debugging use only." + address: + - 8 + mask: + - 0x20 + pixel: 0 + stat: 0 + default: 0x1 + +FC_EnRx: + doc: "Enable the Rx for the fast command, active high. Debugging use only." + address: + - 9 + mask: + - 0x1 + pixel: 0 + stat: 0 + default: 0x1 + +FC_EnTer: + doc: "Enable internal termination of the Rx for the fast command, active high. Debugging use only." + address: + - 9 + mask: + - 0x2 + pixel: 0 + stat: 0 + default: 0x1 + +FC_Equ: + doc: |- + Equalization strength of the Rx for the fast command. + 2'b00: equalization is turned off; + 2'b11: maximal equalization. + Debugging use only. + address: + - 9 + mask: + - 0xC + pixel: 0 + stat: 0 + default: 0x0 + +FC_InvData: + doc: "Inverting data of the Rx for the fast command, active high. Debugging use only." + address: + - 9 + mask: + - 0x10 + pixel: 0 + stat: 0 + default: 0x0 + +FC_SetCM: + doc: "Set common voltage of the Rx for the fast command to 1/2 vdd, active high. Debugging use only." + address: + - 9 + mask: + - 0x20 + pixel: 0 + stat: 0 + default: 0x1 + +disPowerSequence: + doc: "Disabling the power up sequence, active high." + address: + - 18 + mask: + - 0x1 + pixel: 0 + stat: 0 + default: 0x1 + +softBoot: + doc: "Reset power sequencer controller, active high." + address: + - 18 + mask: + - 0x2 + pixel: 0 + stat: 0 + default: 0x0 + +EFuse_TCKHP: + doc: |- + The register controlling the SCLK pulse width, ranging ranges from 3 us to 10 us with step of 0.5 us. + The default value is 4 corresponding to 5 us pulse width. + Debugging use only. + address: + - 20 + mask: + - 0xF0 + pixel: 0 + stat: 0 + default: 0x4 + +EFuse_EnClk: + doc: |- + EFuse clock enable. + 1'b1: enabling the clock of the EFuse controller; + 1'b0: disabling the clock of the EFuse controller. + address: + - 21 + mask: + - 0x1 + pixel: 0 + stat: 0 + default: 0x0 + +EFuse_Mode: + doc: |- + Operation mode of EFuse. + 2'b01: programming mode; + 2'b10: reading mode. + address: + - 21 + mask: + - 0x6 + pixel: 0 + stat: 0 + default: 0x2 + +EFuse_Rstn: + doc: "Reset signal of the EFuse controller, active low." + address: + - 21 + mask: + - 0x8 + pixel: 0 + stat: 0 + default: 0x0 + +EFuse_Start: + doc: "Start signal of the EFuse programming. A positive pulse will start the programming." + address: + - 21 + mask: + - 0x10 + pixel: 0 + stat: 0 + default: 0x0 + +EFuse_Prog: + doc: "Data to be written into EFuse." + address: + - 22 + - 23 + - 24 + - 25 + mask: + - 0xFF + - 0xFF + - 0xFF + - 0xFF + pixel: 0 + stat: 0 + default: 0x0 + +EFuse_Bypass: + doc: |- + Bypass EFuse. + 1'b0: EFuse output Q[31:0] is output; + 1'b1: EFuse raw data from I2C (EFuse_Prog[31:0]) is output. + address: + - 21 + mask: + - 0x20 + pixel: 0 + stat: 0 + default: 0x1 + +IfLockThrCounter: + doc: "If the number of instantLock is true for 2^IfLockThrCounter in a row, the PLL is locked in the initial status." + address: + - 30 + mask: + - 0xF + pixel: 0 + stat: 0 + default: 0xB + +IfReLockThrCounter: + doc: "If the number of instantLock is true for 2^IfReLockThrCounter in a row, the PLL is relocked before the unlock status is confirmed." + address: + - 30 + mask: + - 0xF0 + pixel: 0 + stat: 0 + default: 0xB + +IfUnLockThrCounter: + doc: "If the number of instantLock is false for 2^IfUnLockThrCounter in a row, the PLL is unlocked." + address: + - 31 + mask: + - 0xF + pixel: 0 + stat: 0 + default: 0xB + +asyAlignFastcommand: + doc: |- + The fast command bit clock alignment command is issued by I2C. + Used in self-alignment only. + Initializing the clock phase alignment process at its rising edge (synchronized by the 40 MHz PLL clock) + address: + - 13 + mask: + - 0x20 + pixel: 0 + stat: 0 + default: 0x0 + +asyLinkReset: + doc: "Link reset signal from I2C, active high. If it is high, ETROC2 sends test pattern via link." + address: + - 13 + mask: + - 0x40 + pixel: 0 + stat: 0 + default: 0x0 + +asyPLLReset: + doc: "Reset PLL AFC from I2C, active low." + address: + - 13 + mask: + - 0x80 + pixel: 0 + stat: 0 + default: 0x1 + +asyResetChargeInj: + doc: "Reset charge injection module, active low." + address: + - 14 + mask: + - 0x20 + pixel: 0 + stat: 0 + default: 0x1 + +asyResetFastcommand: + doc: "Reset fastcommand from I2C, active low." + address: + - 14 + mask: + - 0x40 + pixel: 0 + stat: 0 + default: 0x1 + +asyResetGlobalReadout: + doc: "Reset globalReadout module, active low." + address: + - 14 + mask: + - 0x80 + pixel: 0 + stat: 0 + default: 0x1 + +asyResetLockDetect: + doc: "Reset lock detect, active low (original lockDetect reset is active high, polarity changed)" + address: + - 15 + mask: + - 0x20 + pixel: 0 + stat: 0 + default: 0x1 + +asyStartCalibration: + doc: "Start PLL calibration process, active high." + address: + - 15 + mask: + - 0x40 + pixel: 0 + stat: 0 + default: 0x1 + +VRefGen_PD: + doc: |- + Power down voltage reference generator, active high. + 1'b1: the voltage reference generator is down. + 1'b0: the voltage reference generator is up. + address: + - 3 + mask: + - 0x80 + pixel: 0 + stat: 0 + default: 0x0 + +TS_PD: + doc: |- + Power down the temperature sensor, active high. + 1'b1: the temperature sensor is down; + 1'b0: the temperature sensor is up. + address: + - 4 + mask: + - 0x80 + pixel: 0 + stat: 0 + default: 0x0 + +TDCClockTest: + doc: |- + The TDC clock testing enable. + 1'b1: sending TDC clock at the left serial port; + 1'b0: sending left serializer data at the left port. + address: + - 31 + mask: + - 0x10 + pixel: 0 + stat: 0 + default: 0x0 + +TDCStrobeTest: + doc: |- + The TDC reference strobe testing enable. + 1'b1: sending TDC reference strobe at the right serial port; + 1'b0: sending right serializer data at the right port. + address: + - 31 + mask: + - 0x20 + pixel: 0 + stat: 0 + default: 0x0 + +LTx_AmplSel: + doc: |- + Left Tx amplitude selection. + 3'b000: min amplitude (50 mV) + 3'b111: max amplitude (320 mV) + Step size is about 40 mV. + address: + - 16 + mask: + - 0xE0 + pixel: 0 + stat: 0 + default: 0x4 + +RTx_AmplSel: + doc: |- + Right Tx amplitude selection. + 3'b000: min amplitude (50 mV) + 3'b111: max amplitude (320 mV) + Step size is about 40 mV. + address: + - 17 + mask: + - 0xE0 + pixel: 0 + stat: 0 + default: 0x4 + +disLTx: + doc: "Left Tx disable, active high." + address: + - 18 + mask: + - 0x80 + pixel: 0 + stat: 0 + default: 0x0 + +disRTx: + doc: "Right Tx disable, active high." + address: + - 19 + mask: + - 0x80 + pixel: 0 + stat: 0 + default: 0x0 + +GRO_TOARST_N: + doc: "GRO TOA reset, active low." + address: + - 7 + mask: + - 0x80 + pixel: 0 + stat: 0 + default: 0x1 + +GRO_Start: + doc: "GRO Start, active high." + address: + - 7 + mask: + - 0x40 + pixel: 0 + stat: 0 + default: 0x0 + +GRO_TOA_Latch: + doc: "GRO TOA latch clock." + address: + - 8 + mask: + - 0x80 + pixel: 0 + stat: 0 + default: 0x1 + +GRO_TOA_CK: + doc: "GRO TOA clock." + address: + - 8 + mask: + - 0x40 + pixel: 0 + stat: 0 + default: 0x1 + +GRO_TOT_CK: + doc: "GRO TOT clock." # Potential name mismatch of registers between page 58 and page 60 of Users manual + address: + - 9 + mask: + - 0x80 + pixel: 0 + stat: 0 + default: 0x1 + +GRO_TOTRST_N: + doc: "GRO TOT reset, active low." + address: + - 9 + mask: + - 0x40 + pixel: 0 + stat: 0 + default: 0x1 + +############################################ +######## Peripheral Status Registers ####### +############################################ + +fcBitAlignError: + doc: "Bit alignment error" + address: + - 2 + mask: + - 0x1 + pixel: 0 + stat: 1 + +PS_Late: + doc: "Phase shifter late" + address: + - 0 + mask: + - 0x80 + pixel: 0 + stat: 1 + +AFCcalCap: + doc: "AFC capacitance" + address: + - 0 + mask: + - 0x7E + pixel: 0 + stat: 1 + +AFCBusy: + doc: "AFC busy, 1: AFC is ongoing, 0: AFC is done" + address: + - 0 + mask: + - 0x1 + pixel: 0 + stat: 1 + +fcAlignFinalState: + doc: "Fast command alignment FSM state" + address: + - 1 + mask: + - 0xF0 + pixel: 0 + stat: 1 + +controllerState: + doc: "Global control FSM state" + address: + - 1 + mask: + - 0xF + pixel: 0 + stat: 1 + +fcAlignStatus: + doc: "Fast command self-alignment error indicator, ed[3:0] in figure 53" + address: + - 2 + mask: + - 0xF0 + pixel: 0 + stat: 1 + +invalidFCCount: + doc: "Count of invalid fast command received" + address: + - 3 + - 4 + mask: + - 0xFF + - 0xF + pixel: 0 + stat: 1 + +pllUnlockCount: + doc: "Count of PLL unlock detected" + address: + - 4 + - 5 + mask: + - 0xF0 + - 0xFF + pixel: 0 + stat: 1 + +EFuseQ: + doc: "32-bit EFuse output" + address: + - 6 + - 7 + - 8 + - 9 + mask: + - 0xFF + - 0xFF + - 0xFF + - 0xFF + pixel: 0 + stat: 1 -- GitLab From 338c942a751f2b47c8711245e17923d93728f34a Mon Sep 17 00:00:00 2001 From: Diego Lopez Gutierrez <dlopezgu@bu.edu> Date: Mon, 1 May 2023 13:53:17 -0400 Subject: [PATCH 2/4] Add functions in ETROC.py for every register available in ETROC2 --- tamalero/ETROC.py | 1058 +++++++++++++++++++++++++++++++++++++++------ 1 file changed, 922 insertions(+), 136 deletions(-) diff --git a/tamalero/ETROC.py b/tamalero/ETROC.py index 7495c88..89517aa 100644 --- a/tamalero/ETROC.py +++ b/tamalero/ETROC.py @@ -218,7 +218,9 @@ class ETROC(): self.wr_reg('mergeTriggerData', 0) self.wr_reg('disScrambler', 1) + # *********************** # *** IN-PIXEL CONFIG *** + # *********************** # (FOR ALL PIXELS) set/get load capacitance of preamp first stage # 0, 80, 80, or 160 fC FIXME typo? 80 appears twice in doc @@ -280,200 +282,984 @@ class ETROC(): self.wr_reg('PD_DACDiscri', 1, row=row, col=col) # (FOR ALL PIXELS) set/get injected charge - # 1 ~ 36 fC, typical charge is 7fC - def set_Qinj(self, C): + # 1 ~ 32 fC, typical charge is 7fC + def set_Qinj(self, C, row=0, col=0, broadcast=True): if C > 32: raise Exception('Injected charge should be < 32 fC.') - self.wr_reg('QSel', 0, C-1) + self.wr_reg('QSel', C-1, row=row, col=col, broadcast=broadcast) - def get_Qinj(self): - return self.rd_reg('QSel', 0)+1 + def get_Qinj(self, row=0, col=0): + return self.rd_reg('QSel', row=row, col=col) - # enable/disable charge injection - def enable_Qinj(self, pix): - self.wr_reg('QInjEn', pix, 1) + # (FOR ALL PIXELS) enable/disable charge injection + def enable_Qinj(self, row=0, col=0, broadcast=True): + self.wr_reg('QInjEn', 1, row=row, col=col, broadcast=broadcast) - def disable_Qinj(self, pix): - self.wr_reg('QInjEn', pix, 0) + def disable_Qinj(self, row=0, col=0, broadcast=True): + self.wr_reg('QInjEn', 0, row=row, col=col, broadcast=broadcast) - # TDC control - def autoReset_TDC(self, pix): - self.wr_reg('autoReset_TDC', pix, 1) + # (FOR ALL PIXELS) TDC control + # TDC automatically reset controller for every clock period + def autoReset_TDC(self, row=0, col=0, broadcast=True): + self.wr_reg('autoReset_TDC', 1, row=row, col=col, broadcast=broadcast) - def enable_TDC(self, pix): - self.wr_reg('enable_TDC', pix, 1) + # enable/disable TDC conversion + def enable_TDC(self, row=0, col=0, broadcast=True): + self.wr_reg('enable_TDC', 1, row=row, col=col, broadcast=broadcast) - def disable_TDC(self, pix): - self.wr_reg('enable_TDC', pix, 0) + def disable_TDC(self, row=0, col=0, broadcast=True): + self.wr_reg('enable_TDC', 0, row=row, col=col, broadcast=broadcast) - def set_level_TDC(self, pix, w): + # Bit width of bubble tolerant in TDC encode + def set_level_TDC(self, w, row=0, col=0, broadcast=True): if w > 0b011: raise Exception('bit width can be up to 0b011.') - self.wr_reg('level_TDC', pix, w) - - def get_level_TDC(self, pix): - return self.rd_reg('level_TDC', pix) - - def reset_TDC(self, pix): - self.wr_reg('resetn_TDC', pix, 1) #FIXME reg name has typo in doc? - - def enable_TDC_testMode(self, pix): - self.wr_reg('testMode_TDC', pix, 1) - - def disable_TDC_testMode(self, pix): - self.wr_reg('testMode_TDC', pix, 0) - - # threshold callibration - def bypass_THCal(self, pix): - self.wr_reg('Bypass_THCal', pix, 1) - - def apply_THCal(self, pix): - self.wr_reg('Bypass_THCal', pix, 0) - - def set_Vth_pix(self, pix, vth): - self.wr_reg('DAC', vth, pix) - - def set_Vth_mV(self, vth, row=0, col=0, broadcast=True): - # FIXME this needs to be understood - # Pretend that we set the threshold and then the "DAC" register - # sets the threshold in offset_step/2**10 steps? - offset_step = (1000/2**6) - th_step = offset_step/2**10 - offset = int(vth/offset_step) - residual = vth - offset*offset_step - th = round(residual/th_step) - self.wr_reg('TH_offset', offset, row=row, col=col, broadcast=broadcast) - self.wr_reg('DAC', th, row=row, col=col, broadcast=broadcast) - #if self.usefake: - # self.fakeETROC.data['vth'] = vth - # print("Vth set to %f."%vth) - #else: - # v = vth # FIXME: convert from mV to bit representation - # self.wr_reg('DAC', vth, pix) - - def get_Vth_mV(self, row=0, col=0): - offset_step = (1000/2**6) - th_step = offset_step/2**10 - offset = self.rd_reg('TH_offset', row=row, col=col) - th = self.rd_reg('DAC', row=row, col=col) - return offset*offset_step + th*th_step - - def set_THoffset(self, pix, V): - self.wr_reg('TH_offset', pix, V) - - def reset_THCal(self, pix): - self.wr_reg('RSTn_THCal', pix, 1) - - def init_THCal(self, pix): #FIXME better name? - self.wr_reg('ScanStart_THCal', pix, 1) - - def enable_THCal_buffer(self, pix): - self.wr_reg('BufEn_THCal', pix, 1) - - def disable_THCal_buffer(self, pix): - self.wr_reg('BufEn_THCal', pix, 0) - - def enable_THCal_clock(self, pix): - self.wr_reg('CLKEn_THCal', pix, 1) - - def disable_THCal_clock(self, pix): - self.wr_reg('CLKEn_THCal', pix, 0) - - def set_workMode(self, pix, mode): + self.wr_reg('level_TDC', w, row=row, col=col, broadcast=broadcast) + + def get_level_TDC(self, row=0, col=0): + return self.rd_reg('level_TDC', row=row, col=col) + + # Reset TDC encoder, active low + def reset_TDC(self, row=0, col=0, broadcast=True): + self.wr_reg('resetn_TDC', 0, row=row, col=col, broadcast=broadcast) #FIXME reg name has typo in doc? + + # enable/disable test mode where TDC generates a fixed test pulse as input signal for test for every 25 ns + def enable_TDC_testMode(self, row=0, col=0, broadcast=True): + self.wr_reg('testMode_TDC', 1, row=row, col=col, broadcast=broadcast) + + def disable_TDC_testMode(self, row=0, col=0, broadcast=True): + self.wr_reg('testMode_TDC', 0, row=row, col=col, broadcast=broadcast) + + # (FOR ALL PIXELS) THCal control + # Bypass/apply in-pixel threshold calibration block + def bypass_THCal(self, row=0, col=0, broadcast=True): + self.wr_reg('Bypass_THCal', 1, row=row, col=col, broadcast=broadcast) + + def apply_THCal(self, row=0, col=0, broadcast=True): + self.wr_reg('Bypass_THCal', 0, row=row, col=col, broadcast=broadcast) + + # When Bypass_THCal = 1, TH = DAC + def set_Vth_pix(self, vth, row=0, col=0, broadcast=True): + self.wr_reg('DAC', vth, row=row, col=col, broadcast=broadcast) + + def get_Vth_pix(self, row=0, col=0): + return self.rd_reg('DAC', row=row, col=col) +# def set_Vth_mV(self, vth, row=0, col=0, broadcast=True): +# # FIXME this needs to be understood +# # Pretend that we set the threshold and then the "DAC" register +# # sets the threshold in offset_step/2**10 steps? +# offset_step = (1000/2**6) +# th_step = offset_step/2**10 +# offset = int(vth/offset_step) +# residual = vth - offset*offset_step +# th = round(residual/th_step) +# self.wr_reg('TH_offset', offset, row=row, col=col, broadcast=broadcast) +# self.wr_reg('DAC', th, row=row, col=col, broadcast=broadcast) +# #if self.usefake: +# # self.fakeETROC.data['vth'] = vth +# # print("Vth set to %f."%vth) +# #else: +# # v = vth # FIXME: convert from mV to bit representation +# # self.wr_reg('DAC', vth, pix) +# +# def get_Vth_mV(self, row=0, col=0): +# offset_step = (1000/2**6) +# th_step = offset_step/2**10 +# offset = self.rd_reg('TH_offset', row=row, col=col) +# th = self.rd_reg('DAC', row=row, col=col) +# return offset*offset_step + th*th_step + + # Threshold offset for calibrated baseline. TH = BL + TH_offset + def set_THoffset(self, V, row=0, col=0, broadcast=True): + self.wr_reg('TH_offset', V, row=row, col=col, broadcast=broadcast) + + def get_THoffset(self, row=0, col=0): + return self.rd_reg('TH_offset', row=row, col=col) + + # Reset of threshold calibration block, active low + def reset_THCal(self, row=0, col=0, broadcast=True): + self.wr_reg('RSTn_THCal', 0, row=row, col=col, broadcast=broadcast) + + # Initialize threshold calibration + def init_THCal(self, row=0, col=0, broadcast=True): #FIXME better name? + self.wr_reg('ScanStart_THCal', 1, row=row, col=col, broadcast=broadcast) + + # Enable/disable threshold calibration buffer + def enable_THCal_buffer(self, row=0, col=0, broadcast=True): + self.wr_reg('BufEn_THCal', 1, row=row, col=col, broadcast=broadcast) + + def disable_THCal_buffer(self, row=0, col=0, broadcast=True): + self.wr_reg('BufEn_THCal', 0, row=row, col=col, broadcast=broadcast) + + # Enable/disable threshold calibration clock. Only used when threshold calibration clock is bypassed. + def enable_THCal_clock(self, row=0, col=0, broadcast=True): + self.wr_reg('CLKEn_THCal', 1, row=row, col=col, broadcast=broadcast) + + def disable_THCal_clock(self, row=0, col=0, broadcast=True): + self.wr_reg('CLKEn_THCal', 0, row=row, col=col, broadcast=broadcast) + + # (FOR ALL PIXELS) Readout control + # Readout work mode selection + def set_workMode(self, mode, row=0, col=0, broadcast=True): val = {'normal': 0b00, 'self test fixed': 0b01, 'self test random': 0b10} try: - self.wr_reg('workMode', pix, val(mode)) + self.wr_reg('workMode', val(mode), row=row, col=col, broadcast=broadcast) except KeyError: print('Choose between \'normal\', \'self test fixed\', \'self test random\'.') - def get_workMode(self, pix): + def get_workMode(self, row=0, col=0): val = {0b00:'normal', 0b01:'self test fixed', 0b10:'self test random'} - return val[self.wr_reg('workMod', pix)] + return val[self.wr_reg('workMode', row=row, col=col)] - def set_L1Adelay(self, pix, delay): - self.wr_reg('L1Adelay', pix, delay) + # L1A latency + def set_L1Adelay(self, delay, row=0, col=0, broadcast=True): + self.wr_reg('L1Adelay', delay, row=row, col=col, broadcast=broadcast) - def get_L1Adelay(self, pix): - return self.rd_reg('L1Adelay', pix) + def get_L1Adelay(self, row=0, col=0): + return self.rd_reg('L1Adelay', row=row, col=col) - def enable_data_readout(self, pix): - self.wr_reg('disDataReadout', pix, 0) + # Enable/disable TDC data readout of current pixel + def enable_data_readout(self, row=0, col=0, broadcast=True): + self.wr_reg('disDataReadout', 0, row=row, col=col, broadcast=broadcast) - def disable_data_readout(self, pix): - self.wr_reg('disDataReadout', pix, 1) + def disable_data_readout(self, row=0, col=0, broadcast=True): + self.wr_reg('disDataReadout', 1, row=row, col=col, broadcast=broadcast) - def enable_trigger_readout(self, pix): - self.wr_reg('disTrigPath', pix, 0) + # Enable/disable trigger readout of current pixel + def enable_trigger_readout(self, row=0, col=0, broadcast=True): + self.wr_reg('disTrigPath', 0, row=row, col=col, broadcast=broadcast) - def disable_trigger_readout(self, pix): - self.wr_reg('disTrigPath', pix, 1) + def disable_trigger_readout(self, row=0, col=0, broadcast=True): + self.wr_reg('disTrigPath', 1, row=row, col=col, broadcast=broadcast) - def set_trigger_TH(self, pix, datatype, upper=None, lower=None): + # Set upper/lower thresholds for trigger readout of TOA, TOT, Cal + def set_trigger_TH(self, datatype, upper=None, lower=None, row=0, col=0, broadcast=True): if datatype not in ['TOA', 'TOT', 'Cal']: raise Exception('type of data should be TOA, TOT or CAL.') if upper is not None: - self.wr_reg('upper'+data+'Trig', pix, upper) + self.wr_reg('upper'+data+'Trig', upper, row=row, col=col, broadcast=broadcast) if lower is not None: - self.wr_reg('lower'+data+'Trig', pix, lower) + self.wr_reg('lower'+data+'Trig', lower, row=row, col=col, broadcast=broadcast) - def get_trigger_TH(self, pix, datatype): + def get_trigger_TH(self, datatype, row=0, col=0): if datatype not in ['TOA', 'TOT', 'Cal']: raise Exception('type of data should be TOA, TOT or CAL.') upper = 'upper'+data+'Trig' lower = 'lower'+data+'Trig' - return self.rd_reg(upper, pix), self.rd_reg(lower, pix) + return self.rd_reg(upper, row=row, col=col), self.rd_reg(lower, row=row, col=col) - def set_data_TH(self, pix, datatype, upper=None, lower=None): + # Set upper/lower thresholds for TDC data readout of TOA, TOT, Cal + def set_data_TH(self, datatype, upper=None, lower=None, row=0, col=0, broadcast=True): if datatype not in ['TOA', 'TOT', 'Cal']: raise Exception('type of data should be TOA, TOT or CAL.') if upper is not None: - self.wr_reg('upper'+data, pix, upper) + self.wr_reg('upper'+data, upper, row=row, col=col, broadcast=broadcast) if lower is not None: - self.wr_reg('lower'+data, pix, lower) + self.wr_reg('lower'+data, lower, row=row, col=col, broadcast=broadcast) - def get_data_TH(self, pix, datatype): + def get_data_TH(self, datatype, row=0, col=0): if datatype not in ['TOA', 'TOT', 'Cal']: raise Exception('type of data should be TOA, TOT or CAL.') upper = 'upper'+data lower = 'lower'+data - return self.rd_reg(upper, pix), self.rd_reg(lower, pix) + return self.rd_reg(upper, row=row, col=col), self.rd_reg(lower, row=row, col=col) - def enable_adr_offset(self, pix): - self.wr_reg('addrOffset', pix, 1) + # Enable/disable circular buffer write address offset + def enable_adr_offset(self, row=0, col=0, broadcast=True): + self.wr_reg('addrOffset', 1, row=row, col=col, broadcast=broadcast) - def disable_adr_offset(self, pix): - self.wr_reg('addrOffset', pix, 0) + def disable_adr_offset(self, row=0, col=0, broadcast=True): + self.wr_reg('addrOffset', 0, row=row, col=col, broadcast=broadcast) - def set_selftest_occupancy(self, pix, occ): - self.wr_reg('selfTestOccupancy', pix, occ) + # Self-test data occupancy is selfTestOccupancy[6:0]/128 + def set_selftest_occupancy(self, occ, row=0, col=0, broadcast=True): + self.wr_reg('selfTestOccupancy', occ, row=row, col=col, broadcast=broadcast) - def get_selftest_occupancy(self, pix): - return self.rd_reg('selfTestOccupancy', pix) + def get_selftest_occupancy(self, row=0, col=0): + return self.rd_reg('selfTestOccupancy', row=row, col=col) + # *********************** # *** IN-PIXEL STATUS *** + # *********************** - def get_ACC(self, pix): - return self.rd_reg('ACC', pix) + # (FOR ALL PIXELS) Accumulator of the threshold calibration + def get_ACC(self, row=0, col=0): + return self.rd_reg('ACC', row=row, col=col) - def is_scanDone(self, pix): - result = self.rd_reg('ScanDone', pix) + # (FOR ALL PIXELS) Scan done signal of the threshold calibration + def is_scanDone(self, row=0, col=0): + result = self.rd_reg('ScanDone', row=row, col=col) if result == 1: return True else: return False - def get_baseline(self, pix): - return self.rd_reg('BL', pix) + # (FOR ALL PIXELS) Baseline obtained from threshold calibration + def get_baseline(self, row=0, col=0): + return self.rd_reg('BL', row=row, col=col) + + # (FOR ALL PIXELS) Noise width from threshold calibration. Expect less than 10. + def get_noisewidth(self, row=0, col=0): + return self.rd_reg('NW', row=row, col=col) + + # (FOR ALL PIXELS) 10-bit threshold applied to the DAC input + def get_threshold(self, row=0, col=0): + return self.rd_reg('TH', row=row, col=col) + + # (FOR ALL PIXELS) Threshold calibration state machine output + def get_THstate(self, row=0, col=0): + return self.rd_reg('THstate', row=row, col=col) + + # (FOR ALL PIXELS) Col[3:0], Row[3:0] + def get_pixelID(self, row=0, col=0): + return self.rd_reg('PixelID', row=row, col=col) + + # *********************** + # **** PERIPH CONFIG **** + # *********************** + + # Phase delay of readout clock, 780 ps a step (Pixel or Global) + def set_readoutClkDelay(self, clk, delay): + if clk not in ['Pixel', 'Global']: + raise Exception('Clock should be either Pixel or Global') + self.wr_reg('readoutClockDelay'+clk, delay) + + def get_readoutClkDelay(self, clk): + if clk not in ['Pixel', 'Global']: + raise Exception('Clock should be either Pixel or Global') + return self.rd_reg('readoutClockDelay'+clk) + + # Positive pulse width of readout clock, 780 ps a step (Pixel or Global) + def set_readoutClkWidth(self, clk, width): + if clk not in ['Pixel', 'Global']: + raise Exception('Clock should be either Pixel or Global') + self.wr_reg('readoutClockWidth'+clk, width) + + def get_readoutClkWidth(self, clk): + if clk not in ['Pixel', 'Global']: + raise Exception('Clock should be either Pixel or Global') + return self.rd_reg('readoutClockWidth'+clk) + + # Data rate selection of Right or Left serial port + def set_dataRate(self, port, rate): + if port not in ['Left', 'Right']: + raise Exception('Choose between Left or Right serial port') + val = {320:0b00, 640:0b01, 1280:0b10} + try: + self.wr_reg('serRate'+port, val[rate]) + except KeyError: + print('Choose between rates of 320 Mbps, 640 Mbps and 1280 Mbps') + + def get_dataRate(self, port): + if port not in ['Left', 'Right']: + raise Exception('Choose between Left or Right serial port') + val = {0b00:320, 0b01:640, 0b10:1280} + return val[self.rd_reg('serRate'+port)] + + # Link reset test pattern selection + def set_linkResetTestPattern(self, mode): + val = {'PRBS':0b0, 'Fixed pattern':0b1} + try: + self.wr_reg('linkResetTestPattern', val[mode]) + except KeyError: + print('Choose between \'PRBS\' and \'Fixed pattern\' selections') + + def get_linkResetTestPattern(self): + val = {0b0:'PRBS', 0b1:'Fixed pattern'} + return val[self.rd_reg('linkResetTestPattern')] + + # User-specified pattern to be sent during link reset, LSB first + def set_linkResetFixedPattern(self, pattern): + self.wr_reg('linkResetFixedPattern', pattern) + + def get_linkResetFixedPattern(self): + return self.rd_reg('linkResetFixedPattern') + + # Empty BCID slot for synchronization + def set_BCID(self, bcid): + self.wr_reg('emptySlotBCID', bcid) + + def get_BCID(self): + return self.rd_reg('emptySlotBCID') + + # Trigger data size, can be 0, 1, 2, 4, 8, 16 + def set_triggerGranularity(self, size): + val = {0:0, 1:1, 2:2, 4:3, 8:4, 16:5} + try: + self.wr_reg('triggerGranularity', val[size]) + except KeyError: + print('Trigger data size can only be 0, 1, 2, 4, 8 or 16') + + def get_triggerGranularity(self): + val = {0:0, 1:1, 2:2, 3:4, 4:8, 5:16, 6:0, 7:0} + return val[self.rd_reg('triggerGranularity')] + + # Enable/disable scrambler + def enable_Scrambler(self): + self.wr_reg('disScrambler', 0) + + def disable_Scrambler(self): + self.wr_reg('disScrambler', 1) + + # Merge trigger and data in a port + def set_mergeTriggerData(self, mode): + val = {'separate':0, 'merge':1} + if (self.get_singlePort == 'right') and (mode == 'separate'): + raise Exception('Trigger and data in separate ports is only allowed when singlePort is set to \'both\'') + try: + self.wr_reg('mergeTriggerData', val[mode]) + except KeyError: + print('Choose between \'merge\' and \'separate\' options') + + def get_mergeTriggerData(self): + val = {0: 'separate', 1:'merge'} + return val[self.rd_reg('mergeTriggerData')] + + # Enable single port (right) or both ports + def set_singlePort(self, mode): + val = {'both':0, 'right':1} + try: + self.wr_reg('singlePort', val[mode]) + except KeyError: + print('Choose between \'both\' and \'right\' options') + + def get_singlePort(self): + val = {0:'both', 1:'right'} + return val[self.rd_reg('singlePort')] + + # On-chip L1A mode + def set_l1aMode(self, mode): + val = {'disable':0b00, 'periodic':0b10, 'random':0b11} + try: + self.wr_reg('onChipL1AConf', val[mode]) + except KeyError: + print('Choose between \'disable\', \'periodic\' and \'random\' options') + + def get_l1aMode(self): + val = {0b00:'disable', 0b10:'periodic', 0b11:'random', 0b01:'disable'} + return val[self.rd_reg('onChipL1AConf')] + + # BCID when BCID is reset + def set_BCIDoffset(self, offset): + self.wr_reg('BCIDoffset', offset) + + def get_BCIDoffset(self, offset): + self.rd_reg('BCIDoffset') + + # Fast command decoder self-alignment or manual alignment + def set_fcAlign(self, mode): + val = {'manual':0, 'self':1} + try: + self.wr_reg('fcSelfAlignEn', val[mode]) + except KeyError: + print('Choose between \'manual\' and \'self\' options') + + def get_fcAlign(self): + val = {0:'manual', 1:'self'} + return val[self.rd_reg('fcSelfAlignEn')] + + # Enable/disable clock delay in fast command manual alignment mode + def enable_fcClkDelay(self): + assert self.get_fcAlign() == 'manual' + self.wr_reg('fcClkDelayEn', 1) + + def disable_fcClkDelay(self): + assert self.get_fcAlign() == 'manual' + self.wr_reg('fcClkDelayEn', 0) + + # Enable/disable data delay in fast command manual alignment mode, active high + def enable_fcDataDelay(self): + assert self.get_fcAlign() == 'manual' + self.wr_reg('fcDataDelayEn', 1) + + def disable_fcDataDelay(self): + assert self.get_fcAlign() == 'manual' + self.wr_reg('fcDataDelayEn', 0) + + # The charge injection delay to the 40 MHz clock rising edge. Start from rising edge + # of 40 MHz clock, each step 781 ps. The pulse width is fixed of 50 ns. + def set_chargeInjDelay(self, delay): + self.wr_reg('chargeInjectionDelay', delay) + + def get_chargeInjDelay(self): + return self.rd_reg('chargeInjectionDelay') + + # TDC Reference strobe selection + def set_refStr(self, refStr): + self.wr_reg('RefStrSel', refStr) + + def get_refStr(self): + return self.rd_reg('RefStrSel') + + # Charge pump bias current selection, [0:8:120] uA. Debugging use only. + def set_PLLBiasGen(self, bias): + self.wr_reg('PLL_BIASGEN_CONFIG', bias) + + def get_PLLBiasGen(self): + return self.rd_reg('PLL_BIASGEN_CONFIG') + + # Bias current selection of the I-filter (0:1.1:8 uA) or P-filter (0:5.46:82 uA) unit cell in PLL mod. Debugging use only. + def set_PLLConfig(self, filt, bias): + if filt not in ['I', 'P']: + raise Exception('Choose between \'I\' or \'P\' filter') + self.wr_reg('PLL_CONFIG_'+filt+'_PLL', bias) + + def get_PLLConfig(self, filt): + if filt not in ['I', 'P']: + raise Exception('Choose between \'I\' or \'P\' filter') + return self.rd_reg('PLL_CONFIG_'+filt+'_PLL') + + # Resistor selection of the P-path in PLL mode [R=1/2*79.8k/CONFIG] Ohm. Debugging use only. + def set_PLLRes(self, R): + config = 1 / (2 * 79.8e3) / R + self.wr_reg('PLL_R_CONFIG', config) + + def get_PLLRes(self): + config = self.rd_reg('PLL_R_CONFIG') + R = 1 / (2 * 79.8e3) / config + return R + + # Bias current selection of the VCO core [0:0.470:7.1] mA. Debugging use only. + def set_PLLvco(self, bias): + self.wr_reg('PLL_vcoDAC', bias) + + def get_PLLvco(self): + return self.rd_reg('PLL_vcoDAC') + + # Output rail-to-rail mode selection of the VCO, active low. Debugging use only. + def set_PLLvcoRail(self, mode): + if mode not in ['rail', 'CML']: + raise Exception('Chose between \'rail\' and \'CML\' options') + val = {'rail':0, 'CML':1} + self.wr_reg('PLL_vcoRailMode', val[mode]) + + def get_PLLvcoRail(self): + val = {0:'rail', 'CML':1} + return val[self.rd_reg('PLL_vcoRailMode')] + + # Enable/disable PLL mode, active high. Debugging use only. + def enable_PLL(self): + self.wr_reg('PLL_ENABLEPLL', 1) + + def disable_PLL(self): + self.wr_reg('PLL_ENABLEPLL', 0) + + # Adjusting the phase of the output clk1G28 of freqPrescaler in the feedback + # divider (N=64) by one skip from low to high. Debugging use only. + def set_PLLFBDiv(self, skip): + self.wr_reg('PLL_FBDiv_skip', skip) + + def get_PLLFBDiv(self): + return self.rd_reg('PLL_FBDiv_skip') + + # Enable/disable feedback divider + def enable_PLLFB(self): + self.wr_reg('PLL_FBDiv_clkTreeDisable', 0) + + def disable_PLLFB(self): + self.wr_reg('PLL_FBDiv_clkTreeDisable', 1) + + # Enable/disable output clocks for serializer + def enable_PLLclkSer(self): + self.wr_reg('PLLclkgen_disSER', 0) + + def disable_PLLclkSer(self): + self.wr_reg('PLLclkgen_disSER', 1) + + # Enable/disable VCO output buffer (associated with clk5g12lshp, clk5g12lshn), active high. + # clk5g12lsh is the output clock of the first input buffer in prescaler, and the source + # clock for all output clocks. Once disabled, all output clocks are disabled. Debugging use only. + def enable_PLLvcoBuff(self): + self.wr_reg('PLLclkgen_disVCO', 0) + + def disable_PLLvcoBuff(self): + self.wr_reg('PLLclkgen_disVCO', 1) + + # Enable/disable output clocks for EOM, active high. When PLLclkgen_disEOM is high, the following + # clocks are disabled: clk5g12EOMp, clk5g12EOMn. Debugging use only. + def enable_PLLEOM(self): + self.wr_reg('PLLclkgen_disEOM', 0) + + def disable_PLLEOM(self): + self.wr_reg('PLLclkgen_disEOM', 1) + + # Enable/disable the internal clock buffers and 1/2 clock divider in prescaler, active high. When + # PLLclkgen_disCLK is high, all output clocks are disabled. Debugging use only. + def enable_PLLclk(self): + self.wr_reg('PLLclkgen_disCLK', 0) + + def disable_PLLclk(self): + self.wr_reg('PLLclkgen_disCLK', 1) + + # Enable/disable output clocks for deserializer, active high. When PLLclkgen_disDES is high, the + # following clocks are disabled: clk2g56Qp, clk2g56Qn, clk2g56lp, clk2g56ln. clk2g56Q is + # the 2.56 GHz clock for test in ETROC_PLL. clk2g56Q is used as WS clock in ETROC2. Debugging use only. + def enable_PLLDes(self): + self.wr_reg('PLLclkgen_disDES', 0) + + def disable_PLLDes(self): + self.wr_reg('PLLclkgen_disDES', 1) + + # Selecting PLL clock or off-chip clock for TDC and readout. Debugging use only. + def set_CLKSel(self, clk): + if clk not in ['off-chip', 'PLL']: + raise Exception('Choose between \'off-chip\' and \'PLL\' options') + val = {'off-chip':0, 'PLL':1} + self.wr_reg('CLKSel', val[clk]) + + def get_CLKSel(self): + val = {0:'off-chip', 1:'PLL'} + return val[self.rd_reg('CLKSel')] + + # Charge pump current control bits, range from 0 to 15uA for charge and discharge. Debugging use only. + def set_CPCurrent(self, current): + self.wr_reg('PS_CPCurrent', current) + + def get_CPCurrent(self): + return self.rd_reg('PS_CPCurrent') + + # Reset the control voltage of DLL to power supply, active high. Debugging use only. + def toggle_CapRst(self): + val = ~self.get_CapRst() + self.wr_reg('PS_CapRst', val) + + def get_CapRst(self): + return self.rd_reg('PS_CapRst') + + # Enable/disable DLL, active high. Debugging use only. + def enable_DLL(self): + self.wr_reg('PS_Enable', 1) + + def disable_DLL(self): + self.wr_reg('PS_Enable', 0) + + # Force to pull down the output of the phase detector, active high. Debugging use only. + def set_PSForceDown(self, boolean): + if not isinstance(boolean, bool): + raise TypeError('Argument must be a boolean') + val = 1 if boolean else 0 + self.wr_reg('PS_ForceDown', val) + + def get_PSForceDown(self): + val = self.rd_reg('PS_ForceDown') + return True if val == 1 else False + + # Phase selecting control bits, PS_PhaseAdj[7:3] for coarse, PS_PhaseAdj[2:0] for fine. + def set_PhaseAdj(self, phase): + self.wr_reg('PS_PhaseAdj', phase) + + def get_PhaseAdj(self): + return self.rd_reg('PS_PhaseAdj') + + # Enable/disable the Rx for the 40 MHz, 1.28 GHz reference clock or the fast command, active high. Debugging use only + def set_Rx(self, mode, boolean): + if not isinstance(boolean, bool): + raise TypeError('Argument must be True (enable) or False (disable)') + val = 1 if boolean else 0 + regs = {40:'CLK40_EnRx', 1280:'CLK1280_EnRx', 'FC':'FC_EnRx'} + try: + self.wr_reg(regs[mode], val) + except KeyError: + print('Choose between 40 (40 MHz ref. clock), 1280 (1.28 GHz ref. clock) and \'FC\' (fast command) options') + + def get_Rx(self, mode): + regs = {40:'CLK40_EnRx', 1280:'CLK1280_EnRx', 'FC':'FC_EnRx'} + try: + return self.rd_reg(regs[mode]) + except KeyError: + print('Choose between 40 (40 MHz ref. clock), 1280 (1.28 GHz ref. clock) and \'FC\' (fast command) options') + + # Enable/disable internal termination of the Rx for the 40 MHz, 1.28 GHz reference clock or the fast command, active high. Debugging use only. + def set_Ter(self, mode, boolean): + if not isinstance(boolean, bool): + raise TypeError('Argument must be True (enable) or False (disable)') + val = 1 if boolean else 0 + regs = {40:'CLK40_EnTer', 1280:'CLK1280_EnTer', 'FC':'FC_EnTer'} + try: + self.wr_reg(regs[mode], val) + except KeyError: + print('Choose between 40 (40 MHz ref. clock), 1280 (1.28 GHz ref. clock) and \'FC\' (fast command) options') + + def get_Ter(self, mode): + regs = {40:'CLK40_EnTer', 1280:'CLK1280_EnTer', 'FC':'FC_EnTer'} + try: + return self.rd_reg(regs[mode]) + except KeyError: + print('Choose between 40 (40 MHz ref. clock), 1280 (1.28 GHz ref. clock) and \'FC\' (fast command) options') + + # Equalization strength of the Rx for the 40 MHz, 1.28 GHz reference clock or the fast command. Debugging use only. + # 2'b00: equalization is turned off; 2'b11: maximal equalization. + def set_Equ(self, mode, equalization): + regs = {40:'CLK40_Equ', 1280:'CLK1280_Equ', 'FC':'FC_Equ'} + try: + self.wr_reg(regs[mode], equalization) + except KeyError: + print('Choose between 40 (40 MHz ref. clock), 1280 (1.28 GHz ref. clock) and \'FC\' (fast command) options for \'mode\' arg.') + + def get_Equ(self, mode): + regs = {40:'CLK40_Equ', 1280:'CLK1280_Equ', 'FC':'FC_Equ'} + try: + return self.rd_reg(regs[mode]) + except KeyError: + print('Choose between 40 (40 MHz ref. clock), 1280 (1.28 GHz ref. clock) and \'FC\' (fast command) options') + + # Inverting data of the Rx for the 40 MHz, 1.28 GHz reference clock or the fast command, active high. Debugging use only. + def set_Inv(self, mode, boolean): + if not isinstance(boolean, bool): + raise TypeError('Argument must be True (invert) or False (don\'t invert)') + val = 1 if boolean else 0 + regs = {40:'CLK40_InvData', 1280:'CLK1280_InvData', 'FC':'FC_InvData'} + try: + self.wr_reg(regs[mode], val) + except KeyError: + print('Choose between 40 (40 MHz ref. clock), 1280 (1.28 GHz ref. clock) and \'FC\' (fast command) options') + + def get_Inv(self, mode): + regs = {40:'CLK40_InvData', 1280:'CLK1280_InvData', 'FC':'FC_InvData'} + try: + return self.rd_reg(regs[mode]) + except KeyError: + print('Choose between 40 (40 MHz ref. clock), 1280 (1.28 GHz ref. clock) and \'FC\' (fast command) options') + + # Set common voltage of the Rx for the 40 MHz, 1.28 GHz reference clock or the fast command to 1/2 vdd, active high. Debugging use only. + def set_commonV(self, mode, boolean): + if not isinstance(boolean, bool): + raise TypeError('Argument must be True (set) or False (don\'t set)') + val = 1 if boolean else 0 + regs = {40:'CLK40_SetCM', 1280:'CLK1280_SetCM', 'FC':'FC_SetCM'} + try: + self.wr_reg(regs[mode], val) + except KeyError: + print('Choose between 40 (40 MHz ref. clock), 1280 (1.28 GHz ref. clock) and \'FC\' (fast command) options') + + def get_commonV(self, mode): + regs = {40:'CLK40_SetCM', 1280:'CLK1280_SetCM', 'FC':'FC_SetCM'} + try: + return self.rd_reg(regs[mode]) + except KeyError: + print('Choose between 40 (40 MHz ref. clock), 1280 (1.28 GHz ref. clock) and \'FC\' (fast command) options') + + # Enable/disable the power up sequence, active high + def enable_PowerUp(self): + self.wr_reg('disPowerSequence', 0) + + def disable_PowerUp(self): + self.wr_reg('disPowerSequence', 1) + + # Reset power sequencer controller, active high + def reset_Power(self): + self.wr_reg('softBoot', 1) + + # The register controlling the SCLK pulse width, ranging ranges from 3 us to 10 us with step of 0.5 us. + # The default value is 4 corresponding to 5 us pulse width. Debugging use only. + def set_SCLKWidth(self, width): + self.wr_reg('EFuse_TCKHP', width) + + def get_SCLKWidth(self): + return self.rd_reg('EFuse_TCKHP') + + # Enable/disable EFuse clock + def enable_EFuseClk(self): + self.wr_reg('EFuse_EnClk', 1) + + def disable_EFuseClk(self): + self.wr_reg('EFuse_EnClk', 0) + + # Operation mode of EFuse. + # 2'b01: programming mode; + # 2'b10: reading mode. + def set_EFuseMode(self, mode): + val = {'programming':0b01, 'reading':0b10} + try: + self.wr_reg('EFuse_Mode', val[mode]) + except KeyError: + print('Choose between \'programming\' and \'reading\' options') + + def get_EFuseMode(self): + val = {0b01:'programming', 0b10:'reading'} + return val[self.rd_reg('EFuse_Mode')] + + # Reset signal of the EFuse controller, active low + def reset_EFuse(self): + self.wr_reg('EFuse_Rstn', 0) + + # Start signal of the EFuse programming. A positive pulse will start the programming + def start_EFuse(self): + self.wr_reg('EFuse_Start', 1) + + # Data to be written into EFuse + def set_EFuseDat(self, data): + self.wr_reg('EFuse_Prog', data) + + def get_EFuseDat(self): + return self.rd_reg('EFuse_Prog') + + # Bypass EFuse. + # 1'b0: EFuse output Q[31:0] is output; + # 1'b1: EFuse raw data from I2C (EFuse_Prog[31:0]) is output + def bypass_EFuse(self, bypass): + if not isinstance(bypass, bool): + raise TypeError('Argument must be True (bypass) or False (don\'t bypass)') + val = 1 if bypass else 0 + self.wr_reg('EFuse_Bypass', val) + + # If the number of instantLock is true for 2^IfLockThrCounter in a row, the PLL is locked in the initial status + def set_IfLockThrCounter(self, counter): + self.wr_reg('IfLockThrCounter', counter) + + def get_IfLockThrCounter(self): + return self.rd_reg('IfLockThrCounter') + + # If the number of instantLock is true for 2^IfReLockThrCounter in a row, the PLL is relocked before the unlock status is confirmed + def set_IfReLockThrCounter(self, counter): + self.wr_reg('IfReLockThrCounter', counter) + + def get_IfReLockThrCounter(self): + return self.rd_reg('IfReLockThrCounter') + + # If the number of instantLock is false for 2^IfUnLockThrCounter in a row, the PLL is unlocked + def set_IfUnLockThrCounter(self, counter): + self.wr_reg('IfUnLockThrCounter', counter) + + def get_IfUnLockThrCounter(self): + return self.rd_reg('IfUnLockThrCounter') + + # The fast command bit clock alignment command is issued by I2C. + # Used in self-alignment only. + # Initializing the clock phase alignment process at its rising edge (synchronized by the 40 MHz PLL clock) + def enable_FCClkPhaseAlign(self): + assert self.get_fcAlign() == 'self' + self.wr_reg('asyAlignFastcommand', 1) + + def disable_FCClkPhaseAlign(self): + assert self.get_fcAlign() == 'self' + self.wr_reg('asyAlignFastcommand', 0) + + # Link reset signal from I2C, active high. If it is high, ETROC2 sends test pattern via link + def set_LinkReset(self, reset): + if not isinstance(reset, bool): + raise TypeError('Argument must be True (reset) or False (don\'t reset)') + val = 1 if reset else 0 + self.wr_reg('asyLinkReset', val) + + def get_LinkReset(self): + return self.rd_reg('asyLinkReset') + + # Reset PLL AFC from I2C, active low + def set_PLLReset(self, reset): + if not isinstance(reset, bool): + raise TypeError('Argument must be True (reset) or False (don\'t reset)') + val = 0 if reset else 1 + self.wr_reg('asyPLLReset', val) + + def get_PLLReset(self): + return self.rd_reg('asyPLLReset') + + # Reset charge injection module, active low + def set_ChargeInjReset(self, reset): + if not isinstance(reset, bool): + raise TypeError('Argument must be True (reset) or False (don\'t reset)') + val = 0 if reset else 1 + self.wr_reg('asyResetChargeInj', val) + + def get_ChargeInjReset(self): + return self.rd_reg('asyResetChargeInj') + + # Reset fastcommand from I2C, active low + def set_FCReset(self, reset): + if not isinstance(reset, bool): + raise TypeError('Argument must be True (reset) or False (don\'t reset)') + val = 0 if reset else 1 + self.wr_reg('asyResetFastcommand', val) + + def get_FCReset(self): + return self.rd_reg('asyResetFastcommand') + + # Reset globalReadout module, active low + def set_GlobalReadoutReset(self, reset): + if not isinstance(reset, bool): + raise TypeError('Argument must be True (reset) or False (don\'t reset)') + val = 0 if reset else 1 + self.wr_reg('asyResetGlobalReadout', val) + + def get_GlobalReadoutReset(self): + return self.rd_reg('asyResetGlobalReadout') + + # Reset lock detect, active low (original lockDetect reset is active high, polarity changed) + def set_LockDetectReset(self, reset): + if not isinstance(reset, bool): + raise TypeError('Argument must be True (reset) or False (don\'t reset)') + val = 0 if reset else 1 + self.wr_reg('asyResetLockDetect', val) + + def get_LockDetectReset(self): + return self.rd_reg('asyResetLockDetect') + + # Start PLL calibration process, active high + def start_PLLCal(self): + self.wr_reg('asyStartCalibration', 1) + + def stop_PLLCal(self): + self.wr_reg('asyStartCalibration', 0) + + # Power down voltage reference generator, active high. + # 1'b1: the voltage reference generator is down. + # 1'b0: the voltage reference generator is up. + def power_up_VRef(self): + self.wr_reg('VRefGen_PD', 0) + + def power_down_VRef(self): + self.wr_reg('VRefGen_PD', 1) + + # Power down the temperature sensor, active high. + # 1'b1: the temperature sensor is down; + # 1'b0: the temperature sensor is up. + def power_up_TempSen(self): + self.wr_reg('TS_PD', 0) + + def power_down_TempSen(self): + self.wr_reg('TS_PD', 1) + + # The TDC clock testing enable. + # 1'b1: sending TDC clock at the left serial port; + # 1'b0: sending left serializer data at the left port. + def enable_TDCClkTest(self): + self.wr_reg('TDCClockTest', 1) + + def disable_TDCClkTest(self): + self.wr_reg('TDCClockTest', 0) + + # The TDC reference strobe testing enable. + # 1'b1: sending TDC reference strobe at the right serial port; + # 1'b0: sending right serializer data at the right port. + def enable_TDCRefStrTest(self): + self.wr_reg('TDCStrobeTest', 1) + + def disable_TDCRefStrTest(self): + self.wr_reg('TDCStrobeTest', 0) + + # Left/Right Tx amplitude selection. + # 3'b000: min amplitude (50 mV) + # 3'b111: max amplitude (320 mV) + # Step size is about 40 mV. + def set_TxAmplSel(self, side, amp): + regs = {'left':'LTx_AmplSel', 'right':'RTx_AmplSel'} + try: + self.wr_reg(regs[side], amp) + except KeyError: + print('Choose between \'left\' or \'right\' side options') + + def get_TxAmplSel(self, side): + regs = {'left':'LTx_AmplSel', 'right':'RTx_AmplSel'} + try: + return self.rd_reg(regs[side]) + except KeyError: + print('Choose between \'left\' or \'right\' side options') + + # Left/Right Tx disable, active high. + def enable_Tx(self, side): + regs = {'left':'disLTx', 'right':'disRTx'} + try: + self.wr_reg(regs[side], 0) + except KeyError: + print('Choose between \'left\' or \'right\' side options') + + def disable_Tx(self, side): + regs = {'left':'disLTx', 'right':'disRTx'} + try: + self.wr_reg(regs[side], 1) + except KeyError: + print('Choose between \'left\' or \'right\' side options') + + # GRO TOA reset, active low + def set_GROTOAReset(self, reset): + if not isinstance(reset, bool): + raise TypeError('Argument must be True (reset) or False (don\'t reset)') + val = 0 if reset else 1 + self.wr_reg('GRO_TOARST_N', val) + + def get_GROTOAReset(self): + return self.rd_reg('GRO_TOARST_N') + + # GRO Start, active high. + def start_GRO(self): + self.wr_reg('GRO_Start', 1) + + def stop_GRO(self): + self.wr_reg('GRO_Start', 0) + + # GRO TOA latch clock. (Guessing this means enable/disable) + def enable_GROTOALatch(self): + self.wr_reg('GRO_TOA_Latch', 1) + + def disable_GROTOALatch(self): + self.wr_reg('GRO_TOA_Latch', 0) + + # GRO TOA clock. + def enable_GROTOAClk(self): + self.wr_reg('GRO_TOA_CK', 1) + + def disable_GROTOAClk(self): + self.wr_reg('GRO_TOA_CK', 0) + + # GRO TOT clock. + def enable_GROTOTClk(self): + self.wr_reg('GRO_TOT_CK', 1) + + def disable_GROTOTClk(self): + self.wr_reg('GRO_TOT_CK', 0) + + # GRO TOT reset, active low. + def set_GROTOTReset(self, reset): + if not isinstance(reset, bool): + raise TypeError('Argument must be True (reset) or False (don\'t reset)') + val = 0 if reset else 1 + self.wr_reg('GRO_TOTRST_N', val) + + def get_GROTOTReset(self): + return self.rd_reg('GRO_TOTRST_N') + + # *********************** + # **** PERIPH STATUS **** + # *********************** + + # Bit alignment error + def get_BitAlignErr(self): + return self.rd_reg('fcBitAlignError') + + # Phase shifter late + def get_PhaseShiftLate(self): + return self.rd_reg('PS_Late') + + # AFC capacitance + def get_AFCCap(self): + return self.rd_reg('AFCcalCap') + + # AFC busy, 1: AFC is ongoing, 0: AFC is done + def get_AFCBusy(self): + return self.rd_reg('AFCBusy') + + # Fast command alignment FSM state + def get_FSM_FCAlign(self): + return self.rd_reg('fcAlignFinalState') + + # Global control FSM state + def get_FSM_GlobCtrl(self): + return self.rd_reg('controllerState') - def get_noisewidth(self, pix): - return self.rd_reg('NW', pix) + # Fast command self-alignment error indicator, ed[3:0] in figure 53 + def get_SelfAlignErr(self): + return self.rd_reg('fcAlignStatus') - def get_threshold(self, pix): - return self.rd_reg('TH', pix) + # Count of invalid fast command received + def get_invalidFCCount(self): + return self.rd_reg('invalidFCCount') - def get_THstate(self, pix): - return self.rd_reg('THstate', pix) + # Count of PLL unlock detected + def get_PLLUnlockCount(self): + return self.rd_reg('pllUnlockCount') - def get_pixelID(self, pix): - return self.rd_reg('PixelID', pix) + # 32-bit EFuse output + def get_EFuseOut(self): + return self.rd_reg('EFuseQ') -- GitLab From da3f44a9e12e9e91664c1d3e2c4a20cabccd8c1b Mon Sep 17 00:00:00 2001 From: Diego Lopez Gutierrez <dlopezgu@bu.edu> Date: Mon, 1 May 2023 14:13:02 -0400 Subject: [PATCH 3/4] Fix typos in registers in ETROC2_example.yaml --- address_table/ETROC2_example.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/address_table/ETROC2_example.yaml b/address_table/ETROC2_example.yaml index d9776e4..094f795 100644 --- a/address_table/ETROC2_example.yaml +++ b/address_table/ETROC2_example.yaml @@ -542,7 +542,7 @@ PixelID: ############################################ readoutClockDelayPixel: - doc: "phase delay of pixel readout clock, 780 ps a step." + doc: "Phase delay of pixel readout clock, 780 ps a step." address: - 13 mask: @@ -597,7 +597,7 @@ serRateRight: serRateLeft: doc: |- - Data rate selection of the right data port. + Data rate selection of the left data port. 2'b00: 320 Mbps; 2'b01: 640 Mbps; 2'b10: 1280 Mbps. @@ -767,7 +767,7 @@ fcDataDelayEn: chargeInjectionDelay: doc: |- - The charge injection delay to the 40 MHz clcok rising + The charge injection delay to the 40 MHz clock rising edge. Start from the rising edge of 40 MHz clock, each step 781 ps. The pulse width is fixed of 50 ns. address: -- GitLab From 7ff460ba3800a1dac30c9d63c6469950acc8dc87 Mon Sep 17 00:00:00 2001 From: Diego Lopez Gutierrez <dlopezgu@bu.edu> Date: Mon, 1 May 2023 14:21:19 -0400 Subject: [PATCH 4/4] Use one function to handle DAC and TH_offset registers in ETROC --- tamalero/ETROC.py | 66 +++++++++++++++++++++++------------------------ 1 file changed, 33 insertions(+), 33 deletions(-) diff --git a/tamalero/ETROC.py b/tamalero/ETROC.py index 89517aa..784e888 100644 --- a/tamalero/ETROC.py +++ b/tamalero/ETROC.py @@ -339,42 +339,42 @@ class ETROC(): self.wr_reg('Bypass_THCal', 0, row=row, col=col, broadcast=broadcast) # When Bypass_THCal = 1, TH = DAC - def set_Vth_pix(self, vth, row=0, col=0, broadcast=True): - self.wr_reg('DAC', vth, row=row, col=col, broadcast=broadcast) - - def get_Vth_pix(self, row=0, col=0): - return self.rd_reg('DAC', row=row, col=col) -# def set_Vth_mV(self, vth, row=0, col=0, broadcast=True): -# # FIXME this needs to be understood -# # Pretend that we set the threshold and then the "DAC" register -# # sets the threshold in offset_step/2**10 steps? -# offset_step = (1000/2**6) -# th_step = offset_step/2**10 -# offset = int(vth/offset_step) -# residual = vth - offset*offset_step -# th = round(residual/th_step) -# self.wr_reg('TH_offset', offset, row=row, col=col, broadcast=broadcast) -# self.wr_reg('DAC', th, row=row, col=col, broadcast=broadcast) -# #if self.usefake: -# # self.fakeETROC.data['vth'] = vth -# # print("Vth set to %f."%vth) -# #else: -# # v = vth # FIXME: convert from mV to bit representation -# # self.wr_reg('DAC', vth, pix) +# def set_Vth_pix(self, vth, row=0, col=0, broadcast=True): +# self.wr_reg('DAC', vth, row=row, col=col, broadcast=broadcast) # -# def get_Vth_mV(self, row=0, col=0): -# offset_step = (1000/2**6) -# th_step = offset_step/2**10 -# offset = self.rd_reg('TH_offset', row=row, col=col) -# th = self.rd_reg('DAC', row=row, col=col) -# return offset*offset_step + th*th_step +# def get_Vth_pix(self, row=0, col=0): +# return self.rd_reg('DAC', row=row, col=col) + def set_Vth_mV(self, vth, row=0, col=0, broadcast=True): + # FIXME this needs to be understood + # Pretend that we set the threshold and then the "DAC" register + # sets the threshold in offset_step/2**10 steps? + offset_step = (1000/2**6) + th_step = offset_step/2**10 + offset = int(vth/offset_step) + residual = vth - offset*offset_step + th = round(residual/th_step) + self.wr_reg('TH_offset', offset, row=row, col=col, broadcast=broadcast) + self.wr_reg('DAC', th, row=row, col=col, broadcast=broadcast) + #if self.usefake: + # self.fakeETROC.data['vth'] = vth + # print("Vth set to %f."%vth) + #else: + # v = vth # FIXME: convert from mV to bit representation + # self.wr_reg('DAC', vth, pix) + + def get_Vth_mV(self, row=0, col=0): + offset_step = (1000/2**6) + th_step = offset_step/2**10 + offset = self.rd_reg('TH_offset', row=row, col=col) + th = self.rd_reg('DAC', row=row, col=col) + return offset*offset_step + th*th_step # Threshold offset for calibrated baseline. TH = BL + TH_offset - def set_THoffset(self, V, row=0, col=0, broadcast=True): - self.wr_reg('TH_offset', V, row=row, col=col, broadcast=broadcast) - - def get_THoffset(self, row=0, col=0): - return self.rd_reg('TH_offset', row=row, col=col) +# def set_THoffset(self, V, row=0, col=0, broadcast=True): +# self.wr_reg('TH_offset', V, row=row, col=col, broadcast=broadcast) +# +# def get_THoffset(self, row=0, col=0): +# return self.rd_reg('TH_offset', row=row, col=col) # Reset of threshold calibration block, active low def reset_THCal(self, row=0, col=0, broadcast=True): -- GitLab