diff --git a/.gitignore b/.gitignore index d3e6668f1..04def9488 100644 --- a/.gitignore +++ b/.gitignore @@ -104,6 +104,14 @@ firmware/mmc3_m26_eth/vivado/* firmware/mmc3_beast_eth/vivado/* !firmware/mmc3_beast_eth/vivado/*.xpr +# MMC3 8chip firmware +firmware/mmc3_8chip_eth/vivado/* +!firmware/mmc3_8chip_eth/vivado/*.xpr + +# MMC3 8chip with multi TX firmware +firmware/mmc3_8chip_multi_tx_eth/vivado/* +!firmware/mmc3_8chip_multi_tx_eth/vivado/*.xpr + # Simulation output firmware/mio/cosim/sim_build firmware/mio/cosim/sim_build.zip diff --git a/README.md b/README.md index 42e3141a2..7baa55e35 100644 --- a/README.md +++ b/README.md @@ -6,22 +6,25 @@ pyBAR - Bonn ATLAS Readout in Python PyBAR is a versatile readout and test system for the ATLAS FEI4(A/B) pixel readout chip. It uses the [basil](https://github.com/SiLab-Bonn/basil) framework to access the readout hardware. PyBAR's FPGA firmware and host software includes support for different hardware platforms. -PyBAR is *not only* targeting experienced users and developers. The easy-to-use scripts allow a quick setup and start. PyBAR is a very flexible readout and test system and provides the capability to conduct tests and characterization measurements of individual chips. +PyBAR is *not only* targeting experienced users and developers. The easy-to-use scripts allow a quick setup and start. PyBAR is a very flexible readout and test system and provides the capability to conduct tests and characterization measurements of individual chips, and tests of large-scale detectors with multiple multi-chip modules and multiple readout boards. The features of the FPGA firmware in a nutshell: - supported readout boards: any hardware that is supported by basil (e.g., MIO2, MIO3, and MMC3) - supported adapter cards: Single Chip Adapter Card, Burn-in Card (Quad Module Adapter Card) and the General Purpose Analog Card (GPAC) -- readout of single chip modules +- readout of multiple readout boards +- readout of multiple multi-chip modules (e.g., single, dual, quad module, and any combination of those) +- simultaneous readout (e.g., data taking with external trigger, individual tuning of chips) - continuous data taking -- automatic data to clock phase alignment +- individual and automatic data to clock phase alignment on each channel - full support of EUDAQ TLU and availability of EUDAQ Producer The features of the host software in Python: - no GUI - support for Windows, Linux and macOS - scan/tuning/calibration algorithms are implemented in stand-alone scripts +- scripts are implemented for operating single chips but are working with multi-chip configurations as well - fast development and implementation of new scan/tuning/calibration algorithms - configuration files are human readable (compatible to RCE/HSIO) - full control over FEI4 command generation, sending any arbitrary bit stream and configuration sequence to the FEI4 @@ -33,7 +36,7 @@ The features of the host software in Python: The following packages are required for pyBAR's core functionality: ``` - basil_daq bitarray cython matplotlib numba numpy pixel_clusterizer progressbar-latest pytables pyyaml scipy + basil_daq bitarray contextlib2 cython matplotlib numba numpy pixel_clusterizer progressbar-latest pytables pyyaml scipy ``` For full functionality, the following additional packages are required: @@ -43,7 +46,7 @@ For full functionality, the following additional packages are required: Run the **following commands** to install the packages: ``` - conda install python=2.7 bitarray cython ipython matplotlib mock nose numba numpy pyserial pytables pyyaml pyzmq scipy sphinx + conda install python=2.7 bitarray contextlib2 cython ipython matplotlib mock nose numba numpy pyserial pytables pyyaml pyzmq scipy sphinx pip install progressbar-latest pyvisa pyvisa-py git+https://github.com/pyqtgraph/pyqtgraph.git@pyqtgraph-0.10.0 ``` @@ -68,7 +71,7 @@ On Windows, the `pywin32` package is required: pip install 'pixel_clusterizer>=3.1,<3.2' ``` -To enable support for USB devices (MIO, MIO3 and MMC3), the following additional packages are required: +To enable support for USB devices (MIO2), the following additional packages are required: - [PyUSB](https://github.com/walac/pyusb) (>=1.0.0rc1): ``` pip install pyusb diff --git a/VERSION b/VERSION index 7ec1d6db4..4a36342fc 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -2.1.0 +3.0.0 diff --git a/examples/example_run_manager/example_run_manager.py b/examples/example_run_manager/example_run_manager.py index 5b00e7577..2653ce67f 100644 --- a/examples/example_run_manager/example_run_manager.py +++ b/examples/example_run_manager/example_run_manager.py @@ -9,7 +9,7 @@ # The initial FE configuration will be created during the first run. # # (from configuration.yaml) - # fe_flavor : fei4a + # flavor : fei4a # ... # # Initializing the run manager: @@ -18,17 +18,17 @@ # During the first run, an module data directory relative to the configuration.yaml file will be created. # If configuration.yaml is placed inside /host/pybar/ the module data will be stored inside /host/pybar/ (where is defined inside configuration.yaml). # - # If fe_configuration inside configuration.yaml is not given, the latest valid FE configuration file will be taken (the file with the highest run number and run status 'FINISHED'). + # If configuration inside configuration.yaml is not given, the latest valid FE configuration file will be taken (the file with the highest run number and run status 'FINISHED'). # # (from configuration.yaml) - # fe_configuration: + # configuration: # ... # - # If no configuration file exists, a initial configuration will be create according to fe_flavor. + # If no configuration file exists, a initial configuration will be create according to flavor. # To load a specific configuration file, a path to FE configuration file or a run number (e.g. 5) can be given: # # (from configuration.yaml) - # fe_configuration: 1 + # configuration: 1 # ... # # This will retain the configuration for the following scans. diff --git a/firmware/lx9/src/top.v b/firmware/lx9/src/top.v index e709d7997..082896212 100644 --- a/firmware/lx9/src/top.v +++ b/firmware/lx9/src/top.v @@ -266,7 +266,7 @@ module top ( .BUS_DATA(BUS_DATA) ); - //MODULE ADREESSES + //MODULE ADDRESSES localparam CMD_BASEADDR = 32'h0000; localparam CMD_HIGHADDR = 32'h8000-1; @@ -343,7 +343,7 @@ module top ( .FIFO_EMPTY(FE_FIFO_EMPTY[i]), .FIFO_DATA(FE_FIFO_DATA[i]), - .RX_FIFO_FULL(RX_FIFO_FULL[i]), + .RX_FIFO_FULL(RX_FIFO_FULL[i]), .RX_ENABLED(), .BUS_CLK(BUS_CLK), diff --git a/firmware/mio/cosim/sim.yaml b/firmware/mio/cosim/sim.yaml index 37e0224fc..39b1445df 100644 --- a/firmware/mio/cosim/sim.yaml +++ b/firmware/mio/cosim/sim.yaml @@ -19,23 +19,23 @@ hw_drivers: # interface : USB # base_addr : 0x0 - - name : CH4 + - name : DATA_CH4 type : fei4_rx interface : USB base_addr : 0x18300 # Uncomment for FEI4QuadModuleAdapterCard - - name : CH3 + - name : DATA_CH3 type : fei4_rx interface : USB base_addr : 0x18400 - - - name : CH2 + + - name : DATA_CH2 type : fei4_rx interface : USB base_addr : 0x18500 - - - name : CH1 + + - name : DATA_CH1 type : fei4_rx interface : USB base_addr : 0x18600 @@ -89,7 +89,7 @@ hw_drivers: base_addr : 0x18900 user_drivers: - + registers: - name : ENABLE_CHANNEL type : StdRegister @@ -102,16 +102,16 @@ registers: - name : TLU size : 1 offset : 4 - - name : CH4 + - name : DATA_CH4 size : 1 offset : 3 - - name : CH3 + - name : DATA_CH3 size : 1 offset : 2 - - name : CH2 + - name : DATA_CH2 size : 1 offset : 1 - - name : CH1 + - name : DATA_CH1 size : 1 offset : 0 diff --git a/firmware/mio/cosim/sim_test.py b/firmware/mio/cosim/sim_test.py index 843a00a36..f2590ab1e 100644 --- a/firmware/mio/cosim/sim_test.py +++ b/firmware/mio/cosim/sim_test.py @@ -22,10 +22,10 @@ dut['POWER_SCC'].write() # enabling readout -dut['rx']['CH1'] = 1 -dut['rx']['CH2'] = 1 -dut['rx']['CH3'] = 1 -dut['rx']['CH4'] = 1 +dut['rx']['DATA_CH1'] = 1 +dut['rx']['DATA_CH2'] = 1 +dut['rx']['DATA_CH3'] = 1 +dut['rx']['DATA_CH4'] = 1 dut['rx']['TLU'] = 1 dut['rx']['TDC'] = 1 dut['rx'].write() @@ -45,7 +45,8 @@ def cmd(data, size): cmd([0xB1, 0x00], 9) # ECR cmd([0xB4, 0x50, 0x0E], 23) # conf mode -dut['rx_1']['RESET'] # let rx sync +dut['rx_1']['RX_RESET'] # RX sync +dut['rx_1']['ENABLE_RX'] # enable RX cmd([0xB4, 0x08, 0x00], 23) # readbck a register diff --git a/firmware/mio/src/top.v b/firmware/mio/src/top.v index 58eb8586a..c7657a220 100644 --- a/firmware/mio/src/top.v +++ b/firmware/mio/src/top.v @@ -201,10 +201,11 @@ assign TRIGGER_ACKNOWLEDGE_FLAG = CMD_READY & ~CMD_READY_FF; wire CMD_START_FLAG; // sending FE command triggered by external devices //reg CMD_CAL; // when CAL command is send +wire TRIGGER_ENABLED, TLU_ENABLED; // LEMO Tx assign TX[0] = TLU_CLOCK; -assign TX[1] = EXT_TRIGGER_ENABLE ? TLU_BUSY : ~CMD_READY; +assign TX[1] = TLU_ENABLED ? TLU_BUSY : ~CMD_READY; assign TX[2] = RJ45_TRIGGER; // ------- RESRT/CLOCK ------- // @@ -307,7 +308,7 @@ clock_divider #( .CLOCK(CLK_3HZ) ); -// ------- MODULE ADREESSES ------- // +// ------- MODULE ADDRESSES ------- // localparam CMD_BASEADDR = 16'h0000; localparam CMD_HIGHADDR = 16'h8000-1; @@ -511,7 +512,7 @@ tdc_s3 #( .BASEADDR(TDC_BASEADDR), .HIGHADDR(TDC_HIGHADDR), .CLKDV(4), - .DATA_IDENTIFIER(4'b0100), // one-hot + .DATA_IDENTIFIER(4'b0100), .FAST_TDC(1), .FAST_TRIGGER(1) ) i_tdc ( @@ -586,11 +587,15 @@ tlu_controller #( .FIFO_PREEMPT_REQ(TRIGGER_FIFO_PEEMPT_REQ), + .TRIGGER_ENABLED(TRIGGER_ENABLED), + .TRIGGER_SELECTED(), + .TLU_ENABLED(TLU_ENABLED), + .TRIGGER({3'b0, CCPD_TDC_FROM_TDC, TDC_IN_FROM_TDC, MULTI_PURPOSE, LEMO_TRIGGER_FROM_TDC, MONHIT}), .TRIGGER_VETO({6'b0, MULTI_PURPOSE, FIFO_FULL}), .EXT_TRIGGER_ENABLE(EXT_TRIGGER_ENABLE), - .TRIGGER_ACKNOWLEDGE(EXT_TRIGGER_ENABLE == 1'b0 ? TRIGGER_ACCEPTED_FLAG : TRIGGER_ACKNOWLEDGE_FLAG), + .TRIGGER_ACKNOWLEDGE(TRIGGER_ACKNOWLEDGE_FLAG), .TRIGGER_ACCEPTED_FLAG(TRIGGER_ACCEPTED_FLAG), .TLU_TRIGGER(RJ45_TRIGGER), @@ -663,11 +668,15 @@ tlu_controller #( .FIFO_PREEMPT_REQ(TRIGGER_FIFO_PEEMPT_REQ), + .TRIGGER_ENABLED(TRIGGER_ENABLED), + .TRIGGER_SELECTED(), + .TLU_ENABLED(TLU_ENABLED), + .TRIGGER({4'b0, TDC_IN_FROM_TDC, MULTI_PURPOSE, LEMO_TRIGGER_FROM_TDC, MONHIT}), .TRIGGER_VETO({6'b0, MULTI_PURPOSE, FIFO_FULL}), .EXT_TRIGGER_ENABLE(EXT_TRIGGER_ENABLE), - .TRIGGER_ACKNOWLEDGE(EXT_TRIGGER_ENABLE == 1'b0 ? TRIGGER_ACCEPTED_FLAG : TRIGGER_ACKNOWLEDGE_FLAG), + .TRIGGER_ACKNOWLEDGE(TRIGGER_ACKNOWLEDGE_FLAG), .TRIGGER_ACCEPTED_FLAG(TRIGGER_ACCEPTED_FLAG), .TLU_TRIGGER(RJ45_TRIGGER), diff --git a/firmware/mio3/src/KX7_IF_Test_Top.v b/firmware/mio3/src/KX7_IF_Test_Top.v index 59e061e85..e51af0026 100644 --- a/firmware/mio3/src/KX7_IF_Test_Top.v +++ b/firmware/mio3/src/KX7_IF_Test_Top.v @@ -183,7 +183,7 @@ PLLE2_BASE #( .I(clk16mhz_pll) // Clock buffer input ); -// ------- MODULE ADREESSES ------- // +// ------- MODULE ADDRESSES ------- // localparam CMD_BASEADDR = 32'h0000; localparam CMD_HIGHADDR = 32'h8000-1; diff --git a/firmware/mio3/src/mmc3_top.v b/firmware/mio3/src/mmc3_top.v index e1c38cfd0..832de166b 100644 --- a/firmware/mio3/src/mmc3_top.v +++ b/firmware/mio3/src/mmc3_top.v @@ -182,7 +182,7 @@ PLLE2_BASE #( .I(clk16mhz_pll) // Clock buffer input ); -// ------- MODULE ADREESSES ------- // +// ------- MODULE ADDRESSES ------- // localparam CMD_BASEADDR = 32'h0000; localparam CMD_HIGHADDR = 32'h1000-1; diff --git a/firmware/mmc3_16chip_multi_tx_eth/README.md b/firmware/mmc3_16chip_multi_tx_eth/README.md new file mode 100644 index 000000000..d7e515606 --- /dev/null +++ b/firmware/mmc3_16chip_multi_tx_eth/README.md @@ -0,0 +1,5 @@ + +### pyBAR firmware for max. 8 FEI4s with multiple TX + + + diff --git a/firmware/mmc3_16chip_multi_tx_eth/src/mmc3.xdc b/firmware/mmc3_16chip_multi_tx_eth/src/mmc3.xdc new file mode 100644 index 000000000..ed8170cde --- /dev/null +++ b/firmware/mmc3_16chip_multi_tx_eth/src/mmc3.xdc @@ -0,0 +1,210 @@ + +create_clock -period 10.000 -name clkin -add [get_ports clkin] +create_clock -period 8.000 -name rgmii_rxc -add [get_ports rgmii_rxc] + +set_false_path -from [get_clocks CLK125PLLTX] -to [get_clocks BUS_CLK_PLL] +set_false_path -from [get_clocks BUS_CLK_PLL] -to [get_clocks CLK125PLLTX] +set_false_path -from [get_clocks BUS_CLK_PLL] -to [get_clocks rgmii_rxc] +set_false_path -from [get_clocks rgmii_rxc] -to [get_clocks BUS_CLK_PLL] +set_false_path -from [get_clocks BUS_CLK_PLL] -to [get_clocks rgmii_rxc] +set_false_path -from [get_clocks rgmii_rxc] -to [get_clocks BUS_CLK_PLL] +set_false_path -from [get_clocks CLK16_PLL] -to [get_clocks BUS_CLK_PLL] +set_false_path -from [get_clocks BUS_CLK_PLL] -to [get_clocks CLK16_PLL] +set_false_path -from [get_clocks CLK160_PLL] -to [get_clocks BUS_CLK_PLL] +set_false_path -from [get_clocks BUS_CLK_PLL] -to [get_clocks CLK160_PLL] +set_false_path -from [get_clocks CLK40_PLL] -to [get_clocks BUS_CLK_PLL] +set_false_path -from [get_clocks BUS_CLK_PLL] -to [get_clocks CLK40_PLL] + +#NET "Clk100" LOC = "AA3" | IOSTANDARD = "LVCMOS15"; 100MHz +set_property PACKAGE_PIN AA3 [get_ports clkin] +set_property IOSTANDARD LVCMOS15 [get_ports clkin] + +set_property PACKAGE_PIN C18 [get_ports RESET_N] +set_property IOSTANDARD LVCMOS25 [get_ports RESET_N] +set_property PULLUP true [get_ports RESET_N] + +set_property SLEW FAST [get_ports mdio_phy_mdc] +set_property IOSTANDARD LVCMOS25 [get_ports mdio_phy_mdc] +set_property PACKAGE_PIN N16 [get_ports mdio_phy_mdc] + +set_property SLEW FAST [get_ports mdio_phy_mdio] +set_property IOSTANDARD LVCMOS25 [get_ports mdio_phy_mdio] +set_property PACKAGE_PIN U16 [get_ports mdio_phy_mdio] + +set_property SLEW FAST [get_ports phy_rst_n] +set_property IOSTANDARD LVCMOS25 [get_ports phy_rst_n] +set_property PACKAGE_PIN M20 [get_ports phy_rst_n] + +set_property IOSTANDARD LVCMOS25 [get_ports rgmii_rxc] +set_property PACKAGE_PIN R21 [get_ports rgmii_rxc] + +set_property IOSTANDARD LVCMOS25 [get_ports rgmii_rx_ctl] +set_property PACKAGE_PIN P21 [get_ports rgmii_rx_ctl] +set_property IOSTANDARD LVCMOS25 [get_ports {rgmii_rxd[0]}] +set_property PACKAGE_PIN P16 [get_ports {rgmii_rxd[0]}] +set_property IOSTANDARD LVCMOS25 [get_ports {rgmii_rxd[1]}] +set_property PACKAGE_PIN N17 [get_ports {rgmii_rxd[1]}] +set_property IOSTANDARD LVCMOS25 [get_ports {rgmii_rxd[2]}] +set_property PACKAGE_PIN R16 [get_ports {rgmii_rxd[2]}] +set_property IOSTANDARD LVCMOS25 [get_ports {rgmii_rxd[3]}] +set_property PACKAGE_PIN R17 [get_ports {rgmii_rxd[3]}] + +set_property SLEW FAST [get_ports rgmii_txc] +set_property IOSTANDARD LVCMOS25 [get_ports rgmii_txc] +set_property PACKAGE_PIN R18 [get_ports rgmii_txc] + +set_property SLEW FAST [get_ports rgmii_tx_ctl] +set_property IOSTANDARD LVCMOS25 [get_ports rgmii_tx_ctl] +set_property PACKAGE_PIN P18 [get_ports rgmii_tx_ctl] + +set_property SLEW FAST [get_ports {rgmii_txd[0]}] +set_property IOSTANDARD LVCMOS25 [get_ports {rgmii_txd[0]}] +set_property PACKAGE_PIN N18 [get_ports {rgmii_txd[0]}] +set_property SLEW FAST [get_ports {rgmii_txd[1]}] +set_property IOSTANDARD LVCMOS25 [get_ports {rgmii_txd[1]}] +set_property PACKAGE_PIN M19 [get_ports {rgmii_txd[1]}] +set_property SLEW FAST [get_ports {rgmii_txd[2]}] +set_property IOSTANDARD LVCMOS25 [get_ports {rgmii_txd[2]}] +set_property PACKAGE_PIN U17 [get_ports {rgmii_txd[2]}] +set_property SLEW FAST [get_ports {rgmii_txd[3]}] +set_property IOSTANDARD LVCMOS25 [get_ports {rgmii_txd[3]}] +set_property PACKAGE_PIN T17 [get_ports {rgmii_txd[3]}] + + +set_property PACKAGE_PIN M17 [get_ports {LED[0]}] +set_property PACKAGE_PIN L18 [get_ports {LED[1]}] +set_property PACKAGE_PIN L17 [get_ports {LED[2]}] +set_property PACKAGE_PIN K18 [get_ports {LED[3]}] +set_property PACKAGE_PIN P26 [get_ports {LED[4]}] +set_property PACKAGE_PIN M25 [get_ports {LED[5]}] +set_property PACKAGE_PIN L25 [get_ports {LED[6]}] +set_property PACKAGE_PIN P23 [get_ports {LED[7]}] +set_property IOSTANDARD LVCMOS25 [get_ports LED*] +set_property SLEW SLOW [get_ports LED*] + +set_property PACKAGE_PIN F10 [get_ports RJ45_HITOR_N[0]] +set_property IOSTANDARD LVDS_25 [get_ports RJ45_HITOR*] +set_property KEEPER true [get_ports RJ45_HITOR_P[0]] + + +#PORT CMD +set_property PACKAGE_PIN D8 [get_ports CMD_DATA_N[0]] +set_property IOSTANDARD LVDS_25 [get_ports CMD_DATA*] +set_property KEEPER true [get_ports CMD_DATA_P[0]] +set_property PACKAGE_PIN B9 [get_ports CMD_CLK_N[0]] +set_property IOSTANDARD LVDS_25 [get_ports CMD_CLK*] +set_property KEEPER true [get_ports CMD_CLK_P[0]] +set_property PACKAGE_PIN F12 [get_ports CMD_DATA_N[1]] +set_property IOSTANDARD LVDS_25 [get_ports CMD_DATA*] +set_property KEEPER true [get_ports CMD_DATA_P[1]] +set_property PACKAGE_PIN C13 [get_ports CMD_CLK_N[1]] +set_property IOSTANDARD LVDS_25 [get_ports CMD_CLK*] +set_property KEEPER true [get_ports CMD_CLK_P[1]] +set_property PACKAGE_PIN A17 [get_ports CMD_DATA_N[2]] +set_property IOSTANDARD LVDS_25 [get_ports CMD_DATA*] +set_property KEEPER true [get_ports CMD_DATA_P[2]] +set_property PACKAGE_PIN B19 [get_ports CMD_CLK_N[2]] +set_property IOSTANDARD LVDS_25 [get_ports CMD_CLK*] +set_property KEEPER true [get_ports CMD_CLK_P[2]] +set_property PACKAGE_PIN F18 [get_ports CMD_DATA_N[3]] +set_property IOSTANDARD LVDS_25 [get_ports CMD_DATA*] +set_property KEEPER true [get_ports CMD_DATA_P[3]] +set_property PACKAGE_PIN J16 [get_ports CMD_CLK_N[3]] +set_property IOSTANDARD LVDS_25 [get_ports CMD_CLK*] +set_property KEEPER true [get_ports CMD_CLK_P[3]] + +set_property PACKAGE_PIN G14 [get_ports CMD_DATA_N[4]] +set_property IOSTANDARD LVDS_25 [get_ports CMD_DATA*] +set_property KEEPER true [get_ports CMD_DATA_P[4]] +set_property PACKAGE_PIN H13 [get_ports CMD_CLK_N[4]] +set_property IOSTANDARD LVDS_25 [get_ports CMD_CLK*] +set_property KEEPER true [get_ports CMD_CLK_P[4]] +set_property PACKAGE_PIN F13 [get_ports CMD_DATA_N[5]] +set_property IOSTANDARD LVDS_25 [get_ports CMD_DATA*] +set_property KEEPER true [get_ports CMD_DATA_P[5]] +set_property PACKAGE_PIN H8 [get_ports CMD_CLK_N[5]] +set_property IOSTANDARD LVDS_25 [get_ports CMD_CLK*] +set_property KEEPER true [get_ports CMD_CLK_P[5]] +set_property PACKAGE_PIN A14 [get_ports CMD_DATA_N[6]] +set_property IOSTANDARD LVDS_25 [get_ports CMD_DATA*] +set_property KEEPER true [get_ports CMD_DATA_P[6]] +set_property PACKAGE_PIN E12 [get_ports CMD_CLK_N[6]] +set_property IOSTANDARD LVDS_25 [get_ports CMD_CLK*] +set_property KEEPER true [get_ports CMD_CLK_P[6]] +set_property PACKAGE_PIN E17 [get_ports CMD_DATA_N[7]] +set_property IOSTANDARD LVDS_25 [get_ports CMD_DATA*] +set_property KEEPER true [get_ports CMD_DATA_P[7]] +set_property PACKAGE_PIN A19 [get_ports CMD_CLK_N[7]] +set_property IOSTANDARD LVDS_25 [get_ports CMD_CLK*] +set_property KEEPER true [get_ports CMD_CLK_P[7]] + + +set_property BITSTREAM.CONFIG.UNUSEDPIN PULLUP [current_design] + + + +set_property PACKAGE_PIN E16 [get_ports DOBOUT_N[15]] +set_property IOSTANDARD LVDS_25 [get_ports DOBOUT*] +set_property KEEPER true [get_ports DOBOUT_P[15]] +set_property PACKAGE_PIN A10 [get_ports DOBOUT_N[14]] +set_property IOSTANDARD LVDS_25 [get_ports DOBOUT*] +set_property KEEPER true [get_ports DOBOUT_P[14]] +set_property PACKAGE_PIN D11 [get_ports DOBOUT_N[13]] +set_property IOSTANDARD LVDS_25 [get_ports DOBOUT*] +set_property KEEPER true [get_ports DOBOUT_P[13]] +set_property PACKAGE_PIN D10 [get_ports DOBOUT_N[12]] +set_property IOSTANDARD LVDS_25 [get_ports DOBOUT*] +set_property KEEPER true [get_ports DOBOUT_P[12]] + +set_property PACKAGE_PIN G16 [get_ports DOBOUT_N[11]] +set_property IOSTANDARD LVDS_25 [get_ports DOBOUT*] +set_property KEEPER true [get_ports DOBOUT_P[11]] +set_property PACKAGE_PIN A15 [get_ports DOBOUT_N[10]] +set_property IOSTANDARD LVDS_25 [get_ports DOBOUT*] +set_property KEEPER true [get_ports DOBOUT_P[10]] +set_property PACKAGE_PIN C11 [get_ports DOBOUT_N[9]] +set_property IOSTANDARD LVDS_25 [get_ports DOBOUT*] +set_property KEEPER true [get_ports DOBOUT_P[9]] +set_property PACKAGE_PIN H11 [get_ports DOBOUT_N[8]] +set_property IOSTANDARD LVDS_25 [get_ports DOBOUT*] +set_property KEEPER true [get_ports DOBOUT_P[8]] + +set_property PACKAGE_PIN F15 [get_ports DOBOUT_N[7]] +set_property IOSTANDARD LVDS_25 [get_ports DOBOUT*] +set_property KEEPER true [get_ports DOBOUT_P[7]] +set_property PACKAGE_PIN B16 [get_ports DOBOUT_N[6]] +set_property IOSTANDARD LVDS_25 [get_ports DOBOUT*] +set_property KEEPER true [get_ports DOBOUT_P[6]] +set_property PACKAGE_PIN D13 [get_ports DOBOUT_N[5]] +set_property IOSTANDARD LVDS_25 [get_ports DOBOUT*] +set_property KEEPER true [get_ports DOBOUT_P[5]] +set_property PACKAGE_PIN A8 [get_ports DOBOUT_N[4]] +set_property IOSTANDARD LVDS_25 [get_ports DOBOUT*] +set_property KEEPER true [get_ports DOBOUT_P[4]] + +set_property PACKAGE_PIN D16 [get_ports DOBOUT_N[3]] +set_property IOSTANDARD LVDS_25 [get_ports DOBOUT*] +set_property KEEPER true [get_ports DOBOUT_P[3]] +set_property PACKAGE_PIN B11 [get_ports DOBOUT_N[2]] +set_property IOSTANDARD LVDS_25 [get_ports DOBOUT*] +set_property KEEPER true [get_ports DOBOUT_P[2]] +set_property PACKAGE_PIN F8 [get_ports DOBOUT_N[1]] +set_property IOSTANDARD LVDS_25 [get_ports DOBOUT*] +set_property KEEPER true [get_ports DOBOUT_P[1]] +set_property PACKAGE_PIN J10 [get_ports DOBOUT_N[0]] +set_property IOSTANDARD LVDS_25 [get_ports DOBOUT*] +set_property KEEPER true [get_ports DOBOUT_P[0]] + + +set_property PACKAGE_PIN V23 [get_ports RJ45_BUSY_LEMO_TX1] +set_property PACKAGE_PIN AB21 [get_ports RJ45_CLK_LEMO_TX0] +set_property PACKAGE_PIN V21 [get_ports RJ45_TRIGGER] +set_property PACKAGE_PIN Y25 [get_ports RJ45_RESET] +set_property IOSTANDARD LVCMOS25 [get_ports RJ45_BUSY_LEMO_TX1] +set_property IOSTANDARD LVCMOS25 [get_ports RJ45_CLK_LEMO_TX0] +set_property IOSTANDARD LVCMOS25 [get_ports RJ45_RESET] +set_property IOSTANDARD LVCMOS25 [get_ports RJ45_TRIGGER] + +set_property PACKAGE_PIN U26 [get_ports {LEMO_RX[1]}] +set_property PACKAGE_PIN U22 [get_ports {LEMO_RX[0]}] +set_property IOSTANDARD LVCMOS25 [get_ports LEMO_RX*] diff --git a/firmware/mmc3_16chip_multi_tx_eth/src/mmc3_16chip_multi_tx_eth.v b/firmware/mmc3_16chip_multi_tx_eth/src/mmc3_16chip_multi_tx_eth.v new file mode 100644 index 000000000..e0a4a269b --- /dev/null +++ b/firmware/mmc3_16chip_multi_tx_eth/src/mmc3_16chip_multi_tx_eth.v @@ -0,0 +1,811 @@ +/** + * This file is part of pyBAR. + * + * pyBAR is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * pyBAR is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with pyBAR. If not, see . + */ + +/** + * ------------------------------------------------------------ + * Copyright (c) All rights reserved + * SiLab, Institute of Physics, University of Bonn + * ------------------------------------------------------------ + */ + +`timescale 1ps / 1ps +`default_nettype none + +module mmc3_16chip_multi_tx_eth( + input wire RESET_N, + input wire clkin, + output wire [3:0] rgmii_txd, + output wire rgmii_tx_ctl, + output wire rgmii_txc, + input wire [3:0] rgmii_rxd, + input wire rgmii_rx_ctl, + input wire rgmii_rxc, + output wire mdio_phy_mdc, + inout wire mdio_phy_mdio, + output wire phy_rst_n, + output wire [7:0] LED, + output wire [7:0] CMD_CLK_P, CMD_CLK_N, + output wire [7:0] CMD_DATA_P, CMD_DATA_N, + input wire [0:0] RJ45_HITOR_N, RJ45_HITOR_P, + input wire [15:0] DOBOUT_N, DOBOUT_P, + output wire RJ45_BUSY_LEMO_TX1, RJ45_CLK_LEMO_TX0, + input wire RJ45_TRIGGER, RJ45_RESET, + input wire [1:0] LEMO_RX +); + + +wire RST; +wire CLK250PLL, CLK125PLLTX, CLK125PLLTX90, CLK125PLLRX; +wire PLL_FEEDBACK, LOCKED; + +PLLE2_BASE #( + .BANDWIDTH("OPTIMIZED"), // OPTIMIZED, HIGH, LOW + .CLKFBOUT_MULT(10), // Multiply value for all CLKOUT, (2-64) + .CLKFBOUT_PHASE(0.0), // Phase offset in degrees of CLKFB, (-360.000-360.000). + .CLKIN1_PERIOD(10.000), // Input clock period in ns to ps resolution (i.e. 33.333 is 30 MHz). + + .CLKOUT0_DIVIDE(7), // Divide amount for CLKOUT0 (1-128) + .CLKOUT0_DUTY_CYCLE(0.5), // Duty cycle for CLKOUT0 (0.001-0.999). + .CLKOUT0_PHASE(0.0), // Phase offset for CLKOUT0 (-360.000-360.000). + + .CLKOUT1_DIVIDE(4), // Divide amount for CLKOUT0 (1-128) + .CLKOUT1_DUTY_CYCLE(0.5), // Duty cycle for CLKOUT0 (0.001-0.999). + .CLKOUT1_PHASE(0.0), // Phase offset for CLKOUT0 (-360.000-360.000). + + .CLKOUT2_DIVIDE(8), // Divide amount for CLKOUT0 (1-128) + .CLKOUT2_DUTY_CYCLE(0.5), // Duty cycle for CLKOUT0 (0.001-0.999). + .CLKOUT2_PHASE(0.0), // Phase offset for CLKOUT0 (-360.000-360.000). + + .CLKOUT3_DIVIDE(8), // Divide amount for CLKOUT0 (1-128) + .CLKOUT3_DUTY_CYCLE(0.5), // Duty cycle for CLKOUT0 (0.001-0.999). + .CLKOUT3_PHASE(90.0), // Phase offset for CLKOUT0 (-360.000-360.000). + + .CLKOUT4_DIVIDE(8), // Divide amount for CLKOUT0 (1-128) + .CLKOUT4_DUTY_CYCLE(0.5), // Duty cycle for CLKOUT0 (0.001-0.999). + .CLKOUT4_PHASE(-5.6), // Phase offset for CLKOUT0 (-360.000-360.000). + //-65 -> 0?; - 45 -> 39; -25 -> 100; -5 -> 0; + + .DIVCLK_DIVIDE(1), // Master division value, (1-56) + .REF_JITTER1(0.0), // Reference input jitter in UI, (0.000-0.999). + .STARTUP_WAIT("FALSE") // Delay DONE until PLL Locks, ("TRUE"/"FALSE") + ) + PLLE2_BASE_inst ( + + .CLKOUT0(), + .CLKOUT1(CLK250PLL), + + .CLKOUT2(CLK125PLLTX), + .CLKOUT3(CLK125PLLTX90), + .CLKOUT4(CLK125PLLRX), + + .CLKOUT5(), + + .CLKFBOUT(PLL_FEEDBACK), + + .LOCKED(LOCKED), // 1-bit output: LOCK + + // Input 100 MHz clock + .CLKIN1(clkin), + + // Control Ports + .PWRDWN(0), + .RST(!RESET_N), + + // Feedback + .CLKFBIN(PLL_FEEDBACK) + ); + +wire PLL_FEEDBACK2, LOCKED2; +wire CLK160_PLL, CLK320_PLL, CLK40_PLL, CLK16_PLL, BUS_CLK_PLL, CLK200_PLL; +PLLE2_BASE #( + .BANDWIDTH("OPTIMIZED"), + .CLKFBOUT_MULT(16), + .CLKFBOUT_PHASE(0.0), + .CLKIN1_PERIOD(10.000), + + .CLKOUT0_DIVIDE(10), + .CLKOUT0_DUTY_CYCLE(0.5), + .CLKOUT0_PHASE(0.0), + + .CLKOUT1_DIVIDE(40), + .CLKOUT1_DUTY_CYCLE(0.5), + .CLKOUT1_PHASE(0.0), + + .CLKOUT2_DIVIDE(5), + .CLKOUT2_DUTY_CYCLE(0.5), + .CLKOUT2_PHASE(0.0), + + .CLKOUT3_DIVIDE(100), + .CLKOUT3_DUTY_CYCLE(0.5), + .CLKOUT3_PHASE(0.0), + + .CLKOUT4_DIVIDE(12), + .CLKOUT4_DUTY_CYCLE(0.5), + .CLKOUT4_PHASE(0.0), + + .CLKOUT5_DIVIDE(8), + .CLKOUT5_DUTY_CYCLE(0.5), + .CLKOUT5_PHASE(0.0), + + + .DIVCLK_DIVIDE(1), + .REF_JITTER1(0.0), + .STARTUP_WAIT("FALSE") +) +PLLE2_BASE_inst_2 ( + + .CLKOUT0(CLK160_PLL), + .CLKOUT1(CLK40_PLL), + .CLKOUT2(CLK320_PLL), + .CLKOUT3(CLK16_PLL), + .CLKOUT4(BUS_CLK_PLL), + .CLKOUT5(CLK200_PLL), + + .CLKFBOUT(PLL_FEEDBACK2), + .LOCKED(LOCKED2), // 1-bit output: LOCK + + .CLKIN1(clkin), + + .PWRDWN(0), + .RST(!RESET_N), + + .CLKFBIN(PLL_FEEDBACK2) +); + + +wire CLK160, CLK40, CLK320, CLK16, BUS_CLK, CLK200; +BUFG BUFG_inst_160 (.O(CLK160), .I(CLK160_PLL) ); +BUFG BUFG_inst_40 (.O(CLK40), .I(CLK40_PLL) ); +BUFG BUFG_inst_320 (.O(CLK320), .I(CLK320_PLL) ); +BUFG BUFG_inst_16 (.O(CLK16), .I(CLK16_PLL) ); +BUFG BUFG_inst_BUS_CLK (.O(BUS_CLK), .I(BUS_CLK_PLL) ); +BUFG BUFG_inst_200 (.O(CLK200), .I(CLK200_PLL) ); +//assign BUS_CLK = CLK160; + +wire IDELAYCTRL_RDY; +IDELAYCTRL IDELAYCTRL_inst ( + .RDY(IDELAYCTRL_RDY), + .REFCLK(CLK200), + .RST(!LOCKED2) +); + + +wire CLK125TX, CLK125TX90, CLK125RX; +BUFG BUFG_inst_CLK125TX ( .O(CLK125TX), .I(CLK125PLLTX) ); +BUFG BUFG_inst_CLK125TX90 ( .O(CLK125TX90), .I(CLK125PLLTX90) ); +BUFG BUFG_inst_CLK125RX ( .O(CLK125RX), .I(rgmii_rxc) ); + +assign RST = !RESET_N | !LOCKED | !LOCKED2; + + +wire gmii_tx_clk; +wire gmii_tx_en; +wire [7:0] gmii_txd; +wire gmii_tx_er; +wire gmii_crs; +wire gmii_col; +wire gmii_rx_clk; +wire gmii_rx_dv; +wire [7:0] gmii_rxd; +wire gmii_rx_er; +wire mdio_gem_mdc; +wire mdio_gem_i; +wire mdio_gem_o; +wire mdio_gem_t; +wire link_status; +wire [1:0] clock_speed; +wire duplex_status; + +rgmii_io rgmii +( + .rgmii_txd(rgmii_txd), + .rgmii_tx_ctl(rgmii_tx_ctl), + .rgmii_txc(rgmii_txc), + + .rgmii_rxd(rgmii_rxd), + .rgmii_rx_ctl(rgmii_rx_ctl), + + .gmii_txd_int(gmii_txd), // Internal gmii_txd signal. + .gmii_tx_en_int(gmii_tx_en), + .gmii_tx_er_int(gmii_tx_er), + .gmii_col_int(gmii_col), + .gmii_crs_int(gmii_crs), + .gmii_rxd_reg(gmii_rxd), // RGMII double data rate data valid. + .gmii_rx_dv_reg(gmii_rx_dv), // gmii_rx_dv_ibuf registered in IOBs. + .gmii_rx_er_reg(gmii_rx_er), // gmii_rx_er_ibuf registered in IOBs. + + .eth_link_status(link_status), + .eth_clock_speed(clock_speed), + .eth_duplex_status(duplex_status), + + // FOllowing are generated by DCMs + .tx_rgmii_clk_int(CLK125TX), // Internal RGMII transmitter clock. + .tx_rgmii_clk90_int(CLK125TX90), // Internal RGMII transmitter clock w/ 90 deg phase + .rx_rgmii_clk_int(CLK125RX), // Internal RGMII receiver clock + + .reset(!phy_rst_n) +); + +// Instantiate tri-state buffer for MDIO +IOBUF i_iobuf_mdio( + .O(mdio_gem_i), + .IO(mdio_phy_mdio), + .I(mdio_gem_o), + .T(mdio_gem_t)); + +wire EEPROM_CS, EEPROM_SK, EEPROM_DI; +wire TCP_CLOSE_REQ; +wire RBCP_ACT, RBCP_WE, RBCP_RE; +wire [7:0] RBCP_WD, RBCP_RD; +wire [31:0] RBCP_ADDR; +wire TCP_RX_WR; +wire [7:0] TCP_RX_DATA; +wire RBCP_ACK; +wire SiTCP_RST; + +wire TCP_TX_FULL; +wire TCP_TX_WR; +wire [7:0] TCP_TX_DATA; + + +WRAP_SiTCP_GMII_XC7K_32K sitcp( + .CLK(BUS_CLK) , // in : System Clock >129MHz + .RST(RST) , // in : System reset + // Configuration parameters + .FORCE_DEFAULTn(1'b0) , // in : Load default parameters + .EXT_IP_ADDR(32'hc0a80b11) , // in : IP address[31:0] //192.168.10.16 + .EXT_TCP_PORT(16'd24) , // in : TCP port #[15:0] + .EXT_RBCP_PORT(16'd4660) , // in : RBCP port #[15:0] + .PHY_ADDR(5'd3) , // in : PHY-device MIF address[4:0] + // EEPROM + .EEPROM_CS(EEPROM_CS) , // out : Chip select + .EEPROM_SK(EEPROM_SK) , // out : Serial data clock + .EEPROM_DI(EEPROM_DI) , // out : Serial write data + .EEPROM_DO(1'b0) , // in : Serial read data + // user data, intialial values are stored in the EEPROM, 0xFFFF_FC3C-3F + .USR_REG_X3C() , // out : Stored at 0xFFFF_FF3C + .USR_REG_X3D() , // out : Stored at 0xFFFF_FF3D + .USR_REG_X3E() , // out : Stored at 0xFFFF_FF3E + .USR_REG_X3F() , // out : Stored at 0xFFFF_FF3F + // MII interface + .GMII_RSTn(phy_rst_n) , // out : PHY reset + .GMII_1000M(1'b1) , // in : GMII mode (0:MII, 1:GMII) + // TX + .GMII_TX_CLK(CLK125TX) , // in : Tx clock + .GMII_TX_EN(gmii_tx_en) , // out : Tx enable + .GMII_TXD(gmii_txd) , // out : Tx data[7:0] + .GMII_TX_ER(gmii_tx_er) , // out : TX error + // RX + .GMII_RX_CLK(CLK125RX) , // in : Rx clock + .GMII_RX_DV(gmii_rx_dv) , // in : Rx data valid + .GMII_RXD(gmii_rxd) , // in : Rx data[7:0] + .GMII_RX_ER(gmii_rx_er) , // in : Rx error + .GMII_CRS(gmii_crs) , // in : Carrier sense + .GMII_COL(gmii_col) , // in : Collision detected + // Management IF + .GMII_MDC(mdio_phy_mdc) , // out : Clock for MDIO + .GMII_MDIO_IN(mdio_gem_i) , // in : Data + .GMII_MDIO_OUT(mdio_gem_o) , // out : Data + .GMII_MDIO_OE(mdio_gem_t) , // out : MDIO output enable + // User I/F + .SiTCP_RST(SiTCP_RST) , // out : Reset for SiTCP and related circuits + // TCP connection control + .TCP_OPEN_REQ(1'b0) , // in : Reserved input, shoud be 0 + .TCP_OPEN_ACK() , // out : Acknowledge for open (=Socket busy) + .TCP_ERROR() , // out : TCP error, its active period is equal to MSL + .TCP_CLOSE_REQ(TCP_CLOSE_REQ) , // out : Connection close request + .TCP_CLOSE_ACK(TCP_CLOSE_REQ) , // in : Acknowledge for closing + // FIFO I/F + .TCP_RX_WC(1'b1) , // in : Rx FIFO write count[15:0] (Unused bits should be set 1) + .TCP_RX_WR(TCP_RX_WR) , // out : Write enable + .TCP_RX_DATA(TCP_RX_DATA) , // out : Write data[7:0] + .TCP_TX_FULL(TCP_TX_FULL) , // out : Almost full flag + .TCP_TX_WR(TCP_TX_WR) , // in : Write enable + .TCP_TX_DATA(TCP_TX_DATA) , // in : Write data[7:0] + // RBCP + .RBCP_ACT(RBCP_ACT) , // out : RBCP active + .RBCP_ADDR(RBCP_ADDR) , // out : Address[31:0] + .RBCP_WD(RBCP_WD) , // out : Data[7:0] + .RBCP_WE(RBCP_WE) , // out : Write enable + .RBCP_RE(RBCP_RE) , // out : Read enable + .RBCP_ACK(RBCP_ACK) , // in : Access acknowledge + .RBCP_RD(RBCP_RD) // in : Read data[7:0] +); + +// ------- BUS SIGNALLING ------- // + +wire BUS_WR, BUS_RD, BUS_RST; +wire [31:0] BUS_ADD; +wire [7:0] BUS_DATA; +assign BUS_RST = SiTCP_RST; + +rbcp_to_bus irbcp_to_bus( + .BUS_RST(BUS_RST), + .BUS_CLK(BUS_CLK), + + .RBCP_ACT(RBCP_ACT), + .RBCP_ADDR(RBCP_ADDR), + .RBCP_WD(RBCP_WD), + .RBCP_WE(RBCP_WE), + .RBCP_RE(RBCP_RE), + .RBCP_ACK(RBCP_ACK), + .RBCP_RD(RBCP_RD), + + .BUS_WR(BUS_WR), + .BUS_RD(BUS_RD), + .BUS_ADD(BUS_ADD), + .BUS_DATA(BUS_DATA) +); + +// ------- MODULE ADDRESSES ------- // + +localparam CMD_BASEADDR = 32'h0000; +localparam CMD_HIGHADDR = 32'h8000-1; + +localparam TLU_BASEADDR = 32'h40000; +localparam TLU_HIGHADDR = 32'h40100-1; + +localparam RX_BASEADDR = 32'h41000; +localparam RX_HIGHADDR = 32'h41100-1; + +localparam TDC_BASEADDR = 32'h42fff; +localparam TDC_HIGHADDR = 32'h430ff-1; + +localparam GPIO_DLY_BASEADDR = 32'h450ef; +localparam GPIO_DLY_HIGHADDR = 32'h651ef-1; + + + +// ------- USER MODULES ------- // +wire [47:0] GPIO_DLY_IO; + +gpio +#( + .BASEADDR(GPIO_DLY_BASEADDR), + .HIGHADDR(GPIO_DLY_HIGHADDR), + .IO_WIDTH(48), + .IO_DIRECTION(48'hffffffffffff) +) i_gpio +( + .BUS_CLK(BUS_CLK), + .BUS_RST(BUS_RST), + .BUS_ADD(BUS_ADD), + .BUS_DATA(BUS_DATA), + .BUS_RD(BUS_RD), + .BUS_WR(BUS_WR), + .IO(GPIO_DLY_IO) +); +wire [4:0] IDELAYE_CINVCTRL; +wire [4:0] IDELAYE_LD; +wire [4:0] IDELAYE_CNTVALUEIN [4:0]; +wire [2:0] SEL_CLK40; + +assign IDELAYE_LD[0] = GPIO_DLY_IO[7]; +assign IDELAYE_CINVCTRL[0] = GPIO_DLY_IO[6]; +assign IDELAYE_CNTVALUEIN[0] = GPIO_DLY_IO[4:0]; +assign IDELAYE_LD[1] = GPIO_DLY_IO[7+1*8]; +assign IDELAYE_CINVCTRL[1] = GPIO_DLY_IO[6+1*8]; +assign IDELAYE_CNTVALUEIN[1] = GPIO_DLY_IO[4+1*8:0+1*8]; +assign IDELAYE_LD[2] = GPIO_DLY_IO[7+2*8]; +assign IDELAYE_CINVCTRL[2] = GPIO_DLY_IO[6+2*8]; +assign IDELAYE_CNTVALUEIN[2] = GPIO_DLY_IO[4+2*8:0+2*8]; +assign IDELAYE_LD[3] = GPIO_DLY_IO[7+3*8]; +assign IDELAYE_CINVCTRL[3] = GPIO_DLY_IO[6+3*8]; +assign IDELAYE_CNTVALUEIN[3] = GPIO_DLY_IO[4+3*8:0+3*8]; +assign IDELAYE_LD[4] = GPIO_DLY_IO[7+4*8]; +assign IDELAYE_CINVCTRL[4] = GPIO_DLY_IO[6+4*8]; +assign IDELAYE_CNTVALUEIN[4] = GPIO_DLY_IO[4+4*8:0+4*8]; +assign SEL_CLK40 = GPIO_DLY_IO[42:40]; + +wire [7:0] CMD_DATA, CMD_CLK; + +wire [7:0] TRIGGER_ENABLE; // from CMD FSM +wire [7:0] CMD_READY; // from CMD FSM +wire [7:0] CMD_START_FLAG; +wire [7:0] TRIGGER_ACCEPTED_FLAG; +wire [7:0] CMD_EXT_START_FLAG; +assign CMD_EXT_START_FLAG = TRIGGER_ACCEPTED_FLAG; +wire [7:0] EXT_TRIGGER_ENABLE; + +reg [7:0] CLK_SR; +reg CLK40_OUT_SEL; +always@(posedge CLK320) + CLK_SR <= {CLK_SR[6:0],CLK40}; + +always@(posedge CLK320) + CLK40_OUT_SEL <= CLK_SR[SEL_CLK40]; + +wire BROADCAST_CMD; +genvar h; +generate + for (h = 0; h < 8; h = h + 1) begin: cmd_gen + cmd_seq #( + .BASEADDR(CMD_BASEADDR+32'h8000*h), + .HIGHADDR(CMD_HIGHADDR+32'h8000*h), + .ABUSWIDTH(32), + .OUTPUTS(1) + ) i_cmd_seq ( + .BUS_CLK(BUS_CLK), + .BUS_RST(BUS_RST), + .BUS_ADD(BUS_ADD), + .BUS_DATA(BUS_DATA), + .BUS_RD(BUS_RD), + .BUS_WR(BUS_WR), + + .CMD_CLK_IN(CLK40), + .CMD_CLK_OUT(CMD_CLK[h]), + .CMD_DATA(CMD_DATA[h]), + + .CMD_EXT_START_FLAG(BROADCAST_CMD ? CMD_EXT_START_FLAG[0] : CMD_EXT_START_FLAG[h]), + .CMD_EXT_START_ENABLE(EXT_TRIGGER_ENABLE[h]), + .CMD_READY(CMD_READY[h]), + .CMD_START_FLAG(CMD_START_FLAG[h]) + ); + + OBUFDS #( + .IOSTANDARD("LVDS_25"), + .SLEW("SLOW") + ) OBUFDS_inst_cmd_clk_out_h ( + .O(CMD_CLK_P[h]), + .OB(CMD_CLK_N[h]), + .I(CLK40_OUT_SEL) + //.I(CMD_CLK) + ); + + OBUFDS #( + .IOSTANDARD("LVDS_25"), + .SLEW("SLOW") + ) OBUFDS_inst_cmd_data_h ( + .O(CMD_DATA_P[h]), + .OB(CMD_DATA_N[h]), + .I(CMD_DATA[h]) +//.I(CMD_CLK) + + ); + end +endgenerate + + +wire [7:0] TRIGGER_ACKNOWLEDGE_FLAG; // to TLU FSM +reg [7:0] CMD_READY_FF; +always @ (posedge CLK40) +begin + CMD_READY_FF <= CMD_READY; +end +assign TRIGGER_ACKNOWLEDGE_FLAG = CMD_READY & ~CMD_READY_FF; + +reg CMD_READY_BROADCAST; +always @ (posedge CLK40) +begin + if (!BROADCAST_CMD) + CMD_READY_BROADCAST <= 1'b0; + else if (~&(CMD_READY | (~EXT_TRIGGER_ENABLE))) + CMD_READY_BROADCAST <= 1'b0; + else if (&(CMD_READY | (~EXT_TRIGGER_ENABLE))) + CMD_READY_BROADCAST <= 1'b1; + else + CMD_READY_BROADCAST <= CMD_READY_BROADCAST; +end + +wire CMD_READY_BROADCAST_FLAG; +reg CMD_READY_BROADCAST_FF; +always @ (posedge CLK40) +begin + CMD_READY_BROADCAST_FF <= CMD_READY_BROADCAST; +end +assign CMD_READY_BROADCAST_FLAG = CMD_READY_BROADCAST & ~CMD_READY_BROADCAST_FF; + +wire [7:0] TRIGGER_FIFO_READ; +wire [7:0] TRIGGER_FIFO_EMPTY; +wire [31:0] TRIGGER_FIFO_DATA [7:0]; +wire [7:0] TRIGGER_FIFO_PREEMPT_REQ; +wire [31:0] TIMESTAMP [7:0]; +wire [0:0] TDC_OUT; +wire [15:0] RX_READY, RX_8B10B_DECODER_ERR, RX_FIFO_OVERFLOW_ERR, RX_FIFO_FULL, RX_ENABLED; +wire FIFO_FULL; +wire TLU_BUSY, TLU_CLOCK; +wire [7:0] TRIGGER_ENABLED, TLU_ENABLED; +wire [7:0] TRIGGER_SELECTED [7:0]; +assign RJ45_BUSY_LEMO_TX1 = TLU_ENABLED[0] ? TLU_BUSY : ~CMD_READY_BROADCAST; +assign RJ45_CLK_LEMO_TX0 = TLU_CLOCK; + +genvar k; +generate + for (k = 1; k < 8; k = k + 1) begin: tlu_gen + tlu_controller #( + .BASEADDR(TLU_BASEADDR+32'h0100*k), + .HIGHADDR(TLU_HIGHADDR+32'h0100*k), + .DIVISOR(8), + .ABUSWIDTH(32), + .WIDTH(9) + ) i_tlu_controller ( + .BUS_CLK(BUS_CLK), + .BUS_RST(BUS_RST), + .BUS_ADD(BUS_ADD), + .BUS_DATA(BUS_DATA), + .BUS_RD(BUS_RD), + .BUS_WR(BUS_WR), + + .TRIGGER_CLK(CLK40), + + .FIFO_READ(TRIGGER_FIFO_READ[k]), + .FIFO_EMPTY(TRIGGER_FIFO_EMPTY[k]), + .FIFO_DATA(TRIGGER_FIFO_DATA[k]), + + .FIFO_PREEMPT_REQ(TRIGGER_FIFO_PREEMPT_REQ[k]), + + .TRIGGER_ENABLED(TRIGGER_ENABLED[k]), + .TRIGGER_SELECTED(TRIGGER_SELECTED[k]), + .TLU_ENABLED(TLU_ENABLED[k]), + + .TRIGGER({TDC_OUT, LEMO_RX[0]}), + .TRIGGER_VETO({RX_FIFO_FULL, FIFO_FULL}), + + .EXT_TRIGGER_ENABLE(BROADCAST_CMD ? 1'b0 : EXT_TRIGGER_ENABLE[k]), + .TRIGGER_ACKNOWLEDGE(BROADCAST_CMD ? 1'b0 : TRIGGER_ACKNOWLEDGE_FLAG[k]), + .TRIGGER_ACCEPTED_FLAG(TRIGGER_ACCEPTED_FLAG[k]), + + .TLU_TRIGGER(1'b0), + .TLU_RESET(1'b0), + .TLU_BUSY(), + .TLU_CLOCK(), + + .TIMESTAMP(TIMESTAMP[k]) + ); + end +endgenerate + +tlu_controller #( + .BASEADDR(TLU_BASEADDR), + .HIGHADDR(TLU_HIGHADDR), + .DIVISOR(8), + .ABUSWIDTH(32), + .WIDTH(9) +) i_tlu_controller_0 ( + .BUS_CLK(BUS_CLK), + .BUS_RST(BUS_RST), + .BUS_ADD(BUS_ADD), + .BUS_DATA(BUS_DATA), + .BUS_RD(BUS_RD), + .BUS_WR(BUS_WR), + + .TRIGGER_CLK(CLK40), + + .FIFO_READ(TRIGGER_FIFO_READ[0]), + .FIFO_EMPTY(TRIGGER_FIFO_EMPTY[0]), + .FIFO_DATA(TRIGGER_FIFO_DATA[0]), + + .FIFO_PREEMPT_REQ(TRIGGER_FIFO_PREEMPT_REQ[0]), + + .TRIGGER_ENABLED(TRIGGER_ENABLED[0]), + .TRIGGER_SELECTED(TRIGGER_SELECTED[0]), + .TLU_ENABLED(TLU_ENABLED[0]), + + .TRIGGER({TDC_OUT, LEMO_RX[0]}), + .TRIGGER_VETO({RX_FIFO_FULL, FIFO_FULL}), + + .EXT_TRIGGER_ENABLE(BROADCAST_CMD ? |EXT_TRIGGER_ENABLE : EXT_TRIGGER_ENABLE[0]), + .TRIGGER_ACKNOWLEDGE(BROADCAST_CMD ? CMD_READY_BROADCAST_FLAG : TRIGGER_ACKNOWLEDGE_FLAG[0]), + .TRIGGER_ACCEPTED_FLAG(TRIGGER_ACCEPTED_FLAG[0]), + + .TLU_TRIGGER(RJ45_TRIGGER), + .TLU_RESET(RJ45_RESET), + .TLU_BUSY(TLU_BUSY), + .TLU_CLOCK(TLU_CLOCK), + + .TIMESTAMP(TIMESTAMP[0]) +); +assign BROADCAST_CMD = (TRIGGER_ENABLED == 8'b0000_0001 && (TLU_ENABLED[0] || TRIGGER_SELECTED[0] == 8'b0000_0001)); + + +wire [15:0] FE_FIFO_READ; +wire [15:0] FE_FIFO_EMPTY; +wire [31:0] FE_FIFO_DATA [15:0]; + +wire [0:0] TDC_FIFO_READ; +wire [0:0] TDC_FIFO_EMPTY; +wire [31:0] TDC_FIFO_DATA [0:0]; + +genvar i; +generate + for (i = 0; i < 16; i = i + 1) begin: rx_gen + wire DOBOUT; + reg DOBOUT_DLY; + fei4_rx #( + .BASEADDR(RX_BASEADDR+32'h0100*i), + .HIGHADDR(RX_HIGHADDR+32'h0100*i), + .DSIZE(10), + .DATA_IDENTIFIER(i), + .ABUSWIDTH(32) + ) i_fei4_rx ( + .RX_CLK(CLK160), + .RX_CLK2X(CLK320), + .DATA_CLK(CLK16), + + .RX_DATA(DOBOUT_DLY), + + .RX_READY(RX_READY[i]), + .RX_8B10B_DECODER_ERR(RX_8B10B_DECODER_ERR[i]), + .RX_FIFO_OVERFLOW_ERR(RX_FIFO_OVERFLOW_ERR[i]), + + .FIFO_READ(FE_FIFO_READ[i]), + .FIFO_EMPTY(FE_FIFO_EMPTY[i]), + .FIFO_DATA(FE_FIFO_DATA[i]), + + .RX_FIFO_FULL(RX_FIFO_FULL[i]), + .RX_ENABLED(RX_ENABLED[i]), + + .BUS_CLK(BUS_CLK), + .BUS_RST(BUS_RST), + .BUS_ADD(BUS_ADD), + .BUS_DATA(BUS_DATA), + .BUS_RD(BUS_RD), + .BUS_WR(BUS_WR) + ); + + IBUFDS #( + .DIFF_TERM("TRUE"), + .IBUF_LOW_PWR("FALSE"), + .IOSTANDARD("LVDS_25") + ) IBUFDS_inst_i ( + .O(DOBOUT), + .I(DOBOUT_P[i]), + .IB(DOBOUT_N[i]) + ); + + always@(*) DOBOUT_DLY = DOBOUT; +end +endgenerate + +wire [0:0] RJ45_HITOR; + +genvar j; +generate + for (j = 0; j < 1; j = j + 1) begin: tdc_gen + tdc_s3 #( + .BASEADDR(TDC_BASEADDR+32'h0100*j), + .HIGHADDR(TDC_HIGHADDR+32'h0100*j), + .ABUSWIDTH(32), + .CLKDV(4), + .DATA_IDENTIFIER(4'b0001 + j), + .FAST_TDC(1), + .FAST_TRIGGER(0) + ) i_tdc ( + .CLK320(CLK320), + .CLK160(CLK160), + .DV_CLK(CLK40), + .TDC_IN(RJ45_HITOR[j]), + .TDC_OUT(TDC_OUT[j]), + .TRIG_IN(), + .TRIG_OUT(), + + .FIFO_READ(TDC_FIFO_READ[j]), + .FIFO_EMPTY(TDC_FIFO_EMPTY[j]), + .FIFO_DATA(TDC_FIFO_DATA[j]), + + .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(CMD_START_FLAG[j]), // arm TDC by sending commands + .EXT_EN(1'b0), + + .TIMESTAMP(TIMESTAMP[j][15:0]) + ); + + IBUFDS #( + .DIFF_TERM("TRUE"), + .IBUF_LOW_PWR("FALSE"), + .IOSTANDARD("LVDS_25") + ) IBUFDS_inst_RJ45_HITOR ( + .O(RJ45_HITOR[j]), + .I(RJ45_HITOR_P[j]), + .IB(RJ45_HITOR_N[j]) + ); + + end +endgenerate + + +wire ARB_READY_OUT, ARB_WRITE_OUT; +wire [31:0] ARB_DATA_OUT; +wire [24:0] READ_GRANT; + +rrp_arbiter #( + .WIDTH(24) +) i_rrp_arbiter ( + .RST(BUS_RST), + .CLK(BUS_CLK), + + .WRITE_REQ({~TDC_FIFO_EMPTY, ~FE_FIFO_EMPTY, ~TRIGGER_FIFO_EMPTY}), + .HOLD_REQ({17'b0, TRIGGER_FIFO_PREEMPT_REQ}), + .DATA_IN({TDC_FIFO_DATA[0], FE_FIFO_DATA[15], FE_FIFO_DATA[14], FE_FIFO_DATA[13], FE_FIFO_DATA[12], FE_FIFO_DATA[11], FE_FIFO_DATA[10], FE_FIFO_DATA[9], FE_FIFO_DATA[8], FE_FIFO_DATA[7], FE_FIFO_DATA[6], FE_FIFO_DATA[5], FE_FIFO_DATA[4], FE_FIFO_DATA[3], FE_FIFO_DATA[2], FE_FIFO_DATA[1], FE_FIFO_DATA[0], TRIGGER_FIFO_DATA[7], TRIGGER_FIFO_DATA[6], TRIGGER_FIFO_DATA[5], TRIGGER_FIFO_DATA[4], TRIGGER_FIFO_DATA[3], TRIGGER_FIFO_DATA[2], TRIGGER_FIFO_DATA[1], TRIGGER_FIFO_DATA[0]}), + .READ_GRANT(READ_GRANT), + + .READY_OUT(ARB_READY_OUT), + .WRITE_OUT(ARB_WRITE_OUT), + .DATA_OUT(ARB_DATA_OUT) +); + +assign TRIGGER_FIFO_READ = READ_GRANT[7:0]; +assign FE_FIFO_READ = READ_GRANT[23:8]; +assign TDC_FIFO_READ = READ_GRANT[24:24]; + +//cdc_fifo is for timing reasons +wire [31:0] cdc_data_out; +wire full_32to8, cdc_fifo_empty; +wire FIFO_EMPTY; +cdc_syncfifo #(.DSIZE(32), .ASIZE(3)) cdc_syncfifo_i +( + .rdata(cdc_data_out), + .wfull(FIFO_FULL), + .rempty(cdc_fifo_empty), + .wdata(ARB_DATA_OUT), + .winc(ARB_WRITE_OUT), .wclk(BUS_CLK), .wrst(BUS_RST), + .rinc(!full_32to8), .rclk(BUS_CLK), .rrst(BUS_RST) +); +assign ARB_READY_OUT = !FIFO_FULL; + +fifo_32_to_8 #(.DEPTH(256*1024)) i_data_fifo ( + .RST(BUS_RST), + .CLK(BUS_CLK), + + .WRITE(!cdc_fifo_empty), + .READ(TCP_TX_WR), + .DATA_IN(cdc_data_out), + .FULL(full_32to8), + .EMPTY(FIFO_EMPTY), + .DATA_OUT(TCP_TX_DATA) +); + +assign TCP_TX_WR = !TCP_TX_FULL && !FIFO_EMPTY; + +wire CLK_1HZ; +clock_divider #( + .DIVISOR(40000000) +) i_clock_divisor_40MHz_to_1Hz ( + .CLK(CLK40), + .RESET(1'b0), + .CE(), + .CLOCK(CLK_1HZ) +); + +wire CLK_3HZ; +clock_divider #( + .DIVISOR(13333333) +) i_clock_divisor_40MHz_to_3Hz ( + .CLK(CLK40), + .RESET(1'b0), + .CE(), + .CLOCK(CLK_3HZ) +); + + + + +assign LED[7:4] = 4'hf; +assign LED[0] = ~((CLK_1HZ | FIFO_FULL) & LOCKED & LOCKED2); +assign LED[1] = ~(((RX_READY & RX_ENABLED) == RX_ENABLED) & ((|(RX_8B10B_DECODER_ERR & RX_ENABLED)? CLK_3HZ : CLK_1HZ) | (|(RX_FIFO_OVERFLOW_ERR & RX_ENABLED)) | (|(RX_FIFO_FULL & RX_ENABLED)))); +assign LED[2] = 1'b1; +assign LED[3] = 1'b1; + + + +endmodule diff --git a/firmware/mmc3_16chip_multi_tx_eth/vivado/mmc3_16chip_multi_tx_eth.xpr b/firmware/mmc3_16chip_multi_tx_eth/vivado/mmc3_16chip_multi_tx_eth.xpr new file mode 100644 index 000000000..0ce07b17a --- /dev/null +++ b/firmware/mmc3_16chip_multi_tx_eth/vivado/mmc3_16chip_multi_tx_eth.xpr @@ -0,0 +1,527 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/firmware/mmc3_8chip_eth/README.md b/firmware/mmc3_8chip_eth/README.md new file mode 100644 index 000000000..6f821267a --- /dev/null +++ b/firmware/mmc3_8chip_eth/README.md @@ -0,0 +1,5 @@ + +### pyBAR firmware for max. 8 FEI4s + + + diff --git a/firmware/mmc3_8chip_eth/src/mmc3.xdc b/firmware/mmc3_8chip_eth/src/mmc3.xdc new file mode 100644 index 000000000..5e3843249 --- /dev/null +++ b/firmware/mmc3_8chip_eth/src/mmc3.xdc @@ -0,0 +1,204 @@ + +create_clock -period 10.000 -name clkin -add [get_ports clkin] +create_clock -period 8.000 -name rgmii_rxc -add [get_ports rgmii_rxc] + +set_false_path -from [get_clocks CLK125PLLTX] -to [get_clocks BUS_CLK_PLL] +set_false_path -from [get_clocks BUS_CLK_PLL] -to [get_clocks CLK125PLLTX] +set_false_path -from [get_clocks BUS_CLK_PLL] -to [get_clocks rgmii_rxc] +set_false_path -from [get_clocks rgmii_rxc] -to [get_clocks BUS_CLK_PLL] +set_false_path -from [get_clocks BUS_CLK_PLL] -to [get_clocks rgmii_rxc] +set_false_path -from [get_clocks rgmii_rxc] -to [get_clocks BUS_CLK_PLL] +set_false_path -from [get_clocks CLK16_PLL] -to [get_clocks BUS_CLK_PLL] +set_false_path -from [get_clocks BUS_CLK_PLL] -to [get_clocks CLK16_PLL] +set_false_path -from [get_clocks CLK160_PLL] -to [get_clocks BUS_CLK_PLL] +set_false_path -from [get_clocks BUS_CLK_PLL] -to [get_clocks CLK160_PLL] +set_false_path -from [get_clocks CLK40_PLL] -to [get_clocks BUS_CLK_PLL] +set_false_path -from [get_clocks BUS_CLK_PLL] -to [get_clocks CLK40_PLL] + +#NET "Clk100" LOC = "AA3" | IOSTANDARD = "LVCMOS15"; 100MHz +set_property PACKAGE_PIN AA3 [get_ports clkin] +set_property IOSTANDARD LVCMOS15 [get_ports clkin] + +set_property PACKAGE_PIN C18 [get_ports RESET_N] +set_property IOSTANDARD LVCMOS25 [get_ports RESET_N] +set_property PULLUP true [get_ports RESET_N] + +set_property SLEW FAST [get_ports mdio_phy_mdc] +set_property IOSTANDARD LVCMOS25 [get_ports mdio_phy_mdc] +set_property PACKAGE_PIN N16 [get_ports mdio_phy_mdc] + +set_property SLEW FAST [get_ports mdio_phy_mdio] +set_property IOSTANDARD LVCMOS25 [get_ports mdio_phy_mdio] +set_property PACKAGE_PIN U16 [get_ports mdio_phy_mdio] + +set_property SLEW FAST [get_ports phy_rst_n] +set_property IOSTANDARD LVCMOS25 [get_ports phy_rst_n] +set_property PACKAGE_PIN M20 [get_ports phy_rst_n] + +set_property IOSTANDARD LVCMOS25 [get_ports rgmii_rxc] +set_property PACKAGE_PIN R21 [get_ports rgmii_rxc] + +set_property IOSTANDARD LVCMOS25 [get_ports rgmii_rx_ctl] +set_property PACKAGE_PIN P21 [get_ports rgmii_rx_ctl] +set_property IOSTANDARD LVCMOS25 [get_ports {rgmii_rxd[0]}] +set_property PACKAGE_PIN P16 [get_ports {rgmii_rxd[0]}] +set_property IOSTANDARD LVCMOS25 [get_ports {rgmii_rxd[1]}] +set_property PACKAGE_PIN N17 [get_ports {rgmii_rxd[1]}] +set_property IOSTANDARD LVCMOS25 [get_ports {rgmii_rxd[2]}] +set_property PACKAGE_PIN R16 [get_ports {rgmii_rxd[2]}] +set_property IOSTANDARD LVCMOS25 [get_ports {rgmii_rxd[3]}] +set_property PACKAGE_PIN R17 [get_ports {rgmii_rxd[3]}] + +set_property SLEW FAST [get_ports rgmii_txc] +set_property IOSTANDARD LVCMOS25 [get_ports rgmii_txc] +set_property PACKAGE_PIN R18 [get_ports rgmii_txc] + +set_property SLEW FAST [get_ports rgmii_tx_ctl] +set_property IOSTANDARD LVCMOS25 [get_ports rgmii_tx_ctl] +set_property PACKAGE_PIN P18 [get_ports rgmii_tx_ctl] + +set_property SLEW FAST [get_ports {rgmii_txd[0]}] +set_property IOSTANDARD LVCMOS25 [get_ports {rgmii_txd[0]}] +set_property PACKAGE_PIN N18 [get_ports {rgmii_txd[0]}] +set_property SLEW FAST [get_ports {rgmii_txd[1]}] +set_property IOSTANDARD LVCMOS25 [get_ports {rgmii_txd[1]}] +set_property PACKAGE_PIN M19 [get_ports {rgmii_txd[1]}] +set_property SLEW FAST [get_ports {rgmii_txd[2]}] +set_property IOSTANDARD LVCMOS25 [get_ports {rgmii_txd[2]}] +set_property PACKAGE_PIN U17 [get_ports {rgmii_txd[2]}] +set_property SLEW FAST [get_ports {rgmii_txd[3]}] +set_property IOSTANDARD LVCMOS25 [get_ports {rgmii_txd[3]}] +set_property PACKAGE_PIN T17 [get_ports {rgmii_txd[3]}] + + +set_property PACKAGE_PIN M17 [get_ports {LED[0]}] +set_property PACKAGE_PIN L18 [get_ports {LED[1]}] +set_property PACKAGE_PIN L17 [get_ports {LED[2]}] +set_property PACKAGE_PIN K18 [get_ports {LED[3]}] +set_property PACKAGE_PIN P26 [get_ports {LED[4]}] +set_property PACKAGE_PIN M25 [get_ports {LED[5]}] +set_property PACKAGE_PIN L25 [get_ports {LED[6]}] +set_property PACKAGE_PIN P23 [get_ports {LED[7]}] +set_property IOSTANDARD LVCMOS25 [get_ports LED*] +set_property SLEW SLOW [get_ports LED*] + +set_property PACKAGE_PIN H11 [get_ports RJ45_HITOR_N[0]] +set_property IOSTANDARD LVDS_25 [get_ports RJ45_HITOR*] +set_property KEEPER true [get_ports RJ45_HITOR_P[0]] +set_property PACKAGE_PIN C11 [get_ports RJ45_HITOR_N[1]] +set_property IOSTANDARD LVDS_25 [get_ports RJ45_HITOR*] +set_property KEEPER true [get_ports RJ45_HITOR_P[1]] +set_property PACKAGE_PIN A15 [get_ports RJ45_HITOR_N[2]] +set_property IOSTANDARD LVDS_25 [get_ports RJ45_HITOR*] +set_property KEEPER true [get_ports RJ45_HITOR_P[2]] +set_property PACKAGE_PIN G16 [get_ports RJ45_HITOR_N[3]] +set_property IOSTANDARD LVDS_25 [get_ports RJ45_HITOR*] +set_property KEEPER true [get_ports RJ45_HITOR_P[3]] +set_property PACKAGE_PIN D10 [get_ports RJ45_HITOR_N[4]] +set_property IOSTANDARD LVDS_25 [get_ports RJ45_HITOR*] +set_property KEEPER true [get_ports RJ45_HITOR_P[4]] +set_property PACKAGE_PIN D11 [get_ports RJ45_HITOR_N[5]] +set_property IOSTANDARD LVDS_25 [get_ports RJ45_HITOR*] +set_property KEEPER true [get_ports RJ45_HITOR_P[5]] +set_property PACKAGE_PIN A10 [get_ports RJ45_HITOR_N[6]] +set_property IOSTANDARD LVDS_25 [get_ports RJ45_HITOR*] +set_property KEEPER true [get_ports RJ45_HITOR_P[6]] +set_property PACKAGE_PIN E16 [get_ports RJ45_HITOR_N[7]] +set_property IOSTANDARD LVDS_25 [get_ports RJ45_HITOR*] +set_property KEEPER true [get_ports RJ45_HITOR_P[7]] + +#PORT CMD +set_property PACKAGE_PIN D8 [get_ports CMD_DATA_N[0]] +set_property IOSTANDARD LVDS_25 [get_ports CMD_DATA*] +set_property KEEPER true [get_ports CMD_DATA_P[0]] +set_property PACKAGE_PIN B9 [get_ports CMD_CLK_N[0]] +set_property IOSTANDARD LVDS_25 [get_ports CMD_CLK*] +set_property KEEPER true [get_ports CMD_CLK_P[0]] +set_property PACKAGE_PIN F12 [get_ports CMD_DATA_N[1]] +set_property IOSTANDARD LVDS_25 [get_ports CMD_DATA*] +set_property KEEPER true [get_ports CMD_DATA_P[1]] +set_property PACKAGE_PIN C13 [get_ports CMD_CLK_N[1]] +set_property IOSTANDARD LVDS_25 [get_ports CMD_CLK*] +set_property KEEPER true [get_ports CMD_CLK_P[1]] +set_property PACKAGE_PIN A17 [get_ports CMD_DATA_N[2]] +set_property IOSTANDARD LVDS_25 [get_ports CMD_DATA*] +set_property KEEPER true [get_ports CMD_DATA_P[2]] +set_property PACKAGE_PIN B19 [get_ports CMD_CLK_N[2]] +set_property IOSTANDARD LVDS_25 [get_ports CMD_CLK*] +set_property KEEPER true [get_ports CMD_CLK_P[2]] +set_property PACKAGE_PIN F18 [get_ports CMD_DATA_N[3]] +set_property IOSTANDARD LVDS_25 [get_ports CMD_DATA*] +set_property KEEPER true [get_ports CMD_DATA_P[3]] +set_property PACKAGE_PIN J16 [get_ports CMD_CLK_N[3]] +set_property IOSTANDARD LVDS_25 [get_ports CMD_CLK*] +set_property KEEPER true [get_ports CMD_CLK_P[3]] + +set_property PACKAGE_PIN G14 [get_ports CMD_DATA_N[4]] +set_property IOSTANDARD LVDS_25 [get_ports CMD_DATA*] +set_property KEEPER true [get_ports CMD_DATA_P[4]] +set_property PACKAGE_PIN H13 [get_ports CMD_CLK_N[4]] +set_property IOSTANDARD LVDS_25 [get_ports CMD_CLK*] +set_property KEEPER true [get_ports CMD_CLK_P[4]] +set_property PACKAGE_PIN F13 [get_ports CMD_DATA_N[5]] +set_property IOSTANDARD LVDS_25 [get_ports CMD_DATA*] +set_property KEEPER true [get_ports CMD_DATA_P[5]] +set_property PACKAGE_PIN H8 [get_ports CMD_CLK_N[5]] +set_property IOSTANDARD LVDS_25 [get_ports CMD_CLK*] +set_property KEEPER true [get_ports CMD_CLK_P[5]] +set_property PACKAGE_PIN A14 [get_ports CMD_DATA_N[6]] +set_property IOSTANDARD LVDS_25 [get_ports CMD_DATA*] +set_property KEEPER true [get_ports CMD_DATA_P[6]] +set_property PACKAGE_PIN E12 [get_ports CMD_CLK_N[6]] +set_property IOSTANDARD LVDS_25 [get_ports CMD_CLK*] +set_property KEEPER true [get_ports CMD_CLK_P[6]] +set_property PACKAGE_PIN E17 [get_ports CMD_DATA_N[7]] +set_property IOSTANDARD LVDS_25 [get_ports CMD_DATA*] +set_property KEEPER true [get_ports CMD_DATA_P[7]] +set_property PACKAGE_PIN A19 [get_ports CMD_CLK_N[7]] +set_property IOSTANDARD LVDS_25 [get_ports CMD_CLK*] +set_property KEEPER true [get_ports CMD_CLK_P[7]] + + +set_property BITSTREAM.CONFIG.UNUSEDPIN PULLUP [current_design] + + + +set_property PACKAGE_PIN F15 [get_ports DOBOUT_N[7]] +set_property IOSTANDARD LVDS_25 [get_ports DOBOUT*] +set_property KEEPER true [get_ports DOBOUT_P[7]] +set_property PACKAGE_PIN B16 [get_ports DOBOUT_N[6]] +set_property IOSTANDARD LVDS_25 [get_ports DOBOUT*] +set_property KEEPER true [get_ports DOBOUT_P[6]] +set_property PACKAGE_PIN D13 [get_ports DOBOUT_N[5]] +set_property IOSTANDARD LVDS_25 [get_ports DOBOUT*] +set_property KEEPER true [get_ports DOBOUT_P[5]] +set_property PACKAGE_PIN A8 [get_ports DOBOUT_N[4]] +set_property IOSTANDARD LVDS_25 [get_ports DOBOUT*] +set_property KEEPER true [get_ports DOBOUT_P[4]] + +set_property PACKAGE_PIN D16 [get_ports DOBOUT_N[3]] +set_property IOSTANDARD LVDS_25 [get_ports DOBOUT*] +set_property KEEPER true [get_ports DOBOUT_P[3]] +set_property PACKAGE_PIN B11 [get_ports DOBOUT_N[2]] +set_property IOSTANDARD LVDS_25 [get_ports DOBOUT*] +set_property KEEPER true [get_ports DOBOUT_P[2]] +set_property PACKAGE_PIN F8 [get_ports DOBOUT_N[1]] +set_property IOSTANDARD LVDS_25 [get_ports DOBOUT*] +set_property KEEPER true [get_ports DOBOUT_P[1]] +set_property PACKAGE_PIN J10 [get_ports DOBOUT_N[0]] +set_property IOSTANDARD LVDS_25 [get_ports DOBOUT*] +set_property KEEPER true [get_ports DOBOUT_P[0]] + + +set_property PACKAGE_PIN V23 [get_ports RJ45_BUSY_LEMO_TX1] +set_property PACKAGE_PIN AB21 [get_ports RJ45_CLK_LEMO_TX0] +set_property PACKAGE_PIN V21 [get_ports RJ45_TRIGGER] +set_property PACKAGE_PIN Y25 [get_ports RJ45_RESET] +set_property IOSTANDARD LVCMOS25 [get_ports RJ45_BUSY_LEMO_TX1] +set_property IOSTANDARD LVCMOS25 [get_ports RJ45_CLK_LEMO_TX0] +set_property IOSTANDARD LVCMOS25 [get_ports RJ45_RESET] +set_property IOSTANDARD LVCMOS25 [get_ports RJ45_TRIGGER] + +set_property PACKAGE_PIN U26 [get_ports {LEMO_RX[1]}] +set_property PACKAGE_PIN U22 [get_ports {LEMO_RX[0]}] +set_property IOSTANDARD LVCMOS25 [get_ports LEMO_RX*] diff --git a/firmware/mmc3_8chip_eth/src/mmc3_8chip_eth.v b/firmware/mmc3_8chip_eth/src/mmc3_8chip_eth.v new file mode 100644 index 000000000..457042e8f --- /dev/null +++ b/firmware/mmc3_8chip_eth/src/mmc3_8chip_eth.v @@ -0,0 +1,827 @@ +/** + * This file is part of pyBAR. + * + * pyBAR is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * pyBAR is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with pyBAR. If not, see . + */ + +/** + * ------------------------------------------------------------ + * Copyright (c) All rights reserved + * SiLab, Institute of Physics, University of Bonn + * ------------------------------------------------------------ + */ + +`timescale 1ps / 1ps +`default_nettype none + +module mmc3_8chip_eth( + input wire RESET_N, + input wire clkin, + output wire [3:0] rgmii_txd, + output wire rgmii_tx_ctl, + output wire rgmii_txc, + input wire [3:0] rgmii_rxd, + input wire rgmii_rx_ctl, + input wire rgmii_rxc, + output wire mdio_phy_mdc, + inout wire mdio_phy_mdio, + output wire phy_rst_n, + output wire [7:0] LED, + output wire [7:0] CMD_CLK_P, CMD_CLK_N, + output wire [7:0] CMD_DATA_P, CMD_DATA_N, + input wire [7:0] RJ45_HITOR_N, RJ45_HITOR_P, + input wire [7:0] DOBOUT_N, DOBOUT_P, + output wire RJ45_BUSY_LEMO_TX1, RJ45_CLK_LEMO_TX0, + input wire RJ45_TRIGGER, RJ45_RESET, + input wire [1:0] LEMO_RX +); + + +wire RST; +wire CLK250PLL, CLK125PLLTX, CLK125PLLTX90, CLK125PLLRX; +wire PLL_FEEDBACK, LOCKED; + +PLLE2_BASE #( + .BANDWIDTH("OPTIMIZED"), // OPTIMIZED, HIGH, LOW + .CLKFBOUT_MULT(10), // Multiply value for all CLKOUT, (2-64) + .CLKFBOUT_PHASE(0.0), // Phase offset in degrees of CLKFB, (-360.000-360.000). + .CLKIN1_PERIOD(10.000), // Input clock period in ns to ps resolution (i.e. 33.333 is 30 MHz). + + .CLKOUT0_DIVIDE(7), // Divide amount for CLKOUT0 (1-128) + .CLKOUT0_DUTY_CYCLE(0.5), // Duty cycle for CLKOUT0 (0.001-0.999). + .CLKOUT0_PHASE(0.0), // Phase offset for CLKOUT0 (-360.000-360.000). + + .CLKOUT1_DIVIDE(4), // Divide amount for CLKOUT0 (1-128) + .CLKOUT1_DUTY_CYCLE(0.5), // Duty cycle for CLKOUT0 (0.001-0.999). + .CLKOUT1_PHASE(0.0), // Phase offset for CLKOUT0 (-360.000-360.000). + + .CLKOUT2_DIVIDE(8), // Divide amount for CLKOUT0 (1-128) + .CLKOUT2_DUTY_CYCLE(0.5), // Duty cycle for CLKOUT0 (0.001-0.999). + .CLKOUT2_PHASE(0.0), // Phase offset for CLKOUT0 (-360.000-360.000). + + .CLKOUT3_DIVIDE(8), // Divide amount for CLKOUT0 (1-128) + .CLKOUT3_DUTY_CYCLE(0.5), // Duty cycle for CLKOUT0 (0.001-0.999). + .CLKOUT3_PHASE(90.0), // Phase offset for CLKOUT0 (-360.000-360.000). + + .CLKOUT4_DIVIDE(8), // Divide amount for CLKOUT0 (1-128) + .CLKOUT4_DUTY_CYCLE(0.5), // Duty cycle for CLKOUT0 (0.001-0.999). + .CLKOUT4_PHASE(-5.6), // Phase offset for CLKOUT0 (-360.000-360.000). + //-65 -> 0?; - 45 -> 39; -25 -> 100; -5 -> 0; + + .DIVCLK_DIVIDE(1), // Master division value, (1-56) + .REF_JITTER1(0.0), // Reference input jitter in UI, (0.000-0.999). + .STARTUP_WAIT("FALSE") // Delay DONE until PLL Locks, ("TRUE"/"FALSE") + ) + PLLE2_BASE_inst ( + + .CLKOUT0(), + .CLKOUT1(CLK250PLL), + + .CLKOUT2(CLK125PLLTX), + .CLKOUT3(CLK125PLLTX90), + .CLKOUT4(CLK125PLLRX), + + .CLKOUT5(), + + .CLKFBOUT(PLL_FEEDBACK), + + .LOCKED(LOCKED), // 1-bit output: LOCK + + // Input 100 MHz clock + .CLKIN1(clkin), + + // Control Ports + .PWRDWN(0), + .RST(!RESET_N), + + // Feedback + .CLKFBIN(PLL_FEEDBACK) + ); + +wire PLL_FEEDBACK2, LOCKED2; +wire CLK160_PLL, CLK320_PLL, CLK40_PLL, CLK16_PLL, BUS_CLK_PLL, CLK200_PLL; +PLLE2_BASE #( + .BANDWIDTH("OPTIMIZED"), + .CLKFBOUT_MULT(16), + .CLKFBOUT_PHASE(0.0), + .CLKIN1_PERIOD(10.000), + + .CLKOUT0_DIVIDE(10), + .CLKOUT0_DUTY_CYCLE(0.5), + .CLKOUT0_PHASE(0.0), + + .CLKOUT1_DIVIDE(40), + .CLKOUT1_DUTY_CYCLE(0.5), + .CLKOUT1_PHASE(0.0), + + .CLKOUT2_DIVIDE(5), + .CLKOUT2_DUTY_CYCLE(0.5), + .CLKOUT2_PHASE(0.0), + + .CLKOUT3_DIVIDE(100), + .CLKOUT3_DUTY_CYCLE(0.5), + .CLKOUT3_PHASE(0.0), + + .CLKOUT4_DIVIDE(12), + .CLKOUT4_DUTY_CYCLE(0.5), + .CLKOUT4_PHASE(0.0), + + .CLKOUT5_DIVIDE(8), + .CLKOUT5_DUTY_CYCLE(0.5), + .CLKOUT5_PHASE(0.0), + + + .DIVCLK_DIVIDE(1), + .REF_JITTER1(0.0), + .STARTUP_WAIT("FALSE") +) +PLLE2_BASE_inst_2 ( + + .CLKOUT0(CLK160_PLL), + .CLKOUT1(CLK40_PLL), + .CLKOUT2(CLK320_PLL), + .CLKOUT3(CLK16_PLL), + .CLKOUT4(BUS_CLK_PLL), + .CLKOUT5(CLK200_PLL), + + .CLKFBOUT(PLL_FEEDBACK2), + .LOCKED(LOCKED2), // 1-bit output: LOCK + + .CLKIN1(clkin), + + .PWRDWN(0), + .RST(!RESET_N), + + .CLKFBIN(PLL_FEEDBACK2) +); + + +wire CLK160, CLK40, CLK320, CLK16, BUS_CLK, CLK200; +BUFG BUFG_inst_160 (.O(CLK160), .I(CLK160_PLL) ); +BUFG BUFG_inst_40 (.O(CLK40), .I(CLK40_PLL) ); +BUFG BUFG_inst_320 (.O(CLK320), .I(CLK320_PLL) ); +BUFG BUFG_inst_16 (.O(CLK16), .I(CLK16_PLL) ); +BUFG BUFG_inst_BUS_CLK (.O(BUS_CLK), .I(BUS_CLK_PLL) ); +BUFG BUFG_inst_200 (.O(CLK200), .I(CLK200_PLL) ); +//assign BUS_CLK = CLK160; + +wire IDELAYCTRL_RDY; +IDELAYCTRL IDELAYCTRL_inst ( + .RDY(IDELAYCTRL_RDY), + .REFCLK(CLK200), + .RST(!LOCKED2) +); + + +wire CLK125TX, CLK125TX90, CLK125RX; +BUFG BUFG_inst_CLK125TX ( .O(CLK125TX), .I(CLK125PLLTX) ); +BUFG BUFG_inst_CLK125TX90 ( .O(CLK125TX90), .I(CLK125PLLTX90) ); +BUFG BUFG_inst_CLK125RX ( .O(CLK125RX), .I(rgmii_rxc) ); + +assign RST = !RESET_N | !LOCKED | !LOCKED2; + + +wire gmii_tx_clk; +wire gmii_tx_en; +wire [7:0] gmii_txd; +wire gmii_tx_er; +wire gmii_crs; +wire gmii_col; +wire gmii_rx_clk; +wire gmii_rx_dv; +wire [7:0] gmii_rxd; +wire gmii_rx_er; +wire mdio_gem_mdc; +wire mdio_gem_i; +wire mdio_gem_o; +wire mdio_gem_t; +wire link_status; +wire [1:0] clock_speed; +wire duplex_status; + +rgmii_io rgmii +( + .rgmii_txd(rgmii_txd), + .rgmii_tx_ctl(rgmii_tx_ctl), + .rgmii_txc(rgmii_txc), + + .rgmii_rxd(rgmii_rxd), + .rgmii_rx_ctl(rgmii_rx_ctl), + + .gmii_txd_int(gmii_txd), // Internal gmii_txd signal. + .gmii_tx_en_int(gmii_tx_en), + .gmii_tx_er_int(gmii_tx_er), + .gmii_col_int(gmii_col), + .gmii_crs_int(gmii_crs), + .gmii_rxd_reg(gmii_rxd), // RGMII double data rate data valid. + .gmii_rx_dv_reg(gmii_rx_dv), // gmii_rx_dv_ibuf registered in IOBs. + .gmii_rx_er_reg(gmii_rx_er), // gmii_rx_er_ibuf registered in IOBs. + + .eth_link_status(link_status), + .eth_clock_speed(clock_speed), + .eth_duplex_status(duplex_status), + + // FOllowing are generated by DCMs + .tx_rgmii_clk_int(CLK125TX), // Internal RGMII transmitter clock. + .tx_rgmii_clk90_int(CLK125TX90), // Internal RGMII transmitter clock w/ 90 deg phase + .rx_rgmii_clk_int(CLK125RX), // Internal RGMII receiver clock + + .reset(!phy_rst_n) +); + +// Instantiate tri-state buffer for MDIO +IOBUF i_iobuf_mdio( + .O(mdio_gem_i), + .IO(mdio_phy_mdio), + .I(mdio_gem_o), + .T(mdio_gem_t)); + +wire EEPROM_CS, EEPROM_SK, EEPROM_DI; +wire TCP_CLOSE_REQ; +wire RBCP_ACT, RBCP_WE, RBCP_RE; +wire [7:0] RBCP_WD, RBCP_RD; +wire [31:0] RBCP_ADDR; +wire TCP_RX_WR; +wire [7:0] TCP_RX_DATA; +wire RBCP_ACK; +wire SiTCP_RST; + +wire TCP_TX_FULL; +wire TCP_TX_WR; +wire [7:0] TCP_TX_DATA; + + +WRAP_SiTCP_GMII_XC7K_32K sitcp( + .CLK(BUS_CLK) , // in : System Clock >129MHz + .RST(RST) , // in : System reset + // Configuration parameters + .FORCE_DEFAULTn(1'b0) , // in : Load default parameters + .EXT_IP_ADDR(32'hc0a80a10) , // in : IP address[31:0] //192.168.10.16 + .EXT_TCP_PORT(16'd24) , // in : TCP port #[15:0] + .EXT_RBCP_PORT(16'd4660) , // in : RBCP port #[15:0] + .PHY_ADDR(5'd3) , // in : PHY-device MIF address[4:0] + // EEPROM + .EEPROM_CS(EEPROM_CS) , // out : Chip select + .EEPROM_SK(EEPROM_SK) , // out : Serial data clock + .EEPROM_DI(EEPROM_DI) , // out : Serial write data + .EEPROM_DO(1'b0) , // in : Serial read data + // user data, intialial values are stored in the EEPROM, 0xFFFF_FC3C-3F + .USR_REG_X3C() , // out : Stored at 0xFFFF_FF3C + .USR_REG_X3D() , // out : Stored at 0xFFFF_FF3D + .USR_REG_X3E() , // out : Stored at 0xFFFF_FF3E + .USR_REG_X3F() , // out : Stored at 0xFFFF_FF3F + // MII interface + .GMII_RSTn(phy_rst_n) , // out : PHY reset + .GMII_1000M(1'b1) , // in : GMII mode (0:MII, 1:GMII) + // TX + .GMII_TX_CLK(CLK125TX) , // in : Tx clock + .GMII_TX_EN(gmii_tx_en) , // out : Tx enable + .GMII_TXD(gmii_txd) , // out : Tx data[7:0] + .GMII_TX_ER(gmii_tx_er) , // out : TX error + // RX + .GMII_RX_CLK(CLK125RX) , // in : Rx clock + .GMII_RX_DV(gmii_rx_dv) , // in : Rx data valid + .GMII_RXD(gmii_rxd) , // in : Rx data[7:0] + .GMII_RX_ER(gmii_rx_er) , // in : Rx error + .GMII_CRS(gmii_crs) , // in : Carrier sense + .GMII_COL(gmii_col) , // in : Collision detected + // Management IF + .GMII_MDC(mdio_phy_mdc) , // out : Clock for MDIO + .GMII_MDIO_IN(mdio_gem_i) , // in : Data + .GMII_MDIO_OUT(mdio_gem_o) , // out : Data + .GMII_MDIO_OE(mdio_gem_t) , // out : MDIO output enable + // User I/F + .SiTCP_RST(SiTCP_RST) , // out : Reset for SiTCP and related circuits + // TCP connection control + .TCP_OPEN_REQ(1'b0) , // in : Reserved input, shoud be 0 + .TCP_OPEN_ACK() , // out : Acknowledge for open (=Socket busy) + .TCP_ERROR() , // out : TCP error, its active period is equal to MSL + .TCP_CLOSE_REQ(TCP_CLOSE_REQ) , // out : Connection close request + .TCP_CLOSE_ACK(TCP_CLOSE_REQ) , // in : Acknowledge for closing + // FIFO I/F + .TCP_RX_WC(1'b1) , // in : Rx FIFO write count[15:0] (Unused bits should be set 1) + .TCP_RX_WR(TCP_RX_WR) , // out : Write enable + .TCP_RX_DATA(TCP_RX_DATA) , // out : Write data[7:0] + .TCP_TX_FULL(TCP_TX_FULL) , // out : Almost full flag + .TCP_TX_WR(TCP_TX_WR) , // in : Write enable + .TCP_TX_DATA(TCP_TX_DATA) , // in : Write data[7:0] + // RBCP + .RBCP_ACT(RBCP_ACT) , // out : RBCP active + .RBCP_ADDR(RBCP_ADDR) , // out : Address[31:0] + .RBCP_WD(RBCP_WD) , // out : Data[7:0] + .RBCP_WE(RBCP_WE) , // out : Write enable + .RBCP_RE(RBCP_RE) , // out : Read enable + .RBCP_ACK(RBCP_ACK) , // in : Access acknowledge + .RBCP_RD(RBCP_RD) // in : Read data[7:0] +); + +// ------- BUS SIGNALLING ------- // + +wire BUS_WR, BUS_RD, BUS_RST; +wire [31:0] BUS_ADD; +wire [7:0] BUS_DATA; +assign BUS_RST = SiTCP_RST; + +rbcp_to_bus irbcp_to_bus( + .BUS_RST(BUS_RST), + .BUS_CLK(BUS_CLK), + + .RBCP_ACT(RBCP_ACT), + .RBCP_ADDR(RBCP_ADDR), + .RBCP_WD(RBCP_WD), + .RBCP_WE(RBCP_WE), + .RBCP_RE(RBCP_RE), + .RBCP_ACK(RBCP_ACK), + .RBCP_RD(RBCP_RD), + + .BUS_WR(BUS_WR), + .BUS_RD(BUS_RD), + .BUS_ADD(BUS_ADD), + .BUS_DATA(BUS_DATA) +); + +// ------- MODULE ADDRESSES ------- // + +localparam CMD_BASEADDR = 32'h0000; +localparam CMD_HIGHADDR = 32'h8000-1; + +localparam TLU_BASEADDR = 32'h8200; +localparam TLU_HIGHADDR = 32'h8300-1; + +localparam RX_BASEADDR = 32'h9000; +localparam RX_HIGHADDR = 32'h9100-1; + +localparam TDC_BASEADDR = 32'ha000; +localparam TDC_HIGHADDR = 32'ha100-1; + +localparam GPIO_DLY_BASEADDR = 32'hb000; +localparam GPIO_DLY_HIGHADDR = 32'hb100-1; + + + +// ------- USER MODULES ------- // +wire [47:0] GPIO_DLY_IO; + +gpio +#( + .BASEADDR(GPIO_DLY_BASEADDR), + .HIGHADDR(GPIO_DLY_HIGHADDR), + .IO_WIDTH(48), + .IO_DIRECTION(48'hffffffffffff) +) i_gpio +( + .BUS_CLK(BUS_CLK), + .BUS_RST(BUS_RST), + .BUS_ADD(BUS_ADD), + .BUS_DATA(BUS_DATA), + .BUS_RD(BUS_RD), + .BUS_WR(BUS_WR), + .IO(GPIO_DLY_IO) +); +wire [4:0] IDELAYE_CINVCTRL; +wire [4:0] IDELAYE_LD; +wire [4:0] IDELAYE_CNTVALUEIN [4:0]; +wire [2:0] SEL_CLK40; + +assign IDELAYE_LD[0] = GPIO_DLY_IO[7]; +assign IDELAYE_CINVCTRL[0] = GPIO_DLY_IO[6]; +assign IDELAYE_CNTVALUEIN[0] = GPIO_DLY_IO[4:0]; +assign IDELAYE_LD[1] = GPIO_DLY_IO[7+1*8]; +assign IDELAYE_CINVCTRL[1] = GPIO_DLY_IO[6+1*8]; +assign IDELAYE_CNTVALUEIN[1] = GPIO_DLY_IO[4+1*8:0+1*8]; +assign IDELAYE_LD[2] = GPIO_DLY_IO[7+2*8]; +assign IDELAYE_CINVCTRL[2] = GPIO_DLY_IO[6+2*8]; +assign IDELAYE_CNTVALUEIN[2] = GPIO_DLY_IO[4+2*8:0+2*8]; +assign IDELAYE_LD[3] = GPIO_DLY_IO[7+3*8]; +assign IDELAYE_CINVCTRL[3] = GPIO_DLY_IO[6+3*8]; +assign IDELAYE_CNTVALUEIN[3] = GPIO_DLY_IO[4+3*8:0+3*8]; +assign IDELAYE_LD[4] = GPIO_DLY_IO[7+4*8]; +assign IDELAYE_CINVCTRL[4] = GPIO_DLY_IO[6+4*8]; +assign IDELAYE_CNTVALUEIN[4] = GPIO_DLY_IO[4+4*8:0+4*8]; +assign SEL_CLK40 = GPIO_DLY_IO[42:40]; + +wire [7:0] CMD_DATA, CMD_CLK; + +wire TRIGGER_ENABLE; // from CMD FSM +wire CMD_READY; // from CMD FSM +wire CMD_START_FLAG; +wire TRIGGER_ACCEPTED_FLAG; +wire CMD_EXT_START_FLAG; +assign CMD_EXT_START_FLAG = TRIGGER_ACCEPTED_FLAG; +wire EXT_TRIGGER_ENABLE; + +cmd_seq #( + .BASEADDR(CMD_BASEADDR), + .HIGHADDR(CMD_HIGHADDR), + .ABUSWIDTH(32), + .OUTPUTS(8) +) icmd ( + .BUS_CLK(BUS_CLK), + .BUS_RST(BUS_RST), + .BUS_ADD(BUS_ADD), + .BUS_DATA(BUS_DATA), + .BUS_RD(BUS_RD), + .BUS_WR(BUS_WR), + + .CMD_CLK_IN(CLK40), + .CMD_CLK_OUT(CMD_CLK), + .CMD_DATA(CMD_DATA), + + .CMD_EXT_START_FLAG(CMD_EXT_START_FLAG), + .CMD_EXT_START_ENABLE(EXT_TRIGGER_ENABLE), + .CMD_READY(CMD_READY), + .CMD_START_FLAG(CMD_START_FLAG) +); + +reg [7:0] CLK_SR; +reg CLK40_OUT_SEL; +always@(posedge CLK320) + CLK_SR <= {CLK_SR[6:0],CLK40}; + +always@(posedge CLK320) + CLK40_OUT_SEL <= CLK_SR[SEL_CLK40]; + +genvar h; +generate + for (h = 0; h < 8; h = h + 1) begin: cmd_gen + OBUFDS #( + .IOSTANDARD("LVDS_25"), + .SLEW("SLOW") + ) OBUFDS_inst_cmd_clk_out_h ( + .O(CMD_CLK_P[h]), + .OB(CMD_CLK_N[h]), + .I(CLK40_OUT_SEL) + //.I(CMD_CLK) + ); + + OBUFDS #( + .IOSTANDARD("LVDS_25"), + .SLEW("SLOW") + ) OBUFDS_inst_cmd_data_h ( + .O(CMD_DATA_P[h]), + .OB(CMD_DATA_N[h]), + .I(CMD_DATA[h]) +//.I(CMD_CLK) + + ); + end +endgenerate + + +wire TRIGGER_ACKNOWLEDGE_FLAG; // to TLU FSM +reg CMD_READY_FF; +always @ (posedge CLK40) +begin + CMD_READY_FF <= CMD_READY; +end +assign TRIGGER_ACKNOWLEDGE_FLAG = CMD_READY & ~CMD_READY_FF; + + +wire TRIGGER_FIFO_READ; +wire TRIGGER_FIFO_EMPTY; +wire [31:0] TRIGGER_FIFO_DATA; +wire TRIGGER_FIFO_PREEMPT_REQ; +wire [31:0] TIMESTAMP; +wire [7:0] TDC_OUT; +wire [7:0] RX_READY, RX_8B10B_DECODER_ERR, RX_FIFO_OVERFLOW_ERR, RX_FIFO_FULL, RX_ENABLED; +wire FIFO_FULL; +wire TLU_BUSY, TLU_CLOCK; +wire TRIGGER_ENABLED, TLU_ENABLED; +assign RJ45_BUSY_LEMO_TX1 = TLU_ENABLED ? TLU_BUSY : ~CMD_READY; +assign RJ45_CLK_LEMO_TX0 = TLU_CLOCK; + +tlu_controller #( + .BASEADDR(TLU_BASEADDR), + .HIGHADDR(TLU_HIGHADDR), + .DIVISOR(8), + .ABUSWIDTH(32), + .WIDTH(9) +) i_tlu_controller ( + .BUS_CLK(BUS_CLK), + .BUS_RST(BUS_RST), + .BUS_ADD(BUS_ADD), + .BUS_DATA(BUS_DATA), + .BUS_RD(BUS_RD), + .BUS_WR(BUS_WR), + + .TRIGGER_CLK(CLK40), + + .FIFO_READ(TRIGGER_FIFO_READ), + .FIFO_EMPTY(TRIGGER_FIFO_EMPTY), + .FIFO_DATA(TRIGGER_FIFO_DATA), + + .FIFO_PREEMPT_REQ(TRIGGER_FIFO_PREEMPT_REQ), + + .TRIGGER_ENABLED(TRIGGER_ENABLED), + .TRIGGER_SELECTED(), + .TLU_ENABLED(TLU_ENABLED), + + .TRIGGER({TDC_OUT, LEMO_RX[0]}), + .TRIGGER_VETO({RX_FIFO_FULL, FIFO_FULL}), + + .EXT_TRIGGER_ENABLE(EXT_TRIGGER_ENABLE), + .TRIGGER_ACKNOWLEDGE(TRIGGER_ACKNOWLEDGE_FLAG), + .TRIGGER_ACCEPTED_FLAG(TRIGGER_ACCEPTED_FLAG), + + .TLU_TRIGGER(RJ45_TRIGGER), + .TLU_RESET(RJ45_RESET), + .TLU_BUSY(TLU_BUSY), + .TLU_CLOCK(TLU_CLOCK), + + .TIMESTAMP(TIMESTAMP) +); + +//reg [31:0] timestamp_gray; +//always@(posedge BUS_CLK) +// timestamp_gray <= (TIMESTAMP>>1) ^ TIMESTAMP; + +wire [7:0] FE_FIFO_READ; +wire [7:0] FE_FIFO_EMPTY; +wire [31:0] FE_FIFO_DATA [7:0]; + +wire [7:0] TDC_FIFO_READ; +wire [7:0] TDC_FIFO_EMPTY; +wire [31:0] TDC_FIFO_DATA [7:0]; + +genvar i; +generate + for (i = 0; i < 8; i = i + 1) begin: rx_gen + wire DOBOUT; + reg DOBOUT_DLY; + fei4_rx #( + .BASEADDR(RX_BASEADDR+32'h0100*i), + .HIGHADDR(RX_HIGHADDR+32'h0100*i), + .DSIZE(10), + .DATA_IDENTIFIER(i), + .ABUSWIDTH(32) + ) i_fei4_rx ( + .RX_CLK(CLK160), + .RX_CLK2X(CLK320), + .DATA_CLK(CLK16), + + .RX_DATA(DOBOUT_DLY), + + .RX_READY(RX_READY[i]), + .RX_8B10B_DECODER_ERR(RX_8B10B_DECODER_ERR[i]), + .RX_FIFO_OVERFLOW_ERR(RX_FIFO_OVERFLOW_ERR[i]), + + .FIFO_READ(FE_FIFO_READ[i]), + .FIFO_EMPTY(FE_FIFO_EMPTY[i]), + .FIFO_DATA(FE_FIFO_DATA[i]), + + .RX_FIFO_FULL(RX_FIFO_FULL[i]), + .RX_ENABLED(RX_ENABLED[i]), + + .BUS_CLK(BUS_CLK), + .BUS_RST(BUS_RST), + .BUS_ADD(BUS_ADD), + .BUS_DATA(BUS_DATA), + .BUS_RD(BUS_RD), + .BUS_WR(BUS_WR) + ); + + IBUFDS #( + .DIFF_TERM("TRUE"), + .IBUF_LOW_PWR("FALSE"), + .IOSTANDARD("LVDS_25") + ) IBUFDS_inst_i ( + .O(DOBOUT), + .I(DOBOUT_P[i]), + .IB(DOBOUT_N[i]) + ); + + /* + reg [1:0] DOBOUT_DDR; + wire DOBOUT_IDELAYE; + IDELAYE2 #( + .CINVCTRL_SEL("FALSE"), // Enable dynamic clock inversion (FALSE, TRUE) + .DELAY_SRC("IDATAIN"), // Delay input (IDATAIN, DATAIN) + .HIGH_PERFORMANCE_MODE("FALSE"), // Reduced jitter ("TRUE"), Reduced power ("FALSE") + .IDELAY_TYPE("VAR_LOAD"), // FIXED, VARIABLE, VAR_LOAD, VAR_LOAD_PIPE + .IDELAY_VALUE(0), // Input delay tap setting (0-31) + .PIPE_SEL("FALSE"), // Select pipelined mode, FALSE, TRUE + .REFCLK_FREQUENCY(200.0), // IDELAYCTRL clock input frequency in MHz (190.0-210.0, 290.0-310.0). + .SIGNAL_PATTERN("DATA") // DATA, CLOCK input signal + ) + IDELAYE2_inst ( + .CNTVALUEOUT(), // 5-bit output: Counter value output + .DATAOUT(DOBOUT_IDELAYE), // 1-bit output: Delayed data output + .C(BUS_CLK), // 1-bit input: Clock input + .CE(1'b0), // 1-bit input: Active high enable increment/decrement input + .CINVCTRL(1'b0), // 1-bit input: Dynamic clock inversion input + .CNTVALUEIN(IDELAYE_CNTVALUEIN[i]), // 5-bit input: Counter value input + .DATAIN(1'b0), // 1-bit input: Internal delay data input + .IDATAIN(DOBOUT), // 1-bit input: Data input from the I/O + .INC(1'b0), // 1-bit input: Increment / Decrement tap delay input + .LD(IDELAYE_LD[i]), // 1-bit input: Load IDELAY_VALUE input + .LDPIPEEN(1'b0), // 1-bit input: Enable PIPELINE register to load data input + .REGRST(!LOCKED2) // 1-bit input: Active-high reset tap-delay input + ); + + always@(posedge CLK160) + DOBOUT_DDR[0] <= DOBOUT_IDELAYE; + + always@(negedge CLK160) + DOBOUT_DDR[1] <= DOBOUT_IDELAYE; + + always@(posedge CLK160) + DOBOUT_DLY <= IDELAYE_CINVCTRL[i] ? DOBOUT_DDR[1] : DOBOUT_DDR[0]; + + */ + + always@(*) DOBOUT_DLY = DOBOUT; +end +endgenerate + +wire [7:0] RJ45_HITOR; + +genvar j; +generate + for (j = 0; j < 7; j = j + 1) begin: tdc_gen + tdc_s3 #( + .BASEADDR(TDC_BASEADDR+32'h0100*j), + .HIGHADDR(TDC_HIGHADDR+32'h0100*j), + .ABUSWIDTH(32), + .CLKDV(4), + .DATA_IDENTIFIER(4'b0001 + j), + .FAST_TDC(1), + .FAST_TRIGGER(0) + ) i_tdc ( + .CLK320(CLK320), + .CLK160(CLK160), + .DV_CLK(CLK40), + .TDC_IN(RJ45_HITOR[j]), + .TDC_OUT(TDC_OUT[j]), + .TRIG_IN(), + .TRIG_OUT(), + + .FIFO_READ(TDC_FIFO_READ[j]), + .FIFO_EMPTY(TDC_FIFO_EMPTY[j]), + .FIFO_DATA(TDC_FIFO_DATA[j]), + + .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(CMD_START_FLAG), // arm TDC by sending commands + .EXT_EN(1'b0), + + .TIMESTAMP(TIMESTAMP[15:0]) + ); + + IBUFDS #( + .DIFF_TERM("TRUE"), + .IBUF_LOW_PWR("FALSE"), + .IOSTANDARD("LVDS_25") + ) IBUFDS_inst_RJ45_HITOR ( + .O(RJ45_HITOR[j]), + .I(RJ45_HITOR_P[j]), + .IB(RJ45_HITOR_N[j]) + ); + + end +endgenerate + +tdc_s3 #( + .BASEADDR(TDC_BASEADDR+32'h0100*7), + .HIGHADDR(TDC_HIGHADDR+32'h0100*7), + .ABUSWIDTH(32), + .CLKDV(4), + .DATA_IDENTIFIER(4'b0001), + .FAST_TDC(1), + .FAST_TRIGGER(0) +) i_tdc_7 ( + .CLK320(CLK320), + .CLK160(CLK160), + .DV_CLK(CLK40), + .TDC_IN(RJ45_HITOR[7]), + .TDC_OUT(TDC_OUT[7]), + .TRIG_IN(), + .TRIG_OUT(), + + .FIFO_READ(TDC_FIFO_READ[7]), + .FIFO_EMPTY(TDC_FIFO_EMPTY[7]), + .FIFO_DATA(TDC_FIFO_DATA[7]), + + .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(CMD_START_FLAG), // arm TDC by sending commands + .EXT_EN(1'b0), + + .TIMESTAMP(TIMESTAMP[15:0]) +); + +IBUFDS #( + .DIFF_TERM("TRUE"), + .IBUF_LOW_PWR("FALSE"), + .IOSTANDARD("LVDS_25") +) IBUFDS_inst_RJ45_HITOR_7 ( + .O(RJ45_HITOR[7]), + .I(RJ45_HITOR_P[7]), + .IB(RJ45_HITOR_N[7]) +); + +wire ARB_READY_OUT, ARB_WRITE_OUT; +wire [31:0] ARB_DATA_OUT; +wire [16:0] READ_GRANT; + +rrp_arbiter #( + .WIDTH(17) +) i_rrp_arbiter ( + .RST(BUS_RST), + .CLK(BUS_CLK), + + .WRITE_REQ({~TDC_FIFO_EMPTY, ~FE_FIFO_EMPTY, ~TRIGGER_FIFO_EMPTY}), + .HOLD_REQ({16'b0, TRIGGER_FIFO_PREEMPT_REQ}), + .DATA_IN({TDC_FIFO_DATA[7], TDC_FIFO_DATA[6], TDC_FIFO_DATA[5], TDC_FIFO_DATA[4], TDC_FIFO_DATA[3], TDC_FIFO_DATA[2], TDC_FIFO_DATA[1], TDC_FIFO_DATA[0], FE_FIFO_DATA[7], FE_FIFO_DATA[6], FE_FIFO_DATA[5], FE_FIFO_DATA[4], FE_FIFO_DATA[3], FE_FIFO_DATA[2], FE_FIFO_DATA[1], FE_FIFO_DATA[0], TRIGGER_FIFO_DATA}), + .READ_GRANT(READ_GRANT), + + .READY_OUT(ARB_READY_OUT), + .WRITE_OUT(ARB_WRITE_OUT), + .DATA_OUT(ARB_DATA_OUT) +); + +assign TRIGGER_FIFO_READ = READ_GRANT[0]; +assign FE_FIFO_READ = READ_GRANT[8:1]; +assign TDC_FIFO_READ = READ_GRANT[16:9]; + +//cdc_fifo is for timing reasons +wire [31:0] cdc_data_out; +wire full_32to8, cdc_fifo_empty; +wire FIFO_EMPTY; +cdc_syncfifo #(.DSIZE(32), .ASIZE(3)) cdc_syncfifo_i +( + .rdata(cdc_data_out), + .wfull(FIFO_FULL), + .rempty(cdc_fifo_empty), + .wdata(ARB_DATA_OUT), + .winc(ARB_WRITE_OUT), .wclk(BUS_CLK), .wrst(BUS_RST), + .rinc(!full_32to8), .rclk(BUS_CLK), .rrst(BUS_RST) +); +assign ARB_READY_OUT = !FIFO_FULL; + +fifo_32_to_8 #(.DEPTH(256*1024)) i_data_fifo ( + .RST(BUS_RST), + .CLK(BUS_CLK), + + .WRITE(!cdc_fifo_empty), + .READ(TCP_TX_WR), + .DATA_IN(cdc_data_out), + .FULL(full_32to8), + .EMPTY(FIFO_EMPTY), + .DATA_OUT(TCP_TX_DATA) +); + +assign TCP_TX_WR = !TCP_TX_FULL && !FIFO_EMPTY; + +wire CLK_1HZ; +clock_divider #( + .DIVISOR(40000000) +) i_clock_divisor_40MHz_to_1Hz ( + .CLK(CLK40), + .RESET(1'b0), + .CE(), + .CLOCK(CLK_1HZ) +); + +wire CLK_3HZ; +clock_divider #( + .DIVISOR(13333333) +) i_clock_divisor_40MHz_to_3Hz ( + .CLK(CLK40), + .RESET(1'b0), + .CE(), + .CLOCK(CLK_3HZ) +); + +assign LED[7:4] = 4'hf; +assign LED[0] = ~((CLK_1HZ | FIFO_FULL) & LOCKED & LOCKED2); +assign LED[1] = ~(((RX_READY & RX_ENABLED) == RX_ENABLED) & ((|(RX_8B10B_DECODER_ERR & RX_ENABLED)? CLK_3HZ : CLK_1HZ) | (|(RX_FIFO_OVERFLOW_ERR & RX_ENABLED)) | (|(RX_FIFO_FULL & RX_ENABLED)))); +assign LED[2] = 1'b1; +assign LED[3] = 1'b1; + +//ila_0 ila( +// .clk(CLK320), +// .probe0({M26_DATA1, M26_DATA0, M26_MKD, M26_CLK}) +//); + +endmodule diff --git a/firmware/mmc3_8chip_eth/vivado/mmc3_8chip_eth.xpr b/firmware/mmc3_8chip_eth/vivado/mmc3_8chip_eth.xpr new file mode 100644 index 000000000..dd84d538e --- /dev/null +++ b/firmware/mmc3_8chip_eth/vivado/mmc3_8chip_eth.xpr @@ -0,0 +1,496 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/firmware/mmc3_8chip_multi_tx_eth/README.md b/firmware/mmc3_8chip_multi_tx_eth/README.md new file mode 100644 index 000000000..d7e515606 --- /dev/null +++ b/firmware/mmc3_8chip_multi_tx_eth/README.md @@ -0,0 +1,5 @@ + +### pyBAR firmware for max. 8 FEI4s with multiple TX + + + diff --git a/firmware/mmc3_8chip_multi_tx_eth/src/mmc3.xdc b/firmware/mmc3_8chip_multi_tx_eth/src/mmc3.xdc new file mode 100644 index 000000000..5e3843249 --- /dev/null +++ b/firmware/mmc3_8chip_multi_tx_eth/src/mmc3.xdc @@ -0,0 +1,204 @@ + +create_clock -period 10.000 -name clkin -add [get_ports clkin] +create_clock -period 8.000 -name rgmii_rxc -add [get_ports rgmii_rxc] + +set_false_path -from [get_clocks CLK125PLLTX] -to [get_clocks BUS_CLK_PLL] +set_false_path -from [get_clocks BUS_CLK_PLL] -to [get_clocks CLK125PLLTX] +set_false_path -from [get_clocks BUS_CLK_PLL] -to [get_clocks rgmii_rxc] +set_false_path -from [get_clocks rgmii_rxc] -to [get_clocks BUS_CLK_PLL] +set_false_path -from [get_clocks BUS_CLK_PLL] -to [get_clocks rgmii_rxc] +set_false_path -from [get_clocks rgmii_rxc] -to [get_clocks BUS_CLK_PLL] +set_false_path -from [get_clocks CLK16_PLL] -to [get_clocks BUS_CLK_PLL] +set_false_path -from [get_clocks BUS_CLK_PLL] -to [get_clocks CLK16_PLL] +set_false_path -from [get_clocks CLK160_PLL] -to [get_clocks BUS_CLK_PLL] +set_false_path -from [get_clocks BUS_CLK_PLL] -to [get_clocks CLK160_PLL] +set_false_path -from [get_clocks CLK40_PLL] -to [get_clocks BUS_CLK_PLL] +set_false_path -from [get_clocks BUS_CLK_PLL] -to [get_clocks CLK40_PLL] + +#NET "Clk100" LOC = "AA3" | IOSTANDARD = "LVCMOS15"; 100MHz +set_property PACKAGE_PIN AA3 [get_ports clkin] +set_property IOSTANDARD LVCMOS15 [get_ports clkin] + +set_property PACKAGE_PIN C18 [get_ports RESET_N] +set_property IOSTANDARD LVCMOS25 [get_ports RESET_N] +set_property PULLUP true [get_ports RESET_N] + +set_property SLEW FAST [get_ports mdio_phy_mdc] +set_property IOSTANDARD LVCMOS25 [get_ports mdio_phy_mdc] +set_property PACKAGE_PIN N16 [get_ports mdio_phy_mdc] + +set_property SLEW FAST [get_ports mdio_phy_mdio] +set_property IOSTANDARD LVCMOS25 [get_ports mdio_phy_mdio] +set_property PACKAGE_PIN U16 [get_ports mdio_phy_mdio] + +set_property SLEW FAST [get_ports phy_rst_n] +set_property IOSTANDARD LVCMOS25 [get_ports phy_rst_n] +set_property PACKAGE_PIN M20 [get_ports phy_rst_n] + +set_property IOSTANDARD LVCMOS25 [get_ports rgmii_rxc] +set_property PACKAGE_PIN R21 [get_ports rgmii_rxc] + +set_property IOSTANDARD LVCMOS25 [get_ports rgmii_rx_ctl] +set_property PACKAGE_PIN P21 [get_ports rgmii_rx_ctl] +set_property IOSTANDARD LVCMOS25 [get_ports {rgmii_rxd[0]}] +set_property PACKAGE_PIN P16 [get_ports {rgmii_rxd[0]}] +set_property IOSTANDARD LVCMOS25 [get_ports {rgmii_rxd[1]}] +set_property PACKAGE_PIN N17 [get_ports {rgmii_rxd[1]}] +set_property IOSTANDARD LVCMOS25 [get_ports {rgmii_rxd[2]}] +set_property PACKAGE_PIN R16 [get_ports {rgmii_rxd[2]}] +set_property IOSTANDARD LVCMOS25 [get_ports {rgmii_rxd[3]}] +set_property PACKAGE_PIN R17 [get_ports {rgmii_rxd[3]}] + +set_property SLEW FAST [get_ports rgmii_txc] +set_property IOSTANDARD LVCMOS25 [get_ports rgmii_txc] +set_property PACKAGE_PIN R18 [get_ports rgmii_txc] + +set_property SLEW FAST [get_ports rgmii_tx_ctl] +set_property IOSTANDARD LVCMOS25 [get_ports rgmii_tx_ctl] +set_property PACKAGE_PIN P18 [get_ports rgmii_tx_ctl] + +set_property SLEW FAST [get_ports {rgmii_txd[0]}] +set_property IOSTANDARD LVCMOS25 [get_ports {rgmii_txd[0]}] +set_property PACKAGE_PIN N18 [get_ports {rgmii_txd[0]}] +set_property SLEW FAST [get_ports {rgmii_txd[1]}] +set_property IOSTANDARD LVCMOS25 [get_ports {rgmii_txd[1]}] +set_property PACKAGE_PIN M19 [get_ports {rgmii_txd[1]}] +set_property SLEW FAST [get_ports {rgmii_txd[2]}] +set_property IOSTANDARD LVCMOS25 [get_ports {rgmii_txd[2]}] +set_property PACKAGE_PIN U17 [get_ports {rgmii_txd[2]}] +set_property SLEW FAST [get_ports {rgmii_txd[3]}] +set_property IOSTANDARD LVCMOS25 [get_ports {rgmii_txd[3]}] +set_property PACKAGE_PIN T17 [get_ports {rgmii_txd[3]}] + + +set_property PACKAGE_PIN M17 [get_ports {LED[0]}] +set_property PACKAGE_PIN L18 [get_ports {LED[1]}] +set_property PACKAGE_PIN L17 [get_ports {LED[2]}] +set_property PACKAGE_PIN K18 [get_ports {LED[3]}] +set_property PACKAGE_PIN P26 [get_ports {LED[4]}] +set_property PACKAGE_PIN M25 [get_ports {LED[5]}] +set_property PACKAGE_PIN L25 [get_ports {LED[6]}] +set_property PACKAGE_PIN P23 [get_ports {LED[7]}] +set_property IOSTANDARD LVCMOS25 [get_ports LED*] +set_property SLEW SLOW [get_ports LED*] + +set_property PACKAGE_PIN H11 [get_ports RJ45_HITOR_N[0]] +set_property IOSTANDARD LVDS_25 [get_ports RJ45_HITOR*] +set_property KEEPER true [get_ports RJ45_HITOR_P[0]] +set_property PACKAGE_PIN C11 [get_ports RJ45_HITOR_N[1]] +set_property IOSTANDARD LVDS_25 [get_ports RJ45_HITOR*] +set_property KEEPER true [get_ports RJ45_HITOR_P[1]] +set_property PACKAGE_PIN A15 [get_ports RJ45_HITOR_N[2]] +set_property IOSTANDARD LVDS_25 [get_ports RJ45_HITOR*] +set_property KEEPER true [get_ports RJ45_HITOR_P[2]] +set_property PACKAGE_PIN G16 [get_ports RJ45_HITOR_N[3]] +set_property IOSTANDARD LVDS_25 [get_ports RJ45_HITOR*] +set_property KEEPER true [get_ports RJ45_HITOR_P[3]] +set_property PACKAGE_PIN D10 [get_ports RJ45_HITOR_N[4]] +set_property IOSTANDARD LVDS_25 [get_ports RJ45_HITOR*] +set_property KEEPER true [get_ports RJ45_HITOR_P[4]] +set_property PACKAGE_PIN D11 [get_ports RJ45_HITOR_N[5]] +set_property IOSTANDARD LVDS_25 [get_ports RJ45_HITOR*] +set_property KEEPER true [get_ports RJ45_HITOR_P[5]] +set_property PACKAGE_PIN A10 [get_ports RJ45_HITOR_N[6]] +set_property IOSTANDARD LVDS_25 [get_ports RJ45_HITOR*] +set_property KEEPER true [get_ports RJ45_HITOR_P[6]] +set_property PACKAGE_PIN E16 [get_ports RJ45_HITOR_N[7]] +set_property IOSTANDARD LVDS_25 [get_ports RJ45_HITOR*] +set_property KEEPER true [get_ports RJ45_HITOR_P[7]] + +#PORT CMD +set_property PACKAGE_PIN D8 [get_ports CMD_DATA_N[0]] +set_property IOSTANDARD LVDS_25 [get_ports CMD_DATA*] +set_property KEEPER true [get_ports CMD_DATA_P[0]] +set_property PACKAGE_PIN B9 [get_ports CMD_CLK_N[0]] +set_property IOSTANDARD LVDS_25 [get_ports CMD_CLK*] +set_property KEEPER true [get_ports CMD_CLK_P[0]] +set_property PACKAGE_PIN F12 [get_ports CMD_DATA_N[1]] +set_property IOSTANDARD LVDS_25 [get_ports CMD_DATA*] +set_property KEEPER true [get_ports CMD_DATA_P[1]] +set_property PACKAGE_PIN C13 [get_ports CMD_CLK_N[1]] +set_property IOSTANDARD LVDS_25 [get_ports CMD_CLK*] +set_property KEEPER true [get_ports CMD_CLK_P[1]] +set_property PACKAGE_PIN A17 [get_ports CMD_DATA_N[2]] +set_property IOSTANDARD LVDS_25 [get_ports CMD_DATA*] +set_property KEEPER true [get_ports CMD_DATA_P[2]] +set_property PACKAGE_PIN B19 [get_ports CMD_CLK_N[2]] +set_property IOSTANDARD LVDS_25 [get_ports CMD_CLK*] +set_property KEEPER true [get_ports CMD_CLK_P[2]] +set_property PACKAGE_PIN F18 [get_ports CMD_DATA_N[3]] +set_property IOSTANDARD LVDS_25 [get_ports CMD_DATA*] +set_property KEEPER true [get_ports CMD_DATA_P[3]] +set_property PACKAGE_PIN J16 [get_ports CMD_CLK_N[3]] +set_property IOSTANDARD LVDS_25 [get_ports CMD_CLK*] +set_property KEEPER true [get_ports CMD_CLK_P[3]] + +set_property PACKAGE_PIN G14 [get_ports CMD_DATA_N[4]] +set_property IOSTANDARD LVDS_25 [get_ports CMD_DATA*] +set_property KEEPER true [get_ports CMD_DATA_P[4]] +set_property PACKAGE_PIN H13 [get_ports CMD_CLK_N[4]] +set_property IOSTANDARD LVDS_25 [get_ports CMD_CLK*] +set_property KEEPER true [get_ports CMD_CLK_P[4]] +set_property PACKAGE_PIN F13 [get_ports CMD_DATA_N[5]] +set_property IOSTANDARD LVDS_25 [get_ports CMD_DATA*] +set_property KEEPER true [get_ports CMD_DATA_P[5]] +set_property PACKAGE_PIN H8 [get_ports CMD_CLK_N[5]] +set_property IOSTANDARD LVDS_25 [get_ports CMD_CLK*] +set_property KEEPER true [get_ports CMD_CLK_P[5]] +set_property PACKAGE_PIN A14 [get_ports CMD_DATA_N[6]] +set_property IOSTANDARD LVDS_25 [get_ports CMD_DATA*] +set_property KEEPER true [get_ports CMD_DATA_P[6]] +set_property PACKAGE_PIN E12 [get_ports CMD_CLK_N[6]] +set_property IOSTANDARD LVDS_25 [get_ports CMD_CLK*] +set_property KEEPER true [get_ports CMD_CLK_P[6]] +set_property PACKAGE_PIN E17 [get_ports CMD_DATA_N[7]] +set_property IOSTANDARD LVDS_25 [get_ports CMD_DATA*] +set_property KEEPER true [get_ports CMD_DATA_P[7]] +set_property PACKAGE_PIN A19 [get_ports CMD_CLK_N[7]] +set_property IOSTANDARD LVDS_25 [get_ports CMD_CLK*] +set_property KEEPER true [get_ports CMD_CLK_P[7]] + + +set_property BITSTREAM.CONFIG.UNUSEDPIN PULLUP [current_design] + + + +set_property PACKAGE_PIN F15 [get_ports DOBOUT_N[7]] +set_property IOSTANDARD LVDS_25 [get_ports DOBOUT*] +set_property KEEPER true [get_ports DOBOUT_P[7]] +set_property PACKAGE_PIN B16 [get_ports DOBOUT_N[6]] +set_property IOSTANDARD LVDS_25 [get_ports DOBOUT*] +set_property KEEPER true [get_ports DOBOUT_P[6]] +set_property PACKAGE_PIN D13 [get_ports DOBOUT_N[5]] +set_property IOSTANDARD LVDS_25 [get_ports DOBOUT*] +set_property KEEPER true [get_ports DOBOUT_P[5]] +set_property PACKAGE_PIN A8 [get_ports DOBOUT_N[4]] +set_property IOSTANDARD LVDS_25 [get_ports DOBOUT*] +set_property KEEPER true [get_ports DOBOUT_P[4]] + +set_property PACKAGE_PIN D16 [get_ports DOBOUT_N[3]] +set_property IOSTANDARD LVDS_25 [get_ports DOBOUT*] +set_property KEEPER true [get_ports DOBOUT_P[3]] +set_property PACKAGE_PIN B11 [get_ports DOBOUT_N[2]] +set_property IOSTANDARD LVDS_25 [get_ports DOBOUT*] +set_property KEEPER true [get_ports DOBOUT_P[2]] +set_property PACKAGE_PIN F8 [get_ports DOBOUT_N[1]] +set_property IOSTANDARD LVDS_25 [get_ports DOBOUT*] +set_property KEEPER true [get_ports DOBOUT_P[1]] +set_property PACKAGE_PIN J10 [get_ports DOBOUT_N[0]] +set_property IOSTANDARD LVDS_25 [get_ports DOBOUT*] +set_property KEEPER true [get_ports DOBOUT_P[0]] + + +set_property PACKAGE_PIN V23 [get_ports RJ45_BUSY_LEMO_TX1] +set_property PACKAGE_PIN AB21 [get_ports RJ45_CLK_LEMO_TX0] +set_property PACKAGE_PIN V21 [get_ports RJ45_TRIGGER] +set_property PACKAGE_PIN Y25 [get_ports RJ45_RESET] +set_property IOSTANDARD LVCMOS25 [get_ports RJ45_BUSY_LEMO_TX1] +set_property IOSTANDARD LVCMOS25 [get_ports RJ45_CLK_LEMO_TX0] +set_property IOSTANDARD LVCMOS25 [get_ports RJ45_RESET] +set_property IOSTANDARD LVCMOS25 [get_ports RJ45_TRIGGER] + +set_property PACKAGE_PIN U26 [get_ports {LEMO_RX[1]}] +set_property PACKAGE_PIN U22 [get_ports {LEMO_RX[0]}] +set_property IOSTANDARD LVCMOS25 [get_ports LEMO_RX*] diff --git a/firmware/mmc3_8chip_multi_tx_eth/src/mmc3_8chip_multi_tx_eth.v b/firmware/mmc3_8chip_multi_tx_eth/src/mmc3_8chip_multi_tx_eth.v new file mode 100644 index 000000000..f76c2600f --- /dev/null +++ b/firmware/mmc3_8chip_multi_tx_eth/src/mmc3_8chip_multi_tx_eth.v @@ -0,0 +1,899 @@ +/** + * This file is part of pyBAR. + * + * pyBAR is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * pyBAR is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with pyBAR. If not, see . + */ + +/** + * ------------------------------------------------------------ + * Copyright (c) All rights reserved + * SiLab, Institute of Physics, University of Bonn + * ------------------------------------------------------------ + */ + +`timescale 1ps / 1ps +`default_nettype none + +module mmc3_8chip_multi_tx_eth( + input wire RESET_N, + input wire clkin, + output wire [3:0] rgmii_txd, + output wire rgmii_tx_ctl, + output wire rgmii_txc, + input wire [3:0] rgmii_rxd, + input wire rgmii_rx_ctl, + input wire rgmii_rxc, + output wire mdio_phy_mdc, + inout wire mdio_phy_mdio, + output wire phy_rst_n, + output wire [7:0] LED, + output wire [7:0] CMD_CLK_P, CMD_CLK_N, + output wire [7:0] CMD_DATA_P, CMD_DATA_N, + input wire [7:0] RJ45_HITOR_N, RJ45_HITOR_P, + input wire [7:0] DOBOUT_N, DOBOUT_P, + output wire RJ45_BUSY_LEMO_TX1, RJ45_CLK_LEMO_TX0, + input wire RJ45_TRIGGER, RJ45_RESET, + input wire [1:0] LEMO_RX +); + + +wire RST; +wire CLK250PLL, CLK125PLLTX, CLK125PLLTX90, CLK125PLLRX; +wire PLL_FEEDBACK, LOCKED; + +PLLE2_BASE #( + .BANDWIDTH("OPTIMIZED"), // OPTIMIZED, HIGH, LOW + .CLKFBOUT_MULT(10), // Multiply value for all CLKOUT, (2-64) + .CLKFBOUT_PHASE(0.0), // Phase offset in degrees of CLKFB, (-360.000-360.000). + .CLKIN1_PERIOD(10.000), // Input clock period in ns to ps resolution (i.e. 33.333 is 30 MHz). + + .CLKOUT0_DIVIDE(7), // Divide amount for CLKOUT0 (1-128) + .CLKOUT0_DUTY_CYCLE(0.5), // Duty cycle for CLKOUT0 (0.001-0.999). + .CLKOUT0_PHASE(0.0), // Phase offset for CLKOUT0 (-360.000-360.000). + + .CLKOUT1_DIVIDE(4), // Divide amount for CLKOUT0 (1-128) + .CLKOUT1_DUTY_CYCLE(0.5), // Duty cycle for CLKOUT0 (0.001-0.999). + .CLKOUT1_PHASE(0.0), // Phase offset for CLKOUT0 (-360.000-360.000). + + .CLKOUT2_DIVIDE(8), // Divide amount for CLKOUT0 (1-128) + .CLKOUT2_DUTY_CYCLE(0.5), // Duty cycle for CLKOUT0 (0.001-0.999). + .CLKOUT2_PHASE(0.0), // Phase offset for CLKOUT0 (-360.000-360.000). + + .CLKOUT3_DIVIDE(8), // Divide amount for CLKOUT0 (1-128) + .CLKOUT3_DUTY_CYCLE(0.5), // Duty cycle for CLKOUT0 (0.001-0.999). + .CLKOUT3_PHASE(90.0), // Phase offset for CLKOUT0 (-360.000-360.000). + + .CLKOUT4_DIVIDE(8), // Divide amount for CLKOUT0 (1-128) + .CLKOUT4_DUTY_CYCLE(0.5), // Duty cycle for CLKOUT0 (0.001-0.999). + .CLKOUT4_PHASE(-5.6), // Phase offset for CLKOUT0 (-360.000-360.000). + //-65 -> 0?; - 45 -> 39; -25 -> 100; -5 -> 0; + + .DIVCLK_DIVIDE(1), // Master division value, (1-56) + .REF_JITTER1(0.0), // Reference input jitter in UI, (0.000-0.999). + .STARTUP_WAIT("FALSE") // Delay DONE until PLL Locks, ("TRUE"/"FALSE") + ) + PLLE2_BASE_inst ( + + .CLKOUT0(), + .CLKOUT1(CLK250PLL), + + .CLKOUT2(CLK125PLLTX), + .CLKOUT3(CLK125PLLTX90), + .CLKOUT4(CLK125PLLRX), + + .CLKOUT5(), + + .CLKFBOUT(PLL_FEEDBACK), + + .LOCKED(LOCKED), // 1-bit output: LOCK + + // Input 100 MHz clock + .CLKIN1(clkin), + + // Control Ports + .PWRDWN(0), + .RST(!RESET_N), + + // Feedback + .CLKFBIN(PLL_FEEDBACK) + ); + +wire PLL_FEEDBACK2, LOCKED2; +wire CLK160_PLL, CLK320_PLL, CLK40_PLL, CLK16_PLL, BUS_CLK_PLL, CLK200_PLL; +PLLE2_BASE #( + .BANDWIDTH("OPTIMIZED"), + .CLKFBOUT_MULT(16), + .CLKFBOUT_PHASE(0.0), + .CLKIN1_PERIOD(10.000), + + .CLKOUT0_DIVIDE(10), + .CLKOUT0_DUTY_CYCLE(0.5), + .CLKOUT0_PHASE(0.0), + + .CLKOUT1_DIVIDE(40), + .CLKOUT1_DUTY_CYCLE(0.5), + .CLKOUT1_PHASE(0.0), + + .CLKOUT2_DIVIDE(5), + .CLKOUT2_DUTY_CYCLE(0.5), + .CLKOUT2_PHASE(0.0), + + .CLKOUT3_DIVIDE(100), + .CLKOUT3_DUTY_CYCLE(0.5), + .CLKOUT3_PHASE(0.0), + + .CLKOUT4_DIVIDE(12), + .CLKOUT4_DUTY_CYCLE(0.5), + .CLKOUT4_PHASE(0.0), + + .CLKOUT5_DIVIDE(8), + .CLKOUT5_DUTY_CYCLE(0.5), + .CLKOUT5_PHASE(0.0), + + + .DIVCLK_DIVIDE(1), + .REF_JITTER1(0.0), + .STARTUP_WAIT("FALSE") +) +PLLE2_BASE_inst_2 ( + + .CLKOUT0(CLK160_PLL), + .CLKOUT1(CLK40_PLL), + .CLKOUT2(CLK320_PLL), + .CLKOUT3(CLK16_PLL), + .CLKOUT4(BUS_CLK_PLL), + .CLKOUT5(CLK200_PLL), + + .CLKFBOUT(PLL_FEEDBACK2), + .LOCKED(LOCKED2), // 1-bit output: LOCK + + .CLKIN1(clkin), + + .PWRDWN(0), + .RST(!RESET_N), + + .CLKFBIN(PLL_FEEDBACK2) +); + + +wire CLK160, CLK40, CLK320, CLK16, BUS_CLK, CLK200; +BUFG BUFG_inst_160 (.O(CLK160), .I(CLK160_PLL) ); +BUFG BUFG_inst_40 (.O(CLK40), .I(CLK40_PLL) ); +BUFG BUFG_inst_320 (.O(CLK320), .I(CLK320_PLL) ); +BUFG BUFG_inst_16 (.O(CLK16), .I(CLK16_PLL) ); +BUFG BUFG_inst_BUS_CLK (.O(BUS_CLK), .I(BUS_CLK_PLL) ); +BUFG BUFG_inst_200 (.O(CLK200), .I(CLK200_PLL) ); +//assign BUS_CLK = CLK160; + +wire IDELAYCTRL_RDY; +IDELAYCTRL IDELAYCTRL_inst ( + .RDY(IDELAYCTRL_RDY), + .REFCLK(CLK200), + .RST(!LOCKED2) +); + + +wire CLK125TX, CLK125TX90, CLK125RX; +BUFG BUFG_inst_CLK125TX ( .O(CLK125TX), .I(CLK125PLLTX) ); +BUFG BUFG_inst_CLK125TX90 ( .O(CLK125TX90), .I(CLK125PLLTX90) ); +BUFG BUFG_inst_CLK125RX ( .O(CLK125RX), .I(rgmii_rxc) ); + +assign RST = !RESET_N | !LOCKED | !LOCKED2; + + +wire gmii_tx_clk; +wire gmii_tx_en; +wire [7:0] gmii_txd; +wire gmii_tx_er; +wire gmii_crs; +wire gmii_col; +wire gmii_rx_clk; +wire gmii_rx_dv; +wire [7:0] gmii_rxd; +wire gmii_rx_er; +wire mdio_gem_mdc; +wire mdio_gem_i; +wire mdio_gem_o; +wire mdio_gem_t; +wire link_status; +wire [1:0] clock_speed; +wire duplex_status; + +rgmii_io rgmii +( + .rgmii_txd(rgmii_txd), + .rgmii_tx_ctl(rgmii_tx_ctl), + .rgmii_txc(rgmii_txc), + + .rgmii_rxd(rgmii_rxd), + .rgmii_rx_ctl(rgmii_rx_ctl), + + .gmii_txd_int(gmii_txd), // Internal gmii_txd signal. + .gmii_tx_en_int(gmii_tx_en), + .gmii_tx_er_int(gmii_tx_er), + .gmii_col_int(gmii_col), + .gmii_crs_int(gmii_crs), + .gmii_rxd_reg(gmii_rxd), // RGMII double data rate data valid. + .gmii_rx_dv_reg(gmii_rx_dv), // gmii_rx_dv_ibuf registered in IOBs. + .gmii_rx_er_reg(gmii_rx_er), // gmii_rx_er_ibuf registered in IOBs. + + .eth_link_status(link_status), + .eth_clock_speed(clock_speed), + .eth_duplex_status(duplex_status), + + // FOllowing are generated by DCMs + .tx_rgmii_clk_int(CLK125TX), // Internal RGMII transmitter clock. + .tx_rgmii_clk90_int(CLK125TX90), // Internal RGMII transmitter clock w/ 90 deg phase + .rx_rgmii_clk_int(CLK125RX), // Internal RGMII receiver clock + + .reset(!phy_rst_n) +); + +// Instantiate tri-state buffer for MDIO +IOBUF i_iobuf_mdio( + .O(mdio_gem_i), + .IO(mdio_phy_mdio), + .I(mdio_gem_o), + .T(mdio_gem_t)); + +wire EEPROM_CS, EEPROM_SK, EEPROM_DI; +wire TCP_CLOSE_REQ; +wire RBCP_ACT, RBCP_WE, RBCP_RE; +wire [7:0] RBCP_WD, RBCP_RD; +wire [31:0] RBCP_ADDR; +wire TCP_RX_WR; +wire [7:0] TCP_RX_DATA; +wire RBCP_ACK; +wire SiTCP_RST; + +wire TCP_TX_FULL; +wire TCP_TX_WR; +wire [7:0] TCP_TX_DATA; + + +WRAP_SiTCP_GMII_XC7K_32K sitcp( + .CLK(BUS_CLK) , // in : System Clock >129MHz + .RST(RST) , // in : System reset + // Configuration parameters + .FORCE_DEFAULTn(1'b0) , // in : Load default parameters + .EXT_IP_ADDR(32'hc0a80a10) , // in : IP address[31:0] //192.168.10.16 + .EXT_TCP_PORT(16'd24) , // in : TCP port #[15:0] + .EXT_RBCP_PORT(16'd4660) , // in : RBCP port #[15:0] + .PHY_ADDR(5'd3) , // in : PHY-device MIF address[4:0] + // EEPROM + .EEPROM_CS(EEPROM_CS) , // out : Chip select + .EEPROM_SK(EEPROM_SK) , // out : Serial data clock + .EEPROM_DI(EEPROM_DI) , // out : Serial write data + .EEPROM_DO(1'b0) , // in : Serial read data + // user data, intialial values are stored in the EEPROM, 0xFFFF_FC3C-3F + .USR_REG_X3C() , // out : Stored at 0xFFFF_FF3C + .USR_REG_X3D() , // out : Stored at 0xFFFF_FF3D + .USR_REG_X3E() , // out : Stored at 0xFFFF_FF3E + .USR_REG_X3F() , // out : Stored at 0xFFFF_FF3F + // MII interface + .GMII_RSTn(phy_rst_n) , // out : PHY reset + .GMII_1000M(1'b1) , // in : GMII mode (0:MII, 1:GMII) + // TX + .GMII_TX_CLK(CLK125TX) , // in : Tx clock + .GMII_TX_EN(gmii_tx_en) , // out : Tx enable + .GMII_TXD(gmii_txd) , // out : Tx data[7:0] + .GMII_TX_ER(gmii_tx_er) , // out : TX error + // RX + .GMII_RX_CLK(CLK125RX) , // in : Rx clock + .GMII_RX_DV(gmii_rx_dv) , // in : Rx data valid + .GMII_RXD(gmii_rxd) , // in : Rx data[7:0] + .GMII_RX_ER(gmii_rx_er) , // in : Rx error + .GMII_CRS(gmii_crs) , // in : Carrier sense + .GMII_COL(gmii_col) , // in : Collision detected + // Management IF + .GMII_MDC(mdio_phy_mdc) , // out : Clock for MDIO + .GMII_MDIO_IN(mdio_gem_i) , // in : Data + .GMII_MDIO_OUT(mdio_gem_o) , // out : Data + .GMII_MDIO_OE(mdio_gem_t) , // out : MDIO output enable + // User I/F + .SiTCP_RST(SiTCP_RST) , // out : Reset for SiTCP and related circuits + // TCP connection control + .TCP_OPEN_REQ(1'b0) , // in : Reserved input, shoud be 0 + .TCP_OPEN_ACK() , // out : Acknowledge for open (=Socket busy) + .TCP_ERROR() , // out : TCP error, its active period is equal to MSL + .TCP_CLOSE_REQ(TCP_CLOSE_REQ) , // out : Connection close request + .TCP_CLOSE_ACK(TCP_CLOSE_REQ) , // in : Acknowledge for closing + // FIFO I/F + .TCP_RX_WC(1'b1) , // in : Rx FIFO write count[15:0] (Unused bits should be set 1) + .TCP_RX_WR(TCP_RX_WR) , // out : Write enable + .TCP_RX_DATA(TCP_RX_DATA) , // out : Write data[7:0] + .TCP_TX_FULL(TCP_TX_FULL) , // out : Almost full flag + .TCP_TX_WR(TCP_TX_WR) , // in : Write enable + .TCP_TX_DATA(TCP_TX_DATA) , // in : Write data[7:0] + // RBCP + .RBCP_ACT(RBCP_ACT) , // out : RBCP active + .RBCP_ADDR(RBCP_ADDR) , // out : Address[31:0] + .RBCP_WD(RBCP_WD) , // out : Data[7:0] + .RBCP_WE(RBCP_WE) , // out : Write enable + .RBCP_RE(RBCP_RE) , // out : Read enable + .RBCP_ACK(RBCP_ACK) , // in : Access acknowledge + .RBCP_RD(RBCP_RD) // in : Read data[7:0] +); + +// ------- BUS SIGNALLING ------- // + +wire BUS_WR, BUS_RD, BUS_RST; +wire [31:0] BUS_ADD; +wire [7:0] BUS_DATA; +assign BUS_RST = SiTCP_RST; + +rbcp_to_bus irbcp_to_bus( + .BUS_RST(BUS_RST), + .BUS_CLK(BUS_CLK), + + .RBCP_ACT(RBCP_ACT), + .RBCP_ADDR(RBCP_ADDR), + .RBCP_WD(RBCP_WD), + .RBCP_WE(RBCP_WE), + .RBCP_RE(RBCP_RE), + .RBCP_ACK(RBCP_ACK), + .RBCP_RD(RBCP_RD), + + .BUS_WR(BUS_WR), + .BUS_RD(BUS_RD), + .BUS_ADD(BUS_ADD), + .BUS_DATA(BUS_DATA) +); + +// ------- MODULE ADDRESSES ------- // + +localparam CMD_BASEADDR = 32'h0000; +localparam CMD_HIGHADDR = 32'h8000-1; + +localparam TLU_BASEADDR = 32'h40000; +localparam TLU_HIGHADDR = 32'h40100-1; + +localparam RX_BASEADDR = 32'h41000; +localparam RX_HIGHADDR = 32'h41100-1; + +localparam TDC_BASEADDR = 32'h41fff; +localparam TDC_HIGHADDR = 32'h420ff-1; + +localparam GPIO_DLY_BASEADDR = 32'h430ef; +localparam GPIO_DLY_HIGHADDR = 32'h631ef-1; + + + +// ------- USER MODULES ------- // +wire [47:0] GPIO_DLY_IO; + +gpio +#( + .BASEADDR(GPIO_DLY_BASEADDR), + .HIGHADDR(GPIO_DLY_HIGHADDR), + .IO_WIDTH(48), + .IO_DIRECTION(48'hffffffffffff) +) i_gpio +( + .BUS_CLK(BUS_CLK), + .BUS_RST(BUS_RST), + .BUS_ADD(BUS_ADD), + .BUS_DATA(BUS_DATA), + .BUS_RD(BUS_RD), + .BUS_WR(BUS_WR), + .IO(GPIO_DLY_IO) +); +wire [4:0] IDELAYE_CINVCTRL; +wire [4:0] IDELAYE_LD; +wire [4:0] IDELAYE_CNTVALUEIN [4:0]; +wire [2:0] SEL_CLK40; + +assign IDELAYE_LD[0] = GPIO_DLY_IO[7]; +assign IDELAYE_CINVCTRL[0] = GPIO_DLY_IO[6]; +assign IDELAYE_CNTVALUEIN[0] = GPIO_DLY_IO[4:0]; +assign IDELAYE_LD[1] = GPIO_DLY_IO[7+1*8]; +assign IDELAYE_CINVCTRL[1] = GPIO_DLY_IO[6+1*8]; +assign IDELAYE_CNTVALUEIN[1] = GPIO_DLY_IO[4+1*8:0+1*8]; +assign IDELAYE_LD[2] = GPIO_DLY_IO[7+2*8]; +assign IDELAYE_CINVCTRL[2] = GPIO_DLY_IO[6+2*8]; +assign IDELAYE_CNTVALUEIN[2] = GPIO_DLY_IO[4+2*8:0+2*8]; +assign IDELAYE_LD[3] = GPIO_DLY_IO[7+3*8]; +assign IDELAYE_CINVCTRL[3] = GPIO_DLY_IO[6+3*8]; +assign IDELAYE_CNTVALUEIN[3] = GPIO_DLY_IO[4+3*8:0+3*8]; +assign IDELAYE_LD[4] = GPIO_DLY_IO[7+4*8]; +assign IDELAYE_CINVCTRL[4] = GPIO_DLY_IO[6+4*8]; +assign IDELAYE_CNTVALUEIN[4] = GPIO_DLY_IO[4+4*8:0+4*8]; +assign SEL_CLK40 = GPIO_DLY_IO[42:40]; + +wire [7:0] CMD_DATA, CMD_CLK; + +wire [7:0] TRIGGER_ENABLE; // from CMD FSM +wire [7:0] CMD_READY; // from CMD FSM +wire [7:0] CMD_START_FLAG; +wire [7:0] TRIGGER_ACCEPTED_FLAG; +wire [7:0] CMD_EXT_START_FLAG; +assign CMD_EXT_START_FLAG = TRIGGER_ACCEPTED_FLAG; +wire [7:0] EXT_TRIGGER_ENABLE; + +reg [7:0] CLK_SR; +reg CLK40_OUT_SEL; +always@(posedge CLK320) + CLK_SR <= {CLK_SR[6:0],CLK40}; + +always@(posedge CLK320) + CLK40_OUT_SEL <= CLK_SR[SEL_CLK40]; + +wire BROADCAST_CMD; +genvar h; +generate + for (h = 0; h < 8; h = h + 1) begin: cmd_gen + cmd_seq #( + .BASEADDR(CMD_BASEADDR+32'h8000*h), + .HIGHADDR(CMD_HIGHADDR+32'h8000*h), + .ABUSWIDTH(32), + .OUTPUTS(1) + ) i_cmd_seq ( + .BUS_CLK(BUS_CLK), + .BUS_RST(BUS_RST), + .BUS_ADD(BUS_ADD), + .BUS_DATA(BUS_DATA), + .BUS_RD(BUS_RD), + .BUS_WR(BUS_WR), + + .CMD_CLK_IN(CLK40), + .CMD_CLK_OUT(CMD_CLK[h]), + .CMD_DATA(CMD_DATA[h]), + + .CMD_EXT_START_FLAG(BROADCAST_CMD ? CMD_EXT_START_FLAG[0] : CMD_EXT_START_FLAG[h]), + .CMD_EXT_START_ENABLE(EXT_TRIGGER_ENABLE[h]), + .CMD_READY(CMD_READY[h]), + .CMD_START_FLAG(CMD_START_FLAG[h]) + ); + + OBUFDS #( + .IOSTANDARD("LVDS_25"), + .SLEW("SLOW") + ) OBUFDS_inst_cmd_clk_out_h ( + .O(CMD_CLK_P[h]), + .OB(CMD_CLK_N[h]), + .I(CLK40_OUT_SEL) + //.I(CMD_CLK) + ); + + OBUFDS #( + .IOSTANDARD("LVDS_25"), + .SLEW("SLOW") + ) OBUFDS_inst_cmd_data_h ( + .O(CMD_DATA_P[h]), + .OB(CMD_DATA_N[h]), + .I(CMD_DATA[h]) +//.I(CMD_CLK) + + ); + end +endgenerate + + +wire [7:0] TRIGGER_ACKNOWLEDGE_FLAG; // to TLU FSM +reg [7:0] CMD_READY_FF; +always @ (posedge CLK40) +begin + CMD_READY_FF <= CMD_READY; +end +assign TRIGGER_ACKNOWLEDGE_FLAG = CMD_READY & ~CMD_READY_FF; + +reg CMD_READY_BROADCAST; +always @ (posedge CLK40) +begin + if (!BROADCAST_CMD) + CMD_READY_BROADCAST <= 1'b0; + else if (~&(CMD_READY | (~EXT_TRIGGER_ENABLE))) + CMD_READY_BROADCAST <= 1'b0; + else if (&(CMD_READY | (~EXT_TRIGGER_ENABLE))) + CMD_READY_BROADCAST <= 1'b1; + else + CMD_READY_BROADCAST <= CMD_READY_BROADCAST; +end + +wire CMD_READY_BROADCAST_FLAG; +reg CMD_READY_BROADCAST_FF; +always @ (posedge CLK40) +begin + CMD_READY_BROADCAST_FF <= CMD_READY_BROADCAST; +end +assign CMD_READY_BROADCAST_FLAG = CMD_READY_BROADCAST & ~CMD_READY_BROADCAST_FF; + +wire [7:0] TRIGGER_FIFO_READ; +wire [7:0] TRIGGER_FIFO_EMPTY; +wire [31:0] TRIGGER_FIFO_DATA [7:0]; +wire [7:0] TRIGGER_FIFO_PREEMPT_REQ; +wire [31:0] TIMESTAMP [7:0]; +wire [7:0] TDC_OUT; +wire [7:0] RX_READY, RX_8B10B_DECODER_ERR, RX_FIFO_OVERFLOW_ERR, RX_FIFO_FULL, RX_ENABLED; +wire FIFO_FULL; +wire TLU_BUSY, TLU_CLOCK; +wire [7:0] TRIGGER_ENABLED, TLU_ENABLED; +wire [7:0] TRIGGER_SELECTED [7:0]; +assign RJ45_BUSY_LEMO_TX1 = TLU_ENABLED[0] ? TLU_BUSY : ~CMD_READY_BROADCAST; +assign RJ45_CLK_LEMO_TX0 = TLU_CLOCK; + +genvar k; +generate + for (k = 1; k < 8; k = k + 1) begin: tlu_gen + tlu_controller #( + .BASEADDR(TLU_BASEADDR+32'h0100*k), + .HIGHADDR(TLU_HIGHADDR+32'h0100*k), + .DIVISOR(8), + .ABUSWIDTH(32), + .WIDTH(9) + ) i_tlu_controller ( + .BUS_CLK(BUS_CLK), + .BUS_RST(BUS_RST), + .BUS_ADD(BUS_ADD), + .BUS_DATA(BUS_DATA), + .BUS_RD(BUS_RD), + .BUS_WR(BUS_WR), + + .TRIGGER_CLK(CLK40), + + .FIFO_READ(TRIGGER_FIFO_READ[k]), + .FIFO_EMPTY(TRIGGER_FIFO_EMPTY[k]), + .FIFO_DATA(TRIGGER_FIFO_DATA[k]), + + .FIFO_PREEMPT_REQ(TRIGGER_FIFO_PREEMPT_REQ[k]), + + .TRIGGER_ENABLED(TRIGGER_ENABLED[k]), + .TRIGGER_SELECTED(TRIGGER_SELECTED[k]), + .TLU_ENABLED(TLU_ENABLED[k]), + + .TRIGGER({TDC_OUT, LEMO_RX[0]}), + .TRIGGER_VETO({RX_FIFO_FULL, FIFO_FULL}), + + .EXT_TRIGGER_ENABLE(BROADCAST_CMD ? 1'b0 : EXT_TRIGGER_ENABLE[k]), + .TRIGGER_ACKNOWLEDGE(BROADCAST_CMD ? 1'b0 : TRIGGER_ACKNOWLEDGE_FLAG[k]), + .TRIGGER_ACCEPTED_FLAG(TRIGGER_ACCEPTED_FLAG[k]), + + .TLU_TRIGGER(1'b0), + .TLU_RESET(1'b0), + .TLU_BUSY(), + .TLU_CLOCK(), + + .TIMESTAMP(TIMESTAMP[k]) + ); + end +endgenerate + +tlu_controller #( + .BASEADDR(TLU_BASEADDR), + .HIGHADDR(TLU_HIGHADDR), + .DIVISOR(8), + .ABUSWIDTH(32), + .WIDTH(9) +) i_tlu_controller_0 ( + .BUS_CLK(BUS_CLK), + .BUS_RST(BUS_RST), + .BUS_ADD(BUS_ADD), + .BUS_DATA(BUS_DATA), + .BUS_RD(BUS_RD), + .BUS_WR(BUS_WR), + + .TRIGGER_CLK(CLK40), + + .FIFO_READ(TRIGGER_FIFO_READ[0]), + .FIFO_EMPTY(TRIGGER_FIFO_EMPTY[0]), + .FIFO_DATA(TRIGGER_FIFO_DATA[0]), + + .FIFO_PREEMPT_REQ(TRIGGER_FIFO_PREEMPT_REQ[0]), + + .TRIGGER_ENABLED(TRIGGER_ENABLED[0]), + .TRIGGER_SELECTED(TRIGGER_SELECTED[0]), + .TLU_ENABLED(TLU_ENABLED[0]), + + .TRIGGER({TDC_OUT, LEMO_RX[0]}), + .TRIGGER_VETO({RX_FIFO_FULL, FIFO_FULL}), + + .EXT_TRIGGER_ENABLE(BROADCAST_CMD ? |EXT_TRIGGER_ENABLE : EXT_TRIGGER_ENABLE[0]), + .TRIGGER_ACKNOWLEDGE(BROADCAST_CMD ? CMD_READY_BROADCAST_FLAG : TRIGGER_ACKNOWLEDGE_FLAG[0]), + .TRIGGER_ACCEPTED_FLAG(TRIGGER_ACCEPTED_FLAG[0]), + + .TLU_TRIGGER(RJ45_TRIGGER), + .TLU_RESET(RJ45_RESET), + .TLU_BUSY(TLU_BUSY), + .TLU_CLOCK(TLU_CLOCK), + + .TIMESTAMP(TIMESTAMP[0]) +); +assign BROADCAST_CMD = (TRIGGER_ENABLED == 8'b0000_0001 && (TLU_ENABLED[0] || TRIGGER_SELECTED[0] == 8'b0000_0001)); + +//reg [31:0] timestamp_gray; +//always@(posedge BUS_CLK) +// timestamp_gray <= ((TIMESTAMP[0])>>1) ^ (TIMESTAMP[0]); + +wire [7:0] FE_FIFO_READ; +wire [7:0] FE_FIFO_EMPTY; +wire [31:0] FE_FIFO_DATA [7:0]; + +wire [7:0] TDC_FIFO_READ; +wire [7:0] TDC_FIFO_EMPTY; +wire [31:0] TDC_FIFO_DATA [7:0]; + +genvar i; +generate + for (i = 0; i < 8; i = i + 1) begin: rx_gen + wire DOBOUT; + reg DOBOUT_DLY; + fei4_rx #( + .BASEADDR(RX_BASEADDR+32'h0100*i), + .HIGHADDR(RX_HIGHADDR+32'h0100*i), + .DSIZE(10), + .DATA_IDENTIFIER(i), + .ABUSWIDTH(32) + ) i_fei4_rx ( + .RX_CLK(CLK160), + .RX_CLK2X(CLK320), + .DATA_CLK(CLK16), + + .RX_DATA(DOBOUT_DLY), + + .RX_READY(RX_READY[i]), + .RX_8B10B_DECODER_ERR(RX_8B10B_DECODER_ERR[i]), + .RX_FIFO_OVERFLOW_ERR(RX_FIFO_OVERFLOW_ERR[i]), + + .FIFO_READ(FE_FIFO_READ[i]), + .FIFO_EMPTY(FE_FIFO_EMPTY[i]), + .FIFO_DATA(FE_FIFO_DATA[i]), + + .RX_FIFO_FULL(RX_FIFO_FULL[i]), + .RX_ENABLED(RX_ENABLED[i]), + + .BUS_CLK(BUS_CLK), + .BUS_RST(BUS_RST), + .BUS_ADD(BUS_ADD), + .BUS_DATA(BUS_DATA), + .BUS_RD(BUS_RD), + .BUS_WR(BUS_WR) + ); + + IBUFDS #( + .DIFF_TERM("TRUE"), + .IBUF_LOW_PWR("FALSE"), + .IOSTANDARD("LVDS_25") + ) IBUFDS_inst_i ( + .O(DOBOUT), + .I(DOBOUT_P[i]), + .IB(DOBOUT_N[i]) + ); + + /* + reg [1:0] DOBOUT_DDR; + wire DOBOUT_IDELAYE; + IDELAYE2 #( + .CINVCTRL_SEL("FALSE"), // Enable dynamic clock inversion (FALSE, TRUE) + .DELAY_SRC("IDATAIN"), // Delay input (IDATAIN, DATAIN) + .HIGH_PERFORMANCE_MODE("FALSE"), // Reduced jitter ("TRUE"), Reduced power ("FALSE") + .IDELAY_TYPE("VAR_LOAD"), // FIXED, VARIABLE, VAR_LOAD, VAR_LOAD_PIPE + .IDELAY_VALUE(0), // Input delay tap setting (0-31) + .PIPE_SEL("FALSE"), // Select pipelined mode, FALSE, TRUE + .REFCLK_FREQUENCY(200.0), // IDELAYCTRL clock input frequency in MHz (190.0-210.0, 290.0-310.0). + .SIGNAL_PATTERN("DATA") // DATA, CLOCK input signal + ) + IDELAYE2_inst ( + .CNTVALUEOUT(), // 5-bit output: Counter value output + .DATAOUT(DOBOUT_IDELAYE), // 1-bit output: Delayed data output + .C(BUS_CLK), // 1-bit input: Clock input + .CE(1'b0), // 1-bit input: Active high enable increment/decrement input + .CINVCTRL(1'b0), // 1-bit input: Dynamic clock inversion input + .CNTVALUEIN(IDELAYE_CNTVALUEIN[i]), // 5-bit input: Counter value input + .DATAIN(1'b0), // 1-bit input: Internal delay data input + .IDATAIN(DOBOUT), // 1-bit input: Data input from the I/O + .INC(1'b0), // 1-bit input: Increment / Decrement tap delay input + .LD(IDELAYE_LD[i]), // 1-bit input: Load IDELAY_VALUE input + .LDPIPEEN(1'b0), // 1-bit input: Enable PIPELINE register to load data input + .REGRST(!LOCKED2) // 1-bit input: Active-high reset tap-delay input + ); + + always@(posedge CLK160) + DOBOUT_DDR[0] <= DOBOUT_IDELAYE; + + always@(negedge CLK160) + DOBOUT_DDR[1] <= DOBOUT_IDELAYE; + + always@(posedge CLK160) + DOBOUT_DLY <= IDELAYE_CINVCTRL[i] ? DOBOUT_DDR[1] : DOBOUT_DDR[0]; + + */ + + always@(*) DOBOUT_DLY = DOBOUT; +end +endgenerate + +wire [7:0] RJ45_HITOR; + +genvar j; +generate + for (j = 0; j < 7; j = j + 1) begin: tdc_gen + tdc_s3 #( + .BASEADDR(TDC_BASEADDR+32'h0100*j), + .HIGHADDR(TDC_HIGHADDR+32'h0100*j), + .ABUSWIDTH(32), + .CLKDV(4), + .DATA_IDENTIFIER(4'b0001 + j), + .FAST_TDC(1), + .FAST_TRIGGER(0) + ) i_tdc ( + .CLK320(CLK320), + .CLK160(CLK160), + .DV_CLK(CLK40), + .TDC_IN(RJ45_HITOR[j]), + .TDC_OUT(TDC_OUT[j]), + .TRIG_IN(), + .TRIG_OUT(), + + .FIFO_READ(TDC_FIFO_READ[j]), + .FIFO_EMPTY(TDC_FIFO_EMPTY[j]), + .FIFO_DATA(TDC_FIFO_DATA[j]), + + .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(CMD_START_FLAG[j]), // arm TDC by sending commands + .EXT_EN(1'b0), + + .TIMESTAMP(TIMESTAMP[j][15:0]) + ); + + IBUFDS #( + .DIFF_TERM("TRUE"), + .IBUF_LOW_PWR("FALSE"), + .IOSTANDARD("LVDS_25") + ) IBUFDS_inst_RJ45_HITOR ( + .O(RJ45_HITOR[j]), + .I(RJ45_HITOR_P[j]), + .IB(RJ45_HITOR_N[j]) + ); + + end +endgenerate + +tdc_s3 #( + .BASEADDR(TDC_BASEADDR+32'h0100*7), + .HIGHADDR(TDC_HIGHADDR+32'h0100*7), + .ABUSWIDTH(32), + .CLKDV(4), + .DATA_IDENTIFIER(4'b0001), + .FAST_TDC(1), + .FAST_TRIGGER(0) +) i_tdc_7 ( + .CLK320(CLK320), + .CLK160(CLK160), + .DV_CLK(CLK40), + .TDC_IN(RJ45_HITOR[7]), + .TDC_OUT(TDC_OUT[7]), + .TRIG_IN(), + .TRIG_OUT(), + + .FIFO_READ(TDC_FIFO_READ[7]), + .FIFO_EMPTY(TDC_FIFO_EMPTY[7]), + .FIFO_DATA(TDC_FIFO_DATA[7]), + + .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(CMD_START_FLAG[7]), // arm TDC by sending commands + .EXT_EN(1'b0), + + .TIMESTAMP(TIMESTAMP[7][15:0]) +); + +IBUFDS #( + .DIFF_TERM("TRUE"), + .IBUF_LOW_PWR("FALSE"), + .IOSTANDARD("LVDS_25") +) IBUFDS_inst_RJ45_HITOR_7 ( + .O(RJ45_HITOR[7]), + .I(RJ45_HITOR_P[7]), + .IB(RJ45_HITOR_N[7]) +); + +wire ARB_READY_OUT, ARB_WRITE_OUT; +wire [31:0] ARB_DATA_OUT; +wire [23:0] READ_GRANT; + +rrp_arbiter #( + .WIDTH(24) +) i_rrp_arbiter ( + .RST(BUS_RST), + .CLK(BUS_CLK), + + .WRITE_REQ({~TDC_FIFO_EMPTY, ~FE_FIFO_EMPTY, ~TRIGGER_FIFO_EMPTY}), + .HOLD_REQ({16'b0, TRIGGER_FIFO_PREEMPT_REQ}), + .DATA_IN({TDC_FIFO_DATA[7], TDC_FIFO_DATA[6], TDC_FIFO_DATA[5], TDC_FIFO_DATA[4], TDC_FIFO_DATA[3], TDC_FIFO_DATA[2], TDC_FIFO_DATA[1], TDC_FIFO_DATA[0], FE_FIFO_DATA[7], FE_FIFO_DATA[6], FE_FIFO_DATA[5], FE_FIFO_DATA[4], FE_FIFO_DATA[3], FE_FIFO_DATA[2], FE_FIFO_DATA[1], FE_FIFO_DATA[0], TRIGGER_FIFO_DATA[7], TRIGGER_FIFO_DATA[6], TRIGGER_FIFO_DATA[5], TRIGGER_FIFO_DATA[4], TRIGGER_FIFO_DATA[3], TRIGGER_FIFO_DATA[2], TRIGGER_FIFO_DATA[1], TRIGGER_FIFO_DATA[0]}), + .READ_GRANT(READ_GRANT), + + .READY_OUT(ARB_READY_OUT), + .WRITE_OUT(ARB_WRITE_OUT), + .DATA_OUT(ARB_DATA_OUT) +); + +assign TRIGGER_FIFO_READ = READ_GRANT[7:0]; +assign FE_FIFO_READ = READ_GRANT[15:8]; +assign TDC_FIFO_READ = READ_GRANT[23:16]; + +//cdc_fifo is for timing reasons +wire [31:0] cdc_data_out; +wire full_32to8, cdc_fifo_empty; +wire FIFO_EMPTY; +cdc_syncfifo #(.DSIZE(32), .ASIZE(3)) cdc_syncfifo_i +( + .rdata(cdc_data_out), + .wfull(FIFO_FULL), + .rempty(cdc_fifo_empty), + .wdata(ARB_DATA_OUT), + .winc(ARB_WRITE_OUT), .wclk(BUS_CLK), .wrst(BUS_RST), + .rinc(!full_32to8), .rclk(BUS_CLK), .rrst(BUS_RST) +); +assign ARB_READY_OUT = !FIFO_FULL; + +fifo_32_to_8 #(.DEPTH(256*1024)) i_data_fifo ( + .RST(BUS_RST), + .CLK(BUS_CLK), + + .WRITE(!cdc_fifo_empty), + .READ(TCP_TX_WR), + .DATA_IN(cdc_data_out), + .FULL(full_32to8), + .EMPTY(FIFO_EMPTY), + .DATA_OUT(TCP_TX_DATA) +); + +assign TCP_TX_WR = !TCP_TX_FULL && !FIFO_EMPTY; + +wire CLK_1HZ; +clock_divider #( + .DIVISOR(40000000) +) i_clock_divisor_40MHz_to_1Hz ( + .CLK(CLK40), + .RESET(1'b0), + .CE(), + .CLOCK(CLK_1HZ) +); + +wire CLK_3HZ; +clock_divider #( + .DIVISOR(13333333) +) i_clock_divisor_40MHz_to_3Hz ( + .CLK(CLK40), + .RESET(1'b0), + .CE(), + .CLOCK(CLK_3HZ) +); + + + + +assign LED[7:4] = 4'hf; +assign LED[0] = ~((CLK_1HZ | FIFO_FULL) & LOCKED & LOCKED2); +assign LED[1] = ~(((RX_READY & RX_ENABLED) == RX_ENABLED) & ((|(RX_8B10B_DECODER_ERR & RX_ENABLED)? CLK_3HZ : CLK_1HZ) | (|(RX_FIFO_OVERFLOW_ERR & RX_ENABLED)) | (|(RX_FIFO_FULL & RX_ENABLED)))); +assign LED[2] = 1'b1; +assign LED[3] = 1'b1; + +//ila_0 ila( +// .clk(CLK320), +// .probe0({M26_DATA1, M26_DATA0, M26_MKD, M26_CLK}) +//); + +endmodule diff --git a/firmware/mmc3_8chip_multi_tx_eth/vivado/mmc3_8chip_multi_tx_eth.xpr b/firmware/mmc3_8chip_multi_tx_eth/vivado/mmc3_8chip_multi_tx_eth.xpr new file mode 100644 index 000000000..80b73a595 --- /dev/null +++ b/firmware/mmc3_8chip_multi_tx_eth/vivado/mmc3_8chip_multi_tx_eth.xpr @@ -0,0 +1,496 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/firmware/mmc3_beast_eth/src/mmc3_beast_eth.v b/firmware/mmc3_beast_eth/src/mmc3_beast_eth.v index 889987a9f..a366a69cf 100644 --- a/firmware/mmc3_beast_eth/src/mmc3_beast_eth.v +++ b/firmware/mmc3_beast_eth/src/mmc3_beast_eth.v @@ -1,4 +1,29 @@ - +/** + * This file is part of pyBAR. + * + * pyBAR is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * pyBAR is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with pyBAR. If not, see . + */ + +/** + * ------------------------------------------------------------ + * Copyright (c) All rights reserved + * SiLab, Institute of Physics, University of Bonn + * ------------------------------------------------------------ + */ + +`timescale 1ps / 1ps +`default_nettype none module mmc3_beast_eth( input wire RESET_N, @@ -24,7 +49,7 @@ module mmc3_beast_eth( wire RST; -wire BUS_CLK_PLL, CLK250PLL, CLK125PLLTX, CLK125PLLTX90, CLK125PLLRX; +wire CLK250PLL, CLK125PLLTX, CLK125PLLTX90, CLK125PLLRX; wire PLL_FEEDBACK, LOCKED; PLLE2_BASE #( @@ -301,7 +326,7 @@ WRAP_SiTCP_GMII_XC7K_32K sitcp( .RBCP_RD(RBCP_RD) // in : Read data[7:0] ); -// ------- BUS SYGNALING ------- // +// ------- BUS SIGNALLING ------- // wire BUS_WR, BUS_RD, BUS_RST; wire [31:0] BUS_ADD; @@ -326,7 +351,7 @@ rbcp_to_bus irbcp_to_bus( .BUS_DATA(BUS_DATA) ); -// ------- MODULE ADREESSES ------- // +// ------- MODULE ADDRESSES ------- // localparam CMD_BASEADDR = 32'h0000; localparam CMD_HIGHADDR = 32'h8000-1; @@ -459,9 +484,15 @@ assign TRIGGER_ACKNOWLEDGE_FLAG = CMD_READY & ~CMD_READY_FF; wire TRIGGER_FIFO_READ; wire TRIGGER_FIFO_EMPTY; wire [31:0] TRIGGER_FIFO_DATA; -wire TRIGGER_FIFO_PEEMPT_REQ; +wire TRIGGER_FIFO_PREEMPT_REQ; wire [31:0] TIMESTAMP; wire [4:0] TDC_OUT; +wire [4:0] RX_READY, RX_8B10B_DECODER_ERR, RX_FIFO_OVERFLOW_ERR, RX_FIFO_FULL, RX_ENABLED; +wire FIFO_FULL; +wire TLU_BUSY, TLU_CLOCK; +wire TRIGGER_ENABLED, TLU_ENABLED; +assign RJ45_BUSY_LEMO_TX1 = TLU_ENABLED ? TLU_BUSY : ~CMD_READY; +assign RJ45_CLK_LEMO_TX0 = TLU_CLOCK; tlu_controller #( .BASEADDR(TLU_BASEADDR), @@ -483,29 +514,31 @@ tlu_controller #( .FIFO_EMPTY(TRIGGER_FIFO_EMPTY), .FIFO_DATA(TRIGGER_FIFO_DATA), - .FIFO_PREEMPT_REQ(TRIGGER_FIFO_PEEMPT_REQ), + .FIFO_PREEMPT_REQ(TRIGGER_FIFO_PREEMPT_REQ), + + .TRIGGER_ENABLED(TRIGGER_ENABLED), + .TRIGGER_SELECTED(), + .TLU_ENABLED(TLU_ENABLED), - .TRIGGER({2'b0, LEMO_RX[0], TDC_OUT}), - .TRIGGER_VETO({7'b0, FIFO_FULL}), + .TRIGGER({2'b0, TDC_OUT, LEMO_RX[0]}), + .TRIGGER_VETO({2'b0, RX_FIFO_FULL, FIFO_FULL}), .EXT_TRIGGER_ENABLE(EXT_TRIGGER_ENABLE), - .TRIGGER_ACKNOWLEDGE(EXT_TRIGGER_ENABLE == 1'b0 ? TRIGGER_ACCEPTED_FLAG : TRIGGER_ACKNOWLEDGE_FLAG), + .TRIGGER_ACKNOWLEDGE(TRIGGER_ACKNOWLEDGE_FLAG), .TRIGGER_ACCEPTED_FLAG(TRIGGER_ACCEPTED_FLAG), .TLU_TRIGGER(RJ45_TRIGGER), .TLU_RESET(RJ45_RESET), - .TLU_BUSY(RJ45_BUSY_LEMO_TX1), - .TLU_CLOCK(RJ45_CLK_LEMO_TX0), + .TLU_BUSY(TLU_BUSY), + .TLU_CLOCK(TLU_CLOCK), .TIMESTAMP(TIMESTAMP) ); -reg [31:0] timestamp_gray; -always@(posedge BUS_CLK) - timestamp_gray <= (TIMESTAMP>>1) ^ TIMESTAMP; - +//reg [31:0] timestamp_gray; +//always@(posedge BUS_CLK) +// timestamp_gray <= (TIMESTAMP>>1) ^ TIMESTAMP; -wire [4:0] RX_READY, RX_8B10B_DECODER_ERR, RX_FIFO_OVERFLOW_ERR, RX_FIFO_FULL; wire [4:0] FE_FIFO_READ; wire [4:0] FE_FIFO_EMPTY; wire [31:0] FE_FIFO_DATA [4:0]; @@ -523,7 +556,7 @@ generate .BASEADDR(RX_BASEADDR+32'h0100*i), .HIGHADDR(RX_HIGHADDR+32'h0100*i), .DSIZE(10), - .DATA_IDENTIFIER(i+1), + .DATA_IDENTIFIER(i), .ABUSWIDTH(32) ) i_fei4_rx ( .RX_CLK(CLK160), @@ -541,7 +574,7 @@ generate .FIFO_DATA(FE_FIFO_DATA[i]), .RX_FIFO_FULL(RX_FIFO_FULL[i]), - .RX_ENABLED(), + .RX_ENABLED(RX_ENABLED[i]), .BUS_CLK(BUS_CLK), .BUS_RST(BUS_RST), @@ -608,7 +641,7 @@ generate .HIGHADDR(TDC_HIGHADDR+32'h0100*i), .ABUSWIDTH(32), .CLKDV(4), - .DATA_IDENTIFIER(4'b0001 + i), // one-hot + .DATA_IDENTIFIER(4'b0001 + i), .FAST_TDC(1), .FAST_TRIGGER(0) ) i_tdc ( @@ -660,7 +693,7 @@ rrp_arbiter #( .CLK(BUS_CLK), .WRITE_REQ({~TDC_FIFO_EMPTY, ~FE_FIFO_EMPTY, ~TRIGGER_FIFO_EMPTY}), - .HOLD_REQ({10'b0, TRIGGER_FIFO_PEEMPT_REQ }), + .HOLD_REQ({10'b0, TRIGGER_FIFO_PREEMPT_REQ }), .DATA_IN({TDC_FIFO_DATA[4], TDC_FIFO_DATA[3], TDC_FIFO_DATA[2], TDC_FIFO_DATA[1], TDC_FIFO_DATA[0], FE_FIFO_DATA[4], FE_FIFO_DATA[3], FE_FIFO_DATA[2], FE_FIFO_DATA[1], FE_FIFO_DATA[0], TRIGGER_FIFO_DATA}), .READ_GRANT(READ_GRANT), @@ -676,6 +709,7 @@ assign TDC_FIFO_READ = READ_GRANT[10:6]; //cdc_fifo is for timing reasons wire [31:0] cdc_data_out; wire full_32to8, cdc_fifo_empty; +wire FIFO_EMPTY; cdc_syncfifo #(.DSIZE(32), .ASIZE(3)) cdc_syncfifo_i ( .rdata(cdc_data_out), @@ -687,7 +721,6 @@ cdc_syncfifo #(.DSIZE(32), .ASIZE(3)) cdc_syncfifo_i ); assign ARB_READY_OUT = !FIFO_FULL; -wire FIFO_EMPTY, FIFO_FULL; fifo_32_to_8 #(.DEPTH(256*1024)) i_data_fifo ( .RST(BUS_RST), .CLK(BUS_CLK), @@ -712,10 +745,21 @@ clock_divider #( .CLOCK(CLK_1HZ) ); -assign LED[7:3] = 5'hf; -assign LED[0] = RX_READY; -assign LED[1] = ~(CLK_1HZ); -assign LED[2] = ~(|RX_8B10B_DECODER_ERR & CLK_1HZ); +wire CLK_3HZ; +clock_divider #( + .DIVISOR(13333333) +) i_clock_divisor_40MHz_to_3Hz ( + .CLK(CLK40), + .RESET(1'b0), + .CE(), + .CLOCK(CLK_3HZ) +); + +assign LED[7:4] = 4'hf; +assign LED[0] = ~((CLK_1HZ | FIFO_FULL) & LOCKED & LOCKED2); +assign LED[1] = ~(((RX_READY & RX_ENABLED) == RX_ENABLED) & ((|(RX_8B10B_DECODER_ERR & RX_ENABLED)? CLK_3HZ : CLK_1HZ) | (|(RX_FIFO_OVERFLOW_ERR & RX_ENABLED)) | (|(RX_FIFO_FULL & RX_ENABLED)))); +assign LED[2] = 1'b1; +assign LED[3] = 1'b1; //ila_0 ila( // .clk(CLK320), diff --git a/firmware/mmc3_m26_eth/mmc3_m26_test.py b/firmware/mmc3_m26_eth/mmc3_m26_test.py index 9e7042671..701915658 100644 --- a/firmware/mmc3_m26_eth/mmc3_m26_test.py +++ b/firmware/mmc3_m26_eth/mmc3_m26_test.py @@ -4,6 +4,9 @@ # ------------------------------------------------------------ # +import time + +from basil.dut import Dut cnfg_yaml = """ transfer_layer: @@ -16,22 +19,16 @@ tcp_connection : True hw_drivers: - - name : gpio_drv - type : gpio + - name : TRIGGER_FEI4 + type : tlu interface : ETH - base_addr : 0x9000 - size : 8 + base_addr : 0x8200 - - name : CMD + - name : CMD_FEI4 type : cmd_seq interface : ETH base_addr : 0x0000 - - name : CH0 - type : fei4_rx - interface : ETH - base_addr : 0x8600 - - name : M26_RX1 type : m26_rx interface : ETH @@ -62,62 +59,44 @@ interface : ETH base_addr : 0xa050 - - name : SRAM - type : sram_fifo + - name : FEI4_RX + type : fei4_rx interface : ETH - base_addr : 0x200000000 - base_data_addr : 0x100000000 - -registers: - - name : GPIO_LED - type : StdRegister - hw_driver : gpio_drv - size : 8 - fields: - - name : LED - size : 8 - offset : 7 -""" + base_addr : 0x8600 -import time -from basil.dut import Dut + - name : SITCP_FIFO + type : sitcp_fifo + interface : ETH -chip = Dut(cnfg_yaml) -chip.init() + - name : TDC_FEI4 + type : tdc_s3 + interface : ETH + base_addr : 0x8700 +""" -#for i in range(8): -# chip['GPIO_LED']['LED'] = 0x01 << i -# chip['GPIO_LED'].write() -# print('LED:', chip['GPIO_LED'].get_data()) -# #time.sleep(1) +dut = Dut(cnfg_yaml) +dut.init() -print 'START' -chip['M26_RX1'].reset() -chip['M26_RX2'].reset() -chip['M26_RX3'].reset() -chip['M26_RX4'].reset() -chip['M26_RX5'].reset() -chip['M26_RX6'].reset() +print 'Resetting Mimosa26 receivers' +map(lambda channel: channel.reset(), self.dut.get_modules('m26_rx')) -print 'get_fifo_size', chip['SRAM'].get_fifo_size() -chls = ['M26_RX1', 'M26_RX2', 'M26_RX3', 'M26_RX4', 'M26_RX5', 'M26_RX6'] #['M26_RX1', 'M26_RX2', 'M26_RX3', 'M26_RX4', 'M26_RX5', 'M26_RX6'] +print 'FIFO size', dut['SITCP_FIFO'].get_FIFO_SIZE() -for ch in chls: - chip[ch]["EN"] = True +for channel in self.dut.get_modules('m26_rx'): + channel["EN"] = True time.sleep(0.01) -for ch in chls: - chip[ch].set_en(False) - print chip[ch].get_lost_count(), ch +for channel in self.dut.get_modules('m26_rx'): + channel["EN"] = False + print "Lost count", channel["LOST_COUNT"], "channel name", channel.name -ret = chip['SRAM'].get_fifo_size(), chip['SRAM'].get_fifo_size()/4 -print 'XXX', ret -ret = chip['SRAM'].get_data() +print 'FIFO size', dut['SITCP_FIFO'].get_FIFO_SIZE() + +ret = dut['SITCP_FIFO'].get_data() for i, r in enumerate(ret): if i > 1000 and i < 1100: print i, hex(r), 'id', (r & 0x00F00000) >>20, 'start', (r & 0x00010000) >> 16, 'data', hex(r & 0x000FFFFF) # DATA FORMAT # HEADER(2bit=0x20) + PLANEID(4bit) + 3'b000 + FRAME_START(1bit) + DATA(16bit) - diff --git a/firmware/mmc3_m26_eth/src/mmc3_m26_eth.v b/firmware/mmc3_m26_eth/src/mmc3_m26_eth.v index 505a363ab..eb4ef4694 100644 --- a/firmware/mmc3_m26_eth/src/mmc3_m26_eth.v +++ b/firmware/mmc3_m26_eth/src/mmc3_m26_eth.v @@ -1,10 +1,34 @@ - +/** + * This file is part of pyBAR. + * + * pyBAR is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * pyBAR is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with pyBAR. If not, see . + */ + +/** + * ------------------------------------------------------------ + * Copyright (c) All rights reserved + * SiLab, Institute of Physics, University of Bonn + * ------------------------------------------------------------ + */ + +`timescale 1ps / 1ps +`default_nettype none module mmc3_m26_eth( input wire RESET_N, input wire clkin, - - + output wire [3:0] rgmii_txd, output wire rgmii_tx_ctl, output wire rgmii_txc, @@ -14,24 +38,24 @@ module mmc3_m26_eth( output wire mdio_phy_mdc, inout wire mdio_phy_mdio, output wire phy_rst_n, - + output wire [7:0] LED, - + output wire CMD_CLK_P, CMD_CLK_N, output wire CMD_DATA_P, CMD_DATA_N, input wire RJ45_HITOR_N, RJ45_HITOR_P, input wire DOBOUT_N, DOBOUT_P, - + input wire [5:0] M26_CLK_P, M26_CLK_N, M26_MKD_P, M26_MKD_N, input wire [5:0] M26_DATA1_P, M26_DATA1_N, M26_DATA0_P, M26_DATA0_N, - + output wire M26_TCK_P,M26_TCK_N, output wire M26_TMS_P,M26_TMS_N, output wire M26_TDI_P,M26_TDI_N, input wire M26_TDO_P,M26_TDO_N, - - - output wire RJ45_BUSY_LEMO_TX1, RJ45_CLK_LEMO_TX0, + + + output wire RJ45_BUSY_LEMO_TX1, RJ45_CLK_LEMO_TX0, input wire RJ45_TRIGGER, RJ45_RESET, input wire [1:0] LEMO_RX @@ -39,7 +63,7 @@ module mmc3_m26_eth( wire RST; -wire BUS_CLK_PLL, CLK250PLL, CLK125PLLTX, CLK125PLLTX90, CLK125PLLRX; +wire CLK250PLL, CLK125PLLTX, CLK125PLLTX90, CLK125PLLRX; wire PLL_FEEDBACK, LOCKED; PLLE2_BASE #( @@ -47,28 +71,28 @@ PLLE2_BASE #( .CLKFBOUT_MULT(10), // Multiply value for all CLKOUT, (2-64) .CLKFBOUT_PHASE(0.0), // Phase offset in degrees of CLKFB, (-360.000-360.000). .CLKIN1_PERIOD(10.000), // Input clock period in ns to ps resolution (i.e. 33.333 is 30 MHz). - + .CLKOUT0_DIVIDE(7), // Divide amount for CLKOUT0 (1-128) .CLKOUT0_DUTY_CYCLE(0.5), // Duty cycle for CLKOUT0 (0.001-0.999). .CLKOUT0_PHASE(0.0), // Phase offset for CLKOUT0 (-360.000-360.000). - + .CLKOUT1_DIVIDE(4), // Divide amount for CLKOUT0 (1-128) .CLKOUT1_DUTY_CYCLE(0.5), // Duty cycle for CLKOUT0 (0.001-0.999). .CLKOUT1_PHASE(0.0), // Phase offset for CLKOUT0 (-360.000-360.000). - + .CLKOUT2_DIVIDE(8), // Divide amount for CLKOUT0 (1-128) .CLKOUT2_DUTY_CYCLE(0.5), // Duty cycle for CLKOUT0 (0.001-0.999). .CLKOUT2_PHASE(0.0), // Phase offset for CLKOUT0 (-360.000-360.000). - + .CLKOUT3_DIVIDE(8), // Divide amount for CLKOUT0 (1-128) .CLKOUT3_DUTY_CYCLE(0.5), // Duty cycle for CLKOUT0 (0.001-0.999). .CLKOUT3_PHASE(90.0), // Phase offset for CLKOUT0 (-360.000-360.000). - + .CLKOUT4_DIVIDE(8), // Divide amount for CLKOUT0 (1-128) .CLKOUT4_DUTY_CYCLE(0.5), // Duty cycle for CLKOUT0 (0.001-0.999). .CLKOUT4_PHASE(-5.6), // Phase offset for CLKOUT0 (-360.000-360.000). //-65 -> 0?; - 45 -> 39; -25 -> 100; -5 -> 0; - + .DIVCLK_DIVIDE(1), // Master division value, (1-56) .REF_JITTER1(0.0), // Reference input jitter in UI, (0.000-0.999). .STARTUP_WAIT("FALSE") // Delay DONE until PLL Locks, ("TRUE"/"FALSE") @@ -77,59 +101,59 @@ PLLE2_BASE #( .CLKOUT0(), .CLKOUT1(CLK250PLL), - + .CLKOUT2(CLK125PLLTX), .CLKOUT3(CLK125PLLTX90), .CLKOUT4(CLK125PLLRX), - + .CLKOUT5(), - + .CLKFBOUT(PLL_FEEDBACK), - + .LOCKED(LOCKED), // 1-bit output: LOCK - + // Input 100 MHz clock .CLKIN1(clkin), - + // Control Ports .PWRDWN(0), .RST(!RESET_N), - + // Feedback .CLKFBIN(PLL_FEEDBACK) ); - + wire PLL_FEEDBACK2, LOCKED2; wire CLK160_PLL, CLK320_PLL, CLK40_PLL, CLK16_PLL, BUS_CLK_PLL; PLLE2_BASE #( - .BANDWIDTH("OPTIMIZED"), - .CLKFBOUT_MULT(16), - .CLKFBOUT_PHASE(0.0), - .CLKIN1_PERIOD(10.000), - - .CLKOUT0_DIVIDE(10), - .CLKOUT0_DUTY_CYCLE(0.5), - .CLKOUT0_PHASE(0.0), - - .CLKOUT1_DIVIDE(40), - .CLKOUT1_DUTY_CYCLE(0.5), - .CLKOUT1_PHASE(0.0), - - .CLKOUT2_DIVIDE(5), - .CLKOUT2_DUTY_CYCLE(0.5), + .BANDWIDTH("OPTIMIZED"), + .CLKFBOUT_MULT(16), + .CLKFBOUT_PHASE(0.0), + .CLKIN1_PERIOD(10.000), + + .CLKOUT0_DIVIDE(10), + .CLKOUT0_DUTY_CYCLE(0.5), + .CLKOUT0_PHASE(0.0), + + .CLKOUT1_DIVIDE(40), + .CLKOUT1_DUTY_CYCLE(0.5), + .CLKOUT1_PHASE(0.0), + + .CLKOUT2_DIVIDE(5), + .CLKOUT2_DUTY_CYCLE(0.5), .CLKOUT2_PHASE(0.0), - - .CLKOUT3_DIVIDE(100), - .CLKOUT3_DUTY_CYCLE(0.5), - .CLKOUT3_PHASE(0.0), - - .CLKOUT4_DIVIDE(12), - .CLKOUT4_DUTY_CYCLE(0.5), + + .CLKOUT3_DIVIDE(100), + .CLKOUT3_DUTY_CYCLE(0.5), + .CLKOUT3_PHASE(0.0), + + .CLKOUT4_DIVIDE(12), + .CLKOUT4_DUTY_CYCLE(0.5), .CLKOUT4_PHASE(0.0), - .DIVCLK_DIVIDE(1), - .REF_JITTER1(0.0), - .STARTUP_WAIT("FALSE") + .DIVCLK_DIVIDE(1), + .REF_JITTER1(0.0), + .STARTUP_WAIT("FALSE") ) PLLE2_BASE_inst_2 ( @@ -139,18 +163,18 @@ PLLE2_BASE_inst_2 ( .CLKOUT3(CLK16_PLL), .CLKOUT4(BUS_CLK_PLL), .CLKOUT5(), - + .CLKFBOUT(PLL_FEEDBACK2), .LOCKED(LOCKED2), // 1-bit output: LOCK - + .CLKIN1(clkin), - + .PWRDWN(0), .RST(!RESET_N), .CLKFBIN(PLL_FEEDBACK2) ); - + wire CLK160, CLK40, CLK320, CLK16, BUS_CLK; BUFG BUFG_inst_160 (.O(CLK160), .I(CLK160_PLL) ); @@ -260,7 +284,7 @@ WRAP_SiTCP_GMII_XC7K_32K sitcp( // MII interface .GMII_RSTn(phy_rst_n) , // out : PHY reset .GMII_1000M(1'b1) , // in : GMII mode (0:MII, 1:GMII) - // TX + // TX .GMII_TX_CLK(CLK125TX) , // in : Tx clock .GMII_TX_EN(gmii_tx_en) , // out : Tx enable .GMII_TXD(gmii_txd) , // out : Tx data[7:0] @@ -302,8 +326,8 @@ WRAP_SiTCP_GMII_XC7K_32K sitcp( .RBCP_RD(RBCP_RD) // in : Read data[7:0] ); -// ------- BUS SYGNALING ------- // - +// ------- BUS SIGNALLING ------- // + wire BUS_WR, BUS_RD, BUS_RST; wire [31:0] BUS_ADD; wire [7:0] BUS_DATA; @@ -312,7 +336,7 @@ assign BUS_RST = SiTCP_RST; rbcp_to_bus irbcp_to_bus( .BUS_RST(BUS_RST), .BUS_CLK(BUS_CLK), - + .RBCP_ACT(RBCP_ACT), .RBCP_ADDR(RBCP_ADDR), .RBCP_WD(RBCP_WD), @@ -320,14 +344,14 @@ rbcp_to_bus irbcp_to_bus( .RBCP_RE(RBCP_RE), .RBCP_ACK(RBCP_ACK), .RBCP_RD(RBCP_RD), - + .BUS_WR(BUS_WR), .BUS_RD(BUS_RD), .BUS_ADD(BUS_ADD), .BUS_DATA(BUS_DATA) ); -// ------- MODULE ADREESSES ------- // +// ------- MODULE ADDRESSES ------- // localparam CMD_BASEADDR = 32'h0000; localparam CMD_HIGHADDR = 32'h8000-1; @@ -347,42 +371,42 @@ localparam M26_RX_HIGHADDR = 32'ha00f-1; localparam GPIO_BASEADDR = 32'hb000; localparam GPIO_HIGHADDR = 32'hb01f; - + // ------- USER MODULES ------- // ///////////////////// M26 JTAG wire M26_TCK, M26_TMS,M26_TDI,M26_TDO,M26_TMS_INV,M26_TDI_INV, M26_TDO_INV; wire M26_RESETB; OBUFDS #( .IOSTANDARD("LVDS_25"), - .SLEW("SLOW") + .SLEW("SLOW") ) OBUFDS_inst_m26_tck ( .O(M26_TCK_P), - .OB(M26_TCK_N), - .I(M26_TCK) + .OB(M26_TCK_N), + .I(M26_TCK) ); OBUFDS #( .IOSTANDARD("LVDS_25"), - .SLEW("SLOW") + .SLEW("SLOW") ) OBUFDS_inst_m26_tms ( .O(M26_TMS_P), - .OB(M26_TMS_N), - .I(M26_TMS) + .OB(M26_TMS_N), + .I(M26_TMS) ); OBUFDS #( .IOSTANDARD("LVDS_25"), - .SLEW("SLOW") + .SLEW("SLOW") ) OBUFDS_inst_m26_tdi ( .O(M26_TDI_P), - .OB(M26_TDI_N), - .I(M26_TDI) + .OB(M26_TDI_N), + .I(M26_TDI) ); IBUFDS #( - .DIFF_TERM("TRUE"), - .IBUF_LOW_PWR("FALSE"), - .IOSTANDARD("LVDS_25") + .DIFF_TERM("TRUE"), + .IBUF_LOW_PWR("FALSE"), + .IOSTANDARD("LVDS_25") ) IBUFDS_inst_m26_tdo ( - .O(M26_TDO), - .I(M26_TDO_P), + .O(M26_TDO), + .I(M26_TDO_P), .IB(M26_TDO_N) ); assign M26_TMS= ~M26_TMS_INV; @@ -430,29 +454,29 @@ cmd_seq #( .CMD_CLK_IN(CLK40), .CMD_CLK_OUT(CMD_CLK), .CMD_DATA(CMD_DATA), - + .CMD_EXT_START_FLAG(CMD_EXT_START_FLAG), .CMD_EXT_START_ENABLE(EXT_TRIGGER_ENABLE), .CMD_READY(CMD_READY), .CMD_START_FLAG(CMD_START_FLAG) ); - + OBUFDS #( .IOSTANDARD("LVDS_25"), - .SLEW("SLOW") + .SLEW("SLOW") ) OBUFDS_inst_cmd_clk_out ( .O(CMD_CLK_P), - .OB(CMD_CLK_N), - .I(CMD_CLK) + .OB(CMD_CLK_N), + .I(CMD_CLK) ); OBUFDS #( - .IOSTANDARD("LVDS_25"), + .IOSTANDARD("LVDS_25"), .SLEW("SLOW") ) OBUFDS_inst_cmd_data ( - .O(CMD_DATA_P), - .OB(CMD_DATA_N), - .I(CMD_DATA) + .O(CMD_DATA_P), + .OB(CMD_DATA_N), + .I(CMD_DATA) ); @@ -468,8 +492,15 @@ assign TRIGGER_ACKNOWLEDGE_FLAG = CMD_READY & ~CMD_READY_FF; wire TRIGGER_FIFO_READ; wire TRIGGER_FIFO_EMPTY; wire [31:0] TRIGGER_FIFO_DATA; -wire TRIGGER_FIFO_PEEMPT_REQ; +wire TRIGGER_FIFO_PREEMPT_REQ; wire [31:0] TIMESTAMP; +wire TDC_OUT; +wire RX_READY, RX_8B10B_DECODER_ERR, RX_FIFO_OVERFLOW_ERR, RX_FIFO_FULL, RX_ENABLED; +wire FIFO_FULL; +wire TLU_BUSY, TLU_CLOCK; +wire TRIGGER_ENABLED, TLU_ENABLED; +assign RJ45_BUSY_LEMO_TX1 = TLU_ENABLED ? TLU_BUSY : ~CMD_READY; +assign RJ45_CLK_LEMO_TX0 = TLU_CLOCK; tlu_controller #( .BASEADDR(TLU_BASEADDR), @@ -484,40 +515,43 @@ tlu_controller #( .BUS_DATA(BUS_DATA), .BUS_RD(BUS_RD), .BUS_WR(BUS_WR), - + .TRIGGER_CLK(CLK40), - + .FIFO_READ(TRIGGER_FIFO_READ), .FIFO_EMPTY(TRIGGER_FIFO_EMPTY), .FIFO_DATA(TRIGGER_FIFO_DATA), - - .FIFO_PREEMPT_REQ(TRIGGER_FIFO_PEEMPT_REQ), - - .TRIGGER({8'b0}), - .TRIGGER_VETO({7'b0, FIFO_FULL}), - + + .FIFO_PREEMPT_REQ(TRIGGER_FIFO_PREEMPT_REQ), + + .TRIGGER_ENABLED(TRIGGER_ENABLED), + .TRIGGER_SELECTED(), + .TLU_ENABLED(TLU_ENABLED), + + .TRIGGER({6'b0, TDC_OUT, LEMO_RX[0]}), + .TRIGGER_VETO({6'b0, RX_FIFO_FULL, FIFO_FULL}), + .EXT_TRIGGER_ENABLE(EXT_TRIGGER_ENABLE), - .TRIGGER_ACKNOWLEDGE(EXT_TRIGGER_ENABLE == 1'b0 ? TRIGGER_ACCEPTED_FLAG : TRIGGER_ACKNOWLEDGE_FLAG), + .TRIGGER_ACKNOWLEDGE(TRIGGER_ACKNOWLEDGE_FLAG), .TRIGGER_ACCEPTED_FLAG(TRIGGER_ACCEPTED_FLAG), - + .TLU_TRIGGER(RJ45_TRIGGER), .TLU_RESET(RJ45_RESET), - .TLU_BUSY(RJ45_BUSY_LEMO_TX1), - .TLU_CLOCK(RJ45_CLK_LEMO_TX0), - + .TLU_BUSY(TLU_BUSY), + .TLU_CLOCK(TLU_CLOCK), + .TIMESTAMP(TIMESTAMP) ); reg [31:0] timestamp_gray; -always@(posedge BUS_CLK) - timestamp_gray <= (TIMESTAMP>>1) ^ TIMESTAMP; +always@(posedge BUS_CLK) + timestamp_gray <= (TIMESTAMP>>1) ^ TIMESTAMP; wire DOBOUT; -wire RX_READY, RX_8B10B_DECODER_ERR, RX_FIFO_OVERFLOW_ERR, RX_FIFO_FULL; wire FE_FIFO_READ; wire FE_FIFO_EMPTY; wire [31:0] FE_FIFO_DATA; - + fei4_rx #( .BASEADDR(RX_BASEADDR), .HIGHADDR(RX_HIGHADDR), @@ -540,7 +574,7 @@ fei4_rx #( .FIFO_DATA(FE_FIFO_DATA), .RX_FIFO_FULL(RX_FIFO_FULL), - .RX_ENABLED(), + .RX_ENABLED(RX_ENABLED), .BUS_CLK(BUS_CLK), .BUS_RST(BUS_RST), @@ -549,14 +583,14 @@ fei4_rx #( .BUS_RD(BUS_RD), .BUS_WR(BUS_WR) ); - + IBUFDS #( - .DIFF_TERM("TRUE"), - .IBUF_LOW_PWR("FALSE"), - .IOSTANDARD("LVDS_25") + .DIFF_TERM("TRUE"), + .IBUF_LOW_PWR("FALSE"), + .IOSTANDARD("LVDS_25") ) IBUFDS_inst_i ( - .O(DOBOUT), - .I(DOBOUT_P), + .O(DOBOUT), + .I(DOBOUT_P), .IB(DOBOUT_N) ); @@ -576,72 +610,72 @@ wire [5:0] LOST_ERROR; wire [5:0] FIFO_READ_M26_RX; wire [5:0] FIFO_EMPTY_M26_RX; wire [31:0] FIFO_DATA_M26_RX [5:0]; - + genvar ch; generate for (ch = 0; ch < 6; ch = ch + 1) begin: m26_gen IBUFDS #( - .DIFF_TERM("TRUE"), - .IBUF_LOW_PWR("FALSE"), - .IOSTANDARD("LVDS_25") + .DIFF_TERM("TRUE"), + .IBUF_LOW_PWR("FALSE"), + .IOSTANDARD("LVDS_25") ) IBUFDS_inst_M26_CLK( - .O(M26_CLK[ch]), - .I(M26_CLK_P[ch]), + .O(M26_CLK[ch]), + .I(M26_CLK_P[ch]), .IB(M26_CLK_N[ch]) ); - + IBUFDS #( - .DIFF_TERM("TRUE"), - .IBUF_LOW_PWR("FALSE"), - .IOSTANDARD("LVDS_25") + .DIFF_TERM("TRUE"), + .IBUF_LOW_PWR("FALSE"), + .IOSTANDARD("LVDS_25") ) IBUFDS_inst_M26_MKD( - .O(M26_MKD[ch]), - .I(M26_MKD_P[ch]), + .O(M26_MKD[ch]), + .I(M26_MKD_P[ch]), .IB(M26_MKD_N[ch]) ); IBUFDS #( - .DIFF_TERM("TRUE"), - .IBUF_LOW_PWR("FALSE"), - .IOSTANDARD("LVDS_25") + .DIFF_TERM("TRUE"), + .IBUF_LOW_PWR("FALSE"), + .IOSTANDARD("LVDS_25") ) IBUFDS_inst_M26_DATA0( - .O(M26_DATA0_RX[ch]), - .I(M26_DATA0_P[ch]), + .O(M26_DATA0_RX[ch]), + .I(M26_DATA0_P[ch]), .IB(M26_DATA0_N[ch]) ); - + IBUFDS #( - .DIFF_TERM("TRUE"), - .IBUF_LOW_PWR("FALSE"), - .IOSTANDARD("LVDS_25") + .DIFF_TERM("TRUE"), + .IBUF_LOW_PWR("FALSE"), + .IOSTANDARD("LVDS_25") ) IBUFDS_inst_M26_DATA1( .O(M26_DATA1_RX[ch]), - .I(M26_DATA1_P[ch]), + .I(M26_DATA1_P[ch]), .IB(M26_DATA1_N[ch]) - ); + ); - BUFG BUFG_inst_M26_CLK ( .O(M26_CLK_BUFG[ch]), .I(M26_CLK[ch]) ); + BUFG BUFG_inst_M26_CLK ( .O(M26_CLK_BUFG[ch]), .I(M26_CLK[ch]) ); wire M26_CLK_INV; assign M26_CLK_INV = ~M26_CLK[ch]; - + reg [31:0] timestamp_cdc0, timestamp_cdc1, timestamp_m26; always@(posedge M26_CLK_INV) begin timestamp_cdc0 <= timestamp_gray; timestamp_cdc1 <= timestamp_cdc0; end - + integer gbi; always@(*) begin timestamp_m26[31] = timestamp_cdc1[31]; for(gbi =30; gbi >= 0; gbi = gbi -1) begin timestamp_m26[gbi] = timestamp_cdc1[gbi] ^ timestamp_m26[gbi+1]; end - end - - m26_rx + end + + m26_rx #( - .BASEADDR(M26_RX_BASEADDR + ch*16), + .BASEADDR(M26_RX_BASEADDR + ch*16), .HIGHADDR(M26_RX_HIGHADDR + ch*16), .ABUSWIDTH(32), .HEADER(8'h20), @@ -651,25 +685,25 @@ generate .CLK_RX(M26_CLK_BUFG[ch]), .MKD_RX(M26_MKD[ch]), .DATA_RX({M26_DATA1[ch], M26_DATA0[ch]}), - + .BUS_CLK(BUS_CLK), .BUS_RST(BUS_RST), .BUS_ADD(BUS_ADD), .BUS_DATA(BUS_DATA[7:0]), .BUS_RD(BUS_RD), - .BUS_WR(BUS_WR), - + .BUS_WR(BUS_WR), + .FIFO_READ(FIFO_READ_M26_RX[ch]), .FIFO_EMPTY(FIFO_EMPTY_M26_RX[ch]), .FIFO_DATA(FIFO_DATA_M26_RX[ch]), - + .TIMESTAMP(timestamp_m26), - + .LOST_ERROR(LOST_ERROR[ch]) ); - -end -endgenerate + +end +endgenerate //assign FIFO_EMPTY_M26_RX = 5'hff; @@ -683,22 +717,21 @@ wire TDC_IN_FROM_TDC; wire RJ45_HITOR; IBUFDS #( - .DIFF_TERM("TRUE"), - .IBUF_LOW_PWR("FALSE"), - .IOSTANDARD("LVDS_25") + .DIFF_TERM("TRUE"), + .IBUF_LOW_PWR("FALSE"), + .IOSTANDARD("LVDS_25") ) IBUFDS_inst_RJ45_HITOR ( - .O(RJ45_HITOR), - .I(RJ45_HITOR_P), + .O(RJ45_HITOR), + .I(RJ45_HITOR_P), .IB(RJ45_HITOR_N) ); -wire TDC_OUT; tdc_s3 #( .BASEADDR(TDC_BASEADDR), .HIGHADDR(TDC_HIGHADDR), .ABUSWIDTH(32), .CLKDV(4), - .DATA_IDENTIFIER(4'b0100), // one-hot + .DATA_IDENTIFIER(4'b0100), .FAST_TDC(1), .FAST_TRIGGER(0) ) i_tdc ( @@ -723,7 +756,7 @@ tdc_s3 #( .ARM_TDC(CMD_START_FLAG), // arm TDC by sending commands .EXT_EN(1'b0), - + .TIMESTAMP(TIMESTAMP[15:0]) ); @@ -738,7 +771,7 @@ rrp_arbiter #( .CLK(BUS_CLK), .WRITE_REQ({~TDC_FIFO_EMPTY, ~FIFO_EMPTY_M26_RX, ~FE_FIFO_EMPTY, ~TRIGGER_FIFO_EMPTY}), - .HOLD_REQ({8'b0, TRIGGER_FIFO_PEEMPT_REQ }), + .HOLD_REQ({8'b0, TRIGGER_FIFO_PREEMPT_REQ }), .DATA_IN({TDC_FIFO_DATA, FIFO_DATA_M26_RX[5], FIFO_DATA_M26_RX[4], FIFO_DATA_M26_RX[3], FIFO_DATA_M26_RX[2], FIFO_DATA_M26_RX[1], FIFO_DATA_M26_RX[0], FE_FIFO_DATA, TRIGGER_FIFO_DATA}), .READ_GRANT(READ_GRANT), @@ -755,6 +788,7 @@ assign TDC_FIFO_READ = READ_GRANT[8]; //cdc_fifo is for timing reasons wire [31:0] cdc_data_out; wire full_32to8, cdc_fifo_empty; +wire FIFO_EMPTY; cdc_syncfifo #(.DSIZE(32), .ASIZE(3)) cdc_syncfifo_i ( .rdata(cdc_data_out), @@ -766,11 +800,10 @@ cdc_syncfifo #(.DSIZE(32), .ASIZE(3)) cdc_syncfifo_i ); assign ARB_READY_OUT = !FIFO_FULL; -wire FIFO_EMPTY, FIFO_FULL; fifo_32_to_8 #(.DEPTH(256*1024)) i_data_fifo ( .RST(BUS_RST), .CLK(BUS_CLK), - + .WRITE(!cdc_fifo_empty), .READ(TCP_TX_WR), .DATA_IN(cdc_data_out), @@ -781,7 +814,7 @@ fifo_32_to_8 #(.DEPTH(256*1024)) i_data_fifo ( assign TCP_TX_WR = !TCP_TX_FULL && !FIFO_EMPTY; -wire CLK_1HZ; +wire CLK_1HZ; clock_divider #( .DIVISOR(40000000) ) i_clock_divisor_40MHz_to_1Hz ( @@ -791,10 +824,21 @@ clock_divider #( .CLOCK(CLK_1HZ) ); -assign LED[7:6] = 2'hf; -assign LED[0] = RX_READY; -assign LED[1] = ~(|LOST_ERROR & CLK_1HZ); -assign LED[2] = ~(|RX_8B10B_DECODER_ERR & CLK_1HZ); +wire CLK_3HZ; +clock_divider #( + .DIVISOR(13333333) +) i_clock_divisor_40MHz_to_3Hz ( + .CLK(CLK40), + .RESET(1'b0), + .CE(), + .CLOCK(CLK_3HZ) +); + +assign LED[7:4] = 4'hf; +assign LED[0] = ~((CLK_1HZ | FIFO_FULL) & LOCKED & LOCKED2); +assign LED[1] = ~(((RX_READY & RX_ENABLED) == RX_ENABLED) & ((|(RX_8B10B_DECODER_ERR & RX_ENABLED)? CLK_3HZ : CLK_1HZ) | (|(RX_FIFO_OVERFLOW_ERR & RX_ENABLED)) | (|(RX_FIFO_FULL & RX_ENABLED)))); +assign LED[2] = 1'b1; +assign LED[3] = 1'b1; //ila_0 ila( // .clk(CLK320), diff --git a/firmware/mmc3_m26_eth/vivado/mmc3_m26_eth.xpr b/firmware/mmc3_m26_eth/vivado/mmc3_m26_eth.xpr index f63ae01fc..8180ca3be 100644 --- a/firmware/mmc3_m26_eth/vivado/mmc3_m26_eth.xpr +++ b/firmware/mmc3_m26_eth/vivado/mmc3_m26_eth.xpr @@ -1,9 +1,9 @@ - + - + @@ -325,20 +328,6 @@ - - - - - - - - - - - - @@ -359,24 +348,31 @@ - + - - + + + + + + + + + - + + + + + + + + + - - - - - - - - - + @@ -390,23 +386,95 @@ - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -452,4 +520,5 @@ + diff --git a/firmware/nexys4/src/nexys4.v b/firmware/nexys4/src/nexys4.v index 70e7ff9fd..e2829f796 100644 --- a/firmware/nexys4/src/nexys4.v +++ b/firmware/nexys4/src/nexys4.v @@ -1,16 +1,16 @@ /** * This file is part of pyBAR. - * + * * pyBAR is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. - * + * * pyBAR is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public License * along with pyBAR. If not, see . */ @@ -27,38 +27,38 @@ module nexys4( input wire CLK100MHZ, - + output wire ETH_MDC, inout wire ETH_MDIO, - + output wire ETH_RSTN, - + input wire ETH_CRSDV, input wire ETH_RXERR, input wire [1:0] ETH_RXD, - + output wire ETH_TXEN, output wire [1:0] ETH_TXD, - + output wire ETH_REFCLK, input wire ETH_INTN, - + inout wire SDA, SCL, - + output wire CMD_CLK, - output wire CMD_DATA, + output wire CMD_DATA, input wire [3:0] DOBOUT, - + input wire TDC_IN, TDC_TRIG, - + input wire TLU_TRG, input wire TLU_RST, output wire TLU_BSY, output wire TLU_CLK, - + output wire [4:0] LED - + ); wire CLK_LOCKED, CLKFBIN, CLKFBOUT; @@ -161,24 +161,24 @@ wire ETH_COL, ETH_CRS, ETH_RX_DV, ETH_RX_ER; mii_to_rmii_0 imii_to_rmii_0 ( .rst_n(ETH_RSTN), //IN .ref_clk(ETH_CLK_TX), //IN - + .mac2rmii_tx_en(ETH_TX_EN), //IN .mac2rmii_txd(ETH_TX_D), //IN .mac2rmii_tx_er(ETH_TX_ER), //IN - + .rmii2mac_tx_clk(TX_CLK), //OUT .rmii2mac_rx_clk(RX_CLK), //OUT - + .rmii2mac_col(ETH_COL), //OUT .rmii2mac_crs(ETH_CRS), //OUT .rmii2mac_rx_dv(ETH_RX_DV), //OUT .rmii2mac_rx_er(ETH_RX_ER), //OUT .rmii2mac_rxd(ETH_RX_D), //OUT - + .phy2rmii_crs_dv(ETH_CRSDV), //IN .phy2rmii_rx_er(ETH_RXERR), //IN .phy2rmii_rxd(ETH_RXD), //IN - + .rmii2phy_txd(ETH_TXD), //OUT .rmii2phy_tx_en(ETH_TXEN) //OUT ); @@ -207,7 +207,7 @@ WRAP_SiTCP_GMII_XC7A_32K #(.TIM_PERIOD(50))sitcp( // MII interface .GMII_RSTn(ETH_RSTN) , // out : PHY reset .GMII_1000M(1'b0) , // in : GMII mode (0:MII, 1:GMII) - // TX + // TX .GMII_TX_CLK(TX_CLK) , // in : Tx clock .GMII_TX_EN(ETH_TX_EN) , // out : Tx enable .GMII_TXD({ETH_TX_D_NO,ETH_TX_D}) , // out : Tx data[7:0] @@ -263,7 +263,7 @@ wire [7:0] BUS_DATA; rbcp_to_bus irbcp_to_bus( .BUS_RST(BUS_RST), .BUS_CLK(BUS_CLK), - + .RBCP_ACT(RBCP_ACT), .RBCP_ADDR(RBCP_ADDR), .RBCP_WD(RBCP_WD), @@ -271,14 +271,14 @@ rbcp_to_bus irbcp_to_bus( .RBCP_RE(RBCP_RE), .RBCP_ACK(RBCP_ACK), .RBCP_RD(RBCP_RD), - + .BUS_WR(BUS_WR), .BUS_RD(BUS_RD), .BUS_ADD(BUS_ADD), .BUS_DATA(BUS_DATA) ); -//MODULE ADREESSES +//MODULE ADDRESSES localparam CMD_BASEADDR = 32'h0000; localparam CMD_HIGHADDR = 32'h8000-1; @@ -305,20 +305,20 @@ localparam GPIO_BASEADDR = 32'h8700; localparam GPIO_HIGHADDR = 32'h8800-1; localparam I2C_BASEADDR = 32'h8800; -localparam I2C_HIGHADDR = 32'h8900-1; - +localparam I2C_HIGHADDR = 32'h8900-1; + /// wire I2C_CLK, I2C_CLK_PRE; clock_divider #( .DIVISOR(10000) ) i2c_clkdev ( .CLK(BUS_CLK), .RESET(BUS_RST), .CE(), .CLOCK(I2C_CLK_PRE) ); BUFG BUFG_I2C ( .O(I2C_CLK), .I(I2C_CLK_PRE) ); -i2c -#( - .BASEADDR(I2C_BASEADDR), +i2c +#( + .BASEADDR(I2C_BASEADDR), .HIGHADDR(I2C_HIGHADDR), .ABUSWIDTH(32), - .MEM_BYTES(8) + .MEM_BYTES(8) ) i_i2c ( .BUS_CLK(BUS_CLK), @@ -366,8 +366,8 @@ begin end assign TRIGGER_ACKNOWLEDGE_FLAG = CMD_READY & ~CMD_READY_FF; -cmd_seq -#( +cmd_seq +#( .BASEADDR(CMD_BASEADDR), .HIGHADDR(CMD_HIGHADDR), .ABUSWIDTH(32), @@ -379,16 +379,16 @@ cmd_seq .BUS_DATA(BUS_DATA[7:0]), .BUS_RD(BUS_RD), .BUS_WR(BUS_WR), - + .CMD_CLK_OUT(CMD_CLK), .CMD_CLK_IN(CLK40), - + .CMD_EXT_START_FLAG(TRIGGER_ACCEPTED_FLAG), .CMD_EXT_START_ENABLE(EXT_TRIGGER_ENABLE), .CMD_DATA(CMD_DATA), .CMD_READY(CMD_READY), .CMD_START_FLAG(CMD_START_FLAG) - + ); wire TDC_FIFO_READ; @@ -403,7 +403,7 @@ tdc_s3 #( .HIGHADDR(TDC_HIGHADDR), .ABUSWIDTH(32), .CLKDV(4), - .DATA_IDENTIFIER(4'b0100), // one-hot + .DATA_IDENTIFIER(4'b0100), .FAST_TDC(1), .FAST_TRIGGER(1) ) i_tdc ( @@ -428,7 +428,7 @@ tdc_s3 #( .ARM_TDC(CMD_START_FLAG), // arm TDC by sending commands .EXT_EN(1'b0), - + .TIMESTAMP(TIMESTAMP[15:0]) ); @@ -450,30 +450,34 @@ tlu_controller #( .BUS_DATA(BUS_DATA), .BUS_RD(BUS_RD), .BUS_WR(BUS_WR), - + .TRIGGER_CLK(CLK40), - + .FIFO_READ(TRIGGER_FIFO_READ), .FIFO_EMPTY(TRIGGER_FIFO_EMPTY), .FIFO_DATA(TRIGGER_FIFO_DATA), - + .FIFO_PREEMPT_REQ(TRIGGER_FIFO_PEEMPT_REQ), - + + .TRIGGER_ENABLED(), + .TRIGGER_SELECTED(), + .TLU_ENABLED(), + .TRIGGER({6'b0, TDC_OUT, TRIG_OUT}), .TRIGGER_VETO({7'b0, FIFO_FULL}), - + .EXT_TRIGGER_ENABLE(EXT_TRIGGER_ENABLE), - .TRIGGER_ACKNOWLEDGE(EXT_TRIGGER_ENABLE == 1'b0 ? TRIGGER_ACCEPTED_FLAG : TRIGGER_ACKNOWLEDGE_FLAG), + .TRIGGER_ACKNOWLEDGE(TRIGGER_ACKNOWLEDGE_FLAG), .TRIGGER_ACCEPTED_FLAG(TRIGGER_ACCEPTED_FLAG), - + .TLU_TRIGGER(TLU_TRG), .TLU_RESET(TLU_RST), .TLU_BUSY(TLU_BSY), .TLU_CLOCK(TLU_CLK), - + .TIMESTAMP(TIMESTAMP) -); - +); + wire [3:0] RX_READY, RX_8B10B_DECODER_ERR, RX_FIFO_OVERFLOW_ERR, RX_FIFO_FULL, RX_ENABLED; wire [3:0] FE_FIFO_READ; wire [3:0] FE_FIFO_EMPTY; @@ -519,7 +523,7 @@ endgenerate wire ARB_READY_OUT, ARB_WRITE_OUT; wire [31:0] ARB_DATA_OUT; wire [5:0] READ_GRANT; - + rrp_arbiter #( .WIDTH(6) ) i_rrp_arbiter ( @@ -537,12 +541,12 @@ rrp_arbiter #( assign FE_FIFO_READ = READ_GRANT[5:2]; assign TDC_FIFO_READ = READ_GRANT[1]; assign TRIGGER_FIFO_READ = READ_GRANT[0]; - + wire FIFO_EMPTY, FIFO_FULL; fifo_32_to_8 #(.DEPTH(64*1024)) i_data_fifo ( .RST(BUS_RST), .CLK(BUS_CLK), - + .WRITE(ARB_WRITE_OUT), .READ(TCP_TX_WR), .DATA_IN(ARB_DATA_OUT), @@ -555,8 +559,8 @@ assign TCP_TX_WR = !TCP_TX_FULL && !FIFO_EMPTY; //assign GPIO_LED = RX_READY; -wire CE_1HZ; -wire CLK_1HZ; +wire CE_1HZ; +wire CLK_1HZ; clock_divider #( .DIVISOR(40000000) ) i_clock_divisor_40MHz_to_1Hz ( diff --git a/pybar/ViTablesPlugin/pybar_plugin.py b/pybar/ViTablesPlugin/pybar_plugin.py index c733c3dc1..950346f5a 100644 --- a/pybar/ViTablesPlugin/pybar_plugin.py +++ b/pybar/ViTablesPlugin/pybar_plugin.py @@ -4,7 +4,6 @@ """Plugin that provides plotting of data from the Python Bonn Atlas Readout System (pyBAR). """ - import os from PyQt4 import QtCore @@ -14,8 +13,8 @@ from vitables.vtSite import PLUGINSDIR try: - from matplotlib import colors, cm import matplotlib.pyplot as plt + from matplotlib import colors, cm from mpl_toolkits.axes_grid1 import make_axes_locatable except: print 'ERROR: Cannot load additional libraries needed for the pyBAR ViTables plugin!' diff --git a/pybar/__init__.py b/pybar/__init__.py index 9e23494b4..e91f8ffe6 100644 --- a/pybar/__init__.py +++ b/pybar/__init__.py @@ -2,4 +2,4 @@ from pybar.run_manager import RunManager, run_status from pybar.scans import * -__all__ = ["RunManager", "run_status", "HitOrCalibration", "create_hitor_calibration", "PlsrDacTransientCalibration", "PlsrDacCalibration", "plot_pulser_dac", "PulserDacCorrectionCalibration", "ThresholdCalibration", "create_threshold_calibration", "TotCalibration", "AnalogScan", "CrosstalkScan", "DigitalScan", "ExtTriggerGdacScan", "StopModeExtTriggerScan", "ExtTriggerScan", "FEI4SelfTriggerScan", "HitDelayScan", "IleakScan", "InitScan", "IVScan", "FastThresholdScan", "ThresholdScan", "RegisterTest", "TdcTest", "FdacTuning", "FeedbackTuning", "Fei4Tuning", "GdacTuning", "HotPixelTuning", "MergedPixelsTuning", "NoiseOccupancyTuning", "StuckPixelScan", "TdacTuning", "ThresholdBaselineTuning", "TluTuning"] +__all__ = ["RunManager", "run_status", "HitOrCalibration", "create_hitor_calibration", "PlsrDacTransientCalibration", "PlsrDacCalibration", "plot_pulser_dac", "PulserDacCorrectionCalibration", "ThresholdCalibration", "create_threshold_calibration", "TotCalibration", "AnalogScan", "CrosstalkScan", "DigitalScan", "ExtTriggerGdacScan", "StopModeExtTriggerScan", "ExtTriggerScan", "Fei4SelfTriggerScan", "HitDelayScan", "IleakScan", "InitScan", "IVScan", "FastThresholdScan", "ThresholdScan", "RegisterTest", "TdcTest", "FdacTuning", "FeedbackTuning", "Fei4Tuning", "GdacTuning", "HotPixelTuning", "MergedPixelsTuning", "NoiseOccupancyTuning", "StuckPixelScan", "TdacTuning", "ThresholdBaselineTuning", "TluTuning"] diff --git a/pybar/analysis/analysis.py b/pybar/analysis/analysis.py index cc04961ec..12b333337 100644 --- a/pybar/analysis/analysis.py +++ b/pybar/analysis/analysis.py @@ -5,11 +5,11 @@ import logging import os import time +import re import zlib import numpy as np import tables as tb -import re import progressbar @@ -62,7 +62,7 @@ def analyze_beam_spot(scan_base, combine_n_readouts=1000, chunk_size=10000000, p index = 0 # index where to start the read out, 0 at the beginning, increased during looping best_chunk_size = chunk_size - progress_bar = progressbar.ProgressBar(widgets=['', progressbar.Percentage(), ' ', progressbar.Bar(marker='*', left='|', right='|'), ' ', analysis_utils.ETA()], maxval=hit_table.shape[0], term_width=80) + progress_bar = progressbar.ProgressBar(widgets=['', progressbar.Percentage(), ' ', progressbar.Bar(marker='*', left='|', right='|'), ' ', progressbar.AdaptiveETA()], maxval=hit_table.shape[0], term_width=80) progress_bar.start() # loop over the selected events @@ -193,7 +193,7 @@ def analyse_n_cluster_per_event(scan_base, include_no_cluster=False, time_line_a total_cluster = cluster_table.shape[0] - progress_bar = progressbar.ProgressBar(widgets=['', progressbar.Percentage(), ' ', progressbar.Bar(marker='*', left='|', right='|'), ' ', analysis_utils.ETA()], maxval=total_cluster, term_width=80) + progress_bar = progressbar.ProgressBar(widgets=['', progressbar.Percentage(), ' ', progressbar.Bar(marker='*', left='|', right='|'), ' ', progressbar.AdaptiveETA()], maxval=total_cluster, term_width=80) progress_bar.start() # loop over the selected events @@ -273,7 +273,7 @@ def select_hits_from_cluster_info(input_file_hits, output_file_hits, cluster_siz hit_table_out = out_hit_file_h5.create_table(out_hit_file_h5.root, name='Hits', description=data_struct.HitInfoTable, title='hit_data', filters=tb.Filters(complib='blosc', complevel=5, fletcher32=False)) cluster_table = in_hit_file_h5.root.Cluster last_word_number = 0 - progress_bar = progressbar.ProgressBar(widgets=['', progressbar.Percentage(), ' ', progressbar.Bar(marker='*', left='|', right='|'), ' ', analysis_utils.ETA()], maxval=cluster_table.shape[0], term_width=80) + progress_bar = progressbar.ProgressBar(widgets=['', progressbar.Percentage(), ' ', progressbar.Bar(marker='*', left='|', right='|'), ' ', progressbar.AdaptiveETA()], maxval=cluster_table.shape[0], term_width=80) progress_bar.start() for data, index in analysis_utils.data_aligned_at_events(cluster_table, chunk_size=chunk_size): selected_events_1 = analysis_utils.get_events_with_cluster_size(event_number=data['event_number'], cluster_size=data['size'], condition=cluster_size_condition) # select the events with clusters of a certain size @@ -321,7 +321,7 @@ def select_hits(input_file_hits, output_file_hits, condition=None, cluster_size_ hit_table_out = out_hit_file_h5.create_table(out_hit_file_h5.root, name='Hits', description=data_struct.HitInfoTable, title='hit_data', filters=tb.Filters(complib='blosc', complevel=5, fletcher32=False)) cluster_table = in_hit_file_h5.root.Cluster last_word_number = 0 - progress_bar = progressbar.ProgressBar(widgets=['', progressbar.Percentage(), ' ', progressbar.Bar(marker='*', left='|', right='|'), ' ', analysis_utils.ETA()], maxval=cluster_table.shape[0], term_width=80) + progress_bar = progressbar.ProgressBar(widgets=['', progressbar.Percentage(), ' ', progressbar.Bar(marker='*', left='|', right='|'), ' ', progressbar.AdaptiveETA()], maxval=cluster_table.shape[0], term_width=80) progress_bar.start() for data, index in analysis_utils.data_aligned_at_events(cluster_table, chunk_size=chunk_size): if cluster_size_condition is not None: @@ -384,7 +384,7 @@ def analyze_cluster_size_per_scan_parameter(input_file_hits, output_file_cluster analyze_data.create_cluster_size_hist = True analyze_data.create_cluster_tot_hist = True analyze_data.histogram.set_no_scan_parameter() # one has to tell histogram the # of scan parameters for correct occupancy hist allocation - progress_bar = progressbar.ProgressBar(widgets=['', progressbar.Percentage(), ' ', progressbar.Bar(marker='*', left='|', right='|'), ' ', analysis_utils.ETA()], maxval=hit_table.shape[0], term_width=80) + progress_bar = progressbar.ProgressBar(widgets=['', progressbar.Percentage(), ' ', progressbar.Bar(marker='*', left='|', right='|'), ' ', progressbar.AdaptiveETA()], maxval=hit_table.shape[0], term_width=80) progress_bar.start() for parameter_index, parameter_range in enumerate(parameter_ranges): # loop over the selected events analyze_data.reset() # resets the data of the last analysis @@ -464,7 +464,7 @@ def histogram_cluster_table(analyzed_data_file, output_file, chunk_size=10000000 histogram.set_no_scan_parameter() logging.info('Histogram cluster seeds...') - progress_bar = progressbar.ProgressBar(widgets=['', progressbar.Percentage(), ' ', progressbar.Bar(marker='*', left='|', right='|'), ' ', analysis_utils.ETA()], maxval=in_file_h5.root.Cluster.shape[0], term_width=80) + progress_bar = progressbar.ProgressBar(widgets=['', progressbar.Percentage(), ' ', progressbar.Bar(marker='*', left='|', right='|'), ' ', progressbar.AdaptiveETA()], maxval=in_file_h5.root.Cluster.shape[0], term_width=80) progress_bar.start() total_cluster = 0 # to check analysis for cluster, index in analysis_utils.data_aligned_at_events(in_file_h5.root.Cluster, chunk_size=chunk_size): diff --git a/pybar/analysis/analysis_utils.py b/pybar/analysis/analysis_utils.py index 128a28c04..4e6f295b2 100644 --- a/pybar/analysis/analysis_utils.py +++ b/pybar/analysis/analysis_utils.py @@ -11,6 +11,7 @@ from operator import itemgetter import zlib +import progressbar import numpy as np import tables as tb from tables import dtype_from_descr @@ -18,8 +19,6 @@ from scipy.interpolate import interp1d from scipy.interpolate import splrep, splev -import progressbar - from pybar_fei4_interpreter import analysis_utils from pybar.daq.fei4_record import FEI4Record from pybar.analysis.plotting import plotting @@ -269,7 +268,7 @@ def get_rate_normalization(hit_file, parameter, reference='event', cluster_file= index = 0 # index where to start the read out, 0 at the beginning, increased during looping, variable for read speed up best_chunk_size = chunk_size # variable for read speed up total_cluster = 0 - progress_bar = progressbar.ProgressBar(widgets=['', progressbar.Percentage(), ' ', progressbar.Bar(marker='*', left='|', right='|'), ' ', ETA(smoothing=0.8)], maxval=cluster_table.shape[0], term_width=80) + progress_bar = progressbar.ProgressBar(widgets=['', progressbar.Percentage(), ' ', progressbar.Bar(marker='*', left='|', right='|'), ' ', progressbar.AdaptiveETA()], maxval=cluster_table.shape[0], term_width=80) progress_bar.start() for start_event, stop_event in event_range: # loop over the selected events readout_cluster_len = 0 # variable to calculate a optimal chunk size value from the number of hits for speed up @@ -307,7 +306,7 @@ def get_total_n_data_words(files_dict, precise=False): n_words = 0 if precise: # open all files and determine the total number of words precicely, can take some time if len(files_dict) > 10: - progress_bar = progressbar.ProgressBar(widgets=['', progressbar.Percentage(), ' ', progressbar.Bar(marker='*', left='|', right='|'), ' ', ETA()], maxval=len(files_dict), term_width=80) + progress_bar = progressbar.ProgressBar(widgets=['', progressbar.Percentage(), ' ', progressbar.Bar(marker='*', left='|', right='|'), ' ', progressbar.AdaptiveETA()], maxval=len(files_dict), term_width=80) progress_bar.start() for index, file_name in enumerate(files_dict.iterkeys()): with tb.open_file(file_name, mode="r") as in_file_h5: # open the actual file @@ -609,7 +608,7 @@ def combine_meta_data(files_dict, meta_data_v2=True): ('error', np.uint32)]) if len(files_dict) > 10: - progress_bar = progressbar.ProgressBar(widgets=['', progressbar.Percentage(), ' ', progressbar.Bar(marker='*', left='|', right='|'), ' ', ETA()], maxval=total_length, term_width=80) + progress_bar = progressbar.ProgressBar(widgets=['', progressbar.Percentage(), ' ', progressbar.Bar(marker='*', left='|', right='|'), ' ', progressbar.AdaptiveETA()], maxval=total_length, term_width=80) progress_bar.start() index = 0 @@ -1432,8 +1431,8 @@ def get_pixel_thresholds_from_calibration_array(gdacs, calibration_gdacs, thresh class ETA(progressbar.Timer): - - 'Widget which estimate the time of arrival for the progress bar via exponential moving average.' + '''Progressbar widget which estimate the time of arrival for the progress bar via exponential moving average. + ''' TIME_SENSITIVE = True def __init__(self, smoothing=0.1): @@ -1470,7 +1469,6 @@ def update(self, pbar): speed = 0 -# old, maybe not needed functions def get_n_cluster_per_event_hist(cluster_table): '''Calculates the number of cluster in every event. diff --git a/pybar/analysis/analyze_raw_data.py b/pybar/analysis/analyze_raw_data.py index 8c16adfd7..31f745a13 100644 --- a/pybar/analysis/analyze_raw_data.py +++ b/pybar/analysis/analyze_raw_data.py @@ -715,8 +715,6 @@ def interpret_word_table(self, analyzed_data_file=None, use_settings_from_file=T if self._analyzed_data_file is not None: if self._create_hit_table is True: description = data_struct.HitInfoTable().columns.copy() - if self.trigger_data_format == 1: # use trigger time stamp if trigger number is not available - description['trigger_time_stamp'] = description.pop('trigger_number') hit_table = self.out_file_h5.create_table(self.out_file_h5.root, name='Hits', description=description, title='hit_data', filters=self._filter_table, chunkshape=(self._chunk_size / 100,)) if self._create_meta_word_index is True: meta_word_index_table = self.out_file_h5.create_table(self.out_file_h5.root, name='EventMetaData', description=data_struct.MetaInfoWordTable, title='event_meta_data', filters=self._filter_table, chunkshape=(self._chunk_size / 10,)) @@ -724,8 +722,6 @@ def interpret_word_table(self, analyzed_data_file=None, use_settings_from_file=T cluster_table = self.out_file_h5.create_table(self.out_file_h5.root, name='Cluster', description=data_struct.ClusterInfoTable, title='Cluster data', filters=self._filter_table, expectedrows=self._chunk_size) if self._create_cluster_hit_table: description = data_struct.ClusterHitInfoTable().columns.copy() - if self.trigger_data_format == 1: # use trigger time stamp if trigger number is not available - description['trigger_time_stamp'] = description.pop('trigger_number') cluster_hit_table = self.out_file_h5.create_table(self.out_file_h5.root, name='ClusterHits', description=description, title='cluster_hit_data', filters=self._filter_table, expectedrows=self._chunk_size) logging.info("Interpreting raw data...") @@ -1153,7 +1149,7 @@ def analyze_hit_table(self, analyzed_data_file=None, analyzed_data_out_file=None n_hits = 0 # number of hits in actual chunk logging.info('Analyzing hits...') - progress_bar = progressbar.ProgressBar(widgets=['', progressbar.Percentage(), ' ', progressbar.Bar(marker='*', left='|', right='|'), ' ', progressbar.ETA()], maxval=table_size, term_width=80) + progress_bar = progressbar.ProgressBar(widgets=['', progressbar.Percentage(), ' ', progressbar.Bar(marker='*', left='|', right='|'), ' ', progressbar.AdaptiveETA()], maxval=table_size, term_width=80) progress_bar.start() for hits, index in analysis_utils.data_aligned_at_events(in_file_h5.root.Hits, chunk_size=self._chunk_size): @@ -1393,7 +1389,11 @@ def _deduce_settings_from_file(self, opened_raw_data_file): # TODO: parse bette try: # take infos raw data files (not avalable in old files) flavor = opened_raw_data_file.root.configuration.miscellaneous[:][np.where(opened_raw_data_file.root.configuration.miscellaneous[:]['name'] == 'Flavor')]['value'][0] self._settings_from_file_set = True - trig_count = opened_raw_data_file.root.configuration.global_register[:][np.where(opened_raw_data_file.root.configuration.global_register[:]['name'] == 'Trig_Count')]['value'][0] + # adding this for special cases e.g., stop-mode scan + if "trig_count" in opened_raw_data_file.root.configuration.run_conf[:]['name']: + trig_count = opened_raw_data_file.root.configuration.run_conf[:][np.where(opened_raw_data_file.root.configuration.run_conf[:]['name'] == 'trig_count')]['value'][0] + else: + trig_count = opened_raw_data_file.root.configuration.global_register[:][np.where(opened_raw_data_file.root.configuration.global_register[:]['name'] == 'Trig_Count')]['value'][0] vcal_c0 = opened_raw_data_file.root.configuration.calibration_parameters[:][np.where(opened_raw_data_file.root.configuration.calibration_parameters[:]['name'] == 'Vcal_Coeff_0')]['value'][0] vcal_c1 = opened_raw_data_file.root.configuration.calibration_parameters[:][np.where(opened_raw_data_file.root.configuration.calibration_parameters[:]['name'] == 'Vcal_Coeff_1')]['value'][0] c_low = opened_raw_data_file.root.configuration.calibration_parameters[:][np.where(opened_raw_data_file.root.configuration.calibration_parameters[:]['name'] == 'C_Inj_Low')]['value'][0] diff --git a/pybar/config/m26/mmc3_anemome_th10.yaml b/pybar/config/m26/mmc3_anemome_th10.yaml index 95ef601cf..c5d1140f7 100644 --- a/pybar/config/m26/mmc3_anemome_th10.yaml +++ b/pybar/config/m26/mmc3_anemome_th10.yaml @@ -1,3 +1,38 @@ +ETH: + +FEI4_RX: + INVERT_RX: 0 + +CMD_FEI4: + OUTPUT_MODE: 0 + +M26_RX1: + EN: 0 + TIMESTAMP_HEADER: 0 +M26_RX2: + EN: 0 + TIMESTAMP_HEADER: 0 +M26_RX3: + EN: 0 + TIMESTAMP_HEADER: 0 +M26_RX4: + EN: 0 + TIMESTAMP_HEADER: 0 +M26_RX5: + EN: 0 + TIMESTAMP_HEADER: 0 +M26_RX6: + EN: 0 + TIMESTAMP_HEADER: 0 + +JTAG: + +GPIO_JTAG: + OUTPUT: + - 1 + OUTPUT_EN: + - 0 + BIAS_DAC_ALL: BIAS_DAC: - IAnaBUF: '00110010' @@ -166,17 +201,6 @@ BYPASS_ALL: - BYPASS: '0' - BYPASS: '0' - BYPASS: '0' -CH0: - INVERT_RX: 0 -CMD: - CLOCK_GATE: 0 - CMD_PULSE: 0 - CMD_REPEAT: 1 - CMD_SIZE: 0 - EN_EXT_TRIGGER: 0 - OUTPUT_MODE: 0 - START_SEQUENCE_LENGTH: 0 - STOP_SEQUENCE_LENGTH: 0 CONTROL_PIX_REG_ALL: CONTROL_PIX_REG: - NU: '000' @@ -351,7 +375,6 @@ DIS_DISCRI_ALL: - DisableLatch: '000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001110000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' - DisableLatch: '000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' - DisableLatch: '000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' -ETH: {} HEADER_REG_ALL: HEADER_REG: - header0: '0101010101010101' @@ -394,24 +417,6 @@ LINEPAT1_REG_ALL: - LinePatL1Reg: '000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' - LinePatL1Reg: '000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' - LinePatL1Reg: '000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' -M26_RX1: - EN: 0 - TIMESTAMP_HEADER: 0 -M26_RX2: - EN: 0 - TIMESTAMP_HEADER: 0 -M26_RX3: - EN: 0 - TIMESTAMP_HEADER: 0 -M26_RX4: - EN: 0 - TIMESTAMP_HEADER: 0 -M26_RX5: - EN: 0 - TIMESTAMP_HEADER: 0 -M26_RX6: - EN: 0 - TIMESTAMP_HEADER: 0 RO_MODE0_ALL: RO_MODE0: - DistLVDS: '0' @@ -618,12 +623,3 @@ SEQUENCER_SUZE_REG_ALL: drstline: '0110000000000000' drstpix: '0000010101010101' dstartingline: '1110000000000001' -SRAM: - ALMOST_EMPTY_THRESHOLD: 2 - ALMOST_FULL_THRESHOLD: 2 -gpio_jtag: - OUTPUT: - - 1 - OUTPUT_EN: - - 0 -jtag: {} diff --git a/pybar/config/m26/mmc3_anemome_th11.yaml b/pybar/config/m26/mmc3_anemome_th11.yaml index d8f662984..c1981a9f3 100644 --- a/pybar/config/m26/mmc3_anemome_th11.yaml +++ b/pybar/config/m26/mmc3_anemome_th11.yaml @@ -1,3 +1,38 @@ +ETH: + +FEI4_RX: + INVERT_RX: 0 + +CMD_FEI4: + OUTPUT_MODE: 0 + +M26_RX1: + EN: 0 + TIMESTAMP_HEADER: 0 +M26_RX2: + EN: 0 + TIMESTAMP_HEADER: 0 +M26_RX3: + EN: 0 + TIMESTAMP_HEADER: 0 +M26_RX4: + EN: 0 + TIMESTAMP_HEADER: 0 +M26_RX5: + EN: 0 + TIMESTAMP_HEADER: 0 +M26_RX6: + EN: 0 + TIMESTAMP_HEADER: 0 + +JTAG: + +GPIO_JTAG: + OUTPUT: + - 1 + OUTPUT_EN: + - 0 + BIAS_DAC_ALL: BIAS_DAC: - IAnaBUF: '00110010' @@ -166,17 +201,6 @@ BYPASS_ALL: - BYPASS: '0' - BYPASS: '0' - BYPASS: '0' -CH0: - INVERT_RX: 0 -CMD: - CLOCK_GATE: 0 - CMD_PULSE: 0 - CMD_REPEAT: 1 - CMD_SIZE: 0 - EN_EXT_TRIGGER: 0 - OUTPUT_MODE: 0 - START_SEQUENCE_LENGTH: 0 - STOP_SEQUENCE_LENGTH: 0 CONTROL_PIX_REG_ALL: CONTROL_PIX_REG: - NU: '000' @@ -351,7 +375,6 @@ DIS_DISCRI_ALL: - DisableLatch: '000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001110000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' - DisableLatch: '000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' - DisableLatch: '000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' -ETH: {} HEADER_REG_ALL: HEADER_REG: - header0: '0101010101010101' @@ -394,24 +417,6 @@ LINEPAT1_REG_ALL: - LinePatL1Reg: '000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' - LinePatL1Reg: '000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' - LinePatL1Reg: '000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' -M26_RX1: - EN: 0 - TIMESTAMP_HEADER: 0 -M26_RX2: - EN: 0 - TIMESTAMP_HEADER: 0 -M26_RX3: - EN: 0 - TIMESTAMP_HEADER: 0 -M26_RX4: - EN: 0 - TIMESTAMP_HEADER: 0 -M26_RX5: - EN: 0 - TIMESTAMP_HEADER: 0 -M26_RX6: - EN: 0 - TIMESTAMP_HEADER: 0 RO_MODE0_ALL: RO_MODE0: - DistLVDS: '0' @@ -618,12 +623,3 @@ SEQUENCER_SUZE_REG_ALL: drstline: '0110000000000000' drstpix: '0000010101010101' dstartingline: '1110000000000001' -SRAM: - ALMOST_EMPTY_THRESHOLD: 2 - ALMOST_FULL_THRESHOLD: 2 -gpio_jtag: - OUTPUT: - - 1 - OUTPUT_EN: - - 0 -jtag: {} diff --git a/pybar/config/m26/mmc3_anemome_th4.yaml b/pybar/config/m26/mmc3_anemome_th4.yaml index 9b3f6c968..e468ef80d 100644 --- a/pybar/config/m26/mmc3_anemome_th4.yaml +++ b/pybar/config/m26/mmc3_anemome_th4.yaml @@ -1,3 +1,38 @@ +ETH: + +FEI4_RX: + INVERT_RX: 0 + +CMD_FEI4: + OUTPUT_MODE: 0 + +M26_RX1: + EN: 0 + TIMESTAMP_HEADER: 0 +M26_RX2: + EN: 0 + TIMESTAMP_HEADER: 0 +M26_RX3: + EN: 0 + TIMESTAMP_HEADER: 0 +M26_RX4: + EN: 0 + TIMESTAMP_HEADER: 0 +M26_RX5: + EN: 0 + TIMESTAMP_HEADER: 0 +M26_RX6: + EN: 0 + TIMESTAMP_HEADER: 0 + +JTAG: + +GPIO_JTAG: + OUTPUT: + - 1 + OUTPUT_EN: + - 0 + BIAS_DAC_ALL: BIAS_DAC: - IAnaBUF: '00110010' @@ -166,17 +201,6 @@ BYPASS_ALL: - BYPASS: '0' - BYPASS: '0' - BYPASS: '0' -CH0: - INVERT_RX: 0 -CMD: - CLOCK_GATE: 0 - CMD_PULSE: 0 - CMD_REPEAT: 1 - CMD_SIZE: 0 - EN_EXT_TRIGGER: 0 - OUTPUT_MODE: 0 - START_SEQUENCE_LENGTH: 0 - STOP_SEQUENCE_LENGTH: 0 CONTROL_PIX_REG_ALL: CONTROL_PIX_REG: - NU: '000' @@ -351,7 +375,6 @@ DIS_DISCRI_ALL: - DisableLatch: '000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001110000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' - DisableLatch: '000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' - DisableLatch: '000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' -ETH: {} HEADER_REG_ALL: HEADER_REG: - header0: '0101010101010101' @@ -394,24 +417,6 @@ LINEPAT1_REG_ALL: - LinePatL1Reg: '000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' - LinePatL1Reg: '000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' - LinePatL1Reg: '000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' -M26_RX1: - EN: 0 - TIMESTAMP_HEADER: 0 -M26_RX2: - EN: 0 - TIMESTAMP_HEADER: 0 -M26_RX3: - EN: 0 - TIMESTAMP_HEADER: 0 -M26_RX4: - EN: 0 - TIMESTAMP_HEADER: 0 -M26_RX5: - EN: 0 - TIMESTAMP_HEADER: 0 -M26_RX6: - EN: 0 - TIMESTAMP_HEADER: 0 RO_MODE0_ALL: RO_MODE0: - DistLVDS: '0' @@ -618,12 +623,3 @@ SEQUENCER_SUZE_REG_ALL: drstline: '0110000000000000' drstpix: '0000010101010101' dstartingline: '1110000000000001' -SRAM: - ALMOST_EMPTY_THRESHOLD: 2 - ALMOST_FULL_THRESHOLD: 2 -gpio_jtag: - OUTPUT: - - 1 - OUTPUT_EN: - - 0 -jtag: {} diff --git a/pybar/config/m26/mmc3_anemome_th5.yaml b/pybar/config/m26/mmc3_anemome_th5.yaml index c70e82074..1df71a33e 100644 --- a/pybar/config/m26/mmc3_anemome_th5.yaml +++ b/pybar/config/m26/mmc3_anemome_th5.yaml @@ -1,3 +1,38 @@ +ETH: + +FEI4_RX: + INVERT_RX: 0 + +CMD_FEI4: + OUTPUT_MODE: 0 + +M26_RX1: + EN: 0 + TIMESTAMP_HEADER: 0 +M26_RX2: + EN: 0 + TIMESTAMP_HEADER: 0 +M26_RX3: + EN: 0 + TIMESTAMP_HEADER: 0 +M26_RX4: + EN: 0 + TIMESTAMP_HEADER: 0 +M26_RX5: + EN: 0 + TIMESTAMP_HEADER: 0 +M26_RX6: + EN: 0 + TIMESTAMP_HEADER: 0 + +JTAG: + +GPIO_JTAG: + OUTPUT: + - 1 + OUTPUT_EN: + - 0 + BIAS_DAC_ALL: BIAS_DAC: - IAnaBUF: '00110010' @@ -166,17 +201,6 @@ BYPASS_ALL: - BYPASS: '0' - BYPASS: '0' - BYPASS: '0' -CH0: - INVERT_RX: 0 -CMD: - CLOCK_GATE: 0 - CMD_PULSE: 0 - CMD_REPEAT: 1 - CMD_SIZE: 0 - EN_EXT_TRIGGER: 0 - OUTPUT_MODE: 0 - START_SEQUENCE_LENGTH: 0 - STOP_SEQUENCE_LENGTH: 0 CONTROL_PIX_REG_ALL: CONTROL_PIX_REG: - NU: '000' @@ -351,7 +375,6 @@ DIS_DISCRI_ALL: - DisableLatch: '000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001110000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' - DisableLatch: '000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' - DisableLatch: '000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' -ETH: {} HEADER_REG_ALL: HEADER_REG: - header0: '0101010101010101' @@ -394,24 +417,6 @@ LINEPAT1_REG_ALL: - LinePatL1Reg: '000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' - LinePatL1Reg: '000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' - LinePatL1Reg: '000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' -M26_RX1: - EN: 0 - TIMESTAMP_HEADER: 0 -M26_RX2: - EN: 0 - TIMESTAMP_HEADER: 0 -M26_RX3: - EN: 0 - TIMESTAMP_HEADER: 0 -M26_RX4: - EN: 0 - TIMESTAMP_HEADER: 0 -M26_RX5: - EN: 0 - TIMESTAMP_HEADER: 0 -M26_RX6: - EN: 0 - TIMESTAMP_HEADER: 0 RO_MODE0_ALL: RO_MODE0: - DistLVDS: '0' @@ -618,12 +623,3 @@ SEQUENCER_SUZE_REG_ALL: drstline: '0110000000000000' drstpix: '0000010101010101' dstartingline: '1110000000000001' -SRAM: - ALMOST_EMPTY_THRESHOLD: 2 - ALMOST_FULL_THRESHOLD: 2 -gpio_jtag: - OUTPUT: - - 1 - OUTPUT_EN: - - 0 -jtag: {} diff --git a/pybar/config/m26/mmc3_anemome_th6.yaml b/pybar/config/m26/mmc3_anemome_th6.yaml index 6745cb98b..2f369c4b9 100644 --- a/pybar/config/m26/mmc3_anemome_th6.yaml +++ b/pybar/config/m26/mmc3_anemome_th6.yaml @@ -1,3 +1,38 @@ +ETH: + +FEI4_RX: + INVERT_RX: 0 + +CMD_FEI4: + OUTPUT_MODE: 0 + +M26_RX1: + EN: 0 + TIMESTAMP_HEADER: 0 +M26_RX2: + EN: 0 + TIMESTAMP_HEADER: 0 +M26_RX3: + EN: 0 + TIMESTAMP_HEADER: 0 +M26_RX4: + EN: 0 + TIMESTAMP_HEADER: 0 +M26_RX5: + EN: 0 + TIMESTAMP_HEADER: 0 +M26_RX6: + EN: 0 + TIMESTAMP_HEADER: 0 + +JTAG: + +GPIO_JTAG: + OUTPUT: + - 1 + OUTPUT_EN: + - 0 + BIAS_DAC_ALL: BIAS_DAC: - IAnaBUF: '00110010' @@ -166,17 +201,6 @@ BYPASS_ALL: - BYPASS: '0' - BYPASS: '0' - BYPASS: '0' -CH0: - INVERT_RX: 0 -CMD: - CLOCK_GATE: 0 - CMD_PULSE: 0 - CMD_REPEAT: 1 - CMD_SIZE: 0 - EN_EXT_TRIGGER: 0 - OUTPUT_MODE: 0 - START_SEQUENCE_LENGTH: 0 - STOP_SEQUENCE_LENGTH: 0 CONTROL_PIX_REG_ALL: CONTROL_PIX_REG: - NU: '000' @@ -351,7 +375,6 @@ DIS_DISCRI_ALL: - DisableLatch: '000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001110000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' - DisableLatch: '000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' - DisableLatch: '000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' -ETH: {} HEADER_REG_ALL: HEADER_REG: - header0: '0101010101010101' @@ -394,24 +417,6 @@ LINEPAT1_REG_ALL: - LinePatL1Reg: '000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' - LinePatL1Reg: '000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' - LinePatL1Reg: '000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' -M26_RX1: - EN: 0 - TIMESTAMP_HEADER: 0 -M26_RX2: - EN: 0 - TIMESTAMP_HEADER: 0 -M26_RX3: - EN: 0 - TIMESTAMP_HEADER: 0 -M26_RX4: - EN: 0 - TIMESTAMP_HEADER: 0 -M26_RX5: - EN: 0 - TIMESTAMP_HEADER: 0 -M26_RX6: - EN: 0 - TIMESTAMP_HEADER: 0 RO_MODE0_ALL: RO_MODE0: - DistLVDS: '0' @@ -618,12 +623,3 @@ SEQUENCER_SUZE_REG_ALL: drstline: '0110000000000000' drstpix: '0000010101010101' dstartingline: '1110000000000001' -SRAM: - ALMOST_EMPTY_THRESHOLD: 2 - ALMOST_FULL_THRESHOLD: 2 -gpio_jtag: - OUTPUT: - - 1 - OUTPUT_EN: - - 0 -jtag: {} diff --git a/pybar/config/m26/mmc3_anemome_th7.yaml b/pybar/config/m26/mmc3_anemome_th7.yaml index 9a139f2bd..5b1abcbad 100644 --- a/pybar/config/m26/mmc3_anemome_th7.yaml +++ b/pybar/config/m26/mmc3_anemome_th7.yaml @@ -1,3 +1,38 @@ +ETH: + +FEI4_RX: + INVERT_RX: 0 + +CMD_FEI4: + OUTPUT_MODE: 0 + +M26_RX1: + EN: 0 + TIMESTAMP_HEADER: 0 +M26_RX2: + EN: 0 + TIMESTAMP_HEADER: 0 +M26_RX3: + EN: 0 + TIMESTAMP_HEADER: 0 +M26_RX4: + EN: 0 + TIMESTAMP_HEADER: 0 +M26_RX5: + EN: 0 + TIMESTAMP_HEADER: 0 +M26_RX6: + EN: 0 + TIMESTAMP_HEADER: 0 + +JTAG: + +GPIO_JTAG: + OUTPUT: + - 1 + OUTPUT_EN: + - 0 + BIAS_DAC_ALL: BIAS_DAC: - IAnaBUF: '00110010' @@ -166,17 +201,6 @@ BYPASS_ALL: - BYPASS: '0' - BYPASS: '0' - BYPASS: '0' -CH0: - INVERT_RX: 0 -CMD: - CLOCK_GATE: 0 - CMD_PULSE: 0 - CMD_REPEAT: 1 - CMD_SIZE: 0 - EN_EXT_TRIGGER: 0 - OUTPUT_MODE: 0 - START_SEQUENCE_LENGTH: 0 - STOP_SEQUENCE_LENGTH: 0 CONTROL_PIX_REG_ALL: CONTROL_PIX_REG: - NU: '000' @@ -351,7 +375,6 @@ DIS_DISCRI_ALL: - DisableLatch: '000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001110000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' - DisableLatch: '000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' - DisableLatch: '000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' -ETH: {} HEADER_REG_ALL: HEADER_REG: - header0: '0101010101010101' @@ -394,24 +417,6 @@ LINEPAT1_REG_ALL: - LinePatL1Reg: '000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' - LinePatL1Reg: '000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' - LinePatL1Reg: '000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' -M26_RX1: - EN: 0 - TIMESTAMP_HEADER: 0 -M26_RX2: - EN: 0 - TIMESTAMP_HEADER: 0 -M26_RX3: - EN: 0 - TIMESTAMP_HEADER: 0 -M26_RX4: - EN: 0 - TIMESTAMP_HEADER: 0 -M26_RX5: - EN: 0 - TIMESTAMP_HEADER: 0 -M26_RX6: - EN: 0 - TIMESTAMP_HEADER: 0 RO_MODE0_ALL: RO_MODE0: - DistLVDS: '0' @@ -618,12 +623,3 @@ SEQUENCER_SUZE_REG_ALL: drstline: '0110000000000000' drstpix: '0000010101010101' dstartingline: '1110000000000001' -SRAM: - ALMOST_EMPTY_THRESHOLD: 2 - ALMOST_FULL_THRESHOLD: 2 -gpio_jtag: - OUTPUT: - - 1 - OUTPUT_EN: - - 0 -jtag: {} diff --git a/pybar/config/m26/mmc3_anemome_th8.yaml b/pybar/config/m26/mmc3_anemome_th8.yaml index de81b453e..37b8c0f41 100644 --- a/pybar/config/m26/mmc3_anemome_th8.yaml +++ b/pybar/config/m26/mmc3_anemome_th8.yaml @@ -1,3 +1,38 @@ +ETH: + +FEI4_RX: + INVERT_RX: 0 + +CMD_FEI4: + OUTPUT_MODE: 0 + +M26_RX1: + EN: 0 + TIMESTAMP_HEADER: 0 +M26_RX2: + EN: 0 + TIMESTAMP_HEADER: 0 +M26_RX3: + EN: 0 + TIMESTAMP_HEADER: 0 +M26_RX4: + EN: 0 + TIMESTAMP_HEADER: 0 +M26_RX5: + EN: 0 + TIMESTAMP_HEADER: 0 +M26_RX6: + EN: 0 + TIMESTAMP_HEADER: 0 + +JTAG: + +GPIO_JTAG: + OUTPUT: + - 1 + OUTPUT_EN: + - 0 + BIAS_DAC_ALL: BIAS_DAC: - IAnaBUF: '00110010' @@ -166,17 +201,6 @@ BYPASS_ALL: - BYPASS: '0' - BYPASS: '0' - BYPASS: '0' -CH0: - INVERT_RX: 0 -CMD: - CLOCK_GATE: 0 - CMD_PULSE: 0 - CMD_REPEAT: 1 - CMD_SIZE: 0 - EN_EXT_TRIGGER: 0 - OUTPUT_MODE: 0 - START_SEQUENCE_LENGTH: 0 - STOP_SEQUENCE_LENGTH: 0 CONTROL_PIX_REG_ALL: CONTROL_PIX_REG: - NU: '000' @@ -351,7 +375,6 @@ DIS_DISCRI_ALL: - DisableLatch: '000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001110000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' - DisableLatch: '000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' - DisableLatch: '000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' -ETH: {} HEADER_REG_ALL: HEADER_REG: - header0: '0101010101010101' @@ -394,24 +417,6 @@ LINEPAT1_REG_ALL: - LinePatL1Reg: '000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' - LinePatL1Reg: '000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' - LinePatL1Reg: '000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' -M26_RX1: - EN: 0 - TIMESTAMP_HEADER: 0 -M26_RX2: - EN: 0 - TIMESTAMP_HEADER: 0 -M26_RX3: - EN: 0 - TIMESTAMP_HEADER: 0 -M26_RX4: - EN: 0 - TIMESTAMP_HEADER: 0 -M26_RX5: - EN: 0 - TIMESTAMP_HEADER: 0 -M26_RX6: - EN: 0 - TIMESTAMP_HEADER: 0 RO_MODE0_ALL: RO_MODE0: - DistLVDS: '0' @@ -618,12 +623,3 @@ SEQUENCER_SUZE_REG_ALL: drstline: '0110000000000000' drstpix: '0000010101010101' dstartingline: '1110000000000001' -SRAM: - ALMOST_EMPTY_THRESHOLD: 2 - ALMOST_FULL_THRESHOLD: 2 -gpio_jtag: - OUTPUT: - - 1 - OUTPUT_EN: - - 0 -jtag: {} diff --git a/pybar/config/m26/mmc3_anemome_th9.yaml b/pybar/config/m26/mmc3_anemome_th9.yaml index 9a03acd34..d19eeb7a0 100644 --- a/pybar/config/m26/mmc3_anemome_th9.yaml +++ b/pybar/config/m26/mmc3_anemome_th9.yaml @@ -1,3 +1,38 @@ +ETH: + +FEI4_RX: + INVERT_RX: 0 + +CMD_FEI4: + OUTPUT_MODE: 0 + +M26_RX1: + EN: 0 + TIMESTAMP_HEADER: 0 +M26_RX2: + EN: 0 + TIMESTAMP_HEADER: 0 +M26_RX3: + EN: 0 + TIMESTAMP_HEADER: 0 +M26_RX4: + EN: 0 + TIMESTAMP_HEADER: 0 +M26_RX5: + EN: 0 + TIMESTAMP_HEADER: 0 +M26_RX6: + EN: 0 + TIMESTAMP_HEADER: 0 + +JTAG: + +GPIO_JTAG: + OUTPUT: + - 1 + OUTPUT_EN: + - 0 + BIAS_DAC_ALL: BIAS_DAC: - IAnaBUF: '00110010' @@ -166,17 +201,6 @@ BYPASS_ALL: - BYPASS: '0' - BYPASS: '0' - BYPASS: '0' -CH0: - INVERT_RX: 0 -CMD: - CLOCK_GATE: 0 - CMD_PULSE: 0 - CMD_REPEAT: 1 - CMD_SIZE: 0 - EN_EXT_TRIGGER: 0 - OUTPUT_MODE: 0 - START_SEQUENCE_LENGTH: 0 - STOP_SEQUENCE_LENGTH: 0 CONTROL_PIX_REG_ALL: CONTROL_PIX_REG: - NU: '000' @@ -351,7 +375,6 @@ DIS_DISCRI_ALL: - DisableLatch: '000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001110000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' - DisableLatch: '000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' - DisableLatch: '000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' -ETH: {} HEADER_REG_ALL: HEADER_REG: - header0: '0101010101010101' @@ -394,24 +417,6 @@ LINEPAT1_REG_ALL: - LinePatL1Reg: '000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' - LinePatL1Reg: '000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' - LinePatL1Reg: '000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' -M26_RX1: - EN: 0 - TIMESTAMP_HEADER: 0 -M26_RX2: - EN: 0 - TIMESTAMP_HEADER: 0 -M26_RX3: - EN: 0 - TIMESTAMP_HEADER: 0 -M26_RX4: - EN: 0 - TIMESTAMP_HEADER: 0 -M26_RX5: - EN: 0 - TIMESTAMP_HEADER: 0 -M26_RX6: - EN: 0 - TIMESTAMP_HEADER: 0 RO_MODE0_ALL: RO_MODE0: - DistLVDS: '0' @@ -618,12 +623,3 @@ SEQUENCER_SUZE_REG_ALL: drstline: '0110000000000000' drstpix: '0000010101010101' dstartingline: '1110000000000001' -SRAM: - ALMOST_EMPTY_THRESHOLD: 2 - ALMOST_FULL_THRESHOLD: 2 -gpio_jtag: - OUTPUT: - - 1 - OUTPUT_EN: - - 0 -jtag: {} diff --git a/pybar/configuration.yaml b/pybar/configuration.yaml index a67d237d9..6da7f7184 100644 --- a/pybar/configuration.yaml +++ b/pybar/configuration.yaml @@ -1,47 +1,133 @@ +# *** MIO2 board *** + # *** hardwre setup/configuration *** -dut : dut_mio.yaml # DUT hardware configuration (.yaml). Change to dut_mio_gpac.yaml for GPAC support. -dut_configuration : dut_configuration_mio.yaml # DUT init configuration (.yaml). Change to dut_configuration_mio_gpac.yaml for GPAC support. -# *** front-end configuration *** -fe_configuration : # FE configuration file, text (.cfg) or HDF5 (.h5) file. If not given, latest valid configuration (run status FINISHED) will be taken. If a number is given, configuration from run with specified number will be taken. -fe_flavor : fei4b # FEI4 flavor/type for initial configuration. Valid values: 'fei4a' or 'fei4b' -chip_address : # Chip Address for initial configuration, if not given, broadcast bit will be set -module_id : module_test # module identifier / name, sub-folder with given name will be created inside working_dir +dut : dut_mio.yaml # DUT hardware configuration (.yaml file). E.g. change to dut_mio_gpac.yaml to support the GPAC adapter card. +dut_configuration : dut_configuration_mio.yaml # Initial DUT configuration (.yaml file). E.g. change to dut_configuration_mio_gpac.yaml to support the GPAC adapter card. +working_dir : data # The name of the output data folder. + +# *** module configurations *** + +modules : + module_0 : + activate : True + configuration : # FE configuration file, text (.cfg) or HDF5 (.h5) file. If no value is given, the latest valid configuration (run status 'FINISHED') will be taken. If a number is given, the configuration from the run with the specified number will be taken. + flavor : fei4b # FEI4 flavor/type for initial configuration. Valid values are: 'fei4a', 'fei4b'. + chip_address : # Chip Address for initial configuration. if no value is given, the broadcast bit will be set. + FIFO : SRAM_FIFO # As defined in DUT configuration. + RX : DATA_CH4 # As defined in DUT configuration. + rx_channel : 4 # As implemented in the firmware. + TX : CMD_CH1_TO_CH4 # As defined in DUT configuration. + tx_channel : 0 # As implemented in the firmware. + TDC: TDC_RX2 # As defined in DUT configuration. + tdc_channel : 4 # As implemented in the firmware. + TLU : TRIGGER_CH1_TO_CH4 # As defined in DUT configuration. +# send_data : 'tcp://127.0.0.1:5678' # Address of the online monitor +# Fei4Tuning : +# target_threshold: 30 + +# *** MMC3 board with max. 8 FEI4s *** + +#dut : dut_mmc3_8chip_eth.yaml # DUT hardware configuration (.yaml file). E.g. change to dut_mio_gpac.yaml to support the GPAC adapter card. +#dut_configuration : dut_configuration_mmc3_8chip_eth.yaml # Initial DUT configuration (.yaml file). E.g. change to dut_configuration_mio_gpac.yaml to support the GPAC adapter card. +#working_dir : data # The name of the output data folder. + +#modules : +# module_0 : +# activate : True +# configuration : # FE configuration file, text (.cfg) or HDF5 (.h5) file. If no value is given, the latest valid configuration (run status 'FINISHED') will be taken. If a number is given, the configuration from the run with the specified number will be taken. +# flavor : fei4b # FEI4 flavor/type for initial configuration. Valid values are: 'fei4a', 'fei4b'. +# chip_address : # Chip Address for initial configuration. if no value is given, the broadcast bit will be set. +# FIFO : SITCP_FIFO # As defined in DUT configuration. +# RX : DATA_CH0 # As defined in DUT configuration. +# rx_channel : 0 # As implemented in the firmware. +# TX : CMD_CH0_TO_CH7 # As defined in DUT configuration. +# tx_channel : 0 # As implemented in the firmware. +# TDC: TDC_CH0 # As defined in DUT configuration. +# tdc_channel : 1 # As implemented in the firmware. +# TLU : TRIGGER_CH0_TO_CH7 # As defined in DUT configuration. +# send_data : 'tcp://127.0.0.1:5678' # Address of the online monitor +# Fei4Tuning : +# target_threshold: 30 + +# *** MMC3 board with max. 8 FEI4s with multiple TX *** + +#dut : dut_mmc3_8chip_multi_tx_eth.yaml # DUT hardware configuration (.yaml file). E.g. change to dut_mio_gpac.yaml to support the GPAC adapter card. +#dut_configuration : dut_configuration_mmc3_8chip_multi_tx_eth.yaml # Initial DUT configuration (.yaml file). E.g. change to dut_configuration_mio_gpac.yaml to support the GPAC adapter card. +#working_dir : data # The name of the output data folder. + +#modules : +# module_0 : +# activate : True +# configuration : # FE configuration file, text (.cfg) or HDF5 (.h5) file. If no value is given, the latest valid configuration (run status 'FINISHED') will be taken. If a number is given, the configuration from the run with the specified number will be taken. +# flavor : fei4b # FEI4 flavor/type for initial configuration. Valid values are: 'fei4a', 'fei4b'. +# chip_address : # Chip Address for initial configuration. if no value is given, the broadcast bit will be set. +# FIFO : SITCP_FIFO # As defined in DUT configuration. +# RX : DATA_CH0 # As defined in DUT configuration. +# rx_channel : 0 # As implemented in the firmware. +# TX : CMD_CH0 # As defined in DUT configuration. +# tx_channel : 0 # As implemented in the firmware. +# TDC: TDC_CH0 # As defined in DUT configuration. +# tdc_channel : 1 # As implemented in the firmware. +# TLU : TRIGGER_CH0 # As defined in DUT configuration. +# send_data : 'tcp://127.0.0.1:5678' # Address of the online monitor +# Fei4Tuning : +# target_threshold: 30 + + +# module_1 : +# activate : True +# configuration : # FE configuration file, text (.cfg) or HDF5 (.h5) file. If no value is given, the latest valid configuration (run status 'FINISHED') will be taken. If a number is given, the configuration from the run with the specified number will be taken. +# flavor : fei4b # FEI4 flavor/type for initial configuration. Valid values are: 'fei4a', 'fei4b'. +# chip_address : # Chip Address for initial configuration. if no value is given, the broadcast bit will be set. +# FIFO : SITCP_FIFO # As defined in DUT configuration. +# RX : DATA_CH1 # As defined in DUT configuration. +# rx_channel : 1 # As implemented in the firmware. +# TX : CMD_CH1 # As defined in DUT configuration. +# tx_channel : 0 # As implemented in the firmware. +# TDC: TDC_CH1 # As defined in DUT configuration. +# tdc_channel : 2 # As implemented in the firmware. +# TLU : TRIGGER_CH1 # As defined in DUT configuration. Select TRIGGER_CH0 if single trigger input source is available or EUDAQ TLU is used. +# send_data : 'tcp://127.0.0.1:5679' # Address of the online monitor +# Fei4Tuning : +# target_threshold: 30 # *** configuration *** -#send_data : 'tcp://127.0.0.1:5678' # to allow incoming connections on all interfaces use 0.0.0.0 + #send_message : -# status: ['CRASHED', 'ABORTED', 'STOPPED', 'FINISHED'] # run status that triggers emails +# status: ['CRASHED', 'ABORTED', 'STOPPED', 'FINISHED'] # run status that triggers emails # subject_prefix: "pyBAR run report: " -# smtp_server: 'smtp.alert.com' # outgoing SMTP mail server -# user: 'my.email@alert.com' # usually from_addr -# password: 'my_secret_token' # the password -# from_addr: 'my.email@alert.com' # email address of the sender -# to_addrs: ["pohl@physik.uni-bonn.de", "janssen@physik.uni-bonn.de"] # list of email addresses that will be notified +# smtp_server: 'smtp.alert.com' # outgoing SMTP mail server +# user: 'my.email@alert.com' # usually from_addr +# password: 'my_secret_token' # the password +# from_addr: 'my.email@alert.com' # email address of the sender +# to_addrs: ["pohl@physik.uni-bonn.de", "janssen@physik.uni-bonn.de"] # list of email addresses that will be notified # *** run configuration *** -#run_conf: + +#run_conf : # comment : '' # reset_rx_on_error : False -# + # *** scan specific run configuration *** -#Fei4Tuning: + +#Fei4Tuning : # enable_shift_masks : ["Enable", "C_Low", "C_High"] # target_threshold : 30 # target threshold # target_charge : 280 # target charge # target_tot : 5 # target ToT # global_iterations : 4 # local_iterations : 3 -# -#AnalogScan: -# scan_parameters : '[("PlsrDAC", 280)]' + +#AnalogScan : +# scan_parameters : '[("PlsrDAC", 100)]' # enable_shift_masks : ["Enable", "C_Low", "C_High"] -# + #ThresholdScan: # scan_parameters : '[("PlsrDAC", [None, 100])]' # enable_shift_masks : ["Enable", "C_Low", "C_High"] -# -#ExtTriggerScan: + +#ExtTriggerScan : # trig_count : 0 # trigger_latency : 232 # trigger_delay : 8 @@ -55,8 +141,8 @@ module_id : module_test # module identifier / name, sub-folder with given name # max_triggers : 10000 # enable_tdc : False # reset_rx_on_error : False -# -#FEI4SelfTriggerScan: + +#Fei4SelfTriggerScan : # trig_count : 4 # trigger_latency : 239 # col_span : [1, 80] @@ -65,4 +151,3 @@ module_id : module_test # module identifier / name, sub-folder with given name # use_enable_mask_for_imon : True # no_data_timeout : 10 # scan_timeout : 60 -# diff --git a/pybar/daq/fei4_raw_data.py b/pybar/daq/fei4_raw_data.py index 8d6f728bf..85035e65d 100644 --- a/pybar/daq/fei4_raw_data.py +++ b/pybar/daq/fei4_raw_data.py @@ -5,6 +5,7 @@ from os import remove from docutils.transforms.misc import ClassAttribute +from docutils.transforms.misc import ClassAttribute import tables as tb import zmq @@ -45,7 +46,7 @@ def send_data(socket, data, scan_parameters={}, name='ReadoutData'): pass -def open_raw_data_file(filename, mode="w", title="", scan_parameters=None, context=None, socket_address=None): +def open_raw_data_file(filename, mode="w", title="", scan_parameters=None, socket_address=None): '''Mimics pytables.open_file() and stores the configuration and run configuration Returns: @@ -56,7 +57,7 @@ def open_raw_data_file(filename, mode="w", title="", scan_parameters=None, conte # do something here raw_data_file.append(self.readout.data, scan_parameters={scan_parameter:scan_parameter_value}) ''' - return RawDataFile(filename=filename, mode=mode, title=title, scan_parameters=scan_parameters, context=context, socket_address=socket_address) + return RawDataFile(filename=filename, mode=mode, title=title, scan_parameters=scan_parameters, socket_address=socket_address) class RawDataFile(object): @@ -66,7 +67,7 @@ class RawDataFile(object): '''Raw data file object. Saving data queue to HDF5 file. ''' - def __init__(self, filename, mode="w", title='', scan_parameters=None, context=None, socket_address=None): # mode="r+" to append data, raw_data_file_h5 must exist, "w" to overwrite raw_data_file_h5, "a" to append data, if raw_data_file_h5 does not exist it is created): + def __init__(self, filename, mode="w", title='', scan_parameters=None, socket_address=None): # mode="r+" to append data, raw_data_file_h5 must exist, "w" to overwrite raw_data_file_h5, "a" to append data, if raw_data_file_h5 does not exist it is created): self.lock = RLock() if os.path.splitext(filename)[1].strip().lower() != '.h5': self.base_filename = filename @@ -83,9 +84,8 @@ def __init__(self, filename, mode="w", title='', scan_parameters=None, context=N self.scan_param_table = None self.h5_file = None - if socket_address and not context: - logging.info('Creating ZMQ context') - context = zmq.Context() + if socket_address: + context = zmq.Context.instance() if socket_address and context: logging.info('Creating socket connection to server %s', socket_address) diff --git a/pybar/daq/fifo_readout.py b/pybar/daq/fifo_readout.py index 12accdd46..a2bf143fe 100644 --- a/pybar/daq/fifo_readout.py +++ b/pybar/daq/fifo_readout.py @@ -1,14 +1,16 @@ import logging from time import sleep, time -from threading import Thread, Event -from collections import deque +from itertools import izip +from threading import Thread, Event, Lock +from collections import deque, Iterable from Queue import Queue, Empty import sys import numpy as np +from basil.HL import sitcp_fifo from pybar.utils.utils import get_float_time -from pybar.daq.readout_utils import is_fe_word, is_data_record, is_data_header, logical_or, logical_and +from pybar.daq.readout_utils import is_fe_word, is_data_record, is_data_header, logical_or, logical_and, data_array_from_data_iterable, convert_data_iterable, convert_data_array data_iterable = ("data", "timestamp_start", "timestamp_stop", "error") @@ -37,156 +39,253 @@ class StopTimeout(Exception): class FifoReadout(object): def __init__(self, dut): self.dut = dut + self.is_running_lock = Lock() + self.data_words_per_second_lock = Lock() self.callback = None self.errback = None self.readout_thread = None self.worker_thread = None self.watchdog_thread = None + self.fifos = [] self.fill_buffer = False + self.filter_func = [None] + self.converter_func = [None] + self.fifo_select = [None] + self.enabled_fe_channels = None + self.enabled_m26_channels = None self.readout_interval = 0.05 - self._moving_average_time_period = 10.0 - self._data_deque = deque() - self._data_buffer = deque() - self._words_per_read = deque(maxlen=int(self._moving_average_time_period / self.readout_interval)) - self._result = Queue(maxsize=1) - self._calculate = Event() + self._moving_average_time_period = 10.0 # in seconds + self._n_empty_reads = 3 # number of empty reads before stopping FIFO readout + self._data_deque = None + self._data_buffer = None + self._words_per_read = [] self.stop_readout = Event() - self.force_stop = Event() + self.force_stop = None self.timestamp = None - self.update_timestamp() self._is_running = False - self.reset_rx() - self.reset_sram_fifo() @property def is_running(self): - return self._is_running - - @property - def is_alive(self): - if self.worker_thread: - return self.worker_thread.is_alive() - else: - False - - @property - def data(self): - if self.fill_buffer: - return self._data_buffer - else: - logging.warning('Data requested but software data buffer not active') + with self.is_running_lock: + return self._is_running def data_words_per_second(self): - if self._result.full(): - self._result.get() - self._calculate.set() - try: - result = self._result.get(timeout=2 * self.readout_interval) - except Empty: - self._calculate.clear() - return None - return result / float(self._moving_average_time_period) - - def start(self, callback=None, errback=None, reset_rx=False, reset_sram_fifo=False, clear_buffer=False, fill_buffer=False, no_data_timeout=None): - if self._is_running: - raise RuntimeError('Readout already running: use stop() before start()') - self._is_running = True - logging.info('Starting FIFO readout...') - self.callback = callback - self.errback = errback - self.fill_buffer = fill_buffer - if reset_rx: - self.reset_rx() - if reset_sram_fifo: - self.reset_sram_fifo() - else: - fifo_size = self.dut['SRAM']['FIFO_SIZE'] - data = self.read_data() - dh_dr_select = logical_and(is_fe_word, logical_or(is_data_record, is_data_header)) - if np.count_nonzero(dh_dr_select(data)) != 0: - logging.warning('SRAM FIFO containing events when starting FIFO readout: FIFO_SIZE = %i', fifo_size) - self._words_per_read.clear() - if clear_buffer: - self._data_deque.clear() - self._data_buffer.clear() - self.stop_readout.clear() - self.force_stop.clear() - if self.errback: - self.watchdog_thread = Thread(target=self.watchdog, name='WatchdogThread') - self.watchdog_thread.daemon = True - self.watchdog_thread.start() - if self.callback: - self.worker_thread = Thread(target=self.worker, name='WorkerThread') - self.worker_thread.daemon = True - self.worker_thread.start() - self.readout_thread = Thread(target=self.readout, name='ReadoutThread', kwargs={'no_data_timeout': no_data_timeout}) - self.readout_thread.daemon = True - self.readout_thread.start() + with self.data_words_per_second_lock: + result = [] + curr_time = get_float_time() + for words_per_read in self._words_per_read: + result.append(sum([item[0] for item in words_per_read if item[1] > (curr_time - self._moving_average_time_period)]) / float(self._moving_average_time_period)) + return result + + def start(self, fifos, callback=None, errback=None, reset_rx=False, reset_fifo=False, fill_buffer=False, no_data_timeout=None, filter_func=None, converter_func=None, fifo_select=None, enabled_fe_channels=None, enabled_m26_channels=None): + with self.is_running_lock: + if self._is_running: + raise RuntimeError('FIFO readout threads already started: use stop()') + self._is_running = True + + if isinstance(fifos, basestring): + fifos = [fifos] + if len(fifos) == 0: + raise ValueError('"fifos" parameter is empty.') + if len(set(fifos)) != len(fifos): + raise ValueError('The following strings are occurring multiple times in "fifos": %s' % set([fifo for fifo in fifos if fifos.count(fifo) > 1])) + if isinstance(fifo_select, Iterable) and set(fifo_select) - set(fifos): + raise ValueError("The following FIFOs have filters/converters set but are not read out: %s" % (set(fifo_select) - set(fifos))) + if isinstance(filter_func, Iterable) or isinstance(converter_func, Iterable) or (isinstance(fifo_select, Iterable) and not isinstance(fifo_select, basestring)): + if not isinstance(filter_func, Iterable): + raise ValueError('"filter_func" is not iterable.') + if not isinstance(converter_func, Iterable): + raise ValueError('"converter_func" is not iterable.') + if not isinstance(fifo_select, Iterable): + raise ValueError('"fifo_select" is not iterable.') + if len(filter_func) != len(converter_func): + raise ValueError('Length of "filter_func" and "converter_func" not equal.') + if len(filter_func) != len(fifo_select): + raise ValueError('Length of "filter_func" and "fifo_select" not equal.') + if len(converter_func) != len(fifo_select): + raise ValueError('Length of "converter_func" and "fifo_select" not equal.') + else: + if isinstance(fifo_select, basestring): + # convert to iterable + filter_func = [filter_func] + converter_func = [converter_func] + fifo_select = [fifo_select] + else: + # if fifo_select is None: + # adding filters and converters for each FIFO + filter_func = [filter_func] * len(fifos) + converter_func = [converter_func] * len(fifos) + fifo_select = fifos + if not (set(fifos) & set(fifo_select)) == set(fifo_select): + raise ValueError('"fifo_select" contains non-existing FIFOs: %s' % (set(fifo_select) & set(fifos))) + + if enabled_fe_channels is None: + self.enabled_fe_channels = [rx.name for rx in self.dut.get_modules('fei4_rx')] + else: + self.enabled_fe_channels = enabled_fe_channels + if enabled_m26_channels is None: + self.enabled_m26_channels = [rx.name for rx in self.dut.get_modules('m26_rx')] + else: + self.enabled_m26_channels = enabled_m26_channels + self.fifos = fifos + self.callback = callback + self.errback = errback + self.fill_buffer = fill_buffer + self.filter_func = filter_func + self.converter_func = converter_func + self.fifo_select = fifo_select + + self._fifo_data_deque = {fifo: deque() for fifo in self.fifos} + self._data_buffer = [deque() for _ in self.filter_func] + self.force_stop = {fifo: Event() for fifo in self.fifos} + self.timestamp = {fifo: None for fifo in self.fifos} + len_deque = int(self._moving_average_time_period / self.readout_interval) + curr_time = get_float_time() + self._words_per_read = [deque(iterable=[(0, curr_time, curr_time)] * len_deque, maxlen=len_deque) for _ in self.filter_func] + if reset_rx: + self.reset_rx(fe_channels=self.enabled_fe_channels, m26_channels=self.enabled_m26_channels) + for fifo in self.fifos: + if reset_fifo: + self.reset_fifo([fifo]) + self.update_timestamp(fifo) + fifo_size = self.get_fifo_size(fifo) + if fifo_size != 0: + logging.warning('%s contains data: FIFO_SIZE = %i', fifo, fifo_size) + self.stop_readout.clear() + for event in self.force_stop.values(): + event.clear() + logging.info('Starting FIFO readout...') + if self.errback: + self.watchdog_thread = Thread(target=self.watchdog, name='WatchdogThread') + self.watchdog_thread.daemon = True + self.watchdog_thread.start() + self.readout_threads = [] + self.worker_threads = [] + for fifo in self.fifos: + readout_thread = Thread(target=self.readout, name='%s ReadoutThread' % fifo, kwargs={'fifo': fifo, 'no_data_timeout': no_data_timeout}) + worker_thread = Thread(target=self.worker, name='%s WorkerThread' % fifo, kwargs={'fifo': fifo}) + readout_thread.daemon = True + worker_thread.daemon = True + self.readout_threads.append(readout_thread) + self.worker_threads.append(worker_thread) + for worker_thread in self.worker_threads: + worker_thread.start() + for readout_thread in self.readout_threads: + self.update_timestamp(fifo) + readout_thread.start() + # enabling RX channels + for fifo in self.fifos: + self.update_timestamp(fifo) + for fei4_rx_name in self.enabled_fe_channels: + self.dut[fei4_rx_name].ENABLE_RX = 1 + for m26_rx_name in self.enabled_m26_channels: + self.dut[m26_rx_name].EN = 1 def stop(self, timeout=10.0): - if not self._is_running: - raise RuntimeError('Readout not running: use start() before stop()') - self._is_running = False - self.stop_readout.set() - try: - self.readout_thread.join(timeout=timeout) - if self.readout_thread.is_alive(): - if timeout: - raise StopTimeout('FIFO stop timeout after %0.1f second(s)' % timeout) - else: - logging.warning('FIFO stop timeout') - except StopTimeout as e: - self.force_stop.set() + with self.is_running_lock: + if not self._is_running: + raise RuntimeError('FIFO readout threads not running: use start()') + self._is_running = False + # disabling Mimosa26 RX channels, the Mimosa26 RX is continuously providing data + # and therefore this has to be disabled before readout stop + for m26_rx_name in self.enabled_m26_channels: + self.dut[m26_rx_name].EN = 0 + self.stop_readout.set() + + def wait_for_thread_timeout(thread, fifo, timeout): + try: + thread.join(timeout=timeout) + if thread.is_alive(): + raise StopTimeout('Stopping %s readout thread timed out after %0.1fs' % (fifo, timeout)) + except StopTimeout, e: + self.force_stop[fifo].set() + if self.errback: + self.errback(sys.exc_info()) + else: + logging.error(e) + + join_threads = [] + for i, fifo in enumerate(self.fifos): + join_thread = Thread(target=wait_for_thread_timeout, kwargs={'thread': self.readout_threads[i], 'fifo': fifo, 'timeout': timeout}) + join_thread.daemon = True + join_thread.start() + join_threads.append(join_thread) + for join_thread in join_threads: + if join_thread.is_alive(): + join_thread.join() + for readout_thread in self.readout_threads: + if readout_thread.is_alive(): + readout_thread.join() + self.readout_threads = [] + for worker_thread in self.worker_threads: + worker_thread.join() + self.worker_threads = [] if self.errback: - self.errback(sys.exc_info()) - else: - logging.error(e) - if self.readout_thread.is_alive(): - self.readout_thread.join() - if self.errback: - self.watchdog_thread.join() - if self.callback: - self.worker_thread.join() - self.callback = None - self.errback = None - logging.info('Stopped FIFO readout') + self.watchdog_thread.join() + self.watchdog_thread = None + # disabling FEI4 RX channels + for fei4_rx_name in self.enabled_fe_channels: + self.dut[fei4_rx_name].ENABLE_RX = 0 + self.callback = None + self.errback = None + logging.info('Stopped FIFO readout') def print_readout_status(self): - logging.info('Data queue size: %d', len(self._data_deque)) - logging.info('SRAM FIFO size: %d', self.dut['SRAM']['FIFO_SIZE']) + self.print_fifo_status() + self.print_fei4_rx_status() + self.print_m26_rx_status() + + def print_fifo_status(self): + fifo_sizes = [self.get_fifo_size(fifo) for fifo in self.fifos] + fifo_queue_sizes = [len(self._fifo_data_deque[fifo]) for fifo in self.fifos] + max_len = [max(max(len(repr(fifo_sizes[i])), len(repr(fifo_queue_sizes[i]))), len(fifo)) for i, fifo in enumerate(self.fifos)] + logging.info('FIFO: %s', " | ".join([fifo.rjust(max_len[index]) for index, fifo in enumerate(self.fifos)])) + logging.info('FIFO size: %s', " | ".join([repr(count).rjust(max_len[index]) for index, count in enumerate(fifo_sizes)])) + logging.info('FIFO queue size: %s', " | ".join([repr(count).rjust(max_len[index]) for index, count in enumerate(fifo_queue_sizes)])) + + def print_fei4_rx_status(self): # FEI4 + enable_status = self.get_rx_enable_status() sync_status = self.get_rx_sync_status() discard_count = self.get_rx_fifo_discard_count() error_count = self.get_rx_8b10b_error_count() - if self.dut.get_modules('fei4_rx'): - logging.info('FEI4 Channel: %s', " | ".join([channel.name.rjust(3) for channel in self.dut.get_modules('fei4_rx')])) - logging.info('FEI4 RX sync: %s', " | ".join(["YES".rjust(3) if status is True else "NO".rjust(3) for status in sync_status])) - logging.info('FEI4 RX FIFO discard counter: %s', " | ".join([repr(count).rjust(3) for count in discard_count])) - logging.info('FEI4 RX FIFO 8b10b error counter: %s', " | ".join([repr(count).rjust(3) for count in error_count])) + fei4_rx_names = [rx.name for rx in self.dut.get_modules('fei4_rx')] + if fei4_rx_names: + logging.info('FEI4 RX channel: %s', " | ".join([name.rjust(3) for name in fei4_rx_names])) + logging.info('FEI4 RX enabled: %s', " | ".join(["YES".rjust(max(3, len(fei4_rx_names[index]))) if status is True else "NO".rjust(max(3, len(fei4_rx_names[index]))) for index, status in enumerate(enable_status)])) + logging.info('FEI4 RX sync: %s', " | ".join(["YES".rjust(max(3, len(fei4_rx_names[index]))) if status is True else "NO".rjust(max(3, len(fei4_rx_names[index]))) for index, status in enumerate(sync_status)])) + logging.info('FEI4 RX FIFO discard counter: %s', " | ".join([repr(count).rjust(max(3, len(fei4_rx_names[index]))) for index, count in enumerate(discard_count)])) + logging.info('FEI4 RX FIFO 8b10b error counter: %s', " | ".join([repr(count).rjust(max(3, len(fei4_rx_names[index]))) for index, count in enumerate(error_count)])) if not any(sync_status) or any(discard_count) or any(error_count): logging.warning('FEI4 RX errors detected') + + def print_m26_rx_status(self): # Mimosa26 + m26_enable_status = self.get_m26_rx_enable_status() m26_discard_count = self.get_m26_rx_fifo_discard_count() - if self.dut.get_modules('m26_rx'): - logging.info('M26 Channel: %s', " | ".join([channel.name.rjust(3) for channel in self.dut.get_modules('m26_rx')])) - logging.info('M26 RX FIFO discard counter: %s', " | ".join([repr(count).rjust(7) for count in m26_discard_count])) + m26_rx_names = [rx.name for rx in self.dut.get_modules('m26_rx')] + if m26_rx_names: + logging.info('Mimosa26 RX channel: %s', " | ".join([name.rjust(3) for name in m26_rx_names])) + logging.info('Mimosa26 RX enabled: %s', " | ".join(["YES".rjust(max(3, len(m26_rx_names[index]))) if status is True else "NO".rjust(max(3, len(m26_rx_names[index]))) for index, status in enumerate(m26_enable_status)])) + logging.info('Mimosa26 RX FIFO discard counter: %s', " | ".join([repr(count).rjust(max(3, len(m26_rx_names[index]))) for index, count in enumerate(m26_discard_count)])) if any(m26_discard_count): - logging.warning('M26 RX errors detected') + logging.warning('Mimosa26 RX errors detected') - def readout(self, no_data_timeout=None): - '''Readout thread continuously reading SRAM. + def readout(self, fifo, no_data_timeout=None): + '''Readout thread continuously reading FIFO. - Readout thread, which uses read_data() and appends data to self._data_deque (collection.deque). + Readout thread, which uses read_raw_data_from_fifo() and appends data to self._fifo_data_deque (collection.deque). ''' - logging.debug('Starting %s', self.readout_thread.name) + logging.info('Starting readout thread for %s', fifo) curr_time = get_float_time() time_wait = 0.0 - while not self.force_stop.wait(time_wait if time_wait >= 0.0 else 0.0): + empty_reads = 0 + while not self.force_stop[fifo].wait(time_wait if time_wait >= 0.0 else 0.0): try: time_read = time() if no_data_timeout and curr_time + no_data_timeout < get_float_time(): - raise NoDataTimeout('Received no data for %0.1f second(s)' % no_data_timeout) - data = self.read_data() + raise NoDataTimeout('Received no data for %0.1f second(s) from %s' % (no_data_timeout, fifo)) + raw_data = self.read_raw_data_from_fifo(fifo) except Exception: no_data_timeout = None # raise exception only once if self.errback: @@ -196,126 +295,181 @@ def readout(self, no_data_timeout=None): if self.stop_readout.is_set(): break else: - data_words = data.shape[0] - if data_words > 0: - last_time, curr_time = self.update_timestamp() + n_data_words = raw_data.shape[0] + if n_data_words > 0: + empty_reads = 0 + last_time, curr_time = self.update_timestamp(fifo) status = 0 - if self.callback: - self._data_deque.append((data, last_time, curr_time, status)) - if self.fill_buffer: - self._data_buffer.append((data, last_time, curr_time, status)) - self._words_per_read.append(data_words) + self._fifo_data_deque[fifo].append((raw_data, last_time, curr_time, status)) elif self.stop_readout.is_set(): - break - else: - self._words_per_read.append(0) + if empty_reads == self._n_empty_reads: + break + else: + empty_reads += 1 finally: + # ensure that the readout interval does not depend on the processing time of the data + # and stays more or less constant over time time_wait = self.readout_interval - (time() - time_read) - if self._calculate.is_set(): - self._calculate.clear() - self._result.put(sum(self._words_per_read)) - if self.callback: - self._data_deque.append(None) # last item, will stop worker - logging.debug('Stopped %s', self.readout_thread.name) - - def worker(self): + self._fifo_data_deque[fifo].append(None) # last item, None will stop worker + logging.info('Stopping readout thread for %s', fifo) + + def worker(self, fifo): '''Worker thread continuously calling callback function when data is available. ''' - logging.debug('Starting %s', self.worker_thread.name) + logging.info('Starting worker thread for %s', fifo) while True: try: - data = self._data_deque.popleft() + data_tuple = self._fifo_data_deque[fifo].popleft() except IndexError: - self.stop_readout.wait(self.readout_interval) # sleep a little bit, reducing CPU usage + self.stop_readout.wait(self.readout_interval / 2.0) # sleep a little bit, reducing CPU usage else: - if data is None: # if None then exit + if data_tuple is None: # if None then exit break else: - try: - self.callback(data) - except Exception: - self.errback(sys.exc_info()) - - logging.debug('Stopped %s', self.worker_thread.name) + converted_data_tuple_list = [] + for i, (filter_func, converter_func, fifo_select) in enumerate(izip(self.filter_func, self.converter_func, self.fifo_select)): + if fifo_select is None or fifo_select == fifo: + # filter and do the conversion + converted_data_tuple = convert_data_iterable((data_tuple,), filter_func=filter_func, converter_func=converter_func)[0] + n_data_words = converted_data_tuple[0].shape[0] + with self.data_words_per_second_lock: + self._words_per_read[i].append((n_data_words, converted_data_tuple[1], converted_data_tuple[2])) + converted_data_tuple_list.append(converted_data_tuple) + if self.fill_buffer: + self._data_buffer[i].append(converted_data_tuple) + else: + converted_data_tuple_list.append(None) + if self.callback: + try: + self.callback(converted_data_tuple_list) + except Exception: + self.errback(sys.exc_info()) + logging.info('Stopping worker thread for %s', fifo) def watchdog(self): logging.debug('Starting %s', self.watchdog_thread.name) while True: try: - if not any(self.get_rx_sync_status()): + if not all(self.get_rx_sync_status(channels=self.enabled_fe_channels)): raise RxSyncError('FEI4 RX sync error') - if any(self.get_rx_8b10b_error_count()): + if any(self.get_rx_8b10b_error_count(channels=self.enabled_fe_channels)): raise EightbTenbError('FEI4 RX 8b10b error(s) detected') - if any(self.get_rx_fifo_discard_count()): + if any(self.get_rx_fifo_discard_count(channels=self.enabled_fe_channels)): raise FifoError('FEI4 RX FIFO discard error(s) detected') - if any(self.get_m26_rx_fifo_discard_count()): + if any(self.get_m26_rx_fifo_discard_count(channels=self.enabled_m26_channels)): raise FifoError('M26 RX FIFO discard error(s) detected') except Exception: self.errback(sys.exc_info()) if self.stop_readout.wait(self.readout_interval * 10): break - logging.debug('Stopped %s', self.watchdog_thread.name) + logging.debug('Stopping %s', self.watchdog_thread.name) - def read_data(self): - '''Read SRAM and return data array - - Can be used without threading. + def get_data_from_buffer(self, filter_func=None, converter_func=None): + '''Reads local data buffer and returns data and meta data list. Returns ------- data : list - A list of SRAM data words. + List of data and meta data dicts. + ''' + if self._is_running: + raise RuntimeError('Readout thread running') + if not self.fill_buffer: + logging.warning('Data buffer is not activated') + return [convert_data_iterable(data_iterable, filter_func=filter_func, converter_func=converter_func) for data_iterable in self._data_buffer] + + def get_raw_data_from_buffer(self, filter_func=None, converter_func=None): + '''Reads local data buffer and returns raw data array. + + Returns + ------- + data : np.array + An array containing data words from the local data buffer. + ''' + if self._is_running: + raise RuntimeError('Readout thread running') + if not self.fill_buffer: + logging.warning('Data buffer is not activated') + return [convert_data_array(data_array_from_data_iterable(data_iterable), filter_func=filter_func, converter_func=converter_func) for data_iterable in self._data_buffer] + + def read_raw_data_from_fifo(self, fifo, filter_func=None, converter_func=None): + '''Reads FIFO data and returns raw data array. + + Returns + ------- + data : np.array + An array containing FIFO data words. ''' - return self.dut['SRAM'].get_data() + return convert_data_array(self.dut[fifo].get_data(), filter_func=filter_func, converter_func=converter_func) - def update_timestamp(self): + def update_timestamp(self, fifo): curr_time = get_float_time() - last_time = self.timestamp - self.timestamp = curr_time + last_time = self.timestamp[fifo] + if last_time is None: + last_time = curr_time + self.timestamp[fifo] = curr_time return last_time, curr_time - def read_status(self): - raise NotImplementedError() + def get_fifo_size(self, fifo): + return self.dut[fifo]['FIFO_SIZE'] - def reset_sram_fifo(self): - fifo_size = self.dut['SRAM']['FIFO_SIZE'] - logging.info('Resetting SRAM FIFO: size = %i', fifo_size) - self.update_timestamp() - self.dut['SRAM']['RESET'] - sleep(0.2) # sleep here for a while - fifo_size = self.dut['SRAM']['FIFO_SIZE'] - if fifo_size != 0: - logging.warning('SRAM FIFO not empty after reset: size = %i', fifo_size) - - def reset_rx(self, channels=None): + def reset_rx(self, fe_channels=None, m26_channels=None): logging.info('Resetting RX') + if fe_channels is None: + fe_channels = [rx.name for rx in self.dut.get_modules('fei4_rx')] + if m26_channels is None: + m26_channels = [rx.name for rx in self.dut.get_modules('m26_rx')] + for fei4_rx_name in fe_channels: + self.dut[fei4_rx_name].RESET + for m26_rx_name in m26_channels: + self.dut[m26_rx_name].RESET + + def reset_fifo(self, fifos): + if not isinstance(fifos, Iterable): + fifos = [fifos] + for fifo in fifos: + fifo_size = self.dut[fifo]['FIFO_SIZE'] + logging.info('Resetting %s: size = %i', fifo, fifo_size) + self.dut[fifo]['RESET'] + # sleep for a while, if it is a hardware FIFO + if not isinstance(self.dut[fifo], (sitcp_fifo.sitcp_fifo,)): + sleep(0.2) + fifo_size = self.dut[fifo]['FIFO_SIZE'] + if fifo_size != 0: + logging.warning('%s not empty after reset: size = %i', fifo, fifo_size) + + def get_rx_enable_status(self, channels=None): if channels: - filter(lambda channel: self.dut[channel].RX_RESET, channels) + return map(lambda channel: True if self.dut[channel].ENABLE_RX else False, channels) else: - filter(lambda channel: channel.RX_RESET, self.dut.get_modules('fei4_rx')) - sleep(0.1) # sleep here for a while + return map(lambda channel: True if channel.ENABLE_RX else False, self.dut.get_modules('fei4_rx')) def get_rx_sync_status(self, channels=None): - if channels: - return map(lambda channel: True if self.dut[channel].READY else False, channels) - else: + if channels is None: return map(lambda channel: True if channel.READY else False, self.dut.get_modules('fei4_rx')) + else: + return map(lambda channel: True if self.dut[channel].READY else False, channels) def get_rx_8b10b_error_count(self, channels=None): - if channels: - return map(lambda channel: self.dut[channel].DECODER_ERROR_COUNTER, channels) - else: + if channels is None: return map(lambda channel: channel.DECODER_ERROR_COUNTER, self.dut.get_modules('fei4_rx')) + else: + return map(lambda channel: self.dut[channel].DECODER_ERROR_COUNTER, channels) def get_rx_fifo_discard_count(self, channels=None): - if channels: + if channels is None: + return map(lambda channel: channel.LOST_DATA_COUNTER, self.dut.get_modules('fei4_rx')) + else: return map(lambda channel: self.dut[channel].LOST_DATA_COUNTER, channels) + + def get_m26_rx_enable_status(self, channels=None): + if channels is None: + return map(lambda channel: True if channel.EN else False, self.dut.get_modules('m26_rx')) else: - return map(lambda channel: channel.LOST_DATA_COUNTER, self.dut.get_modules('fei4_rx')) + return map(lambda channel: True if self.dut[channel].EN else False, channels) def get_m26_rx_fifo_discard_count(self, channels=None): - if channels: - return map(lambda channel: self.dut[channel].LOST_COUNT, channels) - else: + if channels is None: return map(lambda channel: channel.LOST_COUNT, self.dut.get_modules('m26_rx')) - \ No newline at end of file + else: + return map(lambda channel: self.dut[channel].LOST_COUNT, channels) diff --git a/pybar/daq/readout_utils.py b/pybar/daq/readout_utils.py index 78bb192f6..0dded0f34 100644 --- a/pybar/daq/readout_utils.py +++ b/pybar/daq/readout_utils.py @@ -11,46 +11,46 @@ class NameValue(tb.IsDescription): def save_configuration_dict(h5_file, configuation_name, configuration, **kwargs): - '''Stores any configuration dictionary to HDF5 file. - - Parameters - ---------- - h5_file : string, file - Filename of the HDF5 configuration file or file object. - configuation_name : str - Configuration name. Will be used for table name. - configuration : dict - Configuration dictionary. - ''' - def save_conf(): - try: - h5_file.remove_node(h5_file.root.configuration, name=configuation_name) - except tb.NodeError: - pass - try: - configuration_group = h5_file.create_group(h5_file.root, "configuration") - except tb.NodeError: - configuration_group = h5_file.root.configuration - - scan_param_table = h5_file.create_table(configuration_group, name=configuation_name, description=NameValue, title=configuation_name) - row_scan_param = scan_param_table.row - for key, value in dict.iteritems(configuration): - row_scan_param['name'] = key - row_scan_param['value'] = str(value) - row_scan_param.append() - scan_param_table.flush() - - if isinstance(h5_file, tb.file.File): + '''Stores any configuration dictionary to HDF5 file. + + Parameters + ---------- + h5_file : string, file + Filename of the HDF5 configuration file or file object. + configuation_name : str + Configuration name. Will be used for table name. + configuration : dict + Configuration dictionary. + ''' + def save_conf(): + try: + h5_file.remove_node(h5_file.root.configuration, name=configuation_name) + except tb.NodeError: + pass + try: + configuration_group = h5_file.create_group(h5_file.root, "configuration") + except tb.NodeError: + configuration_group = h5_file.root.configuration + + scan_param_table = h5_file.create_table(configuration_group, name=configuation_name, description=NameValue, title=configuation_name) + row_scan_param = scan_param_table.row + for key, value in dict.iteritems(configuration): + row_scan_param['name'] = key + row_scan_param['value'] = str(value) + row_scan_param.append() + scan_param_table.flush() + + if isinstance(h5_file, tb.file.File): + save_conf() + else: + if os.path.splitext(h5_file)[1].strip().lower() != ".h5": + h5_file = os.path.splitext(h5_file)[0] + ".h5" + with tb.open_file(h5_file, mode="a", title='', **kwargs) as h5_file: save_conf() - else: - if os.path.splitext(h5_file)[1].strip().lower() != ".h5": - h5_file = os.path.splitext(h5_file)[0] + ".h5" - with tb.open_file(h5_file, mode="a", title='', **kwargs) as h5_file: - save_conf() def convert_data_array(array, filter_func=None, converter_func=None): # TODO: add copy parameter, otherwise in-place - '''Filter and convert raw data numpy array (numpy.ndarray) + '''Filter and convert raw data numpy array (numpy.ndarray). Parameters ---------- @@ -123,45 +123,73 @@ def data_array_from_data_iterable(data_iterable): def is_tdc_from_channel(channel=4): # function factory + '''Selecting TDC data from given channel. + + Parameters + ---------- + channel : int + Channel number (4 is default channel on Single Chip Card). + + Returns + ------- + Function. + + Usage: + 1 Selecting TDC data from channel 4 (combine with is_tdc_word): + filter_tdc_data_from_channel_4 = logical_and(is_tdc_word, is_tdc_from_channel(4)) + tdc_data_from_channel_4 = data_array[filter_tdc_data_from_channel_4(data_array)] + ''' if channel >= 1 and channel < 8: def f(value): - return np.equal(np.right_shift(np.bitwise_and(value, 0xF0000000), 28), channel) + return np.equal(np.right_shift(np.bitwise_and(value, 0x70000000), 28), channel) f.__name__ = "is_tdc_from_channel_" + str(channel) # or use inspect module: inspect.stack()[0][3] return f else: raise ValueError('Invalid channel number') +def convert_tdc_to_channel(channel): + ''' Converts TDC words at a given channel to common TDC header (0x4). + ''' + def f(value): + filter_func = logical_and(is_tdc_word, is_tdc_from_channel(channel)) + select = filter_func(value) + value[select] = np.bitwise_and(value[select], 0x0FFFFFFF) + value[select] = np.bitwise_or(value[select], 0x40000000) + f.__name__ = "convert_tdc_to_channel_" + str(channel) + return value + return f + + def is_data_from_channel(channel=4): # function factory - '''Select data from channel + '''Selecting FE data from given channel. - Parameters: + Parameters + ---------- channel : int - Channel number (4 is default channel on Single Chip Card) + Channel number (4 is default channel on Single Chip Card). - Returns: - Function + Returns + ------- + Function. Usage: - # 1 - is_data_from_channel_4 = is_data_from_channel(4) - data_from_channel_4 = data_array[is_data_from_channel_4(data_array)] - # 2 - filter_func = logical_and(is_data_record, is_data_from_channel(3)) - data_record_from_channel_3 = data_array[filter_func(data_array)] - # 3 - is_raw_data_from_channel_3 = is_data_from_channel(3)(raw_data) - - Similar to: - f_ch3 = functoools.partial(is_data_from_channel, channel=3) + 1 Selecting FE data from channel 4 (combine with is_fe_word): + filter_fe_data_from_channel_4 = logical_and(is_fe_word, is_data_from_channel(4)) + fe_data_from_channel_4 = data_array[filter_fe_data_from_channel_4(data_array)] + 2 Sleceting data from channel 4: + filter_data_from_channel_4 = is_data_from_channel(4) + data_from_channel_4 = data_array[filter_data_from_channel_4(fe_data_array)] + 3 Sleceting data from channel 4: + data_from_channel_4 = is_data_from_channel(4)(fe_raw_data) + + Other usage: + f_ch4 = functoools.partial(is_data_from_channel, channel=4) l_ch4 = lambda x: is_data_from_channel(x, channel=4) - - Note: - Trigger data not included ''' if channel >= 0 and channel < 16: def f(value): - return np.equal(np.right_shift(np.bitwise_and(value, 0xFF000000), 24), channel) + return np.equal(np.right_shift(np.bitwise_and(value, 0x0F000000), 24), channel) f.__name__ = "is_data_from_channel_" + str(channel) # or use inspect module: inspect.stack()[0][3] return f else: @@ -178,10 +206,9 @@ def logical_and(f1, f2): # function factory Returns ------- - Function + Function. - Examples - -------- + Usage: filter_func=logical_and(is_data_record, is_data_from_channel(4)) # new filter function filter_func(array) # array that has Data Records from channel 4 ''' @@ -201,7 +228,7 @@ def logical_or(f1, f2): # function factory Returns ------- - Function + Function. ''' def f(value): return np.logical_or(f1(value), f2(value)) @@ -219,7 +246,7 @@ def logical_not(f): # function factory Returns ------- - Function + Function. ''' def f(value): return np.logical_not(f(value)) @@ -237,7 +264,7 @@ def logical_xor(f1, f2): # function factory Returns ------- - Function + Function. ''' def f(value): return np.logical_xor(f1(value), f2(value)) @@ -245,12 +272,20 @@ def f(value): return f +def true(value): + return np.True_ + + +def false(value): + return np.False_ + + def is_trigger_word(value): return np.equal(np.bitwise_and(value, 0x80000000), 0x80000000) def is_tdc_word(value): - return np.equal(np.bitwise_and(value, 0xC0000000), 0x40000000) + return np.logical_and(np.equal(np.bitwise_and(value, 0x80000000), 0), np.greater(np.bitwise_and(value, 0x70000000), 0)) def is_fe_word(value): @@ -278,25 +313,25 @@ def is_data_record(value): def get_address_record_address(value): - '''Returns the address in the address record + '''Returns the address in the address record. ''' return np.bitwise_and(value, 0x0000EFFF) def get_address_record_type(value): - '''Returns the type in the address record + '''Returns the type in the address record. ''' return np.right_shift(np.bitwise_and(value, 0x00008000), 14) def get_value_record(value): - '''Returns the value in the value record + '''Returns the value in the value record. ''' return np.bitwise_and(value, 0x0000FFFF) def get_col_row_tot_array_from_data_record_array(array): # TODO: max ToT - '''Convert raw data array to column, row, and ToT array + '''Convert raw data array to column, row, and ToT array. Parameters ---------- @@ -309,23 +344,17 @@ def get_col_row_tot_array_from_data_record_array(array): # TODO: max ToT ''' def get_col_row_tot_1_array_from_data_record_array(value): return np.right_shift(np.bitwise_and(value, 0x00FE0000), 17), np.right_shift(np.bitwise_and(value, 0x0001FF00), 8), np.right_shift(np.bitwise_and(value, 0x000000F0), 4) -# return (value & 0xFE0000)>>17, (value & 0x1FF00)>>8, (value & 0x0000F0)>>4 # numpy.vectorize() def get_col_row_tot_2_array_from_data_record_array(value): return np.right_shift(np.bitwise_and(value, 0x00FE0000), 17), np.add(np.right_shift(np.bitwise_and(value, 0x0001FF00), 8), 1), np.bitwise_and(value, 0x0000000F) -# return (value & 0xFE0000)>>17, ((value & 0x1FF00)>>8)+1, (value & 0x0000F) # numpy.vectorize() col_row_tot_1_array = np.column_stack(get_col_row_tot_1_array_from_data_record_array(array)) col_row_tot_2_array = np.column_stack(get_col_row_tot_2_array_from_data_record_array(array)) -# print col_row_tot_1_array, col_row_tot_1_array.shape, col_row_tot_1_array.dtype -# print col_row_tot_2_array, col_row_tot_2_array.shape, col_row_tot_2_array.dtype # interweave array here col_row_tot_array = np.vstack((col_row_tot_1_array.T, col_row_tot_2_array.T)).reshape((3, -1), order='F').T # http://stackoverflow.com/questions/5347065/interweaving-two-numpy-arrays -# print col_row_tot_array, col_row_tot_array.shape, col_row_tot_array.dtype # remove ToT > 14 (late hit, no hit) from array, remove row > 336 in case we saw hit in row 336 (no double hit possible) try: col_row_tot_array_filtered = col_row_tot_array[col_row_tot_array[:, 2] < 14] # [np.logical_and(col_row_tot_array[:,2]<14, col_row_tot_array[:,1]<=336)] -# print col_row_tot_array_filtered, col_row_tot_array_filtered.shape, col_row_tot_array_filtered.dtype except IndexError: # logging.warning('Array is empty') return np.array([], dtype=np.dtype('>u4')), np.array([], dtype=np.dtype('>u4')), np.array([], dtype=np.dtype('>u4')) @@ -389,12 +418,12 @@ def build_events_from_raw_data(array): def interpret_pixel_data(data, dc, pixel_array, invert=True): '''Takes the pixel raw data and interprets them. This includes consistency checks and pixel/data matching. - The data has to come from one double column only but can have more than one pixel bit (e.g. TDAC = 5 bit) + The data has to come from one double column only but can have more than one pixel bit (e.g. TDAC = 5 bit). Parameters ---------- data : numpy.ndarray - The raw data words + The raw data words. dc : int The double column where the data is from. pixel_array : numpy.ma.ndarray @@ -417,7 +446,10 @@ def interpret_pixel_data(data, dc, pixel_array, invert=True): value_split = np.array_split(value, np.where(np.diff(address.astype(np.int32)) < 0)[0] + 1) if len(address_split) > 5: - raise NotImplementedError('Only the data from one double column can be interpreted at once!') + pixel_array.mask[dc * 2, :] = True + pixel_array.mask[dc * 2 + 1, :] = True + logging.warning('Invalid pixel data for DC %d', dc) + return mask = np.empty_like(pixel_array.data) # BUG in numpy: pixel_array is de-masked if not .data is used mask[:] = len(address_split) @@ -425,12 +457,12 @@ def interpret_pixel_data(data, dc, pixel_array, invert=True): for bit, (bit_address, bit_value) in enumerate(zip(address_split, value_split)): # loop over all bits of the pixel data # error output, pixel data is often corrupt for FE-I4A if len(bit_address) == 0: - logging.warning('No pixel data') + logging.warning('No pixel data for DC %d', dc) continue if len(bit_address) != 42: - logging.warning('Some pixel data missing') + logging.warning('Some pixel data missing for DC %d', dc) if (np.any(bit_address > 672)): - RuntimeError('Pixel data corrupt') + RuntimeError('Pixel data corrupt for DC %d', dc) # set pixel that occurred in the data stream pixel = [] for i in bit_address: diff --git a/pybar/dut_configuration_lx9.yaml b/pybar/dut_configuration_lx9.yaml index f51e7125e..8c9a79a15 100644 --- a/pybar/dut_configuration_lx9.yaml +++ b/pybar/dut_configuration_lx9.yaml @@ -6,9 +6,9 @@ ETH: tcp_connection : True # FE-I4 command ouput -CMD: +CMD_CH0: OUTPUT_MODE : 0 # Selecting command output mode: positive edge (0), negative edge (1), Manchester Code according to IEEE 802.3 (2), Manchester Code according to G.E. Thomas (3) # FE-I4 data receiver -CH0: +DATA_CH0: INVERT_RX : 0 diff --git a/pybar/dut_configuration_mio.yaml b/pybar/dut_configuration_mio.yaml index dbeda8d07..0737c8d64 100644 --- a/pybar/dut_configuration_mio.yaml +++ b/pybar/dut_configuration_mio.yaml @@ -8,7 +8,7 @@ ADAPTER_CARD: no_calibration : False # Trigger -TLU: +TRIGGER_CH1_TO_CH4: TRIGGER_MODE : 0 # Selecting trigger mode: Use trigger inputs/trigger select (0), TLU no handshake (1), TLU simple handshake (2), TLU data handshake (3) TRIGGER_SELECT : 0 # Selecting trigger input: RX2 (TDC loop-through) (8), RX1 (4), RX0 (2), MonHit/HitOR from Adapter Card (1), disabled (0) TRIGGER_INVERT : 0 # Inverting trigger input: RX2 (TDC loop-through) (8), RX1 (4), RX0 (2), MonHit/HitOR from Adapter Card (1), disabled (0) @@ -19,7 +19,7 @@ TLU: DATA_FORMAT : 0 # trigger number according to TRIGGER_MODE (0), time stamp only (1), combined, 15bit time stamp + 16bit trigger number (2) # TDC for high precision charge measurements -TDC: +TDC_RX2: EN_WRITE_TIMESTAMP : 0 # Writing trigger timestamp EN_TRIGGER_DIST : 0 # Measuring trigger to TDC delay with 640MHz clock EN_NO_WRITE_TRIG_ERR : 0 # Writing TDC word only if valid trigger occurred @@ -27,18 +27,18 @@ TDC: EN_INVERT_TRIGGER : 0 # Inverting trigger input # FE-I4 command output -CMD: +CMD_CH1_TO_CH4: OUTPUT_MODE : 0 # Selecting command output mode: positive edge (0), negative edge (1), Manchester Code according to IEEE 802.3 (2), Manchester Code according to G.E. Thomas (3) # FE-I4 data receiver -CH4: +DATA_CH4: INVERT_RX : 0 # Inverting data input: disabled (0), enabled (e.g. for DBM modules) (1) -CH3: +DATA_CH3: INVERT_RX : 0 -CH2: +DATA_CH2: INVERT_RX : 0 -CH1: +DATA_CH1: INVERT_RX : 0 diff --git a/pybar/dut_configuration_mio_gpac.yaml b/pybar/dut_configuration_mio_gpac.yaml index b69c48144..58b24ff25 100644 --- a/pybar/dut_configuration_mio_gpac.yaml +++ b/pybar/dut_configuration_mio_gpac.yaml @@ -5,7 +5,7 @@ USB: avoid_download : True # Avoiding download of FPGA firmware if already initialized # Trigger -TLU: +TRIGGER_FEI4: TRIGGER_MODE : 0 # Selecting trigger mode: Use trigger inputs/trigger select (0), TLU no handshake (1), TLU simple handshake (2), TLU data handshake (3) TRIGGER_SELECT : 0 # Selecting trigger input: CCPD Monitor from GPAC (8), RX2 (TDC loop-through) (4), RX0 (2), MonHit/HitOR from GPAC (1), disabled (0) TRIGGER_INVERT : 0 # Inverting trigger input: CCPD Monitor from GPAC (8), RX2 (TDC loop-through) (4), RX0 (2), MonHit/HitOR from GPAC (1), disabled (0) @@ -16,7 +16,7 @@ TLU: DATA_FORMAT : 0 # trigger number according to TRIGGER_MODE (0), time stamp only (1), combined, 15bit time stamp + 16bit trigger number (2) # TDC for high precision charge measurements -TDC: +TDC_RX2: EN_WRITE_TIMESTAMP : 0 # Writing trigger timestamp EN_TRIGGER_DIST : 0 # Measuring trigger to TDC delay with 640MHz clock EN_NO_WRITE_TRIG_ERR : 0 # Writing TDC word only if valid trigger occurred @@ -24,5 +24,5 @@ TDC: EN_INVERT_TRIGGER : 0 # Inverting trigger input # FE-I4 command output -CMD: +CMD_FEI4: OUTPUT_MODE : 0 # Selecting command output mode: positive edge (0), negative edge (1), Manchester Code according to IEEE 802.3 (2), Manchester Code according to G.E. Thomas (3) diff --git a/pybar/dut_configuration_mmc3_16chip_multi_tx_eth.yaml b/pybar/dut_configuration_mmc3_16chip_multi_tx_eth.yaml new file mode 100644 index 000000000..fbcd436b5 --- /dev/null +++ b/pybar/dut_configuration_mmc3_16chip_multi_tx_eth.yaml @@ -0,0 +1,171 @@ +# MMC3 board with max. 8 FEI4s with multiple TX +ETH: + ip : "192.168.10.16" + udp_port : 4660 + tcp_port : 24 + tcp_connection : True + +# Trigger +TRIGGER_CH0: + TRIGGER_MODE : 0 # Selecting trigger mode: Use trigger inputs/trigger select (0), TLU no handshake (1), TLU simple handshake (2), TLU data handshake (3) + TRIGGER_SELECT : 2 # Selecting trigger input: MonHit/HitOR from module 0/1/2/3/4/5/6/7 (2/4/8/16/32/64/128/256), LEMO RX0 (1), disabled (0) + TRIGGER_INVERT : 0 # Inverting trigger input: MonHit/HitOR from module 0/1/2/3/4/5/6/7 (2/4/8/16/32/64/128/256), LEMO RX0 (1), disabled (0) + TRIGGER_VETO_SELECT : 1 # Selecting trigger veto: RX FIFO 0/1/2/3/4/4/6/7 full (2/4/8/16/32/64/128/256), FIFO full (1), disabled (0) + TRIGGER_HANDSHAKE_ACCEPT_WAIT_CYCLES : 3 # Increasing minimum trigger length in TLU data handshale mode (preventing certain TLU flaws) + TRIGGER_DATA_DELAY : 0 # TLU data handshake data delay depends on the cable length and should be adjusted with a delay scan (run scan/tune_tlu.py) + TRIGGER_THRESHOLD : 0 # Standard trigger minimum length in clock cycles of the trigger/TLU FSM + DATA_FORMAT : 0 # 31bit trigger number according to TRIGGER_MODE (0), 31bit time stamp (1), 15bit time stamp + 16bit trigger number (2) + +TRIGGER_CH1: + TRIGGER_MODE : 0 # Selecting trigger mode: Use trigger inputs/trigger select (0), TLU no handshake (1), TLU simple handshake (2), TLU data handshake (3) + TRIGGER_SELECT : 4 # Selecting trigger input: MonHit/HitOR from module 0/1/2/3/4/5/6/7 (2/4/8/16/32/64/128/256), LEMO RX0 (1), disabled (0) + TRIGGER_INVERT : 0 # Inverting trigger input: MonHit/HitOR from module 0/1/2/3/4/5/6/7 (2/4/8/16/32/64/128/256), LEMO RX0 (1), disabled (0) + TRIGGER_VETO_SELECT : 1 # Selecting trigger veto: RX FIFO 0/1/2/3/4/4/6/7 full (2/4/8/16/32/64/128/256), FIFO full (1), disabled (0) + TRIGGER_HANDSHAKE_ACCEPT_WAIT_CYCLES : 3 # Increasing minimum trigger length in TLU data handshale mode (preventing certain TLU flaws) + TRIGGER_DATA_DELAY : 0 # TLU data handshake data delay depends on the cable length and should be adjusted with a delay scan (run scan/tune_tlu.py) + TRIGGER_THRESHOLD : 0 # Standard trigger minimum length in clock cycles of the trigger/TLU FSM + DATA_FORMAT : 0 # 31bit trigger number according to TRIGGER_MODE (0), 31bit time stamp (1), 15bit time stamp + 16bit trigger number (2) + +TRIGGER_CH2: + TRIGGER_MODE : 0 # Selecting trigger mode: Use trigger inputs/trigger select (0), TLU no handshake (1), TLU simple handshake (2), TLU data handshake (3) + TRIGGER_SELECT : 8 # Selecting trigger input: MonHit/HitOR from module 0/1/2/3/4/5/6/7 (2/4/8/16/32/64/128/256), LEMO RX0 (1), disabled (0) + TRIGGER_INVERT : 0 # Inverting trigger input: MonHit/HitOR from module 0/1/2/3/4/5/6/7 (2/4/8/16/32/64/128/256), LEMO RX0 (1), disabled (0) + TRIGGER_VETO_SELECT : 1 # Selecting trigger veto: RX FIFO 0/1/2/3/4/4/6/7 full (2/4/8/16/32/64/128/256), FIFO full (1), disabled (0) + TRIGGER_HANDSHAKE_ACCEPT_WAIT_CYCLES : 3 # Increasing minimum trigger length in TLU data handshale mode (preventing certain TLU flaws) + TRIGGER_DATA_DELAY : 0 # TLU data handshake data delay depends on the cable length and should be adjusted with a delay scan (run scan/tune_tlu.py) + TRIGGER_THRESHOLD : 0 # Standard trigger minimum length in clock cycles of the trigger/TLU FSM + DATA_FORMAT : 0 # 31bit trigger number according to TRIGGER_MODE (0), 31bit time stamp (1), 15bit time stamp + 16bit trigger number (2) + +TRIGGER_CH3: + TRIGGER_MODE : 0 # Selecting trigger mode: Use trigger inputs/trigger select (0), TLU no handshake (1), TLU simple handshake (2), TLU data handshake (3) + TRIGGER_SELECT : 16 # Selecting trigger input: MonHit/HitOR from module 0/1/2/3/4/5/6/7 (2/4/8/16/32/64/128/256), LEMO RX0 (1), disabled (0) + TRIGGER_INVERT : 0 # Inverting trigger input: MonHit/HitOR from module 0/1/2/3/4/5/6/7 (2/4/8/16/32/64/128/256), LEMO RX0 (1), disabled (0) + TRIGGER_VETO_SELECT : 1 # Selecting trigger veto: RX FIFO 0/1/2/3/4/4/6/7 full (2/4/8/16/32/64/128/256), FIFO full (1), disabled (0) + TRIGGER_HANDSHAKE_ACCEPT_WAIT_CYCLES : 3 # Increasing minimum trigger length in TLU data handshale mode (preventing certain TLU flaws) + TRIGGER_DATA_DELAY : 0 # TLU data handshake data delay depends on the cable length and should be adjusted with a delay scan (run scan/tune_tlu.py) + TRIGGER_THRESHOLD : 0 # Standard trigger minimum length in clock cycles of the trigger/TLU FSM + DATA_FORMAT : 0 # 31bit trigger number according to TRIGGER_MODE (0), 31bit time stamp (1), 15bit time stamp + 16bit trigger number (2) + +TRIGGER_CH4: + TRIGGER_MODE : 0 # Selecting trigger mode: Use trigger inputs/trigger select (0), TLU no handshake (1), TLU simple handshake (2), TLU data handshake (3) + TRIGGER_SELECT : 32 # Selecting trigger input: MonHit/HitOR from module 0/1/2/3/4/5/6/7 (2/4/8/16/32/64/128/256), LEMO RX0 (1), disabled (0) + TRIGGER_INVERT : 0 # Inverting trigger input: MonHit/HitOR from module 0/1/2/3/4/5/6/7 (2/4/8/16/32/64/128/256), LEMO RX0 (1), disabled (0) + TRIGGER_VETO_SELECT : 1 # Selecting trigger veto: RX FIFO 0/1/2/3/4/4/6/7 full (2/4/8/16/32/64/128/256), FIFO full (1), disabled (0) + TRIGGER_HANDSHAKE_ACCEPT_WAIT_CYCLES : 3 # Increasing minimum trigger length in TLU data handshale mode (preventing certain TLU flaws) + TRIGGER_DATA_DELAY : 0 # TLU data handshake data delay depends on the cable length and should be adjusted with a delay scan (run scan/tune_tlu.py) + TRIGGER_THRESHOLD : 0 # Standard trigger minimum length in clock cycles of the trigger/TLU FSM + DATA_FORMAT : 0 # 31bit trigger number according to TRIGGER_MODE (0), 31bit time stamp (1), 15bit time stamp + 16bit trigger number (2) + +TRIGGER_CH5: + TRIGGER_MODE : 0 # Selecting trigger mode: Use trigger inputs/trigger select (0), TLU no handshake (1), TLU simple handshake (2), TLU data handshake (3) + TRIGGER_SELECT : 64 # Selecting trigger input: MonHit/HitOR from module 0/1/2/3/4/5/6/7 (2/4/8/16/32/64/128/256), LEMO RX0 (1), disabled (0) + TRIGGER_INVERT : 0 # Inverting trigger input: MonHit/HitOR from module 0/1/2/3/4/5/6/7 (2/4/8/16/32/64/128/256), LEMO RX0 (1), disabled (0) + TRIGGER_VETO_SELECT : 1 # Selecting trigger veto: RX FIFO 0/1/2/3/4/4/6/7 full (2/4/8/16/32/64/128/256/256), FIFO full (1), disabled (0) + TRIGGER_HANDSHAKE_ACCEPT_WAIT_CYCLES : 3 # Increasing minimum trigger length in TLU data handshale mode (preventing certain TLU flaws) + TRIGGER_DATA_DELAY : 0 # TLU data handshake data delay depends on the cable length and should be adjusted with a delay scan (run scan/tune_tlu.py) + TRIGGER_THRESHOLD : 0 # Standard trigger minimum length in clock cycles of the trigger/TLU FSM + DATA_FORMAT : 0 # 31bit trigger number according to TRIGGER_MODE (0), 31bit time stamp (1), 15bit time stamp + 16bit trigger number (2) + +TRIGGER_CH6: + TRIGGER_MODE : 0 # Selecting trigger mode: Use trigger inputs/trigger select (0), TLU no handshake (1), TLU simple handshake (2), TLU data handshake (3) + TRIGGER_SELECT : 128 # Selecting trigger input: MonHit/HitOR from module 0/1/2/3/4/5/6/7 (2/4/8/16/32/64/128/256), LEMO RX0 (1), disabled (0) + TRIGGER_INVERT : 0 # Inverting trigger input: MonHit/HitOR from module 0/1/2/3/4/5/6/7 (2/4/8/16/32/64/128/256), LEMO RX0 (1), disabled (0) + TRIGGER_VETO_SELECT : 1 # Selecting trigger veto: RX FIFO 0/1/2/3/4/4/6/7 full (2/4/8/16/32/64/128/256), FIFO full (1), disabled (0) + TRIGGER_HANDSHAKE_ACCEPT_WAIT_CYCLES : 3 # Increasing minimum trigger length in TLU data handshale mode (preventing certain TLU flaws) + TRIGGER_DATA_DELAY : 0 # TLU data handshake data delay depends on the cable length and should be adjusted with a delay scan (run scan/tune_tlu.py) + TRIGGER_THRESHOLD : 0 # Standard trigger minimum length in clock cycles of the trigger/TLU FSM + DATA_FORMAT : 0 # 31bit trigger number according to TRIGGER_MODE (0), 31bit time stamp (1), 15bit time stamp + 16bit trigger number (2) + +TRIGGER_CH7: + TRIGGER_MODE : 0 # Selecting trigger mode: Use trigger inputs/trigger select (0), TLU no handshake (1), TLU simple handshake (2), TLU data handshake (3) + TRIGGER_SELECT : 256 # Selecting trigger input: MonHit/HitOR from module 0/1/2/3/4/5/6/7 (2/4/8/16/32/64/128/256), LEMO RX0 (1), disabled (0) + TRIGGER_INVERT : 0 # Inverting trigger input: MonHit/HitOR from module 0/1/2/3/4/5/6/7 (2/4/8/16/32/64/128/256), LEMO RX0 (1), disabled (0) + TRIGGER_VETO_SELECT : 1 # Selecting trigger veto: RX FIFO 0/1/2/3/4/4/6/7 full (2/4/8/16/32/64/128/256), FIFO full (1), disabled (0) + TRIGGER_HANDSHAKE_ACCEPT_WAIT_CYCLES : 3 # Increasing minimum trigger length in TLU data handshale mode (preventing certain TLU flaws) + TRIGGER_DATA_DELAY : 0 # TLU data handshake data delay depends on the cable length and should be adjusted with a delay scan (run scan/tune_tlu.py) + TRIGGER_THRESHOLD : 0 # Standard trigger minimum length in clock cycles of the trigger/TLU FSM + DATA_FORMAT : 0 # 31bit trigger number according to TRIGGER_MODE (0), 31bit time stamp (1), 15bit time stamp + 16bit trigger number (2) + +# TDC for high precision charge measurements +TDC_CH0: + EN_WRITE_TIMESTAMP : 1 # Writing trigger timestamp + EN_TRIGGER_DIST : 0 # Measuring trigger to TDC delay with 640MHz clock + EN_NO_WRITE_TRIG_ERR : 0 # Writing TDC word only if valid trigger occurred + EN_INVERT_TDC : 0 # Inverting TDC input + EN_INVERT_TRIGGER : 0 # Inverting trigger input + + + +# FE-I4 command output +CMD_CH0: + OUTPUT_MODE : 3 # Selecting command output mode: positive edge (0), negative edge (1), Manchester Code according to IEEE 802.3 (2), Manchester Code according to G.E. Thomas (3) + +CMD_CH1: + OUTPUT_MODE : 3 # Selecting command output mode: positive edge (0), negative edge (1), Manchester Code according to IEEE 802.3 (2), Manchester Code according to G.E. Thomas (3) + +CMD_CH2: + OUTPUT_MODE : 3 # Selecting command output mode: positive edge (0), negative edge (1), Manchester Code according to IEEE 802.3 (2), Manchester Code according to G.E. Thomas (3) + +CMD_CH3: + OUTPUT_MODE : 3 # Selecting command output mode: positive edge (0), negative edge (1), Manchester Code according to IEEE 802.3 (2), Manchester Code according to G.E. Thomas (3) + +CMD_CH4: + OUTPUT_MODE : 3 # Selecting command output mode: positive edge (0), negative edge (1), Manchester Code according to IEEE 802.3 (2), Manchester Code according to G.E. Thomas (3) + +CMD_CH5: + OUTPUT_MODE : 3 # Selecting command output mode: positive edge (0), negative edge (1), Manchester Code according to IEEE 802.3 (2), Manchester Code according to G.E. Thomas (3) + +CMD_CH6: + OUTPUT_MODE : 3 # Selecting command output mode: positive edge (0), negative edge (1), Manchester Code according to IEEE 802.3 (2), Manchester Code according to G.E. Thomas (3) + +CMD_CH7: + OUTPUT_MODE : 3 # Selecting command output mode: positive edge (0), negative edge (1), Manchester Code according to IEEE 802.3 (2), Manchester Code according to G.E. Thomas (3) + +# FE-I4 data receivers +DATA_CH0: + INVERT_RX : 0 # Inverting data input: disabled (0), enabled (e.g. for DBM modules) (1) + +DATA_CH1: + INVERT_RX : 0 # Inverting data input: disabled (0), enabled (e.g. for DBM modules) (1) + +DATA_CH2: + INVERT_RX : 0 # Inverting data input: disabled (0), enabled (e.g. for DBM modules) (1) + +DATA_CH3: + INVERT_RX : 0 # Inverting data input: disabled (0), enabled (e.g. for DBM modules) (1) + +DATA_CH4: + INVERT_RX : 0 # Inverting data input: disabled (0), enabled (e.g. for DBM modules) (1) + +DATA_CH5: + INVERT_RX : 0 # Inverting data input: disabled (0), enabled (e.g. for DBM modules) (1) + +DATA_CH6: + INVERT_RX : 0 # Inverting data input: disabled (0), enabled (e.g. for DBM modules) (1) + +DATA_CH7: + INVERT_RX : 0 # Inverting data input: disabled (0), enabled (e.g. for DBM modules) (1) + +DATA_CH8: + INVERT_RX : 0 # Inverting data input: disabled (0), enabled (e.g. for DBM modules) (1) + +DATA_CH9: + INVERT_RX : 0 # Inverting data input: disabled (0), enabled (e.g. for DBM modules) (1) + +DATA_CH10: + INVERT_RX : 0 # Inverting data input: disabled (0), enabled (e.g. for DBM modules) (1) + +DATA_CH11: + INVERT_RX : 0 # Inverting data input: disabled (0), enabled (e.g. for DBM modules) (1) + +DATA_CH12: + INVERT_RX : 0 # Inverting data input: disabled (0), enabled (e.g. for DBM modules) (1) + +DATA_CH13: + INVERT_RX : 0 # Inverting data input: disabled (0), enabled (e.g. for DBM modules) (1) + +DATA_CH14: + INVERT_RX : 0 # Inverting data input: disabled (0), enabled (e.g. for DBM modules) (1) + +DATA_CH15: + INVERT_RX : 0 # Inverting data input: disabled (0), enabled (e.g. for DBM modules) (1) diff --git a/pybar/dut_configuration_mmc3_8chip_eth.yaml b/pybar/dut_configuration_mmc3_8chip_eth.yaml new file mode 100644 index 000000000..e5dcb1ae9 --- /dev/null +++ b/pybar/dut_configuration_mmc3_8chip_eth.yaml @@ -0,0 +1,103 @@ +# MMC3 board with max. 8 FEI4s +ETH: + ip : "192.168.10.16" + udp_port : 4660 + tcp_port : 24 + tcp_connection : True + +# Trigger +TRIGGER_CH0_TO_CH7: + TRIGGER_MODE : 0 # Selecting trigger mode: Use trigger inputs/trigger select (0), TLU no handshake (1), TLU simple handshake (2), TLU data handshake (3) + TRIGGER_SELECT : 1 # Selecting trigger input: MonHit/HitOR from module 0/1/2/3/4/5/6/7 (2/4/8/16/32/64/128/256), LEMO RX0 (1), disabled (0) + TRIGGER_INVERT : 0 # Inverting trigger input: MonHit/HitOR from module 0/1/2/3/4/5/6/7 (2/4/8/16/32/64/128/256), LEMO RX0 (1), disabled (0) + TRIGGER_VETO_SELECT : 1 # Selecting trigger veto: RX FIFO 0/1/2/3/4/4/6/7 full (2/4/8/16/32/64/128/256), FIFO full (1), disabled (0) + TRIGGER_HANDSHAKE_ACCEPT_WAIT_CYCLES : 3 # Increasing minimum trigger length in TLU data handshale mode (preventing certain TLU flaws) + TRIGGER_DATA_DELAY : 0 # TLU data handshake data delay depends on the cable length and should be adjusted with a delay scan (run scan/tune_tlu.py) + TRIGGER_THRESHOLD : 0 # Standard trigger minimum length in clock cycles of the trigger/TLU FSM + DATA_FORMAT : 0 # 31bit trigger number according to TRIGGER_MODE (0), 31bit time stamp (1), 15bit time stamp + 16bit trigger number (2) + +# TDC for high precision charge measurements +TDC_CH0: + EN_WRITE_TIMESTAMP : 1 # Writing trigger timestamp + EN_TRIGGER_DIST : 0 # Measuring trigger to TDC delay with 640MHz clock + EN_NO_WRITE_TRIG_ERR : 0 # Writing TDC word only if valid trigger occurred + EN_INVERT_TDC : 0 # Inverting TDC input + EN_INVERT_TRIGGER : 0 # Inverting trigger input + +TDC_CH1: + EN_WRITE_TIMESTAMP : 1 # Writing trigger timestamp + EN_TRIGGER_DIST : 0 # Measuring trigger to TDC delay with 640MHz clock + EN_NO_WRITE_TRIG_ERR : 0 # Writing TDC word only if valid trigger occurred + EN_INVERT_TDC : 0 # Inverting TDC input + EN_INVERT_TRIGGER : 0 # Inverting trigger input + +TDC_CH2: + EN_WRITE_TIMESTAMP : 1 # Writing trigger timestamp + EN_TRIGGER_DIST : 0 # Measuring trigger to TDC delay with 640MHz clock + EN_NO_WRITE_TRIG_ERR : 0 # Writing TDC word only if valid trigger occurred + EN_INVERT_TDC : 0 # Inverting TDC input + EN_INVERT_TRIGGER : 0 # Inverting trigger input + +TDC_CH3: + EN_WRITE_TIMESTAMP : 1 # Writing trigger timestamp + EN_TRIGGER_DIST : 0 # Measuring trigger to TDC delay with 640MHz clock + EN_NO_WRITE_TRIG_ERR : 0 # Writing TDC word only if valid trigger occurred + EN_INVERT_TDC : 0 # Inverting TDC input + EN_INVERT_TRIGGER : 0 # Inverting trigger input + +TDC_CH4: + EN_WRITE_TIMESTAMP : 1 # Writing trigger timestamp + EN_TRIGGER_DIST : 0 # Measuring trigger to TDC delay with 640MHz clock + EN_NO_WRITE_TRIG_ERR : 0 # Writing TDC word only if valid trigger occurred + EN_INVERT_TDC : 0 # Inverting TDC input + EN_INVERT_TRIGGER : 0 # Inverting trigger input + +TDC_CH5: + EN_WRITE_TIMESTAMP : 1 # Writing trigger timestamp + EN_TRIGGER_DIST : 0 # Measuring trigger to TDC delay with 640MHz clock + EN_NO_WRITE_TRIG_ERR : 0 # Writing TDC word only if valid trigger occurred + EN_INVERT_TDC : 0 # Inverting TDC input + EN_INVERT_TRIGGER : 0 # Inverting trigger input + +TDC_CH6: + EN_WRITE_TIMESTAMP : 1 # Writing trigger timestamp + EN_TRIGGER_DIST : 0 # Measuring trigger to TDC delay with 640MHz clock + EN_NO_WRITE_TRIG_ERR : 0 # Writing TDC word only if valid trigger occurred + EN_INVERT_TDC : 0 # Inverting TDC input + EN_INVERT_TRIGGER : 0 # Inverting trigger input + +TDC_CH7: + EN_WRITE_TIMESTAMP : 1 # Writing trigger timestamp + EN_TRIGGER_DIST : 0 # Measuring trigger to TDC delay with 640MHz clock + EN_NO_WRITE_TRIG_ERR : 0 # Writing TDC word only if valid trigger occurred + EN_INVERT_TDC : 0 # Inverting TDC input + EN_INVERT_TRIGGER : 0 # Inverting trigger input + +# FE-I4 command output +CMD_CH0_TO_CH7: + OUTPUT_MODE : 3 # Selecting command output mode: positive edge (0), negative edge (1), Manchester Code according to IEEE 802.3 (2), Manchester Code according to G.E. Thomas (3) + +# FE-I4 data receivers +DATA_CH0: + INVERT_RX : 0 # Inverting data input: disabled (0), enabled (e.g. for DBM modules) (1) + +DATA_CH1: + INVERT_RX : 0 # Inverting data input: disabled (0), enabled (e.g. for DBM modules) (1) + +DATA_CH2: + INVERT_RX : 0 # Inverting data input: disabled (0), enabled (e.g. for DBM modules) (1) + +DATA_CH3: + INVERT_RX : 0 # Inverting data input: disabled (0), enabled (e.g. for DBM modules) (1) + +DATA_CH4: + INVERT_RX : 0 # Inverting data input: disabled (0), enabled (e.g. for DBM modules) (1) + +DATA_CH5: + INVERT_RX : 0 # Inverting data input: disabled (0), enabled (e.g. for DBM modules) (1) + +DATA_CH6: + INVERT_RX : 0 # Inverting data input: disabled (0), enabled (e.g. for DBM modules) (1) + +DATA_CH7: + INVERT_RX : 0 # Inverting data input: disabled (0), enabled (e.g. for DBM modules) (1) diff --git a/pybar/dut_configuration_mmc3_8chip_multi_tx_eth.yaml b/pybar/dut_configuration_mmc3_8chip_multi_tx_eth.yaml new file mode 100644 index 000000000..da8b073e3 --- /dev/null +++ b/pybar/dut_configuration_mmc3_8chip_multi_tx_eth.yaml @@ -0,0 +1,187 @@ +# MMC3 board with max. 8 FEI4s with multiple TX +ETH: + ip : "192.168.10.16" + udp_port : 4660 + tcp_port : 24 + tcp_connection : True + +# Trigger +TRIGGER_CH0: + TRIGGER_MODE : 0 # Selecting trigger mode: Use trigger inputs/trigger select (0), TLU no handshake (1), TLU simple handshake (2), TLU data handshake (3) + TRIGGER_SELECT : 2 # Selecting trigger input: MonHit/HitOR from module 0/1/2/3/4/5/6/7 (2/4/8/16/32/64/128/256), LEMO RX0 (1), disabled (0) + TRIGGER_INVERT : 0 # Inverting trigger input: MonHit/HitOR from module 0/1/2/3/4/5/6/7 (2/4/8/16/32/64/128/256), LEMO RX0 (1), disabled (0) + TRIGGER_VETO_SELECT : 1 # Selecting trigger veto: RX FIFO 0/1/2/3/4/4/6/7 full (2/4/8/16/32/64/128/256), FIFO full (1), disabled (0) + TRIGGER_HANDSHAKE_ACCEPT_WAIT_CYCLES : 3 # Increasing minimum trigger length in TLU data handshale mode (preventing certain TLU flaws) + TRIGGER_DATA_DELAY : 0 # TLU data handshake data delay depends on the cable length and should be adjusted with a delay scan (run scan/tune_tlu.py) + TRIGGER_THRESHOLD : 0 # Standard trigger minimum length in clock cycles of the trigger/TLU FSM + DATA_FORMAT : 0 # 31bit trigger number according to TRIGGER_MODE (0), 31bit time stamp (1), 15bit time stamp + 16bit trigger number (2) + +TRIGGER_CH1: + TRIGGER_MODE : 0 # Selecting trigger mode: Use trigger inputs/trigger select (0), TLU no handshake (1), TLU simple handshake (2), TLU data handshake (3) + TRIGGER_SELECT : 4 # Selecting trigger input: MonHit/HitOR from module 0/1/2/3/4/5/6/7 (2/4/8/16/32/64/128/256), LEMO RX0 (1), disabled (0) + TRIGGER_INVERT : 0 # Inverting trigger input: MonHit/HitOR from module 0/1/2/3/4/5/6/7 (2/4/8/16/32/64/128/256), LEMO RX0 (1), disabled (0) + TRIGGER_VETO_SELECT : 1 # Selecting trigger veto: RX FIFO 0/1/2/3/4/4/6/7 full (2/4/8/16/32/64/128/256), FIFO full (1), disabled (0) + TRIGGER_HANDSHAKE_ACCEPT_WAIT_CYCLES : 3 # Increasing minimum trigger length in TLU data handshale mode (preventing certain TLU flaws) + TRIGGER_DATA_DELAY : 0 # TLU data handshake data delay depends on the cable length and should be adjusted with a delay scan (run scan/tune_tlu.py) + TRIGGER_THRESHOLD : 0 # Standard trigger minimum length in clock cycles of the trigger/TLU FSM + DATA_FORMAT : 0 # 31bit trigger number according to TRIGGER_MODE (0), 31bit time stamp (1), 15bit time stamp + 16bit trigger number (2) + +TRIGGER_CH2: + TRIGGER_MODE : 0 # Selecting trigger mode: Use trigger inputs/trigger select (0), TLU no handshake (1), TLU simple handshake (2), TLU data handshake (3) + TRIGGER_SELECT : 8 # Selecting trigger input: MonHit/HitOR from module 0/1/2/3/4/5/6/7 (2/4/8/16/32/64/128/256), LEMO RX0 (1), disabled (0) + TRIGGER_INVERT : 0 # Inverting trigger input: MonHit/HitOR from module 0/1/2/3/4/5/6/7 (2/4/8/16/32/64/128/256), LEMO RX0 (1), disabled (0) + TRIGGER_VETO_SELECT : 1 # Selecting trigger veto: RX FIFO 0/1/2/3/4/4/6/7 full (2/4/8/16/32/64/128/256), FIFO full (1), disabled (0) + TRIGGER_HANDSHAKE_ACCEPT_WAIT_CYCLES : 3 # Increasing minimum trigger length in TLU data handshale mode (preventing certain TLU flaws) + TRIGGER_DATA_DELAY : 0 # TLU data handshake data delay depends on the cable length and should be adjusted with a delay scan (run scan/tune_tlu.py) + TRIGGER_THRESHOLD : 0 # Standard trigger minimum length in clock cycles of the trigger/TLU FSM + DATA_FORMAT : 0 # 31bit trigger number according to TRIGGER_MODE (0), 31bit time stamp (1), 15bit time stamp + 16bit trigger number (2) + +TRIGGER_CH3: + TRIGGER_MODE : 0 # Selecting trigger mode: Use trigger inputs/trigger select (0), TLU no handshake (1), TLU simple handshake (2), TLU data handshake (3) + TRIGGER_SELECT : 16 # Selecting trigger input: MonHit/HitOR from module 0/1/2/3/4/5/6/7 (2/4/8/16/32/64/128/256), LEMO RX0 (1), disabled (0) + TRIGGER_INVERT : 0 # Inverting trigger input: MonHit/HitOR from module 0/1/2/3/4/5/6/7 (2/4/8/16/32/64/128/256), LEMO RX0 (1), disabled (0) + TRIGGER_VETO_SELECT : 1 # Selecting trigger veto: RX FIFO 0/1/2/3/4/4/6/7 full (2/4/8/16/32/64/128/256), FIFO full (1), disabled (0) + TRIGGER_HANDSHAKE_ACCEPT_WAIT_CYCLES : 3 # Increasing minimum trigger length in TLU data handshale mode (preventing certain TLU flaws) + TRIGGER_DATA_DELAY : 0 # TLU data handshake data delay depends on the cable length and should be adjusted with a delay scan (run scan/tune_tlu.py) + TRIGGER_THRESHOLD : 0 # Standard trigger minimum length in clock cycles of the trigger/TLU FSM + DATA_FORMAT : 0 # 31bit trigger number according to TRIGGER_MODE (0), 31bit time stamp (1), 15bit time stamp + 16bit trigger number (2) + +TRIGGER_CH4: + TRIGGER_MODE : 0 # Selecting trigger mode: Use trigger inputs/trigger select (0), TLU no handshake (1), TLU simple handshake (2), TLU data handshake (3) + TRIGGER_SELECT : 32 # Selecting trigger input: MonHit/HitOR from module 0/1/2/3/4/5/6/7 (2/4/8/16/32/64/128/256), LEMO RX0 (1), disabled (0) + TRIGGER_INVERT : 0 # Inverting trigger input: MonHit/HitOR from module 0/1/2/3/4/5/6/7 (2/4/8/16/32/64/128/256), LEMO RX0 (1), disabled (0) + TRIGGER_VETO_SELECT : 1 # Selecting trigger veto: RX FIFO 0/1/2/3/4/4/6/7 full (2/4/8/16/32/64/128/256), FIFO full (1), disabled (0) + TRIGGER_HANDSHAKE_ACCEPT_WAIT_CYCLES : 3 # Increasing minimum trigger length in TLU data handshale mode (preventing certain TLU flaws) + TRIGGER_DATA_DELAY : 0 # TLU data handshake data delay depends on the cable length and should be adjusted with a delay scan (run scan/tune_tlu.py) + TRIGGER_THRESHOLD : 0 # Standard trigger minimum length in clock cycles of the trigger/TLU FSM + DATA_FORMAT : 0 # 31bit trigger number according to TRIGGER_MODE (0), 31bit time stamp (1), 15bit time stamp + 16bit trigger number (2) + +TRIGGER_CH5: + TRIGGER_MODE : 0 # Selecting trigger mode: Use trigger inputs/trigger select (0), TLU no handshake (1), TLU simple handshake (2), TLU data handshake (3) + TRIGGER_SELECT : 64 # Selecting trigger input: MonHit/HitOR from module 0/1/2/3/4/5/6/7 (2/4/8/16/32/64/128/256), LEMO RX0 (1), disabled (0) + TRIGGER_INVERT : 0 # Inverting trigger input: MonHit/HitOR from module 0/1/2/3/4/5/6/7 (2/4/8/16/32/64/128/256), LEMO RX0 (1), disabled (0) + TRIGGER_VETO_SELECT : 1 # Selecting trigger veto: RX FIFO 0/1/2/3/4/4/6/7 full (2/4/8/16/32/64/128/256/256), FIFO full (1), disabled (0) + TRIGGER_HANDSHAKE_ACCEPT_WAIT_CYCLES : 3 # Increasing minimum trigger length in TLU data handshale mode (preventing certain TLU flaws) + TRIGGER_DATA_DELAY : 0 # TLU data handshake data delay depends on the cable length and should be adjusted with a delay scan (run scan/tune_tlu.py) + TRIGGER_THRESHOLD : 0 # Standard trigger minimum length in clock cycles of the trigger/TLU FSM + DATA_FORMAT : 0 # 31bit trigger number according to TRIGGER_MODE (0), 31bit time stamp (1), 15bit time stamp + 16bit trigger number (2) + +TRIGGER_CH6: + TRIGGER_MODE : 0 # Selecting trigger mode: Use trigger inputs/trigger select (0), TLU no handshake (1), TLU simple handshake (2), TLU data handshake (3) + TRIGGER_SELECT : 128 # Selecting trigger input: MonHit/HitOR from module 0/1/2/3/4/5/6/7 (2/4/8/16/32/64/128/256), LEMO RX0 (1), disabled (0) + TRIGGER_INVERT : 0 # Inverting trigger input: MonHit/HitOR from module 0/1/2/3/4/5/6/7 (2/4/8/16/32/64/128/256), LEMO RX0 (1), disabled (0) + TRIGGER_VETO_SELECT : 1 # Selecting trigger veto: RX FIFO 0/1/2/3/4/4/6/7 full (2/4/8/16/32/64/128/256), FIFO full (1), disabled (0) + TRIGGER_HANDSHAKE_ACCEPT_WAIT_CYCLES : 3 # Increasing minimum trigger length in TLU data handshale mode (preventing certain TLU flaws) + TRIGGER_DATA_DELAY : 0 # TLU data handshake data delay depends on the cable length and should be adjusted with a delay scan (run scan/tune_tlu.py) + TRIGGER_THRESHOLD : 0 # Standard trigger minimum length in clock cycles of the trigger/TLU FSM + DATA_FORMAT : 0 # 31bit trigger number according to TRIGGER_MODE (0), 31bit time stamp (1), 15bit time stamp + 16bit trigger number (2) + +TRIGGER_CH7: + TRIGGER_MODE : 0 # Selecting trigger mode: Use trigger inputs/trigger select (0), TLU no handshake (1), TLU simple handshake (2), TLU data handshake (3) + TRIGGER_SELECT : 256 # Selecting trigger input: MonHit/HitOR from module 0/1/2/3/4/5/6/7 (2/4/8/16/32/64/128/256), LEMO RX0 (1), disabled (0) + TRIGGER_INVERT : 0 # Inverting trigger input: MonHit/HitOR from module 0/1/2/3/4/5/6/7 (2/4/8/16/32/64/128/256), LEMO RX0 (1), disabled (0) + TRIGGER_VETO_SELECT : 1 # Selecting trigger veto: RX FIFO 0/1/2/3/4/4/6/7 full (2/4/8/16/32/64/128/256), FIFO full (1), disabled (0) + TRIGGER_HANDSHAKE_ACCEPT_WAIT_CYCLES : 3 # Increasing minimum trigger length in TLU data handshale mode (preventing certain TLU flaws) + TRIGGER_DATA_DELAY : 0 # TLU data handshake data delay depends on the cable length and should be adjusted with a delay scan (run scan/tune_tlu.py) + TRIGGER_THRESHOLD : 0 # Standard trigger minimum length in clock cycles of the trigger/TLU FSM + DATA_FORMAT : 0 # 31bit trigger number according to TRIGGER_MODE (0), 31bit time stamp (1), 15bit time stamp + 16bit trigger number (2) + +# TDC for high precision charge measurements +TDC_CH0: + EN_WRITE_TIMESTAMP : 1 # Writing trigger timestamp + EN_TRIGGER_DIST : 0 # Measuring trigger to TDC delay with 640MHz clock + EN_NO_WRITE_TRIG_ERR : 0 # Writing TDC word only if valid trigger occurred + EN_INVERT_TDC : 0 # Inverting TDC input + EN_INVERT_TRIGGER : 0 # Inverting trigger input + +TDC_CH1: + EN_WRITE_TIMESTAMP : 1 # Writing trigger timestamp + EN_TRIGGER_DIST : 0 # Measuring trigger to TDC delay with 640MHz clock + EN_NO_WRITE_TRIG_ERR : 0 # Writing TDC word only if valid trigger occurred + EN_INVERT_TDC : 0 # Inverting TDC input + EN_INVERT_TRIGGER : 0 # Inverting trigger input + +TDC_CH2: + EN_WRITE_TIMESTAMP : 1 # Writing trigger timestamp + EN_TRIGGER_DIST : 0 # Measuring trigger to TDC delay with 640MHz clock + EN_NO_WRITE_TRIG_ERR : 0 # Writing TDC word only if valid trigger occurred + EN_INVERT_TDC : 0 # Inverting TDC input + EN_INVERT_TRIGGER : 0 # Inverting trigger input + +TDC_CH3: + EN_WRITE_TIMESTAMP : 1 # Writing trigger timestamp + EN_TRIGGER_DIST : 0 # Measuring trigger to TDC delay with 640MHz clock + EN_NO_WRITE_TRIG_ERR : 0 # Writing TDC word only if valid trigger occurred + EN_INVERT_TDC : 0 # Inverting TDC input + EN_INVERT_TRIGGER : 0 # Inverting trigger input + +TDC_CH4: + EN_WRITE_TIMESTAMP : 1 # Writing trigger timestamp + EN_TRIGGER_DIST : 0 # Measuring trigger to TDC delay with 640MHz clock + EN_NO_WRITE_TRIG_ERR : 0 # Writing TDC word only if valid trigger occurred + EN_INVERT_TDC : 0 # Inverting TDC input + EN_INVERT_TRIGGER : 0 # Inverting trigger input + +TDC_CH5: + EN_WRITE_TIMESTAMP : 1 # Writing trigger timestamp + EN_TRIGGER_DIST : 0 # Measuring trigger to TDC delay with 640MHz clock + EN_NO_WRITE_TRIG_ERR : 0 # Writing TDC word only if valid trigger occurred + EN_INVERT_TDC : 0 # Inverting TDC input + EN_INVERT_TRIGGER : 0 # Inverting trigger input + +TDC_CH6: + EN_WRITE_TIMESTAMP : 1 # Writing trigger timestamp + EN_TRIGGER_DIST : 0 # Measuring trigger to TDC delay with 640MHz clock + EN_NO_WRITE_TRIG_ERR : 0 # Writing TDC word only if valid trigger occurred + EN_INVERT_TDC : 0 # Inverting TDC input + EN_INVERT_TRIGGER : 0 # Inverting trigger input + +# FE-I4 command output +CMD_CH0: + OUTPUT_MODE : 3 # Selecting command output mode: positive edge (0), negative edge (1), Manchester Code according to IEEE 802.3 (2), Manchester Code according to G.E. Thomas (3) + +CMD_CH1: + OUTPUT_MODE : 3 # Selecting command output mode: positive edge (0), negative edge (1), Manchester Code according to IEEE 802.3 (2), Manchester Code according to G.E. Thomas (3) + +CMD_CH2: + OUTPUT_MODE : 3 # Selecting command output mode: positive edge (0), negative edge (1), Manchester Code according to IEEE 802.3 (2), Manchester Code according to G.E. Thomas (3) + +CMD_CH3: + OUTPUT_MODE : 3 # Selecting command output mode: positive edge (0), negative edge (1), Manchester Code according to IEEE 802.3 (2), Manchester Code according to G.E. Thomas (3) + +CMD_CH4: + OUTPUT_MODE : 3 # Selecting command output mode: positive edge (0), negative edge (1), Manchester Code according to IEEE 802.3 (2), Manchester Code according to G.E. Thomas (3) + +CMD_CH5: + OUTPUT_MODE : 3 # Selecting command output mode: positive edge (0), negative edge (1), Manchester Code according to IEEE 802.3 (2), Manchester Code according to G.E. Thomas (3) + +CMD_CH6: + OUTPUT_MODE : 3 # Selecting command output mode: positive edge (0), negative edge (1), Manchester Code according to IEEE 802.3 (2), Manchester Code according to G.E. Thomas (3) + +CMD_CH7: + OUTPUT_MODE : 3 # Selecting command output mode: positive edge (0), negative edge (1), Manchester Code according to IEEE 802.3 (2), Manchester Code according to G.E. Thomas (3) + +# FE-I4 data receivers +DATA_CH0: + INVERT_RX : 0 # Inverting data input: disabled (0), enabled (e.g. for DBM modules) (1) + +DATA_CH1: + INVERT_RX : 0 # Inverting data input: disabled (0), enabled (e.g. for DBM modules) (1) + +DATA_CH2: + INVERT_RX : 0 # Inverting data input: disabled (0), enabled (e.g. for DBM modules) (1) + +DATA_CH3: + INVERT_RX : 0 # Inverting data input: disabled (0), enabled (e.g. for DBM modules) (1) + +DATA_CH4: + INVERT_RX : 0 # Inverting data input: disabled (0), enabled (e.g. for DBM modules) (1) + +DATA_CH5: + INVERT_RX : 0 # Inverting data input: disabled (0), enabled (e.g. for DBM modules) (1) + +DATA_CH6: + INVERT_RX : 0 # Inverting data input: disabled (0), enabled (e.g. for DBM modules) (1) + +DATA_CH7: + INVERT_RX : 0 # Inverting data input: disabled (0), enabled (e.g. for DBM modules) (1) diff --git a/pybar/dut_configuration_mmc3_beast_eth.yaml b/pybar/dut_configuration_mmc3_beast_eth.yaml index d04b8e626..548f7b445 100644 --- a/pybar/dut_configuration_mmc3_beast_eth.yaml +++ b/pybar/dut_configuration_mmc3_beast_eth.yaml @@ -1,4 +1,4 @@ -# MMC3 board for Beast +# MMC3 board supporting BEAST/FANGS ETH: ip : "192.168.10.16" udp_port : 4660 @@ -6,17 +6,46 @@ ETH: tcp_connection : True # Trigger -TLU: +TRIGGER_CH0_TO_CH4: TRIGGER_MODE : 0 # Selecting trigger mode: Use trigger inputs/trigger select (0), TLU no handshake (1), TLU simple handshake (2), TLU data handshake (3) - TRIGGER_SELECT : 1 # Selecting trigger input: RX2 (TDC loop-through) (8), RX1 (4), RX0 (2), MonHit/HitOR from chip 1/2/3/4/5 (1/2/4/8/16), disabled (0) - TRIGGER_INVERT : 0 # Inverting trigger input: RX2 (TDC loop-through) (8), RX1 (4), RX0 (2), MonHit/HitOR from Adapter Card (1), disabled (0) - TRIGGER_VETO_SELECT : 1 # Selecting trigger veto: RX1 (2), RX FIFO full (1), disabled (0) - TRIGGER_HANDSHAKE_ACCEPT_WAIT_CYCLES : 3 # increase minimum trigger length - TRIGGER_DATA_DELAY : 0 # Depends on the cable length and should be adjusted (run scan/tune_tlu.py) - TRIGGER_THRESHOLD : 0 # Standard trigger minimum length + TRIGGER_SELECT : 62 # Selecting trigger input: MonHit/HitOR from module 0/1/2/3/4 (2/4/8/16/32), LEMO RX0 (1), disabled (0) + TRIGGER_INVERT : 0 # Inverting trigger input: MonHit/HitOR from module 0/1/2/3/4 (2/4/8/16/32), LEMO RX0 (1), disabled (0) + TRIGGER_VETO_SELECT : 1 # Selecting trigger veto: RX FIFO 0/1/2/3/4 full (2/4/8/16/32), FIFO full (1), disabled (0) + TRIGGER_HANDSHAKE_ACCEPT_WAIT_CYCLES : 3 # Increasing minimum trigger length in TLU data handshale mode (preventing certain TLU flaws) + TRIGGER_DATA_DELAY : 0 # TLU data handshake data delay depends on the cable length and should be adjusted with a delay scan (run scan/tune_tlu.py) + TRIGGER_THRESHOLD : 0 # Standard trigger minimum length in clock cycles of the trigger/TLU FSM + DATA_FORMAT : 0 # 31bit trigger number according to TRIGGER_MODE (0), 31bit time stamp (1), 15bit time stamp + 16bit trigger number (2) # TDC for high precision charge measurements -TDC: +TDC_CH0: + EN_WRITE_TIMESTAMP : 1 # Writing trigger timestamp + EN_TRIGGER_DIST : 0 # Measuring trigger to TDC delay with 640MHz clock + EN_NO_WRITE_TRIG_ERR : 0 # Writing TDC word only if valid trigger occurred + EN_INVERT_TDC : 0 # Inverting TDC input + EN_INVERT_TRIGGER : 0 # Inverting trigger input + +TDC_CH1: + EN_WRITE_TIMESTAMP : 1 # Writing trigger timestamp + EN_TRIGGER_DIST : 0 # Measuring trigger to TDC delay with 640MHz clock + EN_NO_WRITE_TRIG_ERR : 0 # Writing TDC word only if valid trigger occurred + EN_INVERT_TDC : 0 # Inverting TDC input + EN_INVERT_TRIGGER : 0 # Inverting trigger input + +TDC_CH2: + EN_WRITE_TIMESTAMP : 1 # Writing trigger timestamp + EN_TRIGGER_DIST : 0 # Measuring trigger to TDC delay with 640MHz clock + EN_NO_WRITE_TRIG_ERR : 0 # Writing TDC word only if valid trigger occurred + EN_INVERT_TDC : 0 # Inverting TDC input + EN_INVERT_TRIGGER : 0 # Inverting trigger input + +TDC_CH3: + EN_WRITE_TIMESTAMP : 1 # Writing trigger timestamp + EN_TRIGGER_DIST : 0 # Measuring trigger to TDC delay with 640MHz clock + EN_NO_WRITE_TRIG_ERR : 0 # Writing TDC word only if valid trigger occurred + EN_INVERT_TDC : 0 # Inverting TDC input + EN_INVERT_TRIGGER : 0 # Inverting trigger input + +TDC_CH4: EN_WRITE_TIMESTAMP : 1 # Writing trigger timestamp EN_TRIGGER_DIST : 0 # Measuring trigger to TDC delay with 640MHz clock EN_NO_WRITE_TRIG_ERR : 0 # Writing TDC word only if valid trigger occurred @@ -24,11 +53,21 @@ TDC: EN_INVERT_TRIGGER : 0 # Inverting trigger input # FE-I4 command output -CMD: +CMD_CH0_TO_CH4: OUTPUT_MODE : 3 # Selecting command output mode: positive edge (0), negative edge (1), Manchester Code according to IEEE 802.3 (2), Manchester Code according to G.E. Thomas (3) # FE-I4 data receiver -CH0: +DATA_CH0: + INVERT_RX : 0 # Inverting data input: disabled (0), enabled (e.g. for DBM modules) (1) + +DATA_CH1: INVERT_RX : 0 # Inverting data input: disabled (0), enabled (e.g. for DBM modules) (1) +DATA_CH2: + INVERT_RX : 0 # Inverting data input: disabled (0), enabled (e.g. for DBM modules) (1) +DATA_CH3: + INVERT_RX : 0 # Inverting data input: disabled (0), enabled (e.g. for DBM modules) (1) + +DATA_CH4: + INVERT_RX : 0 # Inverting data input: disabled (0), enabled (e.g. for DBM modules) (1) diff --git a/pybar/dut_configuration_mmc3_m26_eth.yaml b/pybar/dut_configuration_mmc3_m26_eth.yaml index 3428479de..cbb191181 100644 --- a/pybar/dut_configuration_mmc3_m26_eth.yaml +++ b/pybar/dut_configuration_mmc3_m26_eth.yaml @@ -1,4 +1,4 @@ -# MMC3 board +# MMC3 board with single FEI4 and max. 6 Mimosa26 ETH: ip : "192.168.10.16" udp_port : 4660 @@ -6,18 +6,18 @@ ETH: tcp_connection : True # Trigger -TLU: +TRIGGER_FEI4: TRIGGER_MODE : 3 # Selecting trigger mode: Use trigger inputs/trigger select (0), TLU no handshake (1), TLU simple handshake (2), TLU data handshake (3) - TRIGGER_SELECT : 0 # Selecting trigger input: RX2 (TDC loop-through) (8), RX1 (4), RX0 (2), MonHit/HitOR from Adapter Card (1), disabled (0) - TRIGGER_INVERT : 0 # Inverting trigger input: RX2 (TDC loop-through) (8), RX1 (4), RX0 (2), MonHit/HitOR from Adapter Card (1), disabled (0) - TRIGGER_VETO_SELECT : 1 # Selecting trigger veto: RX1 (2), RX FIFO full (1), disabled (0) - TRIGGER_HANDSHAKE_ACCEPT_WAIT_CYCLES : 3 # increase minimum trigger length - TRIGGER_DATA_DELAY : 0 # Depends on the cable length and should be adjusted (run scan/tune_tlu.py) - TRIGGER_THRESHOLD : 0 # Standard trigger minimum length - DATA_FORMAT : 0 # trigger number according to TRIGGER_MODE (0), time stamp only (1), combined, 15bit time stamp + 16bit trigger number (2) + TRIGGER_SELECT : 0 # Selecting trigger input: MonHit/HitOR from module 0 (2), LEMO RX0 (1), disabled (0) + TRIGGER_INVERT : 0 # Inverting trigger input: MonHit/HitOR from module 0 (2), LEMO RX0 (1), disabled (0) + TRIGGER_VETO_SELECT : 1 # Selecting trigger veto: RX FIFO 0 full (2), FIFO full (1), disabled (0) + TRIGGER_HANDSHAKE_ACCEPT_WAIT_CYCLES : 3 # Increasing minimum trigger length in TLU data handshale mode (preventing certain TLU flaws) + TRIGGER_DATA_DELAY : 0 # TLU data handshake data delay depends on the cable length and should be adjusted with a delay scan (run scan/tune_tlu.py) + TRIGGER_THRESHOLD : 0 # Standard trigger minimum length in clock cycles of the trigger/TLU FSM + DATA_FORMAT : 0 # 31bit trigger number according to TRIGGER_MODE (0), 31bit time stamp (1), 15bit time stamp + 16bit trigger number (2) # TDC for high precision charge measurements -TDC: +TDC_FEI4: EN_WRITE_TIMESTAMP : 0 # Writing trigger timestamp EN_TRIGGER_DIST : 0 # Measuring trigger to TDC delay with 640MHz clock EN_NO_WRITE_TRIG_ERR : 0 # Writing TDC word only if valid trigger occurred @@ -25,27 +25,5 @@ TDC: EN_INVERT_TRIGGER : 0 # Inverting trigger input # FE-I4 command output -CMD: +CMD_FEI4: OUTPUT_MODE : 0 # Selecting command output mode: positive edge (0), negative edge (1), Manchester Code according to IEEE 802.3 (2), Manchester Code according to G.E. Thomas (3) - -# FE-I4 data receiver -CH0: - INVERT_RX : 0 # Inverting data input: disabled (0), enabled (e.g. for DBM modules) (1) - -M26_RX1: - EN : 0 - -M26_RX2: - EN : 0 - -M26_RX3: - EN : 0 - -M26_RX4: - EN : 0 - -M26_RX5: - EN : 0 - -M26_RX6: - EN : 0 diff --git a/pybar/dut_configuration_nexys4.yaml b/pybar/dut_configuration_nexys4.yaml index 76472e026..e7793b410 100644 --- a/pybar/dut_configuration_nexys4.yaml +++ b/pybar/dut_configuration_nexys4.yaml @@ -6,7 +6,7 @@ ETH: tcp_connection : True # Trigger -TLU: +TRIGGER_CH1_TO_CH4: TRIGGER_MODE : 0 # Selecting trigger mode: Use trigger inputs/trigger select (0), TLU no handshake (1), TLU simple handshake (2), TLU data handshake (3) TRIGGER_SELECT : 0 # Selecting trigger input: IO_L1P_T0_AD0P_15 (TDC loop-through) (2), IO_L14N_T2_SRCC_15 (1), disabled (0) TRIGGER_INVERT : 0 # Inverting trigger input: IO_L1P_T0_AD0P_15 (TDC loop-through) (2), IO_L14N_T2_SRCC_15 (1), disabled (0) @@ -17,18 +17,18 @@ TLU: DATA_FORMAT : 0 # trigger number according to TRIGGER_MODE (0), time stamp only (1), combined, 15bit time stamp + 16bit trigger number (2) # FE-I4 command ouput -CMD: +CMD_CH1_TO_CH4: OUTPUT_MODE : 0 # Selecting command output mode: positive edge (0), negative edge (1), Manchester Code according to IEEE 802.3 (2), Manchester Code according to G.E. Thomas (3) # FE-I4 data receiver -CH3: +DATA_CH4: INVERT_RX : 0 # Inverting data input: disabled (0), enabled (e.g. for DBM modules) (1) -CH2: +DATA_CH3: INVERT_RX : 0 -CH1: +DATA_CH2: INVERT_RX : 0 -CH0: +DATA_CH1: INVERT_RX : 0 diff --git a/pybar/dut_lx9.yaml b/pybar/dut_lx9.yaml index 06b8e3a26..f4307a1d6 100644 --- a/pybar/dut_lx9.yaml +++ b/pybar/dut_lx9.yaml @@ -13,18 +13,16 @@ transfer_layer: type : SiTcp hw_drivers: - - name : CMD + - name : CMD_CH0 type : cmd_seq interface : ETH base_addr : 0x0000 - - name : SRAM - type : sram_fifo + - name : SITCP_FIFO + type : sitcp_fifo interface : ETH - base_addr : 0x200000000 - base_data_addr : 0x100000000 - - name : CH0 + - name : DATA_CH0 type : fei4_rx interface : ETH base_addr : 0x8600 diff --git a/pybar/dut_mio.yaml b/pybar/dut_mio.yaml index dd6b7a9cc..f42f4274a 100644 --- a/pybar/dut_mio.yaml +++ b/pybar/dut_mio.yaml @@ -30,32 +30,31 @@ transfer_layer: # hw_drivers: - name : ADAPTER_CARD +# Choose adapter card here type : FEI4AdapterCard # type : FEI4QuadModuleAdapterCard interface : USB base_addr : 0x0 - - name : CH4 + - name : DATA_CH4 type : fei4_rx interface : USB base_addr : 0x18300 -# Uncomment to enable additional channels on the FEI4 Quad Module Adapter Card -# -# - name : CH3 -# type : fei4_rx -# interface : USB -# base_addr : 0x18400 -# -# - name : CH2 -# type : fei4_rx -# interface : USB -# base_addr : 0x18500 -# -# - name : CH1 -# type : fei4_rx -# interface : USB -# base_addr : 0x18600 + - name : DATA_CH3 + type : fei4_rx + interface : USB + base_addr : 0x18400 + + - name : DATA_CH2 + type : fei4_rx + interface : USB + base_addr : 0x18500 + + - name : DATA_CH1 + type : fei4_rx + interface : USB + base_addr : 0x18600 # Example of additional lab devices to be used with pyBAR # @@ -85,23 +84,23 @@ hw_drivers: # init : # device : Agilent 33250a - - name : CMD + - name : CMD_CH1_TO_CH4 type : cmd_seq interface : USB base_addr : 0x10000 - - name : SRAM + - name : SRAM_FIFO type : sram_fifo interface : USB base_addr : 0x18100 base_data_addr : 0x0001000000000000 - - name : TLU + - name : TRIGGER_CH1_TO_CH4 type : tlu interface : USB base_addr : 0x18200 - - name : TDC + - name : TDC_RX2 type : tdc_s3 interface : USB base_addr : 0x18700 @@ -128,16 +127,16 @@ registers: - name : TLU size : 1 offset : 4 - - name : CH4 + - name : DATA_CH4 size : 1 offset : 3 - - name : CH3 + - name : DATA_CH3 size : 1 offset : 2 - - name : CH2 + - name : DATA_CH2 size : 1 offset : 1 - - name : CH1 + - name : DATA_CH1 size : 1 offset : 0 @@ -164,27 +163,27 @@ registers: hw_driver : GPIO_POWER size : 8 fields: - - name : OC_CH4 + - name : OC_DATA_CH4 size : 1 offset : 7 - - name : OC_CH3 + - name : OC_DATA_CH3 size : 1 offset : 6 - - name : OC_CH2 + - name : OC_DATA_CH2 size : 1 offset : 5 - - name : OC_CH1 + - name : OC_DATA_CH1 size : 1 offset : 4 - - name : EN_CH4 + - name : EN_DATA_CH4 size : 1 offset : 3 - - name : EN_CH3 + - name : EN_DATA_CH3 size : 1 offset : 2 - - name : EN_CH2 + - name : EN_DATA_CH2 size : 1 offset : 1 - - name : EN_CH1 + - name : EN_DATA_CH1 size : 1 offset : 0 diff --git a/pybar/dut_mio_gpac.yaml b/pybar/dut_mio_gpac.yaml index 111c26e70..4a75620c8 100644 --- a/pybar/dut_mio_gpac.yaml +++ b/pybar/dut_mio_gpac.yaml @@ -12,28 +12,28 @@ hw_drivers: interface : USB base_addr : 0x0 - - name : CMD + - name : CMD_FEI4 type : cmd_seq interface : USB base_addr : 0x10000 - - name : SRAM + - name : SRAM_FIFO type : sram_fifo interface : USB base_addr : 0x18100 base_data_addr : 0x0001000000000000 - - name : TLU + - name : TRIGGER_FEI4 type : tlu interface : USB base_addr : 0x18200 - - name : FE + - name : FEI4_RX type : fei4_rx interface : USB base_addr : 0x18300 - - name : TDC + - name : TDC_RX2 type : tdc_s3 interface : USB base_addr : 0x18700 diff --git a/pybar/dut_mmc3_16chip_multi_tx_eth.yaml b/pybar/dut_mmc3_16chip_multi_tx_eth.yaml new file mode 100644 index 000000000..ac5738125 --- /dev/null +++ b/pybar/dut_mmc3_16chip_multi_tx_eth.yaml @@ -0,0 +1,214 @@ +# +# ------------------------------------------------------------ +# Copyright (c) All rights reserved +# SiLab, Institute of Physics, University of Bonn +# ------------------------------------------------------------ +# +# MMC3 board with max. 8 FEI4s with multiple TX + +name : mmc3_8chip_eth +version : 0.1 + +transfer_layer: + - name : ETH + type : SiTcp + +hw_drivers: + - name : TRIGGER_CH0 + type : tlu + interface : ETH + base_addr : 0x40000 + + - name : TRIGGER_CH1 + type : tlu + interface : ETH + base_addr : 0x40100 + + - name : TRIGGER_CH2 + type : tlu + interface : ETH + base_addr : 0x40200 + + - name : TRIGGER_CH3 + type : tlu + interface : ETH + base_addr : 0x40300 + + - name : TRIGGER_CH4 + type : tlu + interface : ETH + base_addr : 0x40400 + + - name : TRIGGER_CH5 + type : tlu + interface : ETH + base_addr : 0x40500 + + - name : TRIGGER_CH6 + type : tlu + interface : ETH + base_addr : 0x40600 + + - name : TRIGGER_CH7 + type : tlu + interface : ETH + base_addr : 0x40700 + + - name : CMD_CH0 + type : cmd_seq + interface : ETH + base_addr : 0x0000 + + - name : CMD_CH1 + type : cmd_seq + interface : ETH + base_addr : 0x8000 + + - name : CMD_CH2 + type : cmd_seq + interface : ETH + base_addr : 0x10000 + + - name : CMD_CH3 + type : cmd_seq + interface : ETH + base_addr : 0x18000 + + - name : CMD_CH4 + type : cmd_seq + interface : ETH + base_addr : 0x20000 + + - name : CMD_CH5 + type : cmd_seq + interface : ETH + base_addr : 0x28000 + + - name : CMD_CH6 + type : cmd_seq + interface : ETH + base_addr : 0x30000 + + - name : CMD_CH7 + type : cmd_seq + interface : ETH + base_addr : 0x38000 + + - name : DATA_CH0 + type : fei4_rx + interface : ETH + base_addr : 0x41000 + + - name : DATA_CH1 + type : fei4_rx + interface : ETH + base_addr : 0x41100 + + - name : DATA_CH2 + type : fei4_rx + interface : ETH + base_addr : 0x41200 + + - name : DATA_CH3 + type : fei4_rx + interface : ETH + base_addr : 0x41300 + + - name : DATA_CH4 + type : fei4_rx + interface : ETH + base_addr : 0x41400 + + - name : DATA_CH5 + type : fei4_rx + interface : ETH + base_addr : 0x41500 + + - name : DATA_CH6 + type : fei4_rx + interface : ETH + base_addr : 0x41600 + + - name : DATA_CH7 + type : fei4_rx + interface : ETH + base_addr : 0x41700 + + - name : DATA_CH8 + type : fei4_rx + interface : ETH + base_addr : 0x41800 + + - name : DATA_CH9 + type : fei4_rx + interface : ETH + base_addr : 0x41900 + + - name : DATA_CH10 + type : fei4_rx + interface : ETH + base_addr : 0x41a00 + + - name : DATA_CH11 + type : fei4_rx + interface : ETH + base_addr : 0x41b00 + + - name : DATA_CH12 + type : fei4_rx + interface : ETH + base_addr : 0x41c00 + + - name : DATA_CH13 + type : fei4_rx + interface : ETH + base_addr : 0x41d00 + + - name : DATA_CH14 + type : fei4_rx + interface : ETH + base_addr : 0x41e00 + + - name : DATA_CH15 + type : fei4_rx + interface : ETH + base_addr : 0x41f00 + + - name : TDC_CH0 + type : tdc_s3 + interface : ETH + base_addr : 0x42fff + + - name : SITCP_FIFO + type : sitcp_fifo + interface : ETH + + - name : DLY_CONFIG_GPIO + type : gpio + interface : ETH + base_addr : 0x450ef + size : 48 + +registers: + - name : DLY_CONFIG + type : StdRegister + hw_driver : DLY_CONFIG_GPIO + size : 48 + fields : + - name : CLK_DLY + offset : 42 + size : 3 + - name : RX + offset : 39 + size : 8 + repeat : 5 + fields : + - name : LD + size : 1 + offset : 7 + - name : INV + size : 1 + offset : 6 + - name : DLY + size : 5 + offset : 4 diff --git a/pybar/dut_mmc3_8chip_eth.yaml b/pybar/dut_mmc3_8chip_eth.yaml new file mode 100644 index 000000000..b36e17bf4 --- /dev/null +++ b/pybar/dut_mmc3_8chip_eth.yaml @@ -0,0 +1,139 @@ +# +# ------------------------------------------------------------ +# Copyright (c) All rights reserved +# SiLab, Institute of Physics, University of Bonn +# ------------------------------------------------------------ +# +# MMC3 board with max. 8 FEI4s + +name : mmc3_8chip_eth +version : 0.1 + +transfer_layer: + - name : ETH + type : SiTcp + +hw_drivers: + - name : TRIGGER_CH0_TO_CH7 + type : tlu + interface : ETH + base_addr : 0x8200 + + - name : CMD_CH0_TO_CH7 + type : cmd_seq + interface : ETH + base_addr : 0x0000 + + - name : DATA_CH0 + type : fei4_rx + interface : ETH + base_addr : 0x9000 + + - name : DATA_CH1 + type : fei4_rx + interface : ETH + base_addr : 0x9100 + + - name : DATA_CH2 + type : fei4_rx + interface : ETH + base_addr : 0x9200 + + - name : DATA_CH3 + type : fei4_rx + interface : ETH + base_addr : 0x9300 + + - name : DATA_CH4 + type : fei4_rx + interface : ETH + base_addr : 0x9400 + + - name : DATA_CH5 + type : fei4_rx + interface : ETH + base_addr : 0x9500 + + - name : DATA_CH6 + type : fei4_rx + interface : ETH + base_addr : 0x9600 + + - name : DATA_CH7 + type : fei4_rx + interface : ETH + base_addr : 0x9700 + + - name : TDC_CH0 + type : tdc_s3 + interface : ETH + base_addr : 0xa000 + + - name : TDC_CH1 + type : tdc_s3 + interface : ETH + base_addr : 0xa100 + + - name : TDC_CH2 + type : tdc_s3 + interface : ETH + base_addr : 0xa200 + + - name : TDC_CH3 + type : tdc_s3 + interface : ETH + base_addr : 0xa300 + + - name : TDC_CH4 + type : tdc_s3 + interface : ETH + base_addr : 0xa400 + + - name : TDC_CH5 + type : tdc_s3 + interface : ETH + base_addr : 0xa500 + + - name : TDC_CH6 + type : tdc_s3 + interface : ETH + base_addr : 0xa600 + + - name : TDC_CH7 + type : tdc_s3 + interface : ETH + base_addr : 0xa700 + + - name : SITCP_FIFO + type : sitcp_fifo + interface : ETH + + - name : DLY_CONFIG_GPIO + type : gpio + interface : ETH + base_addr : 0xb000 + size : 48 + +registers: + - name : DLY_CONFIG + type : StdRegister + hw_driver : DLY_CONFIG_GPIO + size : 48 + fields : + - name : CLK_DLY + offset : 42 + size : 3 + - name : RX + offset : 39 + size : 8 + repeat : 5 + fields : + - name : LD + size : 1 + offset : 7 + - name : INV + size : 1 + offset : 6 + - name : DLY + size : 5 + offset : 4 diff --git a/pybar/dut_mmc3_8chip_multi_tx_eth.yaml b/pybar/dut_mmc3_8chip_multi_tx_eth.yaml new file mode 100644 index 000000000..acac8418b --- /dev/null +++ b/pybar/dut_mmc3_8chip_multi_tx_eth.yaml @@ -0,0 +1,209 @@ +# +# ------------------------------------------------------------ +# Copyright (c) All rights reserved +# SiLab, Institute of Physics, University of Bonn +# ------------------------------------------------------------ +# +# MMC3 board with max. 8 FEI4s with multiple TX + +name : mmc3_8chip_eth +version : 0.1 + +transfer_layer: + - name : ETH + type : SiTcp + +hw_drivers: + - name : TRIGGER_CH0 + type : tlu + interface : ETH + base_addr : 0x40000 + + - name : TRIGGER_CH1 + type : tlu + interface : ETH + base_addr : 0x40100 + + - name : TRIGGER_CH2 + type : tlu + interface : ETH + base_addr : 0x40200 + + - name : TRIGGER_CH3 + type : tlu + interface : ETH + base_addr : 0x40300 + + - name : TRIGGER_CH4 + type : tlu + interface : ETH + base_addr : 0x40400 + + - name : TRIGGER_CH5 + type : tlu + interface : ETH + base_addr : 0x40500 + + - name : TRIGGER_CH6 + type : tlu + interface : ETH + base_addr : 0x40600 + + - name : TRIGGER_CH7 + type : tlu + interface : ETH + base_addr : 0x40700 + + - name : CMD_CH0 + type : cmd_seq + interface : ETH + base_addr : 0x0000 + + - name : CMD_CH1 + type : cmd_seq + interface : ETH + base_addr : 0x8000 + + - name : CMD_CH2 + type : cmd_seq + interface : ETH + base_addr : 0x10000 + + - name : CMD_CH3 + type : cmd_seq + interface : ETH + base_addr : 0x18000 + + - name : CMD_CH4 + type : cmd_seq + interface : ETH + base_addr : 0x20000 + + - name : CMD_CH5 + type : cmd_seq + interface : ETH + base_addr : 0x28000 + + - name : CMD_CH6 + type : cmd_seq + interface : ETH + base_addr : 0x30000 + + - name : CMD_CH7 + type : cmd_seq + interface : ETH + base_addr : 0x38000 + + - name : DATA_CH0 + type : fei4_rx + interface : ETH + base_addr : 0x41000 + + - name : DATA_CH1 + type : fei4_rx + interface : ETH + base_addr : 0x41100 + + - name : DATA_CH2 + type : fei4_rx + interface : ETH + base_addr : 0x41200 + + - name : DATA_CH3 + type : fei4_rx + interface : ETH + base_addr : 0x41300 + + - name : DATA_CH4 + type : fei4_rx + interface : ETH + base_addr : 0x41400 + + - name : DATA_CH5 + type : fei4_rx + interface : ETH + base_addr : 0x41500 + + - name : DATA_CH6 + type : fei4_rx + interface : ETH + base_addr : 0x41600 + + - name : DATA_CH7 + type : fei4_rx + interface : ETH + base_addr : 0x41700 + + - name : TDC_CH0 + type : tdc_s3 + interface : ETH + base_addr : 0x41fff + + - name : TDC_CH1 + type : tdc_s3 + interface : ETH + base_addr : 0x420ff + + - name : TDC_CH2 + type : tdc_s3 + interface : ETH + base_addr : 0x421ff + + - name : TDC_CH3 + type : tdc_s3 + interface : ETH + base_addr : 0x422ff + + - name : TDC_CH4 + type : tdc_s3 + interface : ETH + base_addr : 0x423ff + + - name : TDC_CH5 + type : tdc_s3 + interface : ETH + base_addr : 0x424ff + + - name : TDC_CH6 + type : tdc_s3 + interface : ETH + base_addr : 0x425ff + + - name : TDC_CH7 + type : tdc_s3 + interface : ETH + base_addr : 0x41fff + + - name : SITCP_FIFO + type : sitcp_fifo + interface : ETH + + - name : DLY_CONFIG_GPIO + type : gpio + interface : ETH + base_addr : 0x430ef + size : 48 + +registers: + - name : DLY_CONFIG + type : StdRegister + hw_driver : DLY_CONFIG_GPIO + size : 48 + fields : + - name : CLK_DLY + offset : 42 + size : 3 + - name : RX + offset : 39 + size : 8 + repeat : 5 + fields : + - name : LD + size : 1 + offset : 7 + - name : INV + size : 1 + offset : 6 + - name : DLY + size : 5 + offset : 4 diff --git a/pybar/dut_mmc3_beast_eth.yaml b/pybar/dut_mmc3_beast_eth.yaml index 736498e72..23bed7b24 100644 --- a/pybar/dut_mmc3_beast_eth.yaml +++ b/pybar/dut_mmc3_beast_eth.yaml @@ -4,86 +4,80 @@ # SiLab, Institute of Physics, University of Bonn # ------------------------------------------------------------ # +# MMC3 board supporting BEAST/FANGS -name : beast +name : mmc3_beast_eth version : 0.1 transfer_layer: - name : ETH type : SiTcp - init: - ip : "192.168.10.16" - udp_port : 4660 - tcp_port : 24 - tcp_connection : True hw_drivers: - - name : CMD + - name : TRIGGER_CH0_TO_CH4 + type : tlu + interface : ETH + base_addr : 0x8200 + + - name : CMD_CH0_TO_CH4 type : cmd_seq interface : ETH base_addr : 0x0000 - - name : CH0 + - name : DATA_CH0 type : fei4_rx interface : ETH base_addr : 0x9000 - - name : CH1 + - name : DATA_CH1 type : fei4_rx interface : ETH base_addr : 0x9100 - - name : CH2 + - name : DATA_CH2 type : fei4_rx interface : ETH base_addr : 0x9200 - - name : CH3 + - name : DATA_CH3 type : fei4_rx interface : ETH base_addr : 0x9300 - - name : CH4 + - name : DATA_CH4 type : fei4_rx interface : ETH base_addr : 0x9400 - - name : SRAM - type : sram_fifo + - name : SITCP_FIFO + type : sitcp_fifo interface : ETH - base_addr : 0x200000000 - base_data_addr : 0x100000000 - - name : TDC + - name : TDC_CH0 type : tdc_s3 interface : ETH base_addr : 0xa000 - - name : TDC1 + - name : TDC_CH1 type : tdc_s3 interface : ETH base_addr : 0xa100 - - name : TDC2 + - name : TDC_CH2 type : tdc_s3 interface : ETH base_addr : 0xa200 - - name : TDC3 + - name : TDC_CH3 type : tdc_s3 interface : ETH base_addr : 0xa300 - - name : TDC4 + - name : TDC_CH4 type : tdc_s3 interface : ETH base_addr : 0xa400 - - name : TLU - type : tlu - interface : ETH - base_addr : 0x8200 - - name : DLY_CONFIG_GPIO type : gpio interface : ETH @@ -91,7 +85,6 @@ hw_drivers: size : 48 registers: - - name : DLY_CONFIG type : StdRegister hw_driver : DLY_CONFIG_GPIO diff --git a/pybar/dut_mmc3_m26_eth.yaml b/pybar/dut_mmc3_m26_eth.yaml index 292fa88b9..a5781614d 100644 --- a/pybar/dut_mmc3_m26_eth.yaml +++ b/pybar/dut_mmc3_m26_eth.yaml @@ -4,6 +4,7 @@ # SiLab, Institute of Physics, University of Bonn # ------------------------------------------------------------ # +# MMC3 board with single FEI4 and max. 6 Mimosa26 name : mmc3_m26_eth version : 0.1 @@ -11,11 +12,6 @@ version : 0.1 transfer_layer: - name : ETH type : SiTcp - init: - ip : "192.168.10.16" - udp_port : 4660 - tcp_port : 24 - tcp_connection : True # The power supply that powers the Mimosa 26 plane # Can be commented out if no communication to the @@ -39,16 +35,22 @@ hw_drivers: init : device : Agilent E3644A - - name : CMD + - name : TRIGGER_FEI4 + type : tlu + interface : ETH + base_addr : 0x8200 + + - name : CMD_FEI4 type : cmd_seq interface : ETH base_addr : 0x0000 - + +# Remove not used Mimosa26 planes by commenting out the drivers - name : M26_RX1 type : m26_rx interface : ETH base_addr : 0xa000 - + - name : M26_RX2 type : m26_rx interface : ETH @@ -68,44 +70,37 @@ hw_drivers: type : m26_rx interface : ETH base_addr : 0xa040 - + - name : M26_RX6 type : m26_rx interface : ETH base_addr : 0xa050 - - name : CH0 + - name : DATA_FEI4 type : fei4_rx interface : ETH base_addr : 0x8600 - - - name : SRAM - type : sram_fifo + + - name : SITCP_FIFO + type : sitcp_fifo interface : ETH - base_addr : 0x200000000 - base_data_addr : 0x100000000 - - name : TDC + - name : TDC_FEI4 type : tdc_s3 interface : ETH base_addr : 0x8700 - - name : TLU - type : tlu - interface : ETH - base_addr : 0x8200 - - - name : gpio_jtag + - name : GPIO_JTAG type : gpio interface : ETH base_addr : 0xb000 size : 8 - - - name : jtag + + - name : JTAG type : JtagGpio - hw_driver : gpio_jtag - size : 8 - + hw_driver : GPIO_JTAG + size : 8 + registers: - name : DEV_ID_ALL type : StdRegister @@ -116,7 +111,7 @@ registers: offset : 191 size : 32 repeat : 6 - fields : + fields : - name : ID_CODE size : 32 offset : 31 @@ -129,7 +124,7 @@ registers: offset : 59 size : 10 repeat : 6 - fields : + fields : - name : Test1Pad size : 1 offset : 0 @@ -160,7 +155,7 @@ registers: offset : 911 size : 152 repeat : 6 - fields : + fields : - name : ICLPDISC size : 8 offset : 7 @@ -227,7 +222,7 @@ registers: offset : 6911 size : 1152 repeat : 6 - fields : + fields : - name : LinePatL0Reg size : 1152 offset : 1151 @@ -240,7 +235,7 @@ registers: offset : 6911 size : 1152 repeat : 6 - fields : + fields : - name : DisableLatch size : 1152 offset : 1151 @@ -253,7 +248,7 @@ registers: offset : 767 size : 128 repeat : 6 - fields : + fields : - name : DataPwrOn size : 32 offset : 31 @@ -284,7 +279,7 @@ registers: offset : 239 size : 40 repeat : 6 - fields : + fields : - name : RowMka size : 10 offset : 9 @@ -312,7 +307,7 @@ registers: offset : 6911 size : 1152 repeat : 6 - fields : + fields : - name : LinePatL1Reg size : 1152 offset : 1151 @@ -325,7 +320,7 @@ registers: offset : 959 size : 160 repeat : 6 - fields : + fields : - name : drstframe size : 16 offset : 15 @@ -359,13 +354,13 @@ registers: - name : HEADER_REG_ALL type : StdRegister size : 384 - driver : None + driver : None fields: - name : HEADER_REG offset : 383 size : 64 repeat : 6 - fields : + fields : - name : trailer1 size : 16 offset : 15 @@ -387,7 +382,7 @@ registers: offset : 287 size : 48 repeat : 6 - fields : + fields : - name : cfgadr size : 3 offset : 2 @@ -466,8 +461,8 @@ registers: fields : - name : Ctrl8b10bReg1 size : 312 - offset : 311 - + offset : 311 + - name : RO_MODE0_ALL type : StdRegister size : 48 @@ -477,7 +472,7 @@ registers: offset : 47 size : 8 repeat : 6 - fields : + fields : - name : JTAG_Start size : 1 offset : 0 @@ -512,7 +507,7 @@ registers: offset : 47 size : 8 repeat : 6 - fields : + fields : - name : EnTestDiscri size : 1 offset : 0 @@ -546,7 +541,7 @@ registers: offset : 5 size : 1 repeat : 6 - fields : + fields : - name : BYPASS size : 1 - offset : 0 \ No newline at end of file + offset : 0 diff --git a/pybar/dut_nexys4.yaml b/pybar/dut_nexys4.yaml index 870f1beec..0d5312a14 100644 --- a/pybar/dut_nexys4.yaml +++ b/pybar/dut_nexys4.yaml @@ -13,39 +13,36 @@ transfer_layer: type : SiTcp hw_drivers: - - name : I2C type : i2c interface : ETH base_addr : 0x8800 - - name : CMD + - name : CMD_CH1_TO_CH4 type : cmd_seq interface : ETH base_addr : 0x0000 - - name : SRAM - type : sram_fifo + - name : SITCP_FIFO + type : sitcp_fifo interface : ETH - base_addr : 0x200000000 - base_data_addr : 0x100000000 - - name : CH3 + - name : DATA_CH4 type : fei4_rx interface : ETH base_addr : 0x8300 - - name : CH2 + - name : DATA_CH3 type : fei4_rx interface : ETH base_addr : 0x8400 - - name : CH1 + - name : DATA_CH2 type : fei4_rx interface : ETH base_addr : 0x8500 - - name : CH0 + - name : DATA_CH1 type : fei4_rx interface : ETH base_addr : 0x8600 @@ -55,12 +52,12 @@ hw_drivers: interface : ETH base_addr : 0x8700 - - name : TLU + - name : TRIGGER_CH1_TO_CH4 type : tlu interface : ETH base_addr : 0x8200 - - name : TDC + - name : TDC_PIN_D14 type : tdc_s3 interface : ETH base_addr : 0x8100 @@ -77,15 +74,15 @@ registers: - name : TLU size : 1 offset : 4 - - name : CH4 + - name : DATA_CH4 size : 1 offset : 3 - - name : CH3 + - name : DATA_CH3 size : 1 offset : 2 - - name : CH2 + - name : DATA_CH2 size : 1 offset : 1 - - name : CH1 + - name : DATA_CH1 size : 1 offset : 0 diff --git a/pybar/fei4/register.py b/pybar/fei4/register.py index d8ba885fb..9fc861e5f 100644 --- a/pybar/fei4/register.py +++ b/pybar/fei4/register.py @@ -23,7 +23,7 @@ class FEI4Register(object): def __init__(self, configuration_file=None, fe_type=None, chip_address=None, broadcast=False): - ''' + '''FE-I4 register class. Note: Chip ID: This 4-bit field consists of broadcast bit and chip address. The broadcast bit, the most significant one, if set, means that the command is broadcasted to all FE chips receiving the data stream. @@ -33,22 +33,24 @@ def __init__(self, configuration_file=None, fe_type=None, chip_address=None, bro if fe_type: self.init_fe_type(fe_type) - self.broadcast = broadcast + self.broadcast = None self.chip_address = None if chip_address is None: chip_address = 0 - self.set_chip_address(chip_address) self.configuration_file = fe_type if configuration_file: self.load_configuration(configuration_file) + else: + self.set_chip_address(chip_address, broadcast) self.config_state = OrderedDict() def __repr__(self): return self.configuration_file - def set_chip_address(self, chip_address): + def set_chip_address(self, chip_address, broadcast): + self.broadcast = broadcast if 7 < chip_address < 0: raise ValueError('Chip address out of range: %i' % chip_address) self.chip_id_initialized = True @@ -250,7 +252,9 @@ def get_commands(self, command_name, **kwargs): if not self.broadcast: self.set_global_register_value("Colpr_Mode", 0) # write only to the addressed double-column self.set_global_register_value("Colpr_Addr", 40) # ivalid address, grounded - commands.extend(self.get_commands("ConfMode", ChipID=8)) # set all chips to conf mode to receive commands + # Broadcasting ConfMode not necessary, writing registers is also possible in RunMode +# commands.extend(self.get_commands("ConfMode", ChipID=8)) # set all chips to conf mode to receive commands# + # set all other chips to invalid addresses, to make broadcasting of WrRegister command possible commands.extend(self.get_commands("WrRegister", name=["Colpr_Mode", "Colpr_Addr"], ChipID=8)) # braodcast self.set_global_register_value("S0", 0) self.set_global_register_value("S1", 0) @@ -594,11 +598,11 @@ def get_pixel_register_bitset(self, register_object, bit_no, dc_no): @contextmanager def restored(self, name=None): - self.create_restore_point(name) + name = self.create_restore_point(name=name) try: yield finally: - self.restore() + self.restore(name=name) def create_restore_point(self, name=None): '''Creating a configuration restore point. @@ -620,6 +624,7 @@ def create_restore_point(self, name=None): if name in self.config_state: raise ValueError('Restore point %s already exists' % name) self.config_state[name] = (copy.deepcopy(self.global_registers), copy.deepcopy(self.pixel_registers)) + return name def restore(self, name=None, keep=False, last=True, global_register=True, pixel_register=True): '''Restoring a configuration restore point. @@ -685,6 +690,23 @@ def can_restore(self): return False +class BroadcastRegister(FEI4Register): + + ''' Defiens a FE-I4 register object for storing register settings to be + broadcasted to multiple Front-Ends. + ''' + + def __init__(self, fe_type=None): + super(BroadcastRegister, self).__init__(configuration_file=None, + fe_type=fe_type, chip_address=None, + broadcast=True) + + def get_commands(self, command_name, **kwargs): + if 'RdRegister' in command_name: + logging.warning('Reading registers in broadcast mode') + return super(BroadcastRegister, self).get_commands(command_name, **kwargs) + + class NameValue(tb.IsDescription): name = tb.StringCol(256, pos=0) value = tb.StringCol(1024, pos=0) @@ -720,8 +742,7 @@ def load_configuration_from_text_file(register, configuration_file): if register.chip_address: pass else: - register.broadcast = True if chip_id & 0x8 else False - register.set_chip_address(chip_id & 0x7) + register.set_chip_address(chip_address=chip_id & 0x7, broadcast=True if chip_id & 0x8 else False) elif 'Chip_Address' in config_dict: chip_address = config_dict.pop('Chip_Address') if register.chip_address: @@ -795,13 +816,12 @@ def load_conf(): if register.chip_address: pass else: - register.broadcast = True if value & 0x8 else False - register.set_chip_address(value & 0x7) + register.set_chip_address(chip_address=value & 0x7, broadcast=True if value & 0x8 else False) elif name == 'Chip_Address': if register.chip_address: pass else: - register.set_chip_address(value) + register.set_chip_address(chip_address=value, broadcast=False) else: register.miscellaneous[name] = value diff --git a/pybar/fei4/register_utils.py b/pybar/fei4/register_utils.py index 606659473..8d6309445 100644 --- a/pybar/fei4/register_utils.py +++ b/pybar/fei4/register_utils.py @@ -69,7 +69,7 @@ def send_commands(self, commands, repeat=1, wait_for_finish=True, concatenate=Tr else: max_length = 0 if repeat is not None: - self.dut['CMD']['CMD_REPEAT'] = repeat + self.dut['TX']['CMD_REPEAT'] = repeat for command in commands: max_length = max(command.length(), max_length) self.send_command(command=command, repeat=None, wait_for_finish=wait_for_finish, set_length=True, clear_memory=False, use_timeout=use_timeout) @@ -78,11 +78,11 @@ def send_commands(self, commands, repeat=1, wait_for_finish=True, concatenate=Tr def send_command(self, command, repeat=1, wait_for_finish=True, set_length=True, clear_memory=False, use_timeout=True): if repeat is not None: - self.dut['CMD']['CMD_REPEAT'] = repeat + self.dut['TX']['CMD_REPEAT'] = repeat # write command into memory command_length = self.set_command(command, set_length=set_length) # sending command - self.dut['CMD']['START'] + self.dut['TX']['START'] # wait for command to be finished if wait_for_finish: self.wait_for_command(length=command_length, repeat=repeat, use_timeout=use_timeout) @@ -97,18 +97,18 @@ def set_command(self, command, set_length=True, byte_offset=0): command_length = command.length() # set command bit length if set_length: - self.dut['CMD']['CMD_SIZE'] = command_length + self.dut['TX']['CMD_SIZE'] = command_length # set command data = bitarray_to_array(command) - self.dut['CMD'].set_data(data=data, addr=byte_offset) + self.dut['TX'].set_data(data=data, addr=byte_offset) return command_length def wait_for_command(self, length=None, repeat=None, use_timeout=True): # for scans using the scan loop, reading length and repeat will decrease processor load by 30 to 50%, but has a marginal influence on scan time if length is None: - length = self.dut['CMD']['CMD_SIZE'] - self.dut['CMD']['START_SEQUENCE_LENGTH'] - self.dut['CMD']['STOP_SEQUENCE_LENGTH'] + length = self.dut['TX']['CMD_SIZE'] - self.dut['TX']['START_SEQUENCE_LENGTH'] - self.dut['TX']['STOP_SEQUENCE_LENGTH'] if repeat is None: - repeat = self.dut['CMD']['CMD_REPEAT'] + repeat = self.dut['TX']['CMD_REPEAT'] if length and repeat > 1: delay = length * 25e-9 * repeat if delay <= 0.0: @@ -120,8 +120,8 @@ def wait_for_command(self, length=None, repeat=None, use_timeout=True): if delay is not None and delay > 0.0: timeout += delay # adding command delay to timeout try: - msg = "Time out while waiting for sending command becoming ready in %s, module %s. Power cycle or reset readout board!" % (self.dut['CMD'].name, self.dut['CMD'].__class__.__module__) - if not self.dut['CMD'].wait_for_ready(timeout=timeout, times=None, delay=delay, abort=self.abort) and not self.abort.is_set(): + msg = "Time out while waiting for sending command becoming ready in %s, module %s. Power cycle or reset readout board!" % (self.dut['TX'].name, self.dut['TX'].__class__.__module__) + if not self.dut['TX'].wait_for_ready(timeout=timeout, times=None, delay=delay, abort=self.abort) and not self.abort.is_set(): raise CmdTimeoutError(msg) except RuntimeError: raise CmdTimeoutError(msg) @@ -133,7 +133,17 @@ def wait_for_command(self, length=None, repeat=None, use_timeout=True): @property def is_ready(self): - return True if self.dut['CMD']['READY'] else False + return True if self.dut['TX']['READY'] else False + + def set_conf_mode(self): + commands = [] + commands.extend(self.register.get_commands("ConfMode")) + self.send_commands(commands) + + def set_run_mode(self): + commands = [] + commands.extend(self.register.get_commands("RunMode")) + self.send_commands(commands) def global_reset(self): '''FEI4 Global Reset @@ -148,7 +158,7 @@ def global_reset(self): time.sleep(0.1) commands = [] commands.extend(self.register.get_commands("ConfMode")) - commands.extend(self.register.get_commands("RunMode")) +# commands.extend(self.register.get_commands("RunMode")) self.send_commands(commands) def reset_service_records(self): @@ -166,6 +176,7 @@ def reset_service_records(self): self.register.set_global_register_value('ReadErrorReq', 0) commands.extend(self.register.get_commands("WrRegister", name=['ReadErrorReq'])) commands.extend(self.register.get_commands("RunMode")) + commands.extend(self.register.get_commands("ConfMode")) self.send_commands(commands) def reset_bunch_counter(self): @@ -179,7 +190,6 @@ def reset_bunch_counter(self): time.sleep(0.1) commands = [] commands.extend(self.register.get_commands("ConfMode")) - commands.extend(self.register.get_commands("RunMode")) self.send_commands(commands) def reset_event_counter(self): @@ -193,7 +203,6 @@ def reset_event_counter(self): time.sleep(0.1) commands = [] commands.extend(self.register.get_commands("ConfMode")) - commands.extend(self.register.get_commands("RunMode")) self.send_commands(commands) def configure_all(self, same_mask_for_all_dc=False): @@ -205,15 +214,15 @@ def configure_global(self): commands = [] commands.extend(self.register.get_commands("ConfMode")) commands.extend(self.register.get_commands("WrRegister", readonly=False)) - commands.extend(self.register.get_commands("RunMode")) - self.send_commands(commands, concatenate=True) +# commands.extend(self.register.get_commands("RunMode")) + self.send_commands(commands) def configure_pixel(self, same_mask_for_all_dc=False): logging.info('Sending pixel configuration to FE') commands = [] commands.extend(self.register.get_commands("ConfMode")) commands.extend(self.register.get_commands("WrFrontEnd", same_mask_for_all_dc=same_mask_for_all_dc, name=["TDAC", "FDAC", "Imon", "Enable", "C_High", "C_Low", "EnableDigInj"])) - commands.extend(self.register.get_commands("RunMode")) +# commands.extend(self.register.get_commands("RunMode")) self.send_commands(commands) def set_gdac(self, value, send_command=True): @@ -263,23 +272,23 @@ def read_chip_sn(self): commands = [] commands.extend(self.register.get_commands("ConfMode")) self.register_utils.send_commands(commands) - self.fifo_readout.reset_sram_fifo() - if self.register.fei4b: + with self.readout(fill_buffer=True, callback=None, errback=None): + if self.register.fei4b: + commands = [] + self.register.set_global_register_value('Efuse_Sense', 1) + commands.extend(self.register.get_commands("WrRegister", name=['Efuse_Sense'])) + commands.extend(self.register.get_commands("GlobalPulse", Width=0)) + self.register.set_global_register_value('Efuse_Sense', 0) + commands.extend(self.register.get_commands("WrRegister", name=['Efuse_Sense'])) + self.register_utils.send_commands(commands) commands = [] - self.register.set_global_register_value('Efuse_Sense', 1) - commands.extend(self.register.get_commands("WrRegister", name=['Efuse_Sense'])) - commands.extend(self.register.get_commands("GlobalPulse", Width=0)) - self.register.set_global_register_value('Efuse_Sense', 0) - commands.extend(self.register.get_commands("WrRegister", name=['Efuse_Sense'])) + self.register.set_global_register_value('Conf_AddrEnable', 1) + commands.extend(self.register.get_commands("WrRegister", name=['Conf_AddrEnable'])) + chip_sn_address = self.register.get_global_register_attributes("addresses", name="Chip_SN") + commands.extend(self.register.get_commands("RdRegister", addresses=chip_sn_address)) self.register_utils.send_commands(commands) - commands = [] - self.register.set_global_register_value('Conf_AddrEnable', 1) - commands.extend(self.register.get_commands("WrRegister", name=['Conf_AddrEnable'])) - chip_sn_address = self.register.get_global_register_attributes("addresses", name="Chip_SN") - commands.extend(self.register.get_commands("RdRegister", addresses=chip_sn_address)) - self.register_utils.send_commands(commands) + data = self.read_data() - data = self.fifo_readout.read_data() if data.shape[0] == 0: logging.error('Chip S/N: No data') return @@ -292,9 +301,9 @@ def read_chip_sn(self): read_value = fei4_next_data_word['value'] read_values.append(read_value) - commands = [] - commands.extend(self.register.get_commands("RunMode")) - self.register_utils.send_commands(commands) +# commands = [] +# commands.extend(self.register.get_commands("RunMode")) +# self.register_utils.send_commands(commands) if len(read_values) == 0: logging.error('No Chip S/N was found') @@ -311,18 +320,16 @@ def test_global_register(self): self.register_utils.configure_global() commands = [] commands.extend(self.register.get_commands("ConfMode")) - self.register_utils.send_commands(commands) - commands = [] self.register.set_global_register_value('Conf_AddrEnable', 1) commands.extend(self.register.get_commands("WrRegister", name='Conf_AddrEnable')) self.register_utils.send_commands(commands) - self.fifo_readout.reset_sram_fifo() - commands = [] - read_from_address = self.register.get_global_register_attributes("addresses", readonly=False) - commands.extend(self.register.get_commands("RdRegister", addresses=read_from_address)) - self.register_utils.send_commands(commands) - time.sleep(1.0) # wait for data - data = self.fifo_readout.read_data() + with self.readout(fill_buffer=True, callback=None, errback=None): + commands = [] + read_from_address = self.register.get_global_register_attributes("addresses", readonly=False) + commands.extend(self.register.get_commands("RdRegister", addresses=read_from_address)) + self.register_utils.send_commands(commands) + data = self.read_data() + if data.shape[0] == 0: logging.error('Global Register Test: No data') return 1 @@ -347,9 +354,9 @@ def test_global_register(self): number_of_errors += 1 logging.warning('Global Register Test: Expected Value Record but found %s', fei4_next_data_word) - commands = [] - commands.extend(self.register.get_commands("RunMode")) - self.register_utils.send_commands(commands) +# commands = [] +# commands.extend(self.register.get_commands("RunMode")) +# self.register_utils.send_commands(commands) not_read_registers = set.difference(set(read_from_address), checked_address) not_read_registers = list(not_read_registers) not_read_registers.sort() @@ -368,7 +375,6 @@ def test_pixel_register(self): commands = [] commands.extend(self.register.get_commands("ConfMode")) self.register_utils.send_commands(commands) - self.fifo_readout.reset_sram_fifo() commands = [] self.register.set_global_register_value('Conf_AddrEnable', 1) @@ -412,38 +418,40 @@ def test_pixel_register(self): commands.extend(self.register.get_commands("WrRegister", name=["Pixel_Strobes"])) self.register_utils.send_commands(commands) for dc_no in range(40): - commands = [] - self.register.set_global_register_value("Colpr_Addr", dc_no) - commands.extend(self.register.get_commands("WrRegister", name=["Colpr_Addr"])) - self.register_utils.send_commands(commands) + with self.readout(fill_buffer=True, callback=None, errback=None): + commands = [] + self.register.set_global_register_value("Colpr_Addr", dc_no) + commands.extend(self.register.get_commands("WrRegister", name=["Colpr_Addr"])) + self.register_utils.send_commands(commands) - if do_latch is True: + if do_latch is True: + commands = [] + self.register.set_global_register_value("S0", 1) + self.register.set_global_register_value("S1", 1) + self.register.set_global_register_value("SR_Clock", 1) + commands.extend(self.register.get_commands("WrRegister", name=["S0", "S1", "SR_Clock"])) + commands.extend(self.register.get_commands("GlobalPulse", Width=0)) + self.register_utils.send_commands(commands) commands = [] - self.register.set_global_register_value("S0", 1) - self.register.set_global_register_value("S1", 1) - self.register.set_global_register_value("SR_Clock", 1) + self.register.set_global_register_value("S0", 0) + self.register.set_global_register_value("S1", 0) + self.register.set_global_register_value("SR_Clock", 0) commands.extend(self.register.get_commands("WrRegister", name=["S0", "S1", "SR_Clock"])) - commands.extend(self.register.get_commands("GlobalPulse", Width=0)) self.register_utils.send_commands(commands) - commands = [] - self.register.set_global_register_value("S0", 0) - self.register.set_global_register_value("S1", 0) - self.register.set_global_register_value("SR_Clock", 0) - commands.extend(self.register.get_commands("WrRegister", name=["S0", "S1", "SR_Clock"])) - self.register_utils.send_commands(commands) - - register_bitset = self.register.get_pixel_register_bitset(register_object, pxstrobe_bit_no if (register_object['littleendian'] is False) else register_object['bitlength'] - pxstrobe_bit_no - 1, dc_no) - - commands = [] - if self.register.fei4b: - self.register.set_global_register_value("SR_Read", 1) - commands.extend(self.register.get_commands("WrRegister", name=["SR_Read"])) - commands.extend([self.register.build_command("WrFrontEnd", pixeldata=register_bitset, chipid=self.register.chip_id)]) - if self.register.fei4b: - self.register.set_global_register_value("SR_Read", 0) - commands.extend(self.register.get_commands("WrRegister", name=["SR_Read"])) - self.register_utils.send_commands(commands) - data = self.fifo_readout.read_data() + + register_bitset = self.register.get_pixel_register_bitset(register_object, pxstrobe_bit_no if (register_object['littleendian'] is False) else register_object['bitlength'] - pxstrobe_bit_no - 1, dc_no) + + commands = [] + if self.register.fei4b: + self.register.set_global_register_value("SR_Read", 1) + commands.extend(self.register.get_commands("WrRegister", name=["SR_Read"])) + commands.extend([self.register.build_command("WrFrontEnd", pixeldata=register_bitset, chipid=self.register.chip_id)]) + if self.register.fei4b: + self.register.set_global_register_value("SR_Read", 0) + commands.extend(self.register.get_commands("WrRegister", name=["SR_Read"])) + self.register_utils.send_commands(commands) + data = self.read_data() + if data.shape[0] == 0: # no data if do_latch: logging.error('Pixel Register Test: No data from PxStrobes Bit %d at DC %d', pxstrobe + pxstrobe_bit_no, dc_no) @@ -523,7 +531,7 @@ def test_pixel_register(self): commands.extend(self.register.get_commands("WrRegister", name=["Colpr_Addr", "Pixel_Strobes", "S0", "S1", "SR_Clock"])) # fixes bug in FEI4 (B only?): reading GR doesn't work after latching pixel register commands.extend(self.register.get_commands("WrFrontEnd", name=["EnableDigInj"])) - commands.extend(self.register.get_commands("RunMode")) +# commands.extend(self.register.get_commands("RunMode")) self.register_utils.send_commands(commands) logging.info('Pixel Register Test: Found %d error(s)', number_of_errors) @@ -544,15 +552,16 @@ def read_global_register(self, name, overwrite_config=False): ''' self.register_utils.send_commands(self.register.get_commands("ConfMode")) - commands = [] - commands.extend(self.register.get_commands("RdRegister", name=name)) - self.register_utils.send_commands(commands) - - data = self.fifo_readout.read_data() + with self.readout(fill_buffer=True, callback=None, errback=None): + commands = [] + commands.extend(self.register.get_commands("RdRegister", name=name)) + self.register_utils.send_commands(commands) + data = self.read_data() register_object = self.register.get_global_register_objects(name=[name])[0] value = BitLogic(register_object['addresses'] * 16) index = 0 + vr_count = 0 for word in np.nditer(data): fei4_data_word = FEI4Record(word, self.register.chip_flavor) if fei4_data_word == 'AR': @@ -560,6 +569,9 @@ def read_global_register(self, name, overwrite_config=False): if address_value != register_object['address'] + index: raise Exception('Unexpected address from Address Record: read: %d, expected: %d' % (address_value, register_object['address'] + index)) elif fei4_data_word == 'VR': + vr_count += 1 + if vr_count >= 2: + raise RuntimeError("Read more than 2 value records") read_value = BitLogic.from_value(fei4_data_word['value'], size=16) if register_object['register_littleendian']: read_value.reverse() @@ -574,6 +586,15 @@ def read_global_register(self, name, overwrite_config=False): return value +def write_global_register(self, parameter, value): + commands = [] + commands.extend(self.register.get_commands("ConfMode")) + self.register.set_global_register_value(parameter, value) + commands.extend(self.register.get_commands("WrRegister", name=[parameter])) +# commands.extend(self.register.get_commands("RunMode")) + self.register_utils.send_commands(commands) + + def read_pixel_register(self, pix_regs=None, dcs=range(40), overwrite_config=False): '''The function reads the pixel register, interprets the data and returns a masked numpy arrays with the data for the chosen pixel register. Pixels without any data are masked. @@ -601,8 +622,10 @@ def read_pixel_register(self, pix_regs=None, dcs=range(40), overwrite_config=Fal for pix_reg in pix_regs: pixel_data = np.ma.masked_array(np.zeros(shape=(80, 336), dtype=np.uint32), mask=True) # the result pixel array, only pixel with data are not masked for dc in dcs: - self.register_utils.send_commands(self.register.get_commands("RdFrontEnd", name=[pix_reg], dcs=[dc])) - data = self.fifo_readout.read_data() + with self.readout(fill_buffer=True, callback=None, errback=None): + self.register_utils.send_commands(self.register.get_commands("RdFrontEnd", name=[pix_reg], dcs=[dc])) + data = self.read_data() + interpret_pixel_data(data, dc, pixel_data, invert=False if pix_reg == "EnableDigInj" else True) if overwrite_config: self.register.set_pixel_register(pix_reg, pixel_data.data) @@ -611,7 +634,7 @@ def read_pixel_register(self, pix_regs=None, dcs=range(40), overwrite_config=Fal def is_fe_ready(self): - '''Get FEI4 status. + '''Get FEI4 status of module. If FEI4 is not ready, resetting service records is necessary to bring the FEI4 to a defined state. @@ -620,13 +643,15 @@ def is_fe_ready(self): value : bool True if FEI4 is ready, False if the FEI4 was powered up recently and is not ready. ''' - commands = [] - commands.extend(self.register.get_commands("ConfMode")) - commands.extend(self.register.get_commands("RdRegister", address=[1])) - commands.extend(self.register.get_commands("RunMode")) - self.register_utils.send_commands(commands) - data = self.fifo_readout.read_data() - if len(data): + with self.readout(fill_buffer=True, callback=None, errback=None): + commands = [] + commands.extend(self.register.get_commands("ConfMode")) + commands.extend(self.register.get_commands("RdRegister", address=[1])) +# commands.extend(self.register.get_commands("RunMode")) + self.register_utils.send_commands(commands) + data = self.read_data() + + if len(data) != 0: return True if FEI4Record(data[-1], self.register.chip_flavor) == 'VR' else False else: return False @@ -950,243 +975,173 @@ def scan_loop(self, command, repeat_command=100, use_delay=True, additional_dela # initial PlsrDAC value for PlsrDAC correction initial_plsr_dac = self.register.get_global_register_value("PlsrDAC") # create restore point - restore_point_name = str(self.run_number) + self.run_id + '_scan_loop' - self.register.create_restore_point(name=restore_point_name) - - # pre-calculate often used commands - conf_mode_command = self.register.get_commands("ConfMode")[0] - run_mode_command = self.register.get_commands("RunMode")[0] - if use_delay: - delay = self.register.get_commands("zeros", length=additional_delay + calculate_wait_cycles(mask_steps))[0] - scan_loop_command = command + delay - else: - scan_loop_command = command - - def enable_columns(dc): - if digital_injection: - return [dc * 2 + 1, dc * 2 + 2] - else: # analog injection - if dc == 0: - return [1] - elif dc == 39: - return [78, 79, 80] - else: - return [dc * 2, dc * 2 + 1] - - def write_double_columns(dc): - if digital_injection: - return [dc] - else: # analog injection - if dc == 0: - return [0] - elif dc == 39: - return [38, 39] - else: - return [dc - 1, dc] - - def get_dc_address_command(dc): - commands = [] - commands.append(conf_mode_command) - self.register.set_global_register_value("Colpr_Addr", dc) - commands.append(self.register.get_commands("WrRegister", name=["Colpr_Addr"])[0]) - if double_column_correction: - self.register.set_global_register_value("PlsrDAC", initial_plsr_dac + int(round(plsr_dac_correction[dc]))) - commands.append(self.register.get_commands("WrRegister", name=["PlsrDAC"])[0]) - commands.append(run_mode_command) - return self.register_utils.concatenate_commands(commands, byte_padding=True) - - if not enable_mask_steps: - enable_mask_steps = range(mask_steps) - - if not enable_double_columns: - enable_double_columns = range(40) + restore_point_name = str(self.run_number) + '_' + self.run_id + '_scan_loop' + with self.register.restored(name=restore_point_name): + # pre-calculate often used commands + conf_mode_command = self.register.get_commands("ConfMode")[0] + run_mode_command = self.register.get_commands("RunMode")[0] + if use_delay: + delay = self.register.get_commands("zeros", length=additional_delay + calculate_wait_cycles(mask_steps))[0] + scan_loop_command = command + delay + else: + scan_loop_command = command + + def enable_columns(dc): + if digital_injection: + return [dc * 2 + 1, dc * 2 + 2] + else: # analog injection + if dc == 0: + return [1] + elif dc == 39: + return [78, 79, 80] + else: + return [dc * 2, dc * 2 + 1] + + def write_double_columns(dc): + if digital_injection: + return [dc] + else: # analog injection + if dc == 0: + return [0] + elif dc == 39: + return [38, 39] + else: + return [dc - 1, dc] - # preparing for scan - commands = [] - commands.append(conf_mode_command) - if digital_injection is True: - # check if C_High and/or C_Low is in enable_shift_mask and/or disable_shift_mask - if "C_High".lower() in map(lambda x: x.lower(), enable_shift_masks) or "C_High".lower() in map(lambda x: x.lower(), disable_shift_masks): - raise ValueError('C_High must not be shift mask when using digital injection') - if "C_Low".lower() in map(lambda x: x.lower(), enable_shift_masks) or "C_Low".lower() in map(lambda x: x.lower(), disable_shift_masks): - raise ValueError('C_Low must not be shift mask when using digital injection') - # turn off all injection capacitors by default - self.register.set_pixel_register_value("C_High", 0) - self.register.set_pixel_register_value("C_Low", 0) - commands.extend(self.register.get_commands("WrFrontEnd", same_mask_for_all_dc=True, name=["C_Low", "C_High"], joint_write=True)) - self.register.set_global_register_value("DIGHITIN_SEL", 1) -# self.register.set_global_register_value("CalEn", 1) # for GlobalPulse instead Cal-Command - else: - self.register.set_global_register_value("DIGHITIN_SEL", 0) - # setting EnableDigInj to 0 not necessary since DIGHITIN_SEL is turned off -# self.register.set_pixel_register_value("EnableDigInj", 0) - -# plotting registers -# plt.clf() -# plt.imshow(curr_en_mask.T, interpolation='nearest', aspect="auto") -# plt.pcolor(curr_en_mask.T) -# plt.colorbar() -# plt.savefig('mask_step' + str(mask_step) + '.pdf') - - commands.extend(self.register.get_commands("WrRegister", name=["DIGHITIN_SEL"])) - self.register_utils.send_commands(commands, concatenate=True) - - for mask_step in enable_mask_steps: - if self.stop_run.is_set(): - break + def get_dc_address_command(dc): + commands = [] + commands.append(conf_mode_command) + self.register.set_global_register_value("Colpr_Addr", dc) + commands.append(self.register.get_commands("WrRegister", name=["Colpr_Addr"])[0]) + if double_column_correction: + self.register.set_global_register_value("PlsrDAC", initial_plsr_dac + int(round(plsr_dac_correction[dc]))) + commands.append(self.register.get_commands("WrRegister", name=["PlsrDAC"])[0]) + commands.append(run_mode_command) + return self.register_utils.concatenate_commands(commands, byte_padding=True) + + if not enable_mask_steps: + enable_mask_steps = range(mask_steps) + + if not enable_double_columns: + enable_double_columns = range(40) + + # preparing for scan commands = [] commands.append(conf_mode_command) - if same_mask_for_all_dc: # generate and write first mask step - if disable_shift_masks: - curr_dis_mask = make_pixel_mask(steps=mask_steps, shift=mask_step, default=1, value=0, mask=mask) - map(lambda mask_name: self.register.set_pixel_register_value(mask_name, curr_dis_mask), disable_shift_masks) - commands.extend(self.register.get_commands("WrFrontEnd", same_mask_for_all_dc=False if mask is not None else True, name=disable_shift_masks, joint_write=True)) - if enable_shift_masks: - curr_en_mask = make_pixel_mask(steps=mask_steps, shift=mask_step, mask=mask) - map(lambda mask_name: self.register.set_pixel_register_value(mask_name, curr_en_mask), enable_shift_masks) - commands.extend(self.register.get_commands("WrFrontEnd", same_mask_for_all_dc=False if mask is not None else True, name=enable_shift_masks, joint_write=True)) - if digital_injection is True: # write EnableDigInj last - # write DIGHITIN_SEL since after mask writing it is disabled - self.register.set_global_register_value("DIGHITIN_SEL", 1) - commands.extend(self.register.get_commands("WrRegister", name=["DIGHITIN_SEL"])) - else: # set masks to default values - if disable_shift_masks: - map(lambda mask_name: self.register.set_pixel_register_value(mask_name, 1), disable_shift_masks) - commands.extend(self.register.get_commands("WrFrontEnd", same_mask_for_all_dc=True, name=disable_shift_masks, joint_write=True)) - if enable_shift_masks: - map(lambda mask_name: self.register.set_pixel_register_value(mask_name, 0), enable_shift_masks) - commands.extend(self.register.get_commands("WrFrontEnd", same_mask_for_all_dc=True, name=enable_shift_masks, joint_write=True)) - if digital_injection is True: # write EnableDigInj last - # write DIGHITIN_SEL since after mask writing it is disabled - self.register.set_global_register_value("DIGHITIN_SEL", 1) - commands.extend(self.register.get_commands("WrRegister", name=["DIGHITIN_SEL"])) - self.register_utils.send_commands(commands, concatenate=True) - logging.info('%d injection(s): mask step %d %s', repeat_command, mask_step, ('[%d - %d]' % (enable_mask_steps[0], enable_mask_steps[-1])) if len(enable_mask_steps) > 1 else ('[%d]' % enable_mask_steps[0])) - - if same_mask_for_all_dc: - if fast_dc_loop: # fast DC loop with optimized pixel register writing - # set repeat, should be 1 by default when arriving here - self.dut['CMD']['CMD_REPEAT'] = repeat_command - - # get DC command for the first DC in the list, DC command is byte padded - # fill CMD memory with DC command and scan loop command, inside the loop only overwrite DC command - dc_address_command = get_dc_address_command(enable_double_columns[0]) - self.dut['CMD']['START_SEQUENCE_LENGTH'] = len(dc_address_command) - self.register_utils.set_command(command=self.register_utils.concatenate_commands((dc_address_command, scan_loop_command), byte_padding=False)) - - for index, dc in enumerate(enable_double_columns): - if self.stop_run.is_set(): - break - if index != 0: # full command is already set before loop - # get DC command before wait to save some time - dc_address_command = get_dc_address_command(dc) - self.register_utils.wait_for_command() - if eol_function: - eol_function() # do this after command has finished - # only set command after FPGA is ready - # overwrite only the DC command in CMD memory - self.register_utils.set_command(dc_address_command, set_length=False) # do not set length here, because it was already set up before the loop - - if bol_function: - bol_function() - - self.dut['CMD']['START'] - - # wait here before we go on because we just jumped out of the loop - self.register_utils.wait_for_command() - if eol_function: - eol_function() - self.dut['CMD']['START_SEQUENCE_LENGTH'] = 0 - - else: # the slow DC loop allows writing commands inside bol and eol functions - for index, dc in enumerate(enable_double_columns): - if self.stop_run.is_set(): - break - dc_address_command = get_dc_address_command(dc) - self.register_utils.send_command(dc_address_command) - - if bol_function: - bol_function() - - self.register_utils.send_command(scan_loop_command, repeat=repeat_command) - - if eol_function: - eol_function() - + if digital_injection is True: + # check if C_High and/or C_Low is in enable_shift_mask and/or disable_shift_mask + if "C_High".lower() in map(lambda x: x.lower(), enable_shift_masks) or "C_High".lower() in map(lambda x: x.lower(), disable_shift_masks): + raise ValueError('C_High must not be shift mask when using digital injection') + if "C_Low".lower() in map(lambda x: x.lower(), enable_shift_masks) or "C_Low".lower() in map(lambda x: x.lower(), disable_shift_masks): + raise ValueError('C_Low must not be shift mask when using digital injection') + # turn off all injection capacitors by default + self.register.set_pixel_register_value("C_High", 0) + self.register.set_pixel_register_value("C_Low", 0) + commands.extend(self.register.get_commands("WrFrontEnd", same_mask_for_all_dc=True, name=["C_Low", "C_High"], joint_write=True)) + self.register.set_global_register_value("DIGHITIN_SEL", 1) + # self.register.set_global_register_value("CalEn", 1) # for GlobalPulse instead Cal-Command else: - if fast_dc_loop: # fast DC loop with optimized pixel register writing - dc = enable_double_columns[0] - ec = enable_columns(dc) - dcs = write_double_columns(dc) - commands = [] - commands.append(conf_mode_command) + self.register.set_global_register_value("DIGHITIN_SEL", 0) + # setting EnableDigInj to 0 not necessary since DIGHITIN_SEL is turned off + # self.register.set_pixel_register_value("EnableDigInj", 0) + + # plotting registers + # plt.clf() + # plt.imshow(curr_en_mask.T, interpolation='nearest', aspect="auto") + # plt.pcolor(curr_en_mask.T) + # plt.colorbar() + # plt.savefig('mask_step' + str(mask_step) + '.pdf') + + commands.extend(self.register.get_commands("WrRegister", name=["DIGHITIN_SEL"])) + self.register_utils.send_commands(commands) + + for mask_step in enable_mask_steps: + if self.abort_run.is_set(): + break + commands = [] + commands.append(conf_mode_command) + if same_mask_for_all_dc: # generate and write first mask step if disable_shift_masks: - curr_dis_mask = make_pixel_mask(steps=mask_steps, shift=mask_step, default=1, value=0, enable_columns=ec, mask=mask) + curr_dis_mask = make_pixel_mask(steps=mask_steps, shift=mask_step, default=1, value=0, mask=mask) map(lambda mask_name: self.register.set_pixel_register_value(mask_name, curr_dis_mask), disable_shift_masks) - commands.extend(self.register.get_commands("WrFrontEnd", same_mask_for_all_dc=False, dcs=dcs, name=disable_shift_masks, joint_write=True)) + commands.extend(self.register.get_commands("WrFrontEnd", same_mask_for_all_dc=False if mask is not None else True, name=disable_shift_masks, joint_write=True)) if enable_shift_masks: - curr_en_mask = make_pixel_mask(steps=mask_steps, shift=mask_step, enable_columns=ec, mask=mask) + curr_en_mask = make_pixel_mask(steps=mask_steps, shift=mask_step, mask=mask) map(lambda mask_name: self.register.set_pixel_register_value(mask_name, curr_en_mask), enable_shift_masks) - commands.extend(self.register.get_commands("WrFrontEnd", same_mask_for_all_dc=False, dcs=dcs, name=enable_shift_masks, joint_write=True)) - if digital_injection is True: + commands.extend(self.register.get_commands("WrFrontEnd", same_mask_for_all_dc=False if mask is not None else True, name=enable_shift_masks, joint_write=True)) + if digital_injection is True: # write EnableDigInj last + # write DIGHITIN_SEL since after mask writing it is disabled self.register.set_global_register_value("DIGHITIN_SEL", 1) commands.extend(self.register.get_commands("WrRegister", name=["DIGHITIN_SEL"])) - self.register_utils.send_commands(commands, concatenate=True) - - dc_address_command = get_dc_address_command(dc) - self.dut['CMD']['START_SEQUENCE_LENGTH'] = len(dc_address_command) - self.dut['CMD']['CMD_REPEAT'] = repeat_command - self.register_utils.set_command(command=self.register_utils.concatenate_commands((dc_address_command, scan_loop_command), byte_padding=False)) + else: # set masks to default values + if disable_shift_masks: + map(lambda mask_name: self.register.set_pixel_register_value(mask_name, 1), disable_shift_masks) + commands.extend(self.register.get_commands("WrFrontEnd", same_mask_for_all_dc=True, name=disable_shift_masks, joint_write=True)) + if enable_shift_masks: + map(lambda mask_name: self.register.set_pixel_register_value(mask_name, 0), enable_shift_masks) + commands.extend(self.register.get_commands("WrFrontEnd", same_mask_for_all_dc=True, name=enable_shift_masks, joint_write=True)) + if digital_injection is True: # write EnableDigInj last + # write DIGHITIN_SEL since after mask writing it is disabled + self.register.set_global_register_value("DIGHITIN_SEL", 1) + commands.extend(self.register.get_commands("WrRegister", name=["DIGHITIN_SEL"])) + self.register_utils.send_commands(commands) + logging.info('%d injection(s): mask step %d %s', repeat_command, mask_step, ('[%d - %d]' % (enable_mask_steps[0], enable_mask_steps[-1])) if len(enable_mask_steps) > 1 else ('[%d]' % enable_mask_steps[0])) + + if same_mask_for_all_dc: + if fast_dc_loop: # fast DC loop with optimized pixel register writing + # set repeat, should be 1 by default when arriving here + self.dut['TX']['CMD_REPEAT'] = repeat_command + + # get DC command for the first DC in the list, DC command is byte padded + # fill CMD memory with DC command and scan loop command, inside the loop only overwrite DC command + dc_address_command = get_dc_address_command(enable_double_columns[0]) + self.dut['TX']['START_SEQUENCE_LENGTH'] = len(dc_address_command) + self.register_utils.set_command(command=self.register_utils.concatenate_commands((dc_address_command, scan_loop_command), byte_padding=False)) + + for index, dc in enumerate(enable_double_columns): + if self.abort_run.is_set(): + break + if index != 0: # full command is already set before loop + # get DC command before wait to save some time + dc_address_command = get_dc_address_command(dc) + self.register_utils.wait_for_command() + if eol_function: + eol_function() # do this after command has finished + # only set command after FPGA is ready + # overwrite only the DC command in CMD memory + self.register_utils.set_command(dc_address_command, set_length=False) # do not set length here, because it was already set up before the loop + + if bol_function: + bol_function() + + self.dut['TX']['START'] + + # wait here before we go on because we just jumped out of the loop + self.register_utils.wait_for_command() + if eol_function: + eol_function() + self.dut['TX']['START_SEQUENCE_LENGTH'] = 0 - for index, dc in enumerate(enable_double_columns): - if self.stop_run.is_set(): - break - if index != 0: # full command is already set before loop - ec = enable_columns(dc) - dcs = write_double_columns(dc) - dcs.extend(write_double_columns(enable_double_columns[index - 1])) - commands = [] - commands.append(conf_mode_command) - if disable_shift_masks: - curr_dis_mask = make_pixel_mask(steps=mask_steps, shift=mask_step, default=1, value=0, enable_columns=ec, mask=mask) - map(lambda mask_name: self.register.set_pixel_register_value(mask_name, curr_dis_mask), disable_shift_masks) - commands.extend(self.register.get_commands("WrFrontEnd", same_mask_for_all_dc=False, dcs=dcs, name=disable_shift_masks, joint_write=True)) - if enable_shift_masks: - curr_en_mask = make_pixel_mask(steps=mask_steps, shift=mask_step, enable_columns=ec, mask=mask) - map(lambda mask_name: self.register.set_pixel_register_value(mask_name, curr_en_mask), enable_shift_masks) - commands.extend(self.register.get_commands("WrFrontEnd", same_mask_for_all_dc=False, dcs=dcs, name=enable_shift_masks, joint_write=True)) - if digital_injection is True: - self.register.set_global_register_value("DIGHITIN_SEL", 1) - commands.extend(self.register.get_commands("WrRegister", name=["DIGHITIN_SEL"])) + else: # the slow DC loop allows writing commands inside bol and eol functions + for index, dc in enumerate(enable_double_columns): + if self.abort_run.is_set(): + break dc_address_command = get_dc_address_command(dc) + self.register_utils.send_command(dc_address_command) - self.register_utils.wait_for_command() - if eol_function: - eol_function() # do this after command has finished - self.register_utils.send_commands(commands, concatenate=True) - - self.dut['CMD']['START_SEQUENCE_LENGTH'] = len(dc_address_command) - self.dut['CMD']['CMD_REPEAT'] = repeat_command - self.register_utils.set_command(command=self.register_utils.concatenate_commands((dc_address_command, scan_loop_command), byte_padding=False)) + if bol_function: + bol_function() - if bol_function: - bol_function() + self.register_utils.send_command(scan_loop_command, repeat=repeat_command) - self.dut['CMD']['START'] - - self.register_utils.wait_for_command() - if eol_function: - eol_function() - self.dut['CMD']['START_SEQUENCE_LENGTH'] = 0 + if eol_function: + eol_function() else: - for index, dc in enumerate(enable_double_columns): - if self.stop_run.is_set(): - break + if fast_dc_loop: # fast DC loop with optimized pixel register writing + dc = enable_double_columns[0] ec = enable_columns(dc) dcs = write_double_columns(dc) - if index != 0: - dcs.extend(write_double_columns(enable_double_columns[index - 1])) commands = [] commands.append(conf_mode_command) if disable_shift_masks: @@ -1200,25 +1155,98 @@ def get_dc_address_command(dc): if digital_injection is True: self.register.set_global_register_value("DIGHITIN_SEL", 1) commands.extend(self.register.get_commands("WrRegister", name=["DIGHITIN_SEL"])) - self.register_utils.send_commands(commands, concatenate=True) + self.register_utils.send_commands(commands) dc_address_command = get_dc_address_command(dc) - self.register_utils.send_command(dc_address_command) + self.dut['TX']['START_SEQUENCE_LENGTH'] = len(dc_address_command) + self.dut['TX']['CMD_REPEAT'] = repeat_command + self.register_utils.set_command(command=self.register_utils.concatenate_commands((dc_address_command, scan_loop_command), byte_padding=False)) + + for index, dc in enumerate(enable_double_columns): + if self.abort_run.is_set(): + break + if index != 0: # full command is already set before loop + ec = enable_columns(dc) + dcs = write_double_columns(dc) + dcs.extend(write_double_columns(enable_double_columns[index - 1])) + commands = [] + commands.append(conf_mode_command) + if disable_shift_masks: + curr_dis_mask = make_pixel_mask(steps=mask_steps, shift=mask_step, default=1, value=0, enable_columns=ec, mask=mask) + map(lambda mask_name: self.register.set_pixel_register_value(mask_name, curr_dis_mask), disable_shift_masks) + commands.extend(self.register.get_commands("WrFrontEnd", same_mask_for_all_dc=False, dcs=dcs, name=disable_shift_masks, joint_write=True)) + if enable_shift_masks: + curr_en_mask = make_pixel_mask(steps=mask_steps, shift=mask_step, enable_columns=ec, mask=mask) + map(lambda mask_name: self.register.set_pixel_register_value(mask_name, curr_en_mask), enable_shift_masks) + commands.extend(self.register.get_commands("WrFrontEnd", same_mask_for_all_dc=False, dcs=dcs, name=enable_shift_masks, joint_write=True)) + if digital_injection is True: + self.register.set_global_register_value("DIGHITIN_SEL", 1) + commands.extend(self.register.get_commands("WrRegister", name=["DIGHITIN_SEL"])) + dc_address_command = get_dc_address_command(dc) + + self.register_utils.wait_for_command() + if eol_function: + eol_function() # do this after command has finished + self.register_utils.send_commands(commands) + + self.dut['TX']['START_SEQUENCE_LENGTH'] = len(dc_address_command) + self.dut['TX']['CMD_REPEAT'] = repeat_command + self.register_utils.set_command(command=self.register_utils.concatenate_commands((dc_address_command, scan_loop_command), byte_padding=False)) + + if bol_function: + bol_function() + + self.dut['TX']['START'] + + self.register_utils.wait_for_command() + if eol_function: + eol_function() + self.dut['TX']['START_SEQUENCE_LENGTH'] = 0 - if bol_function: - bol_function() + else: + for index, dc in enumerate(enable_double_columns): + if self.abort_run.is_set(): + break + ec = enable_columns(dc) + dcs = write_double_columns(dc) + if index != 0: + dcs.extend(write_double_columns(enable_double_columns[index - 1])) + commands = [] + commands.append(conf_mode_command) + if disable_shift_masks: + curr_dis_mask = make_pixel_mask(steps=mask_steps, shift=mask_step, default=1, value=0, enable_columns=ec, mask=mask) + map(lambda mask_name: self.register.set_pixel_register_value(mask_name, curr_dis_mask), disable_shift_masks) + commands.extend(self.register.get_commands("WrFrontEnd", same_mask_for_all_dc=False, dcs=dcs, name=disable_shift_masks, joint_write=True)) + if enable_shift_masks: + curr_en_mask = make_pixel_mask(steps=mask_steps, shift=mask_step, enable_columns=ec, mask=mask) + map(lambda mask_name: self.register.set_pixel_register_value(mask_name, curr_en_mask), enable_shift_masks) + commands.extend(self.register.get_commands("WrFrontEnd", same_mask_for_all_dc=False, dcs=dcs, name=enable_shift_masks, joint_write=True)) + if digital_injection is True: + self.register.set_global_register_value("DIGHITIN_SEL", 1) + commands.extend(self.register.get_commands("WrRegister", name=["DIGHITIN_SEL"])) + self.register_utils.send_commands(commands) - self.register_utils.send_command(scan_loop_command, repeat=repeat_command) + dc_address_command = get_dc_address_command(dc) + self.register_utils.send_command(dc_address_command) - if eol_function: - eol_function() + if bol_function: + bol_function() - # restoring default values - self.register.restore(name=restore_point_name) - self.register_utils.configure_global() # always restore global configuration + self.register_utils.send_command(scan_loop_command, repeat=repeat_command) + + if eol_function: + eol_function() + + commands = [] + commands.extend(self.register.get_commands("ConfMode")) + # write registers that were changed in scan_loop() + commands.extend(self.register.get_commands("WrRegister", name=["DIGHITIN_SEL", "Colpr_Addr", "PlsrDAC"])) if restore_shift_masks: commands = [] + commands.extend(self.register.get_commands("ConfMode")) + commands.extend(self.register.get_commands("WrRegister", name=["DIGHITIN_SEL", "Colpr_Addr", "PlsrDAC"])) commands.extend(self.register.get_commands("WrFrontEnd", same_mask_for_all_dc=False, name=disable_shift_masks)) commands.extend(self.register.get_commands("WrFrontEnd", same_mask_for_all_dc=False, name=enable_shift_masks)) commands.extend(self.register.get_commands("WrFrontEnd", same_mask_for_all_dc=False, name="EnableDigInj")) - self.register_utils.send_commands(commands) +# commands.extend(self.register.get_commands("RunMode")) + self.register_utils.send_commands(commands) diff --git a/pybar/fei4_run_base.py b/pybar/fei4_run_base.py index 004fcb067..6783a458b 100644 --- a/pybar/fei4_run_base.py +++ b/pybar/fei4_run_base.py @@ -1,16 +1,15 @@ import logging import time -import re import os +import itertools import string +import struct import smtplib from socket import gethostname -import zmq -import numpy as np from functools import wraps -from threading import Event, Thread +from threading import Event, Thread, current_thread, Lock, RLock from Queue import Queue -from collections import namedtuple, Mapping +from collections import namedtuple, Mapping, Iterable from contextlib import contextmanager from operator import itemgetter import abc @@ -18,115 +17,364 @@ import inspect import sys +from contextlib2 import ExitStack +import numpy as np + +import basil from basil.dut import Dut +from pybar.utils.utils import groupby_dict, dict_compare, zip_nofill from pybar.run_manager import RunManager, RunBase, RunAborted, RunStopped from pybar.fei4.register import FEI4Register -from pybar.fei4.register_utils import FEI4RegisterUtils, is_fe_ready, CmdTimeoutError +from pybar.fei4.register import flavors as fe_flavors +from pybar.fei4.register_utils import FEI4RegisterUtils, is_fe_ready from pybar.daq.fifo_readout import FifoReadout, RxSyncError, EightbTenbError, FifoError, NoDataTimeout, StopTimeout from pybar.daq.readout_utils import save_configuration_dict from pybar.daq.fei4_raw_data import open_raw_data_file, send_meta_data from pybar.analysis.analysis_utils import AnalysisError +from pybar.daq.readout_utils import convert_data_iterable, logical_or, logical_and, is_trigger_word, is_fe_word, is_data_from_channel, is_tdc_word, is_tdc_from_channel, convert_tdc_to_channel, false + + +_reserved_driver_names = ["FIFO", "TX", "RX", "TLU", "TDC"] class Fei4RunBase(RunBase): '''Basic FEI4 run meta class. Base class for scan- / tune- / analyze-class. + + A fei4 run consist of 3 major steps: + 1. pre_run + - dut initialization (readout system init) + - init readout fifo (data taking buffer) + - load scan parameters from run config + - init each front-end one by one (configure registers, serial) + 2. do_run + The following steps are either run for all front-ends + at once (parallel scan) or one by one (serial scan): + - scan specific configuration + - store run attributes + - run scan + - restore run attributes (some scans change run conf attributes or add new attributes, this restores to before) + - restore scan parameters from default run config (they mighte have been changed in scan) + 3. post_run + - call analysis on raw data files one by one (serial) + + Several handles are provided to encapsulate the underlying hardware + and scan type to be able to use generic scan definitions: + + - serial scan mode: + - register: one FE register data + - register_utils: access to one FE registers + - output_filename: output file name of a selected module + - raw_data_file: one output data file + + - parallel scan mode: + - register: broadcast register or multiple front-end registers + - register_utils: access all FE registers via broadcast or each front-end registers + at different channels + - output_filename: output file name of a selected module + - raw_data_file: all output data files with channel data filters + ''' __metaclass__ = abc.ABCMeta - def __init__(self, conf, run_conf=None): - # default run conf parameters added for all scans - if 'comment' not in self._default_run_conf: - self._default_run_conf.update({'comment': ''}) - if 'reset_rx_on_error' not in self._default_run_conf: - self._default_run_conf.update({'reset_rx_on_error': False}) - - super(Fei4RunBase, self).__init__(conf=conf, run_conf=run_conf) - - # default conf parameters - if 'working_dir' not in conf: - conf.update({'working_dir': ''}) # path string, if empty, path of configuration.yaml file will be used - if 'zmq_context' not in conf: - conf.update({'zmq_context': None}) # ZMQ context - if 'send_data' not in conf: - conf.update({'send_data': None}) # address string of PUB socket - if 'send_error_msg' not in conf: - conf.update({'send_error_msg': None}) # bool - + def __init__(self, conf): + # Sets self._conf = conf + super(Fei4RunBase, self).__init__(conf=conf) self.err_queue = Queue() - self.fifo_readout = None - self.raw_data_file = None + self.global_lock = RLock() + + self._module_run_conf = {} # Store module specific run conf + self._module_cfgs = {} # Store module specific configurations + self._modules = {} # Module IDs of real modules + self._tx_module_groups = {} # Module IDs of TX module groups (virtual modules) + self._registers = {} # Store module specific FEI4 registers + self._register_utils = {} # Store module specific FEI4 register utils + self._raw_data_files = {} # Store module specific raw data files + self._scan_parameters = {} # Store module specific scan parameters + self._module_attr = {} # Store module specific scan attributes + self._module_dut = {} # Store module specific DUT handle + self.fifo_readout = None # FIFO readout instances + self._selected_modules = [] + self._selected_fifos = [] # currently activated FIFOs + self._readout_fifos = [] + self._converter = [] + self._filter = [] + self._enabled_fe_channels = [] # currently activated receivers + self._current_module_handle = None # setting "None" module as default module + self._scan_threads = [] # list of currently running scan threads + self._curr_readout_threads = [] # list of currently running threads awaiting start of FIFO readout + self._readout_lock = Lock() + self._starting_readout_event = Event() + self._starting_readout_event.clear() + self._stopping_readout_event = Event() + self._stopping_readout_event.clear() + self._curr_sync_threads = [] + self._sync_lock = Lock() + self._enter_sync_event = Event() + self._enter_sync_event.clear() + self._exit_sync_event = Event() + self._exit_sync_event.clear() + self._parse_module_cfgs() + self._init_default_run_conf() + # after initialized is set to True, all new attributes are belonging to selected mudule + # by default the "None" module is selected (current_module_handle is None) + self._initialized = True @property - def working_dir(self): - if self.module_id: - return os.path.join(self._conf['working_dir'], self.module_id) + def is_initialized(self): + if "_initialized" in self.__dict__ and self._initialized: + return True else: - return os.path.join(self._conf['working_dir'], self.run_id) + return False @property - def dut(self): - return self._conf['dut'] + def current_module_handle(self): + if self._current_module_handle is None: + thread_name = current_thread().name + module_handles = [module_id for module_id in self._module_cfgs if (module_id is not None and module_id == thread_name)] + if len(module_handles) > 1: + raise RuntimeError("Could not determine module handle. Thread name contains multiple module IDs: %s" % ", ".join(module_handles)) + if len(module_handles) == 0: + return None +# raise RuntimeError('Could not determine module handle from thread name "%s"' % thread_name) + return module_handles[0] + else: + return self._current_module_handle @property def register(self): - return self._conf['fe_configuration'] + return self._registers[self.current_module_handle] + + @property + def register_utils(self): + return self._register_utils[self.current_module_handle] @property def output_filename(self): - if self.module_id: - return os.path.join(self.working_dir, str(self.run_number) + "_" + self.module_id + "_" + self.run_id) - else: - return os.path.join(self.working_dir, str(self.run_number) + "_" + self.run_id) + return self.get_output_filename(module_id=self.current_module_handle) + + @property + def run_conf(self): + run_conf = namedtuple('run_conf', field_names=self._module_run_conf[self.current_module_handle].keys()) + return run_conf(*self._module_run_conf[self.current_module_handle]) # prevent changing dict + + @property + def scan_parameters(self): + return self._scan_parameters[self.current_module_handle] + + @property + def dut(self): + return self._module_dut[self.current_module_handle] @property - def module_id(self): - if 'module_id' in self._conf and self._conf['module_id']: - module_id = str(self._conf['module_id']) - module_id = re.sub(r"[^\w\s+]", '', module_id) - return re.sub(r"\s+", '_', module_id).lower() + def raw_data_file(self): + return self._raw_data_files[self.current_module_handle] + + def _parse_module_cfgs(self): + ''' Extracts the configuration of the modules. + ''' + # Adding here default run config parameters. + if "dut" not in self._conf or self._conf["dut"] is None: + raise ValueError('Parameter "dut" not defined.') + if "dut_configuration" not in self._conf or self._conf["dut_configuration"] is None: + raise ValueError('Parameter "dut_configuration" not defined.') + self._conf.setdefault('working_dir', None) # string, if None, absolute path of configuration.yaml file will be used + + if 'modules' in self._conf and self._conf['modules']: + for module_id, module_cfg in [(key, value) for key, value in self._conf['modules'].items() if ("activate" not in value or ("activate" in value and value["activate"] is True))]: + # Check here for missing module config items. + # Capital letter keys are Basil drivers, other keys are parameters. + # FIFO, RX, TX, TLU and TDC are generic driver names which are used in the scan implementations. + # The use of these reserved driver names allows for abstraction. + # Accessing Basil drivers with real name is still possible. + if "module_group" in module_id: + raise ValueError('The module ID "%s" contains the reserved name "module_group".' % module_id) + if "flavor" not in module_cfg or module_cfg["flavor"] is None: + raise ValueError('No parameter "flavor" defined for module "%s".' % module_id) + if module_cfg["flavor"] in fe_flavors: + for driver_name in _reserved_driver_names: + # TDC is not mandatory + if driver_name == "TDC": + # TDC is allowed to have set None + module_cfg.setdefault('TDC', None) + continue + if driver_name not in module_cfg or module_cfg[driver_name] is None: + raise ValueError('No parameter "%s" defined for module "%s".' % (driver_name, module_id)) + if "rx_channel" not in module_cfg or module_cfg["rx_channel"] is None: + raise ValueError('No parameter "rx_channel" defined for module "%s".' % module_id) + if "tx_channel" not in module_cfg or module_cfg["tx_channel"] is None: + raise ValueError('No parameter "tx_channel" defined for module "%s".' % module_id) + if "chip_address" not in module_cfg: + raise ValueError('No parameter "chip_address" defined for module "%s".' % module_id) + module_cfg.setdefault("tdc_channel", None) + module_cfg.setdefault("configuration", None) # string or number, if None, using the last valid configuration + module_cfg.setdefault("send_data", None) # address string of PUB socket + module_cfg.setdefault("activate", True) # set module active by default + # Save config to dict. + self._module_cfgs[module_id] = module_cfg + self._modules[module_id] = [module_id] + else: + raise ValueError("No module configuration specified") + + def _init_default_run_conf(self): + # set up default run conf parameters + self._default_run_conf.setdefault('comment', '{}'.format(self.__class__.__name__)) + self._default_run_conf.setdefault('reset_rx_on_error', False) + # Enabling broadcast commands will significantly improve the speed of scans. + # Only those scans can be accelerated which commands can be broadcastet and + # which commands are not individual for each module. + self._default_run_conf.setdefault('broadcast_commands', False) + # Enabling threaded scan improves the speed of scans + # and require multiple TX for sending commands. + # If only a single TX is available, no speed improvement is gained. + self._default_run_conf.setdefault('threaded_scan', False) + + def _init_run_conf(self, run_conf): + # same implementation as in base class, but ignore "scan_parameters" property + attribute_names = [key for key in self._default_run_conf.keys() if (key != "scan_parameters" and (key in self.__dict__ or (hasattr(self.__class__, key) and isinstance(getattr(self.__class__, key), property))))] + if attribute_names: + raise RuntimeError('Attribute names already in use. Rename the following parameters in run conf: %s' % ', '.join(attribute_names)) + sc = namedtuple('run_configuration', field_names=self._default_run_conf.keys()) + default_run_conf = sc(**self._default_run_conf) + if run_conf: + self._run_conf = default_run_conf._replace(**run_conf)._asdict() else: - return None + self._run_conf = default_run_conf._asdict() + + # check for invalid run conf parameters + if self._run_conf['broadcast_commands'] and not self._default_run_conf['broadcast_commands']: + raise RuntimeError('Changing "broadcast_commands" parameter from False (default) to True.') + if self._run_conf['broadcast_commands'] and 'modules' in self._conf and self._conf['modules']: + tx_groups = groupby_dict({key: value for (key, value) in self._module_cfgs.items() if key in self._modules}, "TX") + for module_group in tx_groups.values(): + for module_id in module_group: + if self.__class__.__name__ in self._conf["modules"][module_id] and self._conf["modules"][module_id][self.__class__.__name__] is not None: + for other_module_id in module_group: + if self.__class__.__name__ in self._conf["modules"][other_module_id] and self._conf["modules"][other_module_id][self.__class__.__name__] is not None: + if any(dict_compare(self._conf["modules"][module_id][self.__class__.__name__], self._conf["modules"][other_module_id][self.__class__.__name__])[:3]): + raise RuntimeError('Module "%s" has specific run configuration that is different from module "%s" for "%s" and "broadcast_commands" parameter is set to True.' % (other_module_id, module_id, self.__class__.__name__)) + else: + raise RuntimeError('Module "%s" has no specific run configuration for "%s" and "broadcast_commands" parameter is set to True.' % (other_module_id, self.__class__.__name__)) + + + def _set_default_cfg(self): + ''' Sets the default parameters if they are not specified. + ''' + # adding special conf for accessing all DUT drivers + self._module_cfgs[None] = { + 'flavor': None, + 'chip_address': None, + 'FIFO': list(set([self._module_cfgs[module_id]['FIFO'] for module_id in self._modules])), + 'RX': list(set([self._module_cfgs[module_id]['RX'] for module_id in self._modules])), + 'rx_channel': list(set([self._module_cfgs[module_id]['rx_channel'] for module_id in self._modules])), + 'TX': list(set([self._module_cfgs[module_id]['TX'] for module_id in self._modules])), + 'tx_channel': list(set([self._module_cfgs[module_id]['tx_channel'] for module_id in self._modules])), + 'TDC': list(set([self._module_cfgs[module_id]['TDC'] for module_id in self._modules])), + 'tdc_channel': list(set([self._module_cfgs[module_id]['tdc_channel'] for module_id in self._modules])), + 'TLU' : list(set([self._module_cfgs[module_id]['TLU'] for module_id in self._modules])), + 'configuration' : None, + 'send_data' : None} + + tx_groups = groupby_dict({key: value for (key, value) in self._module_cfgs.items() if key in self._modules}, "TX") + for tx, module_group in tx_groups.items(): + flavors = list(set([module_cfg['flavor'] for module_id, module_cfg in self._module_cfgs.items() if module_id in module_group])) + if len(flavors) != 1: + raise ValueError("Parameter 'flavor' must be the same for module group TX=%s." % tx) + + chip_addresses = list(set([module_cfg['chip_address'] for module_id, module_cfg in self._module_cfgs.items() if module_id in module_group])) + if len(module_group) != len(chip_addresses) or (len(module_group) != 1 and None in chip_addresses): + raise ValueError("Parameter 'chip_address' must be different for each module in module group TX=%s." % tx) + + # Adding broadcast config for parallel mode. + self._module_cfgs["module_group_TX=" + tx] = { + 'flavor': flavors[0], + 'chip_address': None, # broadcast + 'FIFO': list(set([module_cfg['FIFO'] for module_id, module_cfg in self._module_cfgs.items() if module_id in module_group])), + 'RX': list(set([module_cfg['RX'] for module_id, module_cfg in self._module_cfgs.items() if module_id in module_group])), + 'rx_channel': list(set([module_cfg['rx_channel'] for module_id, module_cfg in self._module_cfgs.items() if module_id in module_group])), + 'TX': tx, + 'tx_channel': list(set([module_cfg['tx_channel'] for module_id, module_cfg in self._module_cfgs.items() if module_id in module_group])), + 'TDC': list(set([module_cfg['TDC'] for module_id, module_cfg in self._module_cfgs.items() if module_id in module_group])), + 'tdc_channel': list(set([module_cfg['tdc_channel'] for module_id, module_cfg in self._module_cfgs.items() if module_id in module_group])), + 'TLU' : list(set([module_cfg['TLU'] for module_id, module_cfg in self._module_cfgs.items() if module_id in module_group])), + 'configuration' : None, + 'send_data' : None} + self._tx_module_groups["module_group_TX=" + tx] = module_group + + # Setting up per module attributes + self._module_attr = {key: {} for key in self._module_cfgs} + # Setting up per module run conf + for module_id in self._module_cfgs: + sc = namedtuple('run_configuration', field_names=self._default_run_conf.keys()) + run_conf = sc(**self._run_conf) + if module_id in self._modules and self.__class__.__name__ in self._conf["modules"][module_id] and self._conf["modules"][module_id][self.__class__.__name__] is not None: + self._module_run_conf[module_id] = run_conf._replace(**self._conf["modules"][module_id][self.__class__.__name__])._asdict() + else: + self._module_run_conf[module_id] = run_conf._asdict() + # update module group with run specific configuration + if module_id in self._tx_module_groups and self._tx_module_groups[module_id]: + selected_module_id = self._tx_module_groups[module_id][0] + if self.__class__.__name__ in self._conf["modules"][selected_module_id] and self._conf["modules"][selected_module_id][self.__class__.__name__] is not None: + self._module_run_conf[module_id] = run_conf._replace(**self._conf["modules"][selected_module_id][self.__class__.__name__])._asdict() + def init_dut(self): if self.dut.name == 'mio': if self.dut.get_modules('FEI4AdapterCard') and [adapter_card for adapter_card in self.dut.get_modules('FEI4AdapterCard') if adapter_card.name == 'ADAPTER_CARD']: - self.dut['ADAPTER_CARD'].set_voltage('VDDA1', 1.5) - self.dut['ADAPTER_CARD'].set_voltage('VDDA2', 1.5) - self.dut['ADAPTER_CARD'].set_voltage('VDDD1', 1.2) - self.dut['ADAPTER_CARD'].set_voltage('VDDD2', 1.2) + try: + self.dut['ADAPTER_CARD'].set_voltage('VDDA1', 1.5) + self.dut['ADAPTER_CARD'].set_voltage('VDDA2', 1.5) + self.dut['ADAPTER_CARD'].set_voltage('VDDD1', 1.2) + self.dut['ADAPTER_CARD'].set_voltage('VDDD2', 1.2) + except struct.error: + logging.warning('Cannot set adapter card voltages. Maybe card not calibrated?') self.dut['POWER_SCC']['EN_VD1'] = 1 self.dut['POWER_SCC']['EN_VD2'] = 1 # also EN_VPLL on old SCAC self.dut['POWER_SCC']['EN_VA1'] = 1 self.dut['POWER_SCC']['EN_VA2'] = 1 self.dut['POWER_SCC'].write() # enabling readout - self.dut['ENABLE_CHANNEL']['CH1'] = 0 # RD2Bar on SCAC - self.dut['ENABLE_CHANNEL']['CH2'] = 0 # RD1Bar on SCAC - self.dut['ENABLE_CHANNEL']['CH3'] = 0 # RABar on SCAC - self.dut['ENABLE_CHANNEL']['CH4'] = 1 + rx_names = [rx.name for rx in self.dut.get_modules('fei4_rx')] + active_rx_names = [module_cfg["RX"] for (name, module_cfg) in self._module_cfgs.items() if name in self._modules] + for rx_name in rx_names: + # enabling/disabling Rx + if rx_name in active_rx_names: + self.dut[rx_name].ENABLE_RX = 1 + else: + self.dut[rx_name].ENABLE_RX = 0 + self.dut['ENABLE_CHANNEL']['DATA_CH1'] = 0 # RD2Bar on SCAC + self.dut['ENABLE_CHANNEL']['DATA_CH2'] = 0 # RD1Bar on SCAC + self.dut['ENABLE_CHANNEL']['DATA_CH3'] = 0 # RABar on SCAC + self.dut['ENABLE_CHANNEL']['DATA_CH4'] = 1 self.dut['ENABLE_CHANNEL']['TLU'] = 1 self.dut['ENABLE_CHANNEL']['TDC'] = 1 self.dut['ENABLE_CHANNEL'].write() elif self.dut.get_modules('FEI4QuadModuleAdapterCard') and [adapter_card for adapter_card in self.dut.get_modules('FEI4QuadModuleAdapterCard') if adapter_card.name == 'ADAPTER_CARD']: # resetting over current status - self.dut['POWER_QUAD']['EN_CH1'] = 0 - self.dut['POWER_QUAD']['EN_CH2'] = 0 - self.dut['POWER_QUAD']['EN_CH3'] = 0 - self.dut['POWER_QUAD']['EN_CH4'] = 0 + self.dut['POWER_QUAD']['EN_DATA_CH1'] = 0 + self.dut['POWER_QUAD']['EN_DATA_CH2'] = 0 + self.dut['POWER_QUAD']['EN_DATA_CH3'] = 0 + self.dut['POWER_QUAD']['EN_DATA_CH4'] = 0 self.dut['POWER_QUAD'].write() self.dut['ADAPTER_CARD'].set_voltage('CH1', 2.1) self.dut['ADAPTER_CARD'].set_voltage('CH2', 2.1) self.dut['ADAPTER_CARD'].set_voltage('CH3', 2.1) self.dut['ADAPTER_CARD'].set_voltage('CH4', 2.1) self.dut['POWER_QUAD'].write() - channel_names = [channel.name for channel in self.dut.get_modules('fei4_rx')] - for channel in channel_names: - # enabling readout - self.dut['ENABLE_CHANNEL'][channel] = 1 - self.dut['POWER_QUAD']['EN_' + channel] = 1 + rx_names = [rx.name for rx in self.dut.get_modules('fei4_rx')] + active_rx_names = [module_cfg["RX"] for (name, module_cfg) in self._module_cfgs.items() if name in self._modules] + for rx_name in rx_names: + # enabling/disabling Rx + if rx_name in active_rx_names: + self.dut[rx_name].ENABLE_RX = 1 + self.dut['ENABLE_CHANNEL'][rx_name] = 1 + self.dut['POWER_QUAD']['EN_' + rx_name] = 1 + else: + self.dut[rx_name].ENABLE_RX = 0 + self.dut['ENABLE_CHANNEL'][rx_name] = 0 + self.dut['POWER_QUAD']['EN_' + rx_name] = 0 self.dut['ENABLE_CHANNEL']['TLU'] = 1 self.dut['ENABLE_CHANNEL']['TDC'] = 1 self.dut['ENABLE_CHANNEL'].write() @@ -134,39 +382,38 @@ def init_dut(self): else: logging.warning('Unknown adapter card') # do the minimal configuration here - self.dut['ENABLE_CHANNEL']['CH1'] = 0 # RD2Bar on SCAC - self.dut['ENABLE_CHANNEL']['CH2'] = 0 # RD1Bar on SCAC - self.dut['ENABLE_CHANNEL']['CH3'] = 0 # RABar on SCAC - self.dut['ENABLE_CHANNEL']['CH4'] = 1 + self.dut['ENABLE_CHANNEL']['DATA_CH1'] = 0 # RD2Bar on SCAC + self.dut['ENABLE_CHANNEL']['DATA_CH2'] = 0 # RD1Bar on SCAC + self.dut['ENABLE_CHANNEL']['DATA_CH3'] = 0 # RABar on SCAC + self.dut['ENABLE_CHANNEL']['DATA_CH4'] = 1 self.dut['ENABLE_CHANNEL']['TLU'] = 1 self.dut['ENABLE_CHANNEL']['TDC'] = 1 self.dut['ENABLE_CHANNEL'].write() - elif self.dut.name == 'mio_gpac': # PWR self.dut['V_in'].set_current_limit(0.1, unit='A') # one for all, max. 1A # V_in self.dut['V_in'].set_voltage(2.1, unit='V') self.dut['V_in'].set_enable(True) - if self.dut["V_in"].get_over_current(): + if self.dut['V_in'].get_over_current(): self.power_off() raise Exception('V_in overcurrent detected') # Vdd, also enabling LVDS transceivers self.dut['CCPD_Vdd'].set_voltage(1.80, unit='V') self.dut['CCPD_Vdd'].set_enable(True) - if self.dut["CCPD_Vdd"].get_over_current(): + if self.dut['CCPD_Vdd'].get_over_current(): self.power_off() raise Exception('Vdd overcurrent detected') # Vssa self.dut['CCPD_Vssa'].set_voltage(1.50, unit='V') self.dut['CCPD_Vssa'].set_enable(True) - if self.dut["CCPD_Vssa"].get_over_current(): + if self.dut['CCPD_Vssa'].get_over_current(): self.power_off() raise Exception('Vssa overcurrent detected') # VGate self.dut['CCPD_VGate'].set_voltage(2.10, unit='V') self.dut['CCPD_VGate'].set_enable(True) - if self.dut["CCPD_VGate"].get_over_current(): + if self.dut['CCPD_VGate'].get_over_current(): self.power_off() raise Exception('VGate overcurrent detected') # enabling readout @@ -184,93 +431,129 @@ def init_dut(self): self.dut['I2C'].write(0xe8, [6, 0xf0, 0xff]) self.dut['I2C'].write(0xe8, [2, 0x0f, 0x00]) # select channels here - self.dut['ENABLE_CHANNEL']['CH1'] = 1 - self.dut['ENABLE_CHANNEL']['CH2'] = 1 - self.dut['ENABLE_CHANNEL']['CH3'] = 1 - self.dut['ENABLE_CHANNEL']['CH4'] = 1 + self.dut['ENABLE_CHANNEL']['DATA_CH1'] = 1 + self.dut['ENABLE_CHANNEL']['DATA_CH2'] = 1 + self.dut['ENABLE_CHANNEL']['DATA_CH3'] = 1 + self.dut['ENABLE_CHANNEL']['DATA_CH4'] = 1 self.dut['ENABLE_CHANNEL']['TLU'] = 1 self.dut['ENABLE_CHANNEL']['TDC'] = 1 self.dut['ENABLE_CHANNEL'].write() - elif self.dut.name == 'beast': - logging.info('BEAST initialization') + elif self.dut.name == 'mmc3_m26_eth': + pass + # TODO: enable Mimosa26 Rx when necessary + elif self.dut.name == 'mmc3_beast_eth': + self.dut['DLY_CONFIG']['CLK_DLY'] = 0 + self.dut['DLY_CONFIG'].write() + elif self.dut.name == 'mmc3_8chip_eth': self.dut['DLY_CONFIG']['CLK_DLY'] = 0 self.dut['DLY_CONFIG'].write() else: - logging.warning('Omitting initialization of DUT %s', self.dut.name) - # enabling all FEI4 Rx - rx_names = [rx.name for rx in self.dut.get_modules('fei4_rx')] - for rx_name in rx_names: - self.dut[rx_name].ENABLE_RX = 1 - - def init_fe(self): - if 'fe_configuration' in self._conf: - last_configuration = self._get_configuration() - # init config, a number <=0 will also do the initialization (run 0 does not exists) - if (not self._conf['fe_configuration'] and not last_configuration) or (isinstance(self._conf['fe_configuration'], (int, long)) and self._conf['fe_configuration'] <= 0): - if 'chip_address' in self._conf and self._conf['chip_address']: - chip_address = self._conf['chip_address'] - broadcast = False + logging.warning('Unknown DUT name: %s', self.dut.name) + + def init_modules(self): + ''' Initialize all modules consecutively''' + for module_id, module_cfg in self._module_cfgs.items(): + if module_id in self._modules or module_id in self._tx_module_groups: + if module_id in self._modules: + module_id_str = "module " + module_id else: - chip_address = 0 - broadcast = True - if 'fe_flavor' in self._conf and self._conf['fe_flavor']: - self._conf['fe_configuration'] = FEI4Register(fe_type=self._conf['fe_flavor'], chip_address=chip_address, broadcast=broadcast) + module_id_str = module_id.split('=', 1) + module_id_str[0] = module_id_str[0].replace("_", " ") + module_id_str = "=".join(module_id_str) + logging.info("Initializing configuration for %s..." % module_id_str) + # adding scan parameters to dict + if 'scan_parameters' in self._module_run_conf[module_id] and self._module_run_conf[module_id]['scan_parameters'] is not None: + # evaluating string for support of nested lists and other complex data structures + if isinstance(self._module_run_conf[module_id]['scan_parameters'], basestring): + self._module_run_conf[module_id]['scan_parameters'] = ast.literal_eval(self._module_run_conf[module_id]['scan_parameters']) + sp = namedtuple('scan_parameters', field_names=zip(*self._module_run_conf[module_id]['scan_parameters'])[0]) + self._scan_parameters[module_id] = sp(*zip(*self._module_run_conf[module_id]['scan_parameters'])[1]) else: - raise ValueError('No fe_flavor given') - # use existing config - elif not self._conf['fe_configuration'] and last_configuration: - self._conf['fe_configuration'] = FEI4Register(configuration_file=last_configuration) - # path string - elif isinstance(self._conf['fe_configuration'], basestring): - if os.path.isabs(self._conf['fe_configuration']): # absolute path - self._conf['fe_configuration'] = FEI4Register(configuration_file=self._conf['fe_configuration']) - else: # relative path - self._conf['fe_configuration'] = FEI4Register(configuration_file=os.path.join(self._conf['working_dir'], self._conf['fe_configuration'])) - # run number - elif isinstance(self._conf['fe_configuration'], (int, long)) and self._conf['fe_configuration'] > 0: - self._conf['fe_configuration'] = FEI4Register(configuration_file=self._get_configuration(self._conf['fe_configuration'])) - # assume fe_configuration already initialized - elif not isinstance(self._conf['fe_configuration'], FEI4Register): - raise ValueError('No valid fe_configuration given') - # init register utils - self.register_utils = FEI4RegisterUtils(self.dut, self.register) - # reset and configuration - self.register_utils.global_reset() - self.register_utils.configure_all() - if is_fe_ready(self): - reset_service_records = False - else: - reset_service_records = True - self.register_utils.reset_bunch_counter() - self.register_utils.reset_event_counter() - if reset_service_records: - # resetting service records must be done once after power up - self.register_utils.reset_service_records() - else: - pass # no fe_configuration + sp = namedtuple_with_defaults('scan_parameters', field_names=[]) + self._scan_parameters[module_id] = sp() + # init FE config + if module_id in self._modules: + # only real modules can have an existing configuration + last_configuration = self.get_configuration(module_id=module_id) + else: + last_configuration = None + if (('configuration' not in module_cfg or module_cfg['configuration'] is None) and last_configuration is None) or (isinstance(module_cfg['configuration'], (int, long)) and module_cfg['configuration'] <= 0): + if 'chip_address' in module_cfg: + if module_cfg['chip_address'] is None: + chip_address = 0 + broadcast = True + else: + chip_address = module_cfg['chip_address'] + broadcast = False + else: + raise ValueError('Parameter "chip_address" not specified for module "%s".' % module_id) + if 'flavor' in module_cfg and module_cfg['flavor']: + module_cfg['configuration'] = FEI4Register(fe_type=module_cfg['flavor'], chip_address=chip_address, broadcast=broadcast) + else: + raise ValueError('Parameter "flavor" not specified for module "%s".' % module_id) + # use existing config + elif not module_cfg['configuration'] and last_configuration: + module_cfg['configuration'] = FEI4Register(configuration_file=last_configuration) + # path string + elif isinstance(module_cfg['configuration'], basestring): + if os.path.isabs(module_cfg['configuration']): # absolute path + module_cfg['configuration'] = FEI4Register(configuration_file=module_cfg['configuration']) + else: # relative path + module_cfg['configuration'] = FEI4Register(configuration_file=os.path.join(module_cfg['working_dir'], module_cfg['configuration'])) + # run number + elif isinstance(module_cfg['configuration'], (int, long)) and module_cfg['configuration'] > 0: + module_cfg['configuration'] = FEI4Register(configuration_file=self.get_configuration(module_id=module_id, + run_number=module_cfg['configuration'])) + # assume configuration already initialized + elif not isinstance(module_cfg['configuration'], FEI4Register): + raise ValueError('Found no valid value for parameter "configuration" for module "%s".' % module_id) + + # init register utils + self._registers[module_id] = self._module_cfgs[module_id]['configuration'] + self._register_utils[module_id] = FEI4RegisterUtils(self._module_dut[module_id], self._module_cfgs[module_id]['configuration']) + + if module_id in self._modules: + # Create module data path for real modules + module_path = self.get_module_path(module_id) + if not os.path.exists(module_path): + os.makedirs(module_path) + + # Set all modules to conf mode to prevent from receiving BCR and ECR broadcast + for module_id in self._tx_module_groups: + with self.access_module(module_id=module_id): + self.register_utils.set_conf_mode() + + # Initial configuration (reset and configuration) of all modules. + # This is done by iterating over each module individually + for module_id in self._modules: + logging.info("Configuring %s..." % module_id) + with self.access_module(module_id=module_id): + self.register_utils.global_reset() + self.register_utils.configure_all() + if is_fe_ready(self): + fe_not_ready = False + else: + fe_not_ready = True + # BCR and ECR might result in RX errors + # a reset of the RX and FIFO will happen just before scan() + self.register_utils.reset_bunch_counter() + self.register_utils.reset_event_counter() + if fe_not_ready: + # resetting service records must be done once after power up + self.register_utils.reset_service_records() + if not is_fe_ready(self): + logging.warning('Module "%s" is not sending any data.' % module_id) + # set all modules to conf mode afterwards to be immune to ECR and BCR + self.register_utils.set_conf_mode() def pre_run(self): - # clear error queue in case run is executed a second time + # clear error queue in case run is executed another time self.err_queue.queue.clear() - # opening ZMQ context and binding socket - if self._conf['send_data'] and not self._conf['zmq_context']: - logging.info('Creating ZMQ context') - self._conf['zmq_context'] = zmq.Context() # contexts are thread safe unlike sockets - else: - logging.info('Using existing socket') - # scan parameters - if 'scan_parameters' in self._run_conf: - if isinstance(self._run_conf['scan_parameters'], basestring): - self._run_conf['scan_parameters'] = ast.literal_eval(self._run_conf['scan_parameters']) - sp = namedtuple('scan_parameters', field_names=zip(*self._run_conf['scan_parameters'])[0]) - self.scan_parameters = sp(*zip(*self._run_conf['scan_parameters'])[1]) - else: - sp = namedtuple_with_defaults('scan_parameters', field_names=[]) - self.scan_parameters = sp() - logging.info('Scan parameter(s): %s', ', '.join(['%s=%s' % (key, value) for (key, value) in self.scan_parameters._asdict().items()]) if self.scan_parameters else 'None') + # set default configuration, revert any changes that were done by last run + self._set_default_cfg() # init DUT - if not isinstance(self._conf['dut'], Dut): + if not isinstance(self._conf['dut'], Dut): # Check if already initialized module_path = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe()))) if isinstance(self._conf['dut'], basestring): # dirty fix for Windows pathes @@ -285,7 +568,7 @@ def pre_run(self): elif os.path.exists(os.path.join(module_path, self._conf['dut'])): dut = os.path.join(module_path, self._conf['dut']) else: - raise ValueError('dut parameter not a valid path: %s' % self._conf['dut']) + raise ValueError("Parameter 'dut' is not a valid path: %s" % self._conf['dut']) logging.info('Loading DUT configuration from file %s', os.path.abspath(dut)) else: dut = self._conf['dut'] @@ -309,7 +592,7 @@ def pre_run(self): elif os.path.exists(os.path.join(module_path, self._conf['dut_configuration'])): dut_configuration = os.path.join(module_path, self._conf['dut_configuration']) else: - raise ValueError('dut_configuration parameter not a valid path: %s' % self._conf['dut_configuration']) + raise ValueError("Parameter 'dut_configuration' is not a valid path: %s" % self._conf['dut_configuration']) logging.info('Loading DUT initialization parameters from file %s', os.path.abspath(dut_configuration)) # convert to dict dut_configuration = RunManager.open_conf(dut_configuration) @@ -329,64 +612,227 @@ def pre_run(self): elif os.path.exists(os.path.join(module_path, bit_file)): bit_file = os.path.join(module_path, bit_file) else: - raise ValueError('bit_file parameter not a valid path: %s' % bit_file) + raise ValueError("Parameter 'bit_file' is not a valid path: %s" % bit_file) dut_configuration['USB']['bit_file'] = bit_file else: dut_configuration = self._conf['dut_configuration'] else: dut_configuration = None - logging.info('Initializing basil') + # check for existence of reserved driver names + found_reserved_names = [] + for driver_name in _reserved_driver_names: + try: + dut[driver_name] + found_reserved_names.append(driver_name) + except KeyError: + pass + if found_reserved_names: + raise RuntimeError("The basil DUT contains reserved driver names: %s" % ", ".join(found_reserved_names)) + logging.info('Initializing basil...') dut.init(dut_configuration) # assign dut after init in case of exceptions during init self._conf['dut'] = dut + # adding DUT handles + for module_id, module_cfg in self._module_cfgs.items(): + self._module_dut[module_id] = DutHandle(dut=self._conf['dut'], module_cfg=module_cfg) + self.fifo_readout = FifoReadout(dut=self._conf['dut']) # additional init of the DUT self.init_dut() else: - pass # do nothing, already initialized - # FIFO readout - self.fifo_readout = FifoReadout(self.dut) - # initialize the FE - self.init_fe() + # adding DUT handles + for module_id, module_cfg in self._module_cfgs.items(): + self._module_dut[module_id] = DutHandle(dut=self._conf['dut'], module_cfg=module_cfg) + self.fifo_readout = FifoReadout(dut=self._conf['dut']) + + # initialize the modules + self.init_modules() def do_run(self): - with self.register.restored(name=self.run_number): - # configure for scan - self.configure() - self.fifo_readout.reset_rx() - self.fifo_readout.reset_sram_fifo() - self.fifo_readout.print_readout_status() - # open raw data file - with open_raw_data_file(filename=self.output_filename, mode='w', title=self.run_id, scan_parameters=self.scan_parameters._asdict(), context=self._conf['zmq_context'], socket_address=self._conf['send_data']) as self.raw_data_file: - # save configuration data to raw data file - self.register.save_configuration(self.raw_data_file.h5_file) - save_configuration_dict(self.raw_data_file.h5_file, 'conf', self._conf) - save_configuration_dict(self.raw_data_file.h5_file, 'run_conf', self._run_conf) - # send configuration data to online monitor - if self.raw_data_file.socket: - send_meta_data(self.raw_data_file.socket, self.output_filename, name='Filename') - global_register_config = {} - for global_reg in sorted(self.register.get_global_register_objects(readonly=False), key=itemgetter('name')): - global_register_config[global_reg['name']] = global_reg['value'] - send_meta_data(self.raw_data_file.socket, global_register_config, name='GlobalRegisterConf') - send_meta_data(self.raw_data_file.socket, self._run_conf, name='RunConf') - # scan - self.scan() + ''' Start runs on all modules sequentially. - def post_run(self): - # printing FIFO status - try: - self.fifo_readout.print_readout_status() - except Exception: # no device? - pass + Sets properties to access current module properties. + ''' + if self.broadcast_commands: # Broadcast FE commands + if self.threaded_scan: + with ExitStack() as restore_config_stack: + # Configure each FE individually + # Sort module config keys, configure broadcast modules first + for module_id in itertools.chain(self._tx_module_groups, self._modules): + if self.abort_run.is_set(): + break + with self.access_module(module_id=module_id): + if module_id in self._modules: + module_id_str = "module " + module_id + else: + module_id_str = module_id.split('=', 1) + module_id_str[0] = module_id_str[0].replace("_", " ") + module_id_str = "=".join(module_id_str) + logging.info('Scan parameter(s) for %s: %s', module_id_str, ', '.join(['%s=%s' % (key, value) for (key, value) in self.scan_parameters._asdict().items()]) if self.scan_parameters else 'None') + # storing register values until scan has finished and then restore configuration + restore_config_stack.enter_context(self.register.restored(name=self.run_number)) + self.configure() + for module_id in self._tx_module_groups: + if self.abort_run.is_set(): + break + with self.access_module(module_id=module_id): + # set all modules to run mode by before entering scan() + self.register_utils.set_run_mode() - # analyzing data - try: - self.analyze() - except Exception: # analysis errors - self.handle_err(sys.exc_info()) - else: # analyzed data, save config - self.register.save_configuration(self.output_filename) + with self.access_module(module_id=None): + self.fifo_readout.reset_rx() + self.fifo_readout.reset_fifo(self._selected_fifos) + self.fifo_readout.print_fei4_rx_status() + + with self.access_files(): + self._scan_threads = [] + for module_id in self._tx_module_groups: + if self.abort_run.is_set(): + break + t = ExcThread(target=self.scan, name=module_id) + t.daemon = True # exiting program even when thread is alive + self._scan_threads.append(t) + for t in self._scan_threads: + t.start() + while any([t.is_alive() for t in self._scan_threads]): +# if self.abort_run.is_set(): +# break + for t in self._scan_threads: + try: + t.join(0.01) + except: + self._scan_threads.remove(t) + self.handle_err(sys.exc_info()) +# alive_threads = [t.name for t in self._scan_threads if (not t.join(10.0) and t.is_alive())] +# if alive_threads: +# raise RuntimeError("Scan thread(s) not finished: %s" % ", ".join(alive_threads)) + self._scan_threads = [] + for module_id in self._tx_module_groups: + if self.abort_run.is_set(): + break + with self.access_module(module_id=module_id): + # set modules to conf mode by after finishing scan() + self.register_utils.set_conf_mode() + else: + for tx_module_id, tx_group in self._tx_module_groups.items(): + if self.abort_run.is_set(): + break + with ExitStack() as restore_config_stack: + for module_id in itertools.chain([tx_module_id], tx_group): + if self.abort_run.is_set(): + break + with self.access_module(module_id=module_id): + logging.info('Scan parameter(s) for module %s: %s', module_id, ', '.join(['%s=%s' % (key, value) for (key, value) in self.scan_parameters._asdict().items()]) if self.scan_parameters else 'None') + # storing register values until scan has finished and then restore configuration + restore_config_stack.enter_context(self.register.restored(name=self.run_number)) + self.configure() + with self.access_module(module_id=tx_module_id): + # set all modules to run mode by before entering scan() + self.register_utils.set_run_mode() + self.fifo_readout.reset_rx() + self.fifo_readout.reset_fifo(self._selected_fifos) + self.fifo_readout.print_fei4_rx_status() + + # some scans use this event to stop scan loop, clear event here to make another scan possible + self.stop_run.clear() + with self.access_files(): + self.scan() + + with self.access_module(module_id=tx_module_id): + # set modules to conf mode by after finishing scan() + self.register_utils.set_conf_mode() + else: # Scan each FE individually + if self.threaded_scan: + self._scan_threads = [] + # loop over grpups of modules with different TX + for tx_module_ids in zip_nofill(*self._tx_module_groups.values()): + if self.abort_run.is_set(): + break + with ExitStack() as restore_config_stack: + for module_id in tx_module_ids: + if self.abort_run.is_set(): + break + with self.access_module(module_id=module_id): + logging.info('Scan parameter(s) for module %s: %s', module_id, ', '.join(['%s=%s' % (key, value) for (key, value) in self.scan_parameters._asdict().items()]) if self.scan_parameters else 'None') + # storing register values until scan has finished and then restore configuration + restore_config_stack.enter_context(self.register.restored(name=self.run_number)) + self.configure() + # set modules to run mode by before entering scan() + self.register_utils.set_run_mode() + t = ExcThread(target=self.scan, name=module_id) + t.daemon = True # exiting program even when thread is alive + self._scan_threads.append(t) + with self.access_module(module_id=tx_module_ids): + self.fifo_readout.reset_rx() + self.fifo_readout.reset_fifo(self._selected_fifos) + self.fifo_readout.print_fei4_rx_status() + + with self.access_files(): + # some scans use this event to stop scan loop, clear event here to make another scan possible + self.stop_run.clear() + for t in self._scan_threads: + t.start() + while any([t.is_alive() for t in self._scan_threads]): +# if self.abort_run.is_set(): +# break + for t in self._scan_threads: + try: + t.join(0.01) + except: + self._scan_threads.remove(t) + self.handle_err(sys.exc_info()) +# alive_threads = [t.name for t in self._scan_threads if (not t.join(10.0) and t.is_alive())] +# if alive_threads: +# raise RuntimeError("Scan thread(s) not finished: %s" % ", ".join(alive_threads)) + self._scan_threads = [] + + for module_id in tx_module_ids: + if self.abort_run.is_set(): + break + with self.access_module(module_id=module_id): + # set modules to conf mode by after finishing scan() + self.register_utils.set_conf_mode() + else: + for module_id in self._modules: + if self.abort_run.is_set(): + break + # some scans use this event to stop scan loop, clear event here to make another scan possible + self.stop_run.clear() + with self.access_module(module_id=module_id): + logging.info('Scan parameter(s) for module %s: %s', module_id, ', '.join(['%s=%s' % (key, value) for (key, value) in self.scan_parameters._asdict().items()]) if self.scan_parameters else 'None') + with self.register.restored(name=self.run_number): + self.configure() + # set modules to run mode by before entering scan() + self.register_utils.set_run_mode() + + self.fifo_readout.reset_rx() + self.fifo_readout.reset_fifo(self._selected_fifos) + self.fifo_readout.print_fei4_rx_status() + + # some scans use this event to stop scan loop, clear event here to make another scan possible + self.stop_run.clear() + with self.access_files(): + self.scan() + # set modules to conf mode by after finishing scan() + self.register_utils.set_conf_mode() + + if self._modules: + self.fifo_readout.print_readout_status() + + def post_run(self): + # analyzing data and store register cfg per front end one by one + for module_id in [name for name in self._modules if self._module_cfgs[name]["activate"] is True]: + if self.abort_run.is_set(): + break + with self.access_module(module_id=module_id): + try: + self.analyze() + except Exception: # analysis errors + exc = sys.exc_info() + self.err_queue.put(sys.exc_info()) + logging.warning(exc[1].__class__.__name__ + ": " + str(exc[1])) + else: # analyzed data, save config + self.register.save_configuration(self.output_filename) if not self.err_queue.empty(): exc = self.err_queue.get() # well known errors, do not print traceback @@ -395,20 +841,14 @@ def post_run(self): # some other error via handle_err(), print traceback else: raise exc[0], exc[1], exc[2] - elif self.abort_run.is_set(): - raise RunAborted() - elif self.stop_run.is_set(): - raise RunStopped() - # if ending up here, succcess! def cleanup_run(self): # no execption should be thrown here - self.raw_data_file = None # USB interface needs to be closed here, otherwise an USBError may occur # USB interface can be reused at any time after close without another init try: usb_intf = self.dut.get_modules('SiUsb') - except AttributeError: + except (KeyError, AttributeError): pass # not yet initialized else: if usb_intf: @@ -427,10 +867,9 @@ def cleanup_run(self): except AttributeError: pass # USB interface not yet initialized else: - pass -# logging.error('Closed USB device') + logging.debug('Closed USB device') - def handle_data(self, data): + def handle_data(self, data, new_file=False, flush=True): '''Handling of the data. Parameters @@ -438,7 +877,10 @@ def handle_data(self, data): data : list, tuple Data tuple of the format (data (np.array), last_time (float), curr_time (float), status (int)) ''' - self.raw_data_file.append_item(data, scan_parameters=self.scan_parameters._asdict(), flush=True) + for i, module_id in enumerate(self._selected_modules): + if data[i] is None: + continue + self._raw_data_files[module_id].append_item(data_tuple=data[i], scan_parameters=self._scan_parameters[module_id]._asdict(), flush=True) def handle_err(self, exc): '''Handling of Exceptions. @@ -458,20 +900,40 @@ def handle_err(self, exc): self.abort(msg=exc[1].__class__.__name__ + ": " + str(exc[1])) self.err_queue.put(exc) - def _get_configuration(self, run_number=None): + def get_module_path(self, module_id): + if module_id not in self._modules: + raise ValueError('Module ID "%s" is not a valid name.' % module_id) + return os.path.join(self.working_dir, module_id) + + def get_configuration(self, module_id, run_number=None): + ''' Returns the configuration for a given module ID. + + The working directory is searched for a file matching the module_id with the + given run number. If no run number is defined the last successfull run defines + the run number. + ''' def find_file(run_number): - for root, _, files in os.walk(self.working_dir): + module_path = self.get_module_path(module_id) + for root, _, files in os.walk(module_path): for cfgfile in files: cfg_root, cfg_ext = os.path.splitext(cfgfile) - if cfg_root.startswith(''.join([str(run_number), '_', self.module_id])) and cfg_ext.endswith(".cfg"): + if cfg_root.startswith(''.join([str(run_number), '_', module_id])) and cfg_ext.endswith(".cfg"): return os.path.join(root, cfgfile) if not run_number: - run_numbers = sorted(self._get_run_numbers(status='FINISHED').iterkeys(), reverse=True) + run_numbers = sorted(self._get_run_numbers(status='FINISHED').keys(), reverse=True) + found_fin_run_cfg = True + if not run_numbers: + return None + last_fin_run = run_numbers[0] for run_number in run_numbers: cfg_file = find_file(run_number) if cfg_file: + if not found_fin_run_cfg: + logging.warning("Module '%s' has no configuration for run %d, use config of run %d", module_id, last_fin_run, run_number) return cfg_file + else: + found_fin_run_cfg = False else: cfg_file = find_file(run_number) if cfg_file: @@ -490,39 +952,330 @@ def set_scan_parameters(self, *args, **kwargs): if field in fields: raise TypeError('Got multiple values for keyword argument %s' % field) fields[field] = value + if self.current_module_handle is None: + selected_modules = self._modules.keys() + elif self.current_module_handle in self._modules: + selected_modules = [self.current_module_handle] + elif self.current_module_handle in self._tx_module_groups: + selected_modules = self._tx_module_groups[self.current_module_handle] + else: + RuntimeError('Cannot change scan parameters. Module handle "%s" is not valid.' % self.current_module_handle) scan_parameters_old = self.scan_parameters._asdict() - self.scan_parameters = self.scan_parameters._replace(**fields) + with self.global_lock: + for module_id in selected_modules: + self._scan_parameters[module_id] = self.scan_parameters._replace(**fields) scan_parameters_new = self.scan_parameters._asdict() diff = [name for name in scan_parameters_old.keys() if np.any(scan_parameters_old[name] != scan_parameters_new[name])] if diff: logging.info('Changing scan parameter(s): %s', ', '.join([('%s=%s' % (name, fields[name])) for name in diff])) + def __setattr__(self, name, value): + ''' Always called to retrun the value for an attribute. + ''' + if self.is_initialized and name not in self.__dict__: + if name in self._module_run_conf[self.current_module_handle]: + raise RuntimeError('"%s" (current module handle "%s") cannot use attribute "%s" because it is already used in run conf.' % (self.__class__.__name__, self.current_module_handle, name)) + self._module_attr[self.current_module_handle][name] = value + # set attribute for all other mudules in module group + if self.current_module_handle in self._tx_module_groups: + for module_id in self._tx_module_groups[self.current_module_handle]: + self._module_attr[module_id][name] = value + else: + super(Fei4RunBase, self).__setattr__(name, value) + + def __getattr__(self, name): + ''' This is called in a last attempt to receive the value for an attribute that was not found in the usual places. + ''' + # test for attribute name in module attribute dict first + if self.is_initialized and name in self._module_attr[self.current_module_handle]: + return self._module_attr[self.current_module_handle][name] + else: + try: + return self._module_run_conf[self.current_module_handle][name] # Accessing run conf parameters + except KeyError: + try: + return super(Fei4RunBase, self).__getattr__(name) + except AttributeError: + if self.is_initialized: + raise AttributeError('"%s" (current module handle "%s") has no attribute "%s"' % (self.__class__.__name__, self.current_module_handle, name)) + else: + raise + + @contextmanager + def access_module(self, module_id): + self.select_module(module_id=module_id) + try: + yield + finally: + try: + self.deselect_module() + except: + # in case something fails, call this on last resort + self._current_module_handle = None + current_thread().name = "MainThread" + + def select_module(self, module_id): + ''' Select module and give access to the module. + ''' + if not isinstance(module_id, basestring) and isinstance(module_id, Iterable) and set(module_id) - set(self._modules): + raise ValueError('Module IDs invalid:' % ", ".join(set(module_id) - set(self._modules))) + if isinstance(module_id, basestring) and module_id not in self._module_cfgs: + raise ValueError('Module ID "%s" is not valid' % module_id) + if self._current_module_handle is not None: + raise RuntimeError('Module handle "%s" cannot be set because another module is active' % module_id) + + if module_id is None: + self._selected_modules = self._modules.keys() + elif not isinstance(module_id, basestring) and isinstance(module_id, Iterable): + self._selected_modules = module_id + elif module_id in self._modules: + self._selected_modules = [module_id] + elif module_id in self._tx_module_groups: + self._selected_modules = self._tx_module_groups[module_id] + else: + RuntimeError('Cannot open files. Module handle "%s" is not valid.' % self.current_module_handle) + + # FIFO readout + self._selected_fifos = list(set([module_cfg['FIFO'] for (name, module_cfg) in self._module_cfgs.items() if name in self._selected_modules])) + + # Module filter functions dict for quick lookup + self._readout_fifos = [] + self._filter = [] + self._converter = [] + for selected_module_id in self._selected_modules: + module_cfg = self._module_cfgs[selected_module_id] + self._readout_fifos.append(module_cfg['FIFO']) + if 'tdc_channel' not in module_cfg: + tdc_filter = false + self._converter.append(None) + elif module_cfg['tdc_channel'] is None: + tdc_filter = is_tdc_word + self._converter.append(convert_tdc_to_channel(channel=module_cfg['tdc_channel'])) # for the raw data analyzer + else: + tdc_filter = logical_and(is_tdc_word, is_tdc_from_channel(module_cfg['tdc_channel'])) + self._converter.append(convert_tdc_to_channel(channel=module_cfg['tdc_channel'])) # for the raw data analyzer + if 'rx_channel' not in module_cfg: + self._filter.append(logical_or(is_trigger_word, tdc_filter)) + elif module_cfg['rx_channel'] is None: + self._filter.append(logical_or(is_trigger_word, logical_or(tdc_filter, is_fe_word))) + else: + self._filter.append(logical_or(is_trigger_word, logical_or(tdc_filter, logical_and(is_fe_word, is_data_from_channel(module_cfg['rx_channel']))))) + + + # select readout channels and report sync status only from actively selected modules + self._enabled_fe_channels = list(set([module_cfg['RX'] for (name, module_cfg) in self._module_cfgs.items() if name in self._selected_modules])) + + # enabling specific TX channels + tx_channels = list(set([1 << module_cfg['tx_channel'] for (name, module_cfg) in self._module_cfgs.items() if name in self._selected_modules])) + if tx_channels: + self.dut['TX']['OUTPUT_ENABLE'] = reduce(lambda x, y: x | y, tx_channels) + else: + self.dut['TX']['OUTPUT_ENABLE'] = 0 + + if not isinstance(module_id, basestring) and isinstance(module_id, Iterable): + self._current_module_handle = None + else: + self._current_module_handle = module_id + + if module_id is not None and isinstance(module_id, basestring): + current_thread().name = module_id + + def deselect_module(self): + ''' Deselect module and cleanup. + ''' + self._enabled_fe_channels = [] # ignore any RX sync errors + self._readout_fifos = [] + self._filter = [] + self._converter = [] + self.dut['TX']['OUTPUT_ENABLE'] = 0 + self._current_module_handle = None + current_thread().name = "MainThread" + + @contextmanager + def access_files(self): + try: + self.open_files() + yield + self.close_files() + finally: + # in case something fails, call this on last resort + self._raw_data_files.clear() + + def open_files(self): + for selected_module_id in self._selected_modules: + self._raw_data_files[selected_module_id] = open_raw_data_file(filename=self.get_output_filename(module_id=selected_module_id), + mode='w', + title=self.run_id, + scan_parameters=self._scan_parameters[selected_module_id]._asdict(), + socket_address=self._module_cfgs[selected_module_id]['send_data']) + # save configuration data to raw data file + self._registers[selected_module_id].save_configuration(self._raw_data_files[selected_module_id].h5_file) + save_configuration_dict(self._raw_data_files[selected_module_id].h5_file, 'conf', self._conf) + save_configuration_dict(self._raw_data_files[selected_module_id].h5_file, 'run_conf', self._module_run_conf[selected_module_id]) + # send configuration data to online monitor + if self._raw_data_files[selected_module_id].socket: + send_meta_data(self._raw_data_files[selected_module_id].socket, self.output_filename, name='Filename') + global_register_config = {} + for global_reg in sorted(self._registers[selected_module_id].get_global_register_objects(readonly=False), key=itemgetter('name')): + global_register_config[global_reg['name']] = global_reg['value'] + send_meta_data(self._raw_data_files[selected_module_id].socket, global_register_config, name='GlobalRegisterConf') + send_meta_data(self._raw_data_files[selected_module_id].socket, self._run_conf, name='RunConf') + + def close_files(self): + # close all file objects + for f in self._raw_data_files.values(): + f.close() + # delete all file objects + self._raw_data_files.clear() + + def get_output_filename(self, module_id): + if module_id not in self._modules: + raise ValueError('Module ID "%s" is not a valid name.' % module_id) + module_path = os.path.join(self.working_dir, module_id) + return os.path.join(module_path, str(self.run_number) + "_" + module_id + "_" + self.run_id) + + def read_data(self, filter_func=None, converter_func=None): + with self._readout_lock: + if self.fifo_readout.fill_buffer: + return self.get_raw_data_from_buffer(filter_func=None, converter_func=None)[self._selected_modules.index(self.current_module_handle)] + else: + return self.read_raw_data_from_fifo(filter_func=filter_func, converter_func=converter_func) + + def get_raw_data_from_buffer(self, filter_func=None, converter_func=None): + return self.fifo_readout.get_raw_data_from_buffer(filter_func=filter_func, converter_func=converter_func) + + def read_raw_data_from_fifo(self, filter_func=None, converter_func=None): + return self.fifo_readout.read_raw_data_from_fifo(filter_func=filter_func, converter_func=converter_func) + + def data_words_per_second(self): + if self.current_module_handle is None: + return sum(self.fifo_readout.data_words_per_second()) + elif self.current_module_handle in self._modules: + return self.fifo_readout.data_words_per_second()[self._selected_modules.index(self.current_module_handle)] + elif self.current_module_handle in self._tx_module_groups: + return sum([dw_per_s for i, dw_per_s in enumerate(self.fifo_readout.data_words_per_second()) if self._selected_modules[i] in self._tx_module_groups[self.current_module_handle]]) + else: + RuntimeError('Module handle "%s" is not valid.' % self.current_module_handle) + + @contextmanager + def synchronized(self): + ''' Synchronize the execution of a section of code between threads. + ''' + self.enter_sync() + try: + yield + self.exit_sync() + finally: + # in case something fails, call this on last resort + pass + + def enter_sync(self): + ''' Waiting for all threads to appear, then continue. + ''' + if self._scan_threads and self.current_module_handle not in [t.name for t in self._scan_threads]: + raise RuntimeError('Thread name "%s" is not valid.') + if self._scan_threads and self.current_module_handle in self._curr_sync_threads: + raise RuntimeError('Thread "%s" is already actively reading FIFO.') + with self._sync_lock: + self._curr_sync_threads.append(self.current_module_handle) + self._enter_sync_event.clear() + while not self._enter_sync_event.wait(0.01): + if self.abort_run.is_set(): + break + with self._sync_lock: + if len(set(self._curr_sync_threads) & set([t.name for t in self._scan_threads if t.is_alive()])) == len(set([t.name for t in self._scan_threads if t.is_alive()])) or not self._scan_threads: + self._enter_sync_event.set() + + def exit_sync(self): + ''' Waiting for all threads to appear, then continue. + ''' + if self._scan_threads and self.current_module_handle not in [t.name for t in self._scan_threads]: + raise RuntimeError('Thread name "%s" is not valid.') + if self._scan_threads and self.current_module_handle not in self._curr_sync_threads: + raise RuntimeError('Thread "%s" is not reading FIFO.') + with self._sync_lock: + self._curr_sync_threads.remove(self.current_module_handle) + self._exit_sync_event.clear() + while not self._exit_sync_event.wait(0.01): + if self.abort_run.is_set(): + break + with self._sync_lock: + if len(set(self._curr_sync_threads) & set([t.name for t in self._scan_threads if t.is_alive()])) == 0 or not self._scan_threads: + self._exit_sync_event.set() + @contextmanager def readout(self, *args, **kwargs): + ''' Running the FIFO readout while executing other statements. + + Starting and stopping of the FIFO readout is synchronized between the threads. + ''' timeout = kwargs.pop('timeout', 10.0) self.start_readout(*args, **kwargs) try: yield - self.stop_readout(timeout=timeout) finally: - # in case something fails, call this on last resort - if self.fifo_readout.is_running: - self.fifo_readout.stop(timeout=0.0) + try: + self.stop_readout(timeout=timeout) + except: + # in case something fails, call this on last resort + # if run was aborted, immediately stop readout + if self.abort_run.is_set(): + with self._readout_lock: + if self.fifo_readout.is_running: + self.fifo_readout.stop(timeout=0.0) def start_readout(self, *args, **kwargs): + ''' Starting the FIFO readout. + + Starting of the FIFO readout is executed only once by a random thread. + Starting of the FIFO readout is synchronized between all threads reading out the FIFO. + ''' # Pop parameters for fifo_readout.start callback = kwargs.pop('callback', self.handle_data) - clear_buffer = kwargs.pop('clear_buffer', False) - fill_buffer = kwargs.pop('fill_buffer', False) - reset_sram_fifo = kwargs.pop('reset_sram_fifo', False) errback = kwargs.pop('errback', self.handle_err) + reset_rx = kwargs.pop('reset_rx', True) + reset_fifo = kwargs.pop('reset_fifo', True) + fill_buffer = kwargs.pop('fill_buffer', False) no_data_timeout = kwargs.pop('no_data_timeout', None) + enabled_fe_channels = kwargs.pop('enabled_fe_channels', self._enabled_fe_channels) + enabled_m26_channels = kwargs.pop('enabled_m26_channels', []) # use none by default, even if available in firmware if args or kwargs: self.set_scan_parameters(*args, **kwargs) - self.fifo_readout.start(reset_sram_fifo=reset_sram_fifo, fill_buffer=fill_buffer, clear_buffer=clear_buffer, callback=callback, errback=errback, no_data_timeout=no_data_timeout) + if self._scan_threads and self.current_module_handle not in [t.name for t in self._scan_threads]: + raise RuntimeError('Thread name "%s" is not valid.' % t.name) + if self._scan_threads and self.current_module_handle in self._curr_readout_threads: + raise RuntimeError('Thread "%s" is already actively reading FIFO.') + with self._readout_lock: + self._curr_readout_threads.append(self.current_module_handle) + self._starting_readout_event.clear() + while not self._starting_readout_event.wait(0.01): + if self.abort_run.is_set(): + break + with self._readout_lock: + if len(set(self._curr_readout_threads) & set([t.name for t in self._scan_threads if t.is_alive()])) == len(set([t.name for t in self._scan_threads if t.is_alive()])) or not self._scan_threads: + if not self.fifo_readout.is_running: + self.fifo_readout.start(fifos=self._selected_fifos, callback=callback, errback=errback, reset_rx=reset_rx, reset_fifo=reset_fifo, fill_buffer=fill_buffer, no_data_timeout=no_data_timeout, filter_func=self._filter, converter_func=self._converter, fifo_select=self._readout_fifos, enabled_fe_channels=enabled_fe_channels, enabled_m26_channels=enabled_m26_channels) + self._starting_readout_event.set() def stop_readout(self, timeout=10.0): - self.fifo_readout.stop(timeout=timeout) + ''' Stopping the FIFO readout. + + Stopping of the FIFO readout is executed only once by a random thread. + Stopping of the FIFO readout is synchronized between all threads reading out the FIFO. + ''' + if self._scan_threads and self.current_module_handle not in [t.name for t in self._scan_threads]: + raise RuntimeError('Thread name "%s" is not valid.') + if self._scan_threads and self.current_module_handle not in self._curr_readout_threads: + raise RuntimeError('Thread "%s" is not reading FIFO.') + with self._readout_lock: + self._curr_readout_threads.remove(self.current_module_handle) + self._stopping_readout_event.clear() + while not self._stopping_readout_event.wait(0.01): + with self._readout_lock: + if len(set(self._curr_readout_threads) & set([t.name for t in self._scan_threads if t.is_alive()])) == 0 or not self._scan_threads or self.abort_run.is_set(): + if self.fifo_readout.is_running: + self.fifo_readout.stop(timeout=timeout) + self._stopping_readout_event.set() def _cleanup(self): # called in run base after exception handling super(Fei4RunBase, self)._cleanup() @@ -535,31 +1288,131 @@ def _cleanup(self): # called in run base after exception handling except: logging.warning("Failed sending pyBAR status report") - @abc.abstractmethod def configure(self): - '''Implementation of the run configuration. + '''The module configuration happens here. - Will be executed before starting the scan routine. + Will be executed before calling the scan method. + Any changes of the module configuration will be reverted after after finishing the scan method. ''' pass - @abc.abstractmethod def scan(self): - '''Implementation of the scan routine. - - Do you want to write your own scan? Here is the place to begin. + '''Implementation of the scan. ''' pass - @abc.abstractmethod def analyze(self): - '''Implementation of run data processing. + '''Implementation of the data analysis. - Will be executed after finishing the scan routine. + Will be executed after finishing the scan method. ''' pass +class ExcThread(Thread): + def run(self): + self.exc = None + try: + if hasattr(self, '_Thread__target'): + # Thread uses name mangling prior to Python 3. + self._Thread__target(*self._Thread__args, **self._Thread__kwargs) + else: + self._target(*self._args, **self._kwargs) + except: + self.exc = sys.exc_info() + + def join(self, timeout=None): + super(ExcThread, self).join(timeout=timeout) + if self.exc: + raise self.exc[0], self.exc[1], self.exc[2] + + +class RhlHandle(object): + ''' Handle for basil.HL.RegisterHardwareLayer. + + Mimic register interface of RegisterHardwareLayer objects and allows for consecutively reading/writing values in all given modules. + ''' + def __init__(self, dut, module_names): + self._dut = dut + if not module_names: + module_names = [] + if len(set(module_names)) != len(module_names): + raise ValueError('Parameter "module_names" contains duplicate entries.') + if module_names and not all([isinstance(dut[module_name], basil.HL.RegisterHardwareLayer.RegisterHardwareLayer) for module_name in module_names]): + raise ValueError("Not all modules are of type basil.HL.RegisterHardwareLayer.RegisterHardwareLayer.") + self.module_names = module_names + + def __getitem__(self, name): + values = [] + for module_name in self.module_names: + values.append(self._dut[module_name][name]) + if not len(set(values)) == 1: + raise RuntimeError("Returned values for %s are different." % (name,)) + return values[0] + + def __setitem__(self, name, value): + for module_name in self.module_names: + self._dut[module_name][name] = value + + def __getattr__(self, name): + '''called only on last resort if there are no attributes in the instance that match the name + ''' + if name.isupper(): + return self[name] + else: + def method(*args, **kwargs): + nsplit = name.split('_', 1) + if len(nsplit) == 2 and nsplit[0] == 'set' and nsplit[1].isupper() and len(args) == 1 and not kwargs: + self[nsplit[1]] = args[0] # returns None + elif len(nsplit) == 2 and nsplit[0] == 'get' and nsplit[1].isupper() and not args and not kwargs: + return self[nsplit[1]] + else: + values = [] + for module_name in self.module_names: + values.append(getattr(self._dut[module_name], name)(*args, **kwargs)) + if not len(set(values)) == 1: + raise RuntimeError("Returned values for %s are different." % (name,)) + return values[0] +# raise AttributeError("%r object has no attribute %r" % (self.__class__, name)) + return method + + def __setattr__(self, name, value): + if name.isupper(): + self[name] = value + else: + super(RhlHandle, self).__setattr__(name, value) + + +class DutHandle(object): + ''' Handle for DUT. + + Providing interface to Basil DUT object and gives access only to those drivers which are specified in the module configuration. + ''' + def __init__(self, dut, module_cfg): + self._dut = dut + self._module_cfg = module_cfg + + def __getitem__(self, name): + try: + return self._dut[name] + except KeyError: + pass + try: + return self._dut[self._module_cfg[name]] + except TypeError: + # dict item is list + module_names = self._module_cfg[name] + if len(module_names) > 1: + return RhlHandle(dut=self._dut, module_names=module_names) + else: + return self._dut[module_names[0]] + + def __getattr__(self, name): + '''called only on last resort if there are no attributes in the instance that match the name + ''' + return getattr(self._dut, name) + + def timed(f): @wraps(f) def wrapper(*args, **kwargs): diff --git a/pybar/mmc3_16chip_multi_tx_eth.bit b/pybar/mmc3_16chip_multi_tx_eth.bit new file mode 100644 index 000000000..44ff1d2bd Binary files /dev/null and b/pybar/mmc3_16chip_multi_tx_eth.bit differ diff --git a/pybar/mmc3_8chip_eth.bit b/pybar/mmc3_8chip_eth.bit new file mode 100755 index 000000000..ab9decf25 Binary files /dev/null and b/pybar/mmc3_8chip_eth.bit differ diff --git a/pybar/mmc3_8chip_multi_tx_eth.bit b/pybar/mmc3_8chip_multi_tx_eth.bit new file mode 100755 index 000000000..0c0ebc7a9 Binary files /dev/null and b/pybar/mmc3_8chip_multi_tx_eth.bit differ diff --git a/pybar/mmc3_m26_eth.bit b/pybar/mmc3_m26_eth.bit new file mode 100755 index 000000000..6cfcea076 Binary files /dev/null and b/pybar/mmc3_m26_eth.bit differ diff --git a/pybar/online_monitor.py b/pybar/online_monitor.py index 5350b13ca..c6b23e583 100644 --- a/pybar/online_monitor.py +++ b/pybar/online_monitor.py @@ -1,15 +1,15 @@ import sys -import zmq import time -import numpy as np +from threading import Event, Lock from optparse import OptionParser +import zmq +import numpy as np from PyQt5 import Qt import pyqtgraph as pg from pyqtgraph.Qt import QtCore, QtGui from pyqtgraph.dockarea import DockArea, Dock import pyqtgraph.ptime as ptime -from threading import Event, Lock from pybar_fei4_interpreter.data_interpreter import PyDataInterpreter from pybar_fei4_interpreter.data_histograming import PyDataHistograming diff --git a/pybar/run_manager.py b/pybar/run_manager.py index d68367302..a079c66e7 100644 --- a/pybar/run_manager.py +++ b/pybar/run_manager.py @@ -1,5 +1,4 @@ import logging -from yaml import safe_load import datetime import os import re @@ -13,15 +12,16 @@ import abc from contextlib import contextmanager from importlib import import_module -from inspect import getmembers, isclass +from inspect import getmembers, isclass, getargspec from functools import partial from ast import literal_eval from time import time from threading import current_thread from functools import wraps +from yaml import safe_load -punctuation = """!,.:;?""" +punctuation = '!,.:;?' _RunStatus = namedtuple('RunStatus', ['running', 'finished', 'stopped', 'aborted', 'crashed']) @@ -38,15 +38,15 @@ class RunStopped(Exception): pass -class RunBase(): +class RunBase(object): '''Basic run meta class Base class for run class. ''' __metaclass__ = abc.ABCMeta - def __init__(self, conf, run_conf=None): - """Initialize object. + def __init__(self, conf): + '''Initialize object. Parameters ---------- @@ -54,21 +54,38 @@ def __init__(self, conf, run_conf=None): Persistant configuration for all runs. run_conf : dict Run configuration for single run. - """ + ''' self._conf = conf - self._init_run_conf(run_conf) + self._run_conf = None self._run_number = None self._run_status = None self.file_lock = Lock() self.stop_run = Event() # abort condition for loops self.abort_run = Event() self._last_traceback = None + self._run_start_time = None + self._run_stop_time = None + self._total_run_time = None + self._last_error_message = None + self._last_traceback = None + self._cancel_functions = None + self.connect_cancel(["abort"]) + self._initialized = False + + @property + def is_initialized(self): + if "_initialized" in self.__dict__ and self._initialized: + return True + else: + return False -# @abc.abstractproperty -# def _run_id(self): -# '''Defining run name -# ''' -# pass + def __getattr__(self, name): + ''' This is called in a last attempt to receive the value for an attribute that was not found in the usual places. + ''' + try: + return self._run_conf[name] # Accessing run conf parameters + except KeyError: + raise AttributeError("'%s' has no attribute '%s'" % (self.__class__.__name__, name)) @property def run_id(self): @@ -126,6 +143,7 @@ def run_status(self, value): def run(self, run_conf, run_number=None, signal_handler=None): self._init(run_conf, run_number) + self._initialized = True logging.info('Starting run %d (%s) in %s', self.run_number, self.__class__.__name__, self.working_dir) # set up signal handler if current_thread().name == 'MainThread': @@ -140,10 +158,6 @@ def run(self, run_conf, run_number=None, signal_handler=None): self._run_status = run_status.aborted self._last_traceback = None self._last_error_message = e.__class__.__name__ + ": " + str(e) - except RunStopped as e: - self._run_status = run_status.finished - self._last_traceback = None - self._last_error_message = e.__class__.__name__ + ": " + str(e) except Exception as e: self._run_status = run_status.crashed self._last_traceback = traceback.format_exc() @@ -152,6 +166,8 @@ def run(self, run_conf, run_number=None, signal_handler=None): self._run_status = run_status.finished self._last_traceback = None self._last_error_message = None + finally: + self._initialized = False # revert signal handler to default if current_thread().name == 'MainThread': signal.signal(signal.SIGINT, signal.SIG_DFL) @@ -176,24 +192,24 @@ def run(self, run_conf, run_number=None, signal_handler=None): return self.run_status def _init(self, run_conf, run_number=None): - """Initialization before a new run.""" + '''Initialization before a new run. + ''' self.stop_run.clear() self.abort_run.clear() self._run_status = run_status.running self._write_run_number(run_number) - self._init_run_conf(run_conf, update=True) + self._init_run_conf(run_conf) - def _init_run_conf(self, run_conf, update=False): + def _init_run_conf(self, run_conf): + attribute_names = [key for key in self._default_run_conf.keys() if (key in self.__dict__ or (hasattr(self.__class__, key) and isinstance(getattr(self.__class__, key), property)))] + if attribute_names: + raise RuntimeError('Attribute names already in use. Rename the following parameters in run conf: %s' % ', '.join(attribute_names)) sc = namedtuple('run_configuration', field_names=self._default_run_conf.keys()) - if update: - default_run_conf = sc(**self._run_conf) - else: - default_run_conf = sc(**self._default_run_conf) + default_run_conf = sc(**self._default_run_conf) if run_conf: self._run_conf = default_run_conf._replace(**run_conf)._asdict() else: self._run_conf = default_run_conf._asdict() - self.__dict__.update(self._run_conf) @contextmanager def _run(self): @@ -201,37 +217,65 @@ def _run(self): self.pre_run() yield self.post_run() + if self.abort_run.is_set(): + raise RunAborted() finally: self.cleanup_run() @abc.abstractmethod def pre_run(self): - """Before run.""" + '''Before run. + ''' pass @abc.abstractmethod def do_run(self): - """The run.""" + '''The run. + ''' pass @abc.abstractmethod def post_run(self): - """After run.""" + '''After run. + ''' pass @abc.abstractmethod def cleanup_run(self): - """Cleanup after run, will be executed always, even after exception. Avoid throwing exceptions here. - """ + '''Cleanup after run, will be executed always, even after exception. Avoid throwing exceptions here. + ''' pass def _cleanup(self): - """Cleanup after a new run.""" + '''Cleanup after a new run. + ''' self._write_run_status(self.run_status) + def connect_cancel(self, functions): + '''Run given functions when a run is cancelled. + ''' + self._cancel_functions = [] + for func in functions: + if isinstance(func, basestring) and hasattr(self, func) and callable(getattr(self, func)): + self._cancel_functions.append(getattr(self, func)) + elif callable(func): + self._cancel_functions.append(func) + else: + raise ValueError("Unknown function %s" % str(func)) + + def handle_cancel(self, **kwargs): + '''Cancelling a run. + ''' + for func in self._cancel_functions: + f_args = getargspec(func)[0] + f_kwargs = {key: kwargs[key] for key in f_args if key in kwargs} + func(**f_kwargs) + def stop(self, msg=None): - """Stopping a run. Control for loops. - """ + '''Stopping a run. Control for loops. Gentle stop/abort. + + This event should provide a more gentle abort. The run should stop ASAP but the run is still considered complete. + ''' if not self.stop_run.is_set(): if msg: logging.info('%s%s Stopping run...', msg, ('' if msg[-1] in punctuation else '.')) @@ -240,8 +284,10 @@ def stop(self, msg=None): self.stop_run.set() def abort(self, msg=None): - """Aborting a run. Control for loops. Immediate abort. - """ + '''Aborting a run. Control for loops. Immediate stop/abort. + + The implementation should stop a run ASAP when this event is set. The run is considered incomplete. + ''' if not self.abort_run.is_set(): if msg: logging.error('%s%s Aborting run...', msg, ('' if msg[-1] in punctuation else '.')) @@ -309,14 +355,14 @@ def _write_run_status(self, status_msg): def _signal_handler(self, signum, frame): signal.signal(signal.SIGINT, signal.SIG_DFL) # setting default handler... pressing Ctrl-C a second time will kill application - self.stop('Pressed Ctrl-C') + self.handle_cancel(msg='Pressed Ctrl-C') def thunkify(thread_name): - """Make a function immediately return a function of no args which, when called, + '''Make a function immediately return a function of no args which, when called, waits for the result, which will start being processed in another thread. Taken from https://wiki.python.org/moin/PythonDecoratorLibrary. - """ + ''' def actual_decorator(f): @functools.wraps(f) def thunked(*args, **kwargs): @@ -440,15 +486,10 @@ def open_conf(conf): conf_dict.update(conf) return conf_dict - def stop_current_run(self, msg=None): + def cancel_current_run(self, msg=None): '''Control for runs. ''' - self.current_run.stop(msg) - - def abort_current_run(self, msg=None): - '''Control for runs. Immediate abort. - ''' - self.current_run.abort(msg) + self.current_run.handle_cancel(msg=msg) def run_run(self, run, conf=None, run_conf=None, use_thread=False, catch_exception=True): '''Runs a run in another thread. Non-blocking. @@ -589,7 +630,7 @@ def isrun(item, module): def _signal_handler(self, signum, frame): signal.signal(signal.SIGINT, signal.SIG_DFL) # setting default handler... pressing Ctrl-C a second time will kill application - self.stop_current_run('Pressed Ctrl-C') + self.cancel_current_run(msg='Pressed Ctrl-C') def set_event_when_keyboard_interrupt(_lambda): diff --git a/pybar/scans/__init__.py b/pybar/scans/__init__.py index e5e3e5d24..9484cc43a 100644 --- a/pybar/scans/__init__.py +++ b/pybar/scans/__init__.py @@ -1,5 +1,4 @@ from pybar.scans.calibrate_hit_or import HitOrCalibration, create_hitor_calibration -from pybar.scans.calibrate_plsr_dac_transient import PlsrDacTransientCalibration from pybar.scans.calibrate_plsr_dac import PlsrDacCalibration, plot_pulser_dac from pybar.scans.calibrate_pulser_dac_correction import PulserDacCorrectionCalibration from pybar.scans.calibrate_plsr_dac_transient import PlsrDacTransientCalibration @@ -11,7 +10,7 @@ from pybar.scans.scan_ext_trigger_gdac import ExtTriggerGdacScan from pybar.scans.scan_ext_trigger_stop_mode import StopModeExtTriggerScan from pybar.scans.scan_ext_trigger import ExtTriggerScan -from pybar.scans.scan_fei4_self_trigger import FEI4SelfTriggerScan +from pybar.scans.scan_fei4_self_trigger import Fei4SelfTriggerScan from pybar.scans.scan_hit_delay import HitDelayScan from pybar.scans.scan_ileak import IleakScan from pybar.scans.scan_init import InitScan @@ -32,4 +31,4 @@ from pybar.scans.tune_threshold_baseline import ThresholdBaselineTuning from pybar.scans.tune_tlu import TluTuning -__all__ = ["HitOrCalibration", "create_hitor_calibration", "PlsrDacTransientCalibration", "PlsrDacCalibration", "plot_pulser_dac", "PulserDacCorrectionCalibration", "ThresholdCalibration", "create_threshold_calibration", "TotCalibration", "AnalogScan", "CrosstalkScan", "DigitalScan", "ExtTriggerGdacScan", "StopModeExtTriggerScan", "ExtTriggerScan", "FEI4SelfTriggerScan", "HitDelayScan", "IleakScan", "InitScan", "IVScan", "FastThresholdScan", "ThresholdScan", "RegisterTest", "TdcTest", "FdacTuning", "FeedbackTuning", "Fei4Tuning", "GdacTuning", "HotPixelTuning", "MergedPixelsTuning", "NoiseOccupancyTuning", "StuckPixelScan", "TdacTuning", "ThresholdBaselineTuning", "TluTuning"] +__all__ = ["HitOrCalibration", "create_hitor_calibration", "PlsrDacTransientCalibration", "PlsrDacCalibration", "plot_pulser_dac", "PulserDacCorrectionCalibration", "ThresholdCalibration", "create_threshold_calibration", "TotCalibration", "AnalogScan", "CrosstalkScan", "DigitalScan", "ExtTriggerGdacScan", "StopModeExtTriggerScan", "ExtTriggerScan", "Fei4SelfTriggerScan", "HitDelayScan", "IleakScan", "InitScan", "IVScan", "FastThresholdScan", "ThresholdScan", "RegisterTest", "TdcTest", "FdacTuning", "FeedbackTuning", "Fei4Tuning", "GdacTuning", "HotPixelTuning", "MergedPixelsTuning", "NoiseOccupancyTuning", "StuckPixelScan", "TdacTuning", "ThresholdBaselineTuning", "TluTuning"] diff --git a/pybar/scans/analyze_example_conversion.py b/pybar/scans/analyze_example_conversion.py index e23fc14ae..1fa631ad0 100644 --- a/pybar/scans/analyze_example_conversion.py +++ b/pybar/scans/analyze_example_conversion.py @@ -5,8 +5,9 @@ The analyze_raw_data_per_scan_parameter function does the anylysis per scan parameter. """ -from datetime import datetime import logging +from datetime import datetime + from pybar.analysis.analyze_raw_data import AnalyzeRawData from pybar.analysis.analysis import analyze_hits_per_scan_parameter diff --git a/pybar/scans/analyze_source_scan_gdac_data.py b/pybar/scans/analyze_source_scan_gdac_data.py index 4c279396a..6ddc3129e 100644 --- a/pybar/scans/analyze_source_scan_gdac_data.py +++ b/pybar/scans/analyze_source_scan_gdac_data.py @@ -249,6 +249,7 @@ def analyze_injected_charge(data_analyzed_file): if analysis_configuration['use_cluster_rate_correction']: correction_h5.close() + if __name__ == "__main__": data_files = analysis_utils.get_data_file_names_from_scan_base(analysis_configuration['scan_name']) files_dict = analysis_utils.get_parameter_from_files(data_files, unique=True, parameters='GDAC') # get a sorted ordered dict with GDAC, raw_data_filename diff --git a/pybar/scans/analyze_source_scan_tdc_data.py b/pybar/scans/analyze_source_scan_tdc_data.py index 2a9124116..18b1e1973 100644 --- a/pybar/scans/analyze_source_scan_tdc_data.py +++ b/pybar/scans/analyze_source_scan_tdc_data.py @@ -25,7 +25,6 @@ import progressbar from pybar_fei4_interpreter import analysis_utils as fast_analysis_utils - from pybar.analysis import analysis_utils from pybar.analysis.analyze_raw_data import AnalyzeRawData from pybar.analysis.plotting.plotting import plot_three_way, plot_1d_hist @@ -359,6 +358,7 @@ def delete_disabled_regions(hits, enable_mask): elif 'HistTdcCorr' in node.name: plot_tdc_tot_correlation(node[:], node._v_attrs.condition, output_pdf) + if __name__ == "__main__": raw_data_files = analysis_utils.get_data_file_names_from_scan_base(analysis_configuration['scan_name']) logging.info('Found ' + str(len(raw_data_files)) + ' raw data file(s)') diff --git a/pybar/scans/calibrate_hit_or.py b/pybar/scans/calibrate_hit_or.py index 90627a16a..d8d73b967 100644 --- a/pybar/scans/calibrate_hit_or.py +++ b/pybar/scans/calibrate_hit_or.py @@ -42,8 +42,8 @@ def create_hitor_calibration(output_filename, plot_pixel_calibrations=False): analyze_raw_data.interpret_word_table() analyze_raw_data.interpreter.print_summary() analyze_raw_data.plot_histograms() - n_injections = analyze_raw_data.n_injections # use later + n_injections = analyze_raw_data.n_injections # use later meta_data = analyze_raw_data.out_file_h5.root.meta_data[:] scan_parameters_dict = get_scan_parameter(meta_data) inner_loop_parameter_values = scan_parameters_dict[next(reversed(scan_parameters_dict))] # inner loop parameter name is unknown @@ -82,7 +82,7 @@ def create_hitor_calibration(output_filename, plot_pixel_calibrations=False): else: raise ValueError("Unknown scan parameter %s" % item) - # Only pixel of actual column/row should be in the actual data chunk but since SRAM is not cleared for each scan step due to speed reasons and there might be noisy pixels this is not always the case + # Only pixel of actual column/row should be in the actual data chunk but since FIFO is not cleared for each scan step due to speed reasons and there might be noisy pixels this is not always the case n_wrong_pixel = np.count_nonzero(np.logical_or(actual_hits['column'] != actual_col, actual_hits['row'] != actual_row)) if n_wrong_pixel != 0: logging.warning('%d hit(s) from other pixels for scan parameters %s', n_wrong_pixel, ', '.join(['%s=%s' % (name, value) for (name, value) in zip(scan_parameter_names, actual_scan_parameter_values)])) @@ -153,6 +153,8 @@ class HitOrCalibration(Fei4RunBase): ''' HitOR calibration scan ''' _default_run_conf = { + "broadcast_commands": True, + "threaded_scan": True, "n_injections": 200, # number of injections "injection_delay": 5000, # for really low feedbacks (ToT >> 300 ns) one needs to increase the injection delay "scan_parameters": [('column', None), @@ -228,14 +230,14 @@ def inject_double_column(column): self.register_utils.send_commands(commands) self.dut['TDC']['EN_ARMING'] = True - with self.readout(reset_sram_fifo=False, clear_buffer=False, column=column, row=row, **{scan_parameter_name: scan_parameter_value}): + with self.readout(reset_fifo=True, column=column, row=row, **{scan_parameter_name: scan_parameter_value}): self.register_utils.send_command(command=cal_lvl1_command, repeat=self.n_injections) self.dut['TDC']['EN_ARMING'] = False self.dut['TDC']['ENABLE'] = False - def handle_data(self, data): - self.raw_data_file.append_item(data, scan_parameters=self.scan_parameters._asdict(), new_file=['column'], flush=True) # Create new file for each scan parameter change + def handle_data(self, data, new_file=['column'], flush=True): # Create new file for each scan parameter change + super(HitOrCalibration, self).handle_data(data=data, new_file=new_file, flush=flush) def analyze(self): create_hitor_calibration(self.output_filename, plot_pixel_calibrations=True) diff --git a/pybar/scans/calibrate_plsr_dac.py b/pybar/scans/calibrate_plsr_dac.py index 71b518916..5330ee6c0 100644 --- a/pybar/scans/calibrate_plsr_dac.py +++ b/pybar/scans/calibrate_plsr_dac.py @@ -27,6 +27,7 @@ class PlsrDacCalibration(Fei4RunBase): _default_run_conf = { + "broadcast_commands": True, "scan_parameters": [('PlsrDAC', range(0, 1024, 25)), ('Colpr_Addr', range(0, 40))], # the PlsrDAC and Colpr_Addr range "mask_steps": 3, "repeat_measurements": 10, diff --git a/pybar/scans/calibrate_plsr_dac_transient.py b/pybar/scans/calibrate_plsr_dac_transient.py index 559304fd7..4eec51003 100644 --- a/pybar/scans/calibrate_plsr_dac_transient.py +++ b/pybar/scans/calibrate_plsr_dac_transient.py @@ -43,6 +43,7 @@ def interpret_data_from_tektronix(preamble, data): voltage = YZEro + YMUlt * (voltage - YOFf) return time, voltage, time_unit, voltage_unit + # Select actual interpretation function interpret_oscilloscope_data = interpret_data_from_tektronix diff --git a/pybar/scans/calibrate_threshold.py b/pybar/scans/calibrate_threshold.py index 2454d9c70..7a067fc55 100644 --- a/pybar/scans/calibrate_threshold.py +++ b/pybar/scans/calibrate_threshold.py @@ -14,7 +14,6 @@ import progressbar from pybar_fei4_interpreter import data_struct - from pybar.run_manager import RunManager from pybar.scans.scan_threshold_fast import FastThresholdScan from pybar.analysis import analysis_utils @@ -165,8 +164,8 @@ def scan(self): super(ThresholdCalibration, self).scan() logging.info("Finished!") - def handle_data(self, data): - self.raw_data_file.append_item(data, scan_parameters=self.scan_parameters._asdict(), new_file=[self.scan_parameters._fields[1]], flush=True) # Create new file for each scan parameter change + def handle_data(self, data, new_file=['GDAC'], flush=True): # Create new file for each scan parameter change + super(ThresholdCalibration, self).handle_data(data=data, new_file=new_file, flush=flush) def analyze(self): create_threshold_calibration(self.output_filename, create_plots=self.create_plots) diff --git a/pybar/scans/calibrate_tot.py b/pybar/scans/calibrate_tot.py index 910a4534f..a912248ad 100644 --- a/pybar/scans/calibrate_tot.py +++ b/pybar/scans/calibrate_tot.py @@ -17,6 +17,7 @@ class TotCalibration(Fei4RunBase): ''' ToT calibration scan ''' _default_run_conf = { + "broadcast_commands": True, "mask_steps": 3, # mask steps, the injected charge depends on the mask steps "n_injections": 200, # number of injections per PlsrDAC, for higher precision close to the threshold increase n_injections "scan_parameters": [('PlsrDAC', [40, 50, 60, 80, 130, 180, 230, 280, 340, 440, 540, 640, 740])], # 0 400 sufficient for most tunings diff --git a/pybar/scans/deprecated/analyze_data_taking_status.py b/pybar/scans/deprecated/analyze_data_taking_status.py deleted file mode 100644 index bdf2be1bf..000000000 --- a/pybar/scans/deprecated/analyze_data_taking_status.py +++ /dev/null @@ -1,81 +0,0 @@ -''' Script that sends info E-Mails if the data taking stops. Therefore it checks if at least one file of some given files in a specified folder -is changed in a specified time. If not an alert E-Mail is send. If the data taking work again an info email is send -''' -import time -import os -import string -import smtplib -import logging -import pprint -from datetime import datetime -from threading import Event -from watchdog.observers import Observer -from watchdog.events import FileSystemEventHandler - - -configuration = { - "path_to_monitor": 'data/SCC_99', # the monitor the watchdog checks - "timeout": 30 * 60, # the timeout in seconds until an alert email is send (if the data files did not change) - "timeout_alert": 10, # the timeout in seconds until the alert status is reset (if the data files did change) - 'data_files': None, # the files that are monitored for changes - "check_subfolders": True, # check also the subfolders of 'path_to_monitor' - "email_text_alert": 'Sorry, SCC 99 did not collect data within the last 30 min. Usually one GDAC setting takes less than 15. min to collect the desired triggers. Please check ;-)\nSincerely Mr. Beam', # outgoing mail server - "email_text_alert_cleared": 'Very nice, I see that the data taking for SCC 99 works again\nSincerely Mr. Beam', # outgoing mail server - "email_host": 'mail.gmx.net', # outgoing mail server - "email_to": ["pohl@physik.uni-bonn.de", "janssen@physik.uni-bonn.de"], # the Email adresses the status emails are send to - "email_account": ['mr_beam@gmx.de', 'pidub123'] # email account name and password used to send email -} - - -def send_mail(text, subject=''): - logging.info('send status E-Mail (' + subject + ')') - body = string.join(( - "From: %s" % configuration['email_account'][0], - "To: %s" % configuration['email_to'], - "Subject: %s" % subject, - "", - text - ), "\r\n") - server = smtplib.SMTP(configuration['email_host']) - server.login(configuration['email_account'][0], configuration['email_account'][1]) - server.sendmail(configuration['email_account'][0], configuration['email_to'], body) - server.quit() - - -class MyHandler(FileSystemEventHandler): - def on_modified(self, event): - if configuration['data_files'] is None: - data_changed.set() - elif os.path.basename(event.src_path) in configuration['data_files']: - data_changed.set() - -if __name__ == '__main__': - logging.info('Configuration:\n' + pprint.pformat(configuration)) - timeout = configuration['timeout'] - alert_status = Event() - data_changed = Event() - alert_status.clear() - data_changed.clear() - observer = Observer() - observer.schedule(MyHandler(), path=configuration['path_to_monitor'], recursive=configuration['check_subfolders']) - observer.start() - - try: - while True: - time.sleep(timeout) - if not data_changed.is_set(): - logging.info('data taking BAD') - if not alert_status.is_set(): - send_mail(configuration['email_text_alert'], subject='TESTBEAM WARNING') - timeout = configuration['timeout_alert'] - alert_status.set() - else: - logging.info('data taking OK') - if alert_status.is_set(): - send_mail(configuration['email_text_alert_cleared'], subject='TESTBEAM INFO') - timeout = configuration['timeout'] - alert_status.clear() - data_changed.clear() - except KeyboardInterrupt: - observer.stop() - observer.join() diff --git a/pybar/scans/deprecated/analyze_source.py b/pybar/scans/deprecated/analyze_source.py deleted file mode 100644 index 5a1ad9795..000000000 --- a/pybar/scans/deprecated/analyze_source.py +++ /dev/null @@ -1,37 +0,0 @@ -"""This script takes the data of a source scan and determines the number of events, the beam spot and the number of particles per event as a function of time. -""" -import logging -import pprint -from datetime import datetime - -from matplotlib.backends.backend_pdf import PdfPages - -from analysis import analysis -from analysis import analysis_utils - - -analysis_configuration = { - 'scan_base': ['data//SCC_99//20V//SCC_99_ext_trigger_gdac_scan_432'], - 'scan_parameter': False,#'GDAC', # if set the scan_bases represent multiple files with this scan parameter changing, otherwise False - 'combine_n_readouts': 1, - 'time_line_absolute': False, - 'plot_occupancy_hists': False, - 'plot_n_cluster_hists': False, - 'include_no_cluster': False, - 'output_file': 'data//SCC_99//20V//beam_analysis_rate.h5', # if set the data is stored into an hdf5 file with this file name, otherwise False - 'output_pdf': None#PdfPages('data//SCC_99//20V//beam_analysis.pdf') -} - -if __name__ == "__main__": - start_time = datetime.now() - - logging.info('Use the following files') - logging.info(pprint.pformat(analysis_configuration['scan_base'])) - - analysis.analyze_beam_spot(**analysis_configuration) - analysis.analyze_event_rate(**analysis_configuration) - analysis.analyse_n_cluster_per_event(**analysis_configuration) - - if analysis_configuration['output_pdf'] is not None: - analysis_configuration['output_pdf'].close() - logging.info('Script runtime %.1f seconds' % (datetime.now() - start_time).total_seconds()) diff --git a/pybar/scans/deprecated/scan_ext_injection.py b/pybar/scans/deprecated/scan_ext_injection.py deleted file mode 100644 index 704e534eb..000000000 --- a/pybar/scans/deprecated/scan_ext_injection.py +++ /dev/null @@ -1,157 +0,0 @@ -""" Scan to inject charge with an external pulser. A trigger signal (3.3V logic level, TX1 at MultiIO board) - is generated when the CAL command is issued. This trigger can be used to trigger the external pulser. -""" -import logging - -from daq.readout import save_raw_data_from_data_dict_iterable - -from scan.scan import ScanBase - - -local_configuration = { - "mask_steps": 6, - "repeat_command": 1000, - "enable_double_columns": None -} - - -class ExtInjScan(ScanBase): - scan_id = "ext_injection_scan" - - def scan(self): - self.readout.start() - - cal_lvl1_command = self.register.get_commands("CAL")[0] + self.register.get_commands("zeros", length=40)[0] + self.register.get_commands("LV1")[0] + self.register.get_commands("zeros", mask_steps=self.mask_steps)[0] - self.scan_loop(cal_lvl1_command, repeat_command=self.repeat_command, mask_steps=self.mask_steps, enable_mask_steps=None, enable_double_columns=self.enable_double_columns, same_mask_for_all_dc=True, eol_function=None, digital_injection=False, enable_shift_masks=["Enable", "C_High", "C_Low"], restore_shift_masks=False, mask=None) - - self.readout.stop() - - save_raw_data_from_data_dict_iterable(self.readout.data, filename=self.scan_data_filename, title=self.scan_id) - - def analyze(self): - from analysis.analyze_raw_data import AnalyzeRawData - output_file = self.scan_data_filename + "_interpreted.h5" - with AnalyzeRawData(raw_data_file=self.scan_data_filename + ".h5", analyzed_data_file=output_file) as analyze_raw_data: - analyze_raw_data.create_cluster_size_hist = True - analyze_raw_data.create_cluster_tot_hist = True - analyze_raw_data.interpreter.set_warning_output(False) - analyze_raw_data.interpret_word_table() - analyze_raw_data.interpreter.print_summary() - analyze_raw_data.plot_histograms(pdf_filename=self.scan_data_filename) - -if __name__ == "__main__": - import configuration - scan = ExtInjScan(**configuration.default_configuration) - scan.start(run_configure=True, run_analyze=True, use_thread=False, **local_configuration) - scan.stop() - -# -# # Chip Parameters -# Flavor FEI4B -# Chip_ID 8 Broadcast = 8 -# -# # Global Registers -# Amp2Vbn 79 -# Amp2Vbp 85 -# Amp2Vbpff 50 Fixes noise on power supply and dead pixels when irradiated -# Amp2VbpFol 26 -# CalEn 0 -# Chip_SN 0 -# CLK0_S0 0 -# CLK0_S1 0 -# CLK0_S2 1 -# CLK1_S0 0 -# CLK1_S1 0 -# CLK1_S2 0 -# Clk2OutCnfg 0 -# CMDcnt 11 -# Colpr_Addr 0 -# Colpr_Mode 0 -# Conf_AddrEnable 1 -# DIGHITIN_SEL 0 -# DINJ_OVERRIDE 0 -# DisableColumnCnfg 0 -# DisVbn 26 -# Efuse_Sense 0 -# EmptyRecordCnfg 0 -# EN_160M 1 -# EN_320M 0 -# EN_40M 1 -# EN_80M 0 -# EN_PLL 1 -# #ErrorMask 0 -# ErrorMask 17920 disabled FiFo full (Error Code 9) and L1A counter (Error Code 14) -# EventLimit 0 -# ExtAnaCalSW 1 -# ExtDigCalSW 0 -# FdacVbn 50 -# GADCCompBias 100 -# GADCSel 0 -# GADCStart 0 -# GADCVref 170 -# GateHitOr 0 -# HitDiscCnfg 0 -# HITLD_IN 0 -# Latch_En 0 -# LvdsDrvEn 1 -# LvdsDrvIref 171 -# LvdsDrvSet06 1 -# LvdsDrvSet12 1 -# LvdsDrvSet30 1 -# LvdsDrvVos 105 -# MonleakRange 0 -# No8b10b 0 -# Pixel_Strobes 0 -# PllIbias 88 -# PllIcp 28 -# PlsrDAC 0 -# PlsrDacBias 96 -# PlsrDelay 2 -# PlsrIdacRamp 180 -# PlsrPwr 0 -# PlsrRiseUpTau 7 -# PlsrVgOpAmp 255 -# PrmpVbnFol 106 -# PrmpVbnLcc 0 -# PrmpVbp 43 -# PrmpVbpMsbEn 0 -# #PrmpVbpf 150 -# PrmpVbpf 100 -# PrmpVbp_L 43 -# PrmpVbp_R 43 -# ReadErrorReq 0 -# S0 0 -# S1 0 -# SELB 0 -# SmallHitErase 0 -# SR_Clock 0 -# SR_Clr 0 -# SR_Read 0 -# StopClkPulse 0 -# StopModeCnfg 0 -# TdacVbp 100 DAC changed from FEI4A to B -# TempSensDiodeBiasSel 0 -# TempSensDisable 0 -# TempSensIbias 0 -# Trig_Count 0 -# Trig_Lat 210 -# VrefAnTune 0 max. analog voltage (approx. 1.45V) -# VrefDigTune 100 digital voltage (1.2V) -# Vthin_AltCoarse 3 -# Vthin_AltFine 240 -# -# # Pixel Registers -# C_High 1 C:\pyats\trunk\host\config\fei4default\masks\c_high.dat -# C_Low 1 C:\pyats\trunk\host\config\fei4default\masks\c_low.dat -# Enable 1 C:\pyats\trunk\host\config\fei4default\masks\enable.dat -# EnableDigInj 0 C:\pyats\trunk\host\config\fei4default\masks\enablediginj.dat -# FDAC 7 C:\pyats\trunk\host\config\fei4default\fdacs\fdac.dat -# Imon 0 C:\pyats\trunk\host\config\fei4default\masks\imon.dat -# TDAC 15 C:\pyats\trunk\host\config\fei4default\tdacs\tdac.dat -# -# # Calibration Parameters -# C_Inj_Low 0 -# C_Inj_High 0 -# Vcal_Coeff_0 0 -# Vcal_Coeff_1 0 - diff --git a/pybar/scans/deprecated/scan_fei4_trigger.py b/pybar/scans/deprecated/scan_fei4_trigger.py deleted file mode 100644 index 73acffbc5..000000000 --- a/pybar/scans/deprecated/scan_fei4_trigger.py +++ /dev/null @@ -1,203 +0,0 @@ -import time -import logging -import math -import numpy as np - -from scan.scan import ScanBase -from daq.readout import open_raw_data_file - -from fei4.register import FEI4Register -from fei4.register_utils import FEI4RegisterUtils -from fei4.register_utils import make_box_pixel_mask_from_col_row - -from daq.readout import convert_data_array, data_dict_list_from_data_dict_iterable, is_data_from_channel - - -class Fei4TriggerScan(ScanBase): - scan_id = "scan_fei4_trigger" - - def scan(self): - '''Scan loop - - Parameters - ---------- - config_file_trigger_fe : config file name for the second Fe that is used to trigger the first Fe - col_span : list, tuple - Column range (from minimum to maximum value). From 1 to 80. - row_span : list, tuple - Row range (from minimum to maximum value). From 1 to 336. - timeout_no_data : int - In seconds; if no data, stop scan after given time. - scan_timeout : int - In seconds; stop scan after given time. - ''' - - self.configure_triggered_fe() - self.configure_trigger_fe(config_file_trigger_fe, self.col_span, self.row_span) - - with open_raw_data_file(filename=self.scan_data_filename + "_trigger_fe", title=self.scan_id) as raw_data_file_trigger_fe: - with open_raw_data_file(filename=self.scan_data_filename, title=self.scan_id) as raw_data_file: - self.readout.start() - - # preload command - lvl1_command = self.register.get_commands("zeros", length=14)[0] + self.register.get_commands("LV1")[0] # + self.register.get_commands("zeros", length=1000)[0] - self.register_utils.set_command(lvl1_command) - # setting up external trigger - self.dut['tlu']['TRIGGER_COUNTER'] = 0 - self.dut['tlu']['TRIGGER_MODE'] = 0 - self.dut['CMD']['EN_EXT_TRIGGER'] = True - - show_trigger_message_at = 10 ** (int(math.ceil(math.log10(self.max_triggers))) - 1) - last_iteration = time.time() - saw_no_data_at_time = last_iteration - saw_data_at_time = last_iteration - scan_start_time = last_iteration - no_data_at_time = last_iteration - time_from_last_iteration = 0 - scan_stop_time = scan_start_time + self.scan_timeout - current_trigger_number = 0 - last_trigger_number = 0 - while not self.stop_thread_event.wait(self.readout.readout_interval): - current_trigger_number = self.dut['tlu']['TRIGGER_COUNTER'] - if (current_trigger_number % show_trigger_message_at < last_trigger_number % show_trigger_message_at): - logging.info('Collected triggers: %d', current_trigger_number) - last_trigger_number = current_trigger_number - if self.max_triggers and current_trigger_number >= self.max_triggers: - logging.info('Reached maximum triggers. Stopping Scan...') - self.stop_thread_event.set() - if scan_start_time is not None and time.time() > scan_stop_time: - logging.info('Reached maximum scan time. Stopping Scan...') - self.stop_thread_event.set() - - time_from_last_iteration = time.time() - last_iteration - last_iteration = time.time() - while True: - try: - data = self.readout.data.popleft() - raw_data_trigger_fe = data_dict_list_from_data_dict_iterable(data_dict_iterable=(data,), filter_func=is_data_from_channel(self.channel_trigger_fe)) - raw_data_fe = data_dict_list_from_data_dict_iterable(data_dict_iterable=(data,), filter_func=is_data_from_channel(self.channel_triggered_fe)) - raw_data_file_trigger_fe.append(raw_data_trigger_fe) - raw_data_file.append(raw_data_fe) - except IndexError: # no data - no_data_at_time = last_iteration - if self.wait_for_first_trigger is False and saw_no_data_at_time > (saw_data_at_time + self.timeout_no_data): - logging.info('Reached no data timeout. Stopping Scan...') - self.stop_thread_event.set() - elif self.wait_for_first_trigger is False: - saw_no_data_at_time = no_data_at_time - - if no_data_at_time > (saw_data_at_time + 10): - scan_stop_time += time_from_last_iteration - - break # jump out while loop - - saw_data_at_time = last_iteration - - if self.wait_for_first_trigger is True: - logging.info('Taking data...') - self.wait_for_first_trigger = False - - self.dut['CMD']['EN_EXT_TRIGGER'] = False - self.dut['TLU']['TRIGGER_MODE'] = 0 - - logging.info('Total amount of triggers collected: %d', self.dut['tlu']['TRIGGER_COUNTER']) - - self.readout.stop() - - def configure_trigger_fe(self, config_file_trigger_fe, col_span, row_span): - logging.info("Sending configuration to trigger FE") - self.register_trigger_fe = FEI4Register(config_file_trigger_fe) - self.register_utils_trigger_fe = FEI4RegisterUtils(self.dut, self.readout, self.register_trigger_fe) - self.register_utils_trigger_fe.configure_all(same_mask_for_all_dc=True) - - commands = [] - # generate ROI mask for Enable mask - pixel_reg = "Enable" - mask = make_box_pixel_mask_from_col_row(column=col_span, row=row_span) - commands.extend(self.register_trigger_fe.get_commands("ConfMode")) - enable_mask = np.logical_and(mask, self.register_trigger_fe.get_pixel_register_value(pixel_reg)) - self.register_trigger_fe.set_pixel_register_value(pixel_reg, enable_mask) - commands.extend(self.register_trigger_fe.get_commands("WrFrontEnd", same_mask_for_all_dc=False, name=pixel_reg)) - # generate ROI mask for Imon mask - pixel_reg = "Imon" - mask = make_box_pixel_mask_from_col_row(column=col_span, row=row_span, default=1, value=0) - imon_mask = np.logical_or(mask, self.register_trigger_fe.get_pixel_register_value(pixel_reg)) - self.register_trigger_fe.set_pixel_register_value(pixel_reg, imon_mask) - commands.extend(self.register_trigger_fe.get_commands("WrFrontEnd", same_mask_for_all_dc=False, name=pixel_reg)) - # disable C_inj mask - pixel_reg = "C_High" - self.register_trigger_fe.set_pixel_register_value(pixel_reg, 0) - commands.extend(self.register_trigger_fe.get_commands("WrFrontEnd", same_mask_for_all_dc=True, name=pixel_reg)) - pixel_reg = "C_Low" - self.register_trigger_fe.set_pixel_register_value(pixel_reg, 0) - commands.extend(self.register_trigger_fe.get_commands("WrFrontEnd", same_mask_for_all_dc=True, name=pixel_reg)) - # set trigger latency and replication - self.register_trigger_fe.set_global_register_value("Trig_Lat", 222) # set trigger latency - self.register_trigger_fe.set_global_register_value("Trig_Count", 4) # set number of consecutive triggers - commands.extend(self.register_trigger_fe.get_commands("WrRegister", name=["Trig_Lat", "Trig_Count"])) - # setting FE into RunMode - commands.extend(self.register_trigger_fe.get_commands("RunMode")) - self.register_utils_trigger_fe.send_commands(commands) - - def configure_triggered_fe(self): - logging.info("Sending configuration to triggered FE") - commands = [] - commands.extend(self.register.get_commands("ConfMode")) - # disable hitbus - pixel_reg = "Imon" - self.register.set_pixel_register_value(pixel_reg, 1) - commands.extend(self.register.get_commands("WrFrontEnd", same_mask_for_all_dc=True, name=pixel_reg)) - # disable C_inj mask - pixel_reg = "C_High" - self.register.set_pixel_register_value(pixel_reg, 0) - commands.extend(self.register.get_commands("WrFrontEnd", same_mask_for_all_dc=True, name=pixel_reg)) - pixel_reg = "C_Low" - self.register.set_pixel_register_value(pixel_reg, 0) - commands.extend(self.register.get_commands("WrFrontEnd", same_mask_for_all_dc=True, name=pixel_reg)) - # # set trigger latency and replication - self.register.set_global_register_value("Trig_Lat", 221) # set trigger latency - self.register.set_global_register_value("Trig_Count", 4) # set number of consecutive triggers - commands.extend(self.register.get_commands("WrRegister", name=["Trig_Lat", "Trig_Count"])) - # setting FE into RunMode - commands.extend(self.register.get_commands("RunMode")) - self.register_utils.send_commands(commands) - - def analyze(self): - from analysis.analyze_raw_data import AnalyzeRawData - output_file = self.scan_data_filename + "_interpreted.h5" - output_file_trigger_fe = self.scan_data_filename + "_trigger_fe_interpreted.h5" - with AnalyzeRawData(raw_data_file=self.scan_data_filename + ".h5", analyzed_data_file=output_file) as analyze_raw_data: - analyze_raw_data.max_tot_value = 13 - analyze_raw_data.create_hit_table = True - analyze_raw_data.create_source_scan_hist = True - analyze_raw_data.create_cluster_size_hist = True - analyze_raw_data.create_cluster_tot_hist = True - analyze_raw_data.create_cluster_table = True - analyze_raw_data.interpreter.set_warning_output(False) - analyze_raw_data.interpret_word_table() - analyze_raw_data.interpreter.print_summary() - analyze_raw_data.plot_histograms(pdf_filename=self.scan_data_filename, maximum='maximum') - with AnalyzeRawData(raw_data_file=self.scan_data_filename + "_trigger_fe.h5", analyzed_data_file=output_file_trigger_fe) as analyze_raw_data: - analyze_raw_data.max_tot_value = 13 - analyze_raw_data.create_hit_table = True - analyze_raw_data.create_source_scan_hist = True - analyze_raw_data.create_cluster_size_hist = True - analyze_raw_data.create_cluster_tot_hist = True - analyze_raw_data.create_cluster_table = True - analyze_raw_data.interpreter.set_warning_output(False) - analyze_raw_data.interpret_word_table() - analyze_raw_data.interpreter.print_summary() - analyze_raw_data.plot_histograms(pdf_filename=self.scan_data_filename + '_trigger_fe', maximum='maximum') - - -if __name__ == "__main__": - import configuration - import os - - config_file_triggered_fe = os.path.join(os.getcwd(), r'config/fei4/configs/SCC_99_low_thr_tuning.cfg') # Chip 1, GA 1 - config_file_trigger_fe = os.path.join(os.getcwd(), r'config/fei4/configs/SCC_30_tuning.cfg') # Chip 2, GA 2 - - scan = Fei4TriggerScan(**configuration.default_configuration) # configuration of triggered FE - scan.start(config_file_trigger_fe=config_file_trigger_fe, channel_triggered_fe=4, channel_trigger_fe=3, invert_lemo_trigger_input=True, configure=True, use_thread=True, col_span=[5, 75], row_span=[20, 310], timeout_no_data=10, scan_timeout=10 * 60, max_triggers=1000000) - - scan.stop() diff --git a/pybar/scans/deprecated/test_threshold_stability.py b/pybar/scans/deprecated/test_threshold_stability.py index fcaa036b1..67d2c3b9d 100644 --- a/pybar/scans/deprecated/test_threshold_stability.py +++ b/pybar/scans/deprecated/test_threshold_stability.py @@ -13,8 +13,7 @@ import progressbar -import configuration -from scan_threshold_fast import FastThresholdScan +from pybar.scans.scan_threshold_fast import FastThresholdScan from analysis import analysis_utils from analysis.RawDataConverter import data_struct from analysis.plotting import plotting @@ -41,7 +40,7 @@ def select_trigger_hits(input_file_hits, output_file_hits_1, output_file_hits_2) with tb.open_file(output_file_hits_2, mode="w") as out_hit_file_2_h5: hit_table_out_1 = out_hit_file_1_h5.create_table(out_hit_file_1_h5.root, name='Hits', description=data_struct.HitInfoTable, title='hit_data', filters=tb.Filters(complib='blosc', complevel=5, fletcher32=False)) hit_table_out_2 = out_hit_file_2_h5.create_table(out_hit_file_2_h5.root, name='Hits', description=data_struct.HitInfoTable, title='hit_data', filters=tb.Filters(complib='blosc', complevel=5, fletcher32=False)) - progress_bar = progressbar.ProgressBar(widgets=['', progressbar.Percentage(), ' ', progressbar.Bar(marker='*', left='|', right='|'), ' ', analysis_utils.ETA()], maxval=hit_table_in.shape[0], term_width=80) + progress_bar = progressbar.ProgressBar(widgets=['', progressbar.Percentage(), ' ', progressbar.Bar(marker='*', left='|', right='|'), ' ', progressbar.AdaptiveETA()], maxval=hit_table_in.shape[0], term_width=80) progress_bar.start() for data, index in analysis_utils.data_aligned_at_events(hit_table_in, chunk_size=5000000): hit_table_out_1.append(data[data['LVL1ID'] % 2 == 1]) # first trigger hits @@ -164,7 +163,7 @@ def analyze_data(scan_data_filenames, ignore_columns, fei4b=False): mean_threshold_rms_calibration_2 = np.zeros_like(mean_threshold_calibration) # array to hold the analyzed data in ram threshold_calibration_2 = np.zeros_like(threshold_calibration) # array to hold the analyzed data in ram # initialize progress bar - progress_bar = progressbar.ProgressBar(widgets=['', progressbar.Percentage(), ' ', progressbar.Bar(marker='*', left='|', right='|'), ' ', analysis_utils.ETA()], maxval=len(local_configuration['delays']), term_width=80) + progress_bar = progressbar.ProgressBar(widgets=['', progressbar.Percentage(), ' ', progressbar.Bar(marker='*', left='|', right='|'), ' ', progressbar.AdaptiveETA()], maxval=len(local_configuration['delays']), term_width=80) progress_bar.start() # loop over all delay values and analyze the corresponding data for delay_index, delay_value in enumerate(local_configuration['delays']): diff --git a/pybar/scans/scan_analog.py b/pybar/scans/scan_analog.py index 3c3384e06..addba54e2 100644 --- a/pybar/scans/scan_analog.py +++ b/pybar/scans/scan_analog.py @@ -1,5 +1,4 @@ import logging - from collections import Iterable from pybar.fei4_run_base import Fei4RunBase @@ -12,6 +11,8 @@ class AnalogScan(Fei4RunBase): '''Analog scan ''' _default_run_conf = { + "broadcast_commands": False, + "threaded_scan": True, "mask_steps": 3, # mask steps, be carefull PlsrDAC injects different charge for different mask steps "n_injections": 100, # number of injections "scan_parameters": [('PlsrDAC', 280)], # the PlsrDAC setting @@ -19,7 +20,7 @@ class AnalogScan(Fei4RunBase): "enable_shift_masks": ["Enable", "C_High", "C_Low"], # enable masks shifted during scan "disable_shift_masks": [], # disable masks shifted during scan "pulser_dac_correction": False, # PlsrDAC correction for each double column - "enable_tdc": False, # if True, enables TDC (use RX2) + "enable_tdc": False, # if True, enables TDC "same_mask_for_all_dc": True, # if True, all columns have the same mask, if False, mask will be enabled only where injected "enable_double_columns": None, # List of double columns which will be enabled during scan. None will select all double columns "enable_mask_steps": None, # List of mask steps which will be applied. None will select all mask steps. @@ -58,9 +59,6 @@ def scan(self): else: scan_loop(self, cal_lvl1_command, repeat_command=self.n_injections, use_delay=True, mask_steps=self.mask_steps, enable_mask_steps=self.enable_mask_steps, enable_double_columns=self.enable_double_columns, same_mask_for_all_dc=self.same_mask_for_all_dc, digital_injection=False, enable_shift_masks=self.enable_shift_masks, disable_shift_masks=self.disable_shift_masks, restore_shift_masks=False, mask=invert_pixel_mask(self.register.get_pixel_register_value('Enable')) if self.use_enable_mask else None, double_column_correction=self.pulser_dac_correction) - # plotting data -# plot_occupancy(hist=make_occupancy_hist(*convert_data_array(data_array_from_data_dict_iterable(self.fifo_readout.data), filter_func=is_data_record, converter_func=get_col_row_array_from_data_record_array)), z_max='median', filename=self.scan_data_filename + "_occupancy.pdf") - def analyze(self): with AnalyzeRawData(raw_data_file=self.output_filename, create_pdf=True) as analyze_raw_data: analyze_raw_data.create_tot_hist = True @@ -77,5 +75,6 @@ def activate_tdc(self): def deactivate_tdc(self): self.dut['TDC']['ENABLE'] = False + if __name__ == "__main__": RunManager('../configuration.yaml').run_run(AnalogScan) diff --git a/pybar/scans/scan_crosstalk.py b/pybar/scans/scan_crosstalk.py index af9a48cd8..2388fd05d 100644 --- a/pybar/scans/scan_crosstalk.py +++ b/pybar/scans/scan_crosstalk.py @@ -18,6 +18,8 @@ class CrosstalkScan(Fei4RunBase): Crosstalk exists when a threshold higher 0 can be measured (s-curve fit successful). ''' _default_run_conf = { + "broadcast_commands": True, + "threaded_scan": False, "mask_steps": 6, # number of injections per PlsrDAC step "n_injections": 100, # number of injections per PlsrDAC step "scan_parameters": [('PlsrDAC', [None, 800])], # the PlsrDAC range diff --git a/pybar/scans/scan_digital.py b/pybar/scans/scan_digital.py index 487052714..fb1c6cf79 100644 --- a/pybar/scans/scan_digital.py +++ b/pybar/scans/scan_digital.py @@ -11,6 +11,8 @@ class DigitalScan(Fei4RunBase): '''Digital scan ''' _default_run_conf = { + "broadcast_commands": True, + "threaded_scan": False, "mask_steps": 3, # mask steps "n_injections": 100, # number of injections "use_enable_mask": False # if True, use Enable mask during scan, if False, all pixels will be enabled @@ -42,5 +44,6 @@ def analyze(self): analyze_raw_data.plot_histograms() analyze_raw_data.interpreter.print_summary() + if __name__ == "__main__": RunManager('../configuration.yaml').run_run(DigitalScan) diff --git a/pybar/scans/scan_eudaq_ext_trigger.py b/pybar/scans/scan_eudaq_ext_trigger.py index f56a7c638..ae5dc47e6 100755 --- a/pybar/scans/scan_eudaq_ext_trigger.py +++ b/pybar/scans/scan_eudaq_ext_trigger.py @@ -1,23 +1,27 @@ #!/usr/bin/env python2 import logging +import sys from optparse import OptionParser -import numpy as np from time import time, strftime, gmtime, sleep +import numpy as np +from PyEUDAQWrapper import PyProducer + from pybar.run_manager import RunManager, run_status from pybar.scans.scan_ext_trigger import ExtTriggerScan from pybar.daq.readout_utils import build_events_from_raw_data, is_trigger_word -import sys + sys.path.append('/home/telescope/eudaq/python/') -from PyEUDAQWrapper import PyProducer class EudaqExtTriggerScan(ExtTriggerScan): '''External trigger scan that connects to EUDAQ producer (EUDAQ 1.4 and higher). ''' _default_run_conf = { + "broadcast_commands": True, + "threaded_scan": False, "trig_count": 0, # FE-I4 trigger count, number of consecutive BCs, 0 means 16, from 0 to 15 "trigger_latency": 232, # FE-I4 trigger latency, in BCs, external scintillator / TLU / HitOR: 232, USBpix self-trigger: 220 "trigger_delay": 8, # trigger delay, in BCs @@ -29,7 +33,7 @@ class EudaqExtTriggerScan(ExtTriggerScan): "no_data_timeout": None, # no data timeout after which the scan will be aborted, in seconds "scan_timeout": None, # timeout for scan after which the scan will be stopped, in seconds "max_triggers": 0, # maximum triggers after which the scan will be stopped, if 0, no maximum triggers are set - "enable_tdc": False # if True, enables TDC (use RX2) + "enable_tdc": False # if True, enables TDC } def scan(self): @@ -50,12 +54,12 @@ def scan(self): got_data = False while not self.stop_run.wait(1.0): if not got_data: - if self.fifo_readout.data_words_per_second() > 0: + if self.data_words_per_second() > 0: got_data = True logging.info('Taking data...') else: triggers = self.dut['TLU']['TRIGGER_COUNTER'] - data_words = self.fifo_readout.data_words_per_second() + data_words = self.data_words_per_second() logging.info('Runtime: %s\nTriggers: %d\nData words/s: %s\n' % (strftime('%H:%M:%S', gmtime(time() - start)), triggers, str(data_words))) if self.max_triggers and triggers >= self.max_triggers: self.stop(msg='Trigger limit was reached: %i' % self.max_triggers) @@ -71,7 +75,7 @@ def handle_err(self, exc): super(EudaqExtTriggerScan, self).handle_err(exc=exc) self.data_error_occurred = True - def handle_data(self, data): + def handle_data(self, data, new_file=False, flush=True): events = build_events_from_raw_data(data[0]) for item in events: if item.shape[0] == 0: @@ -101,8 +105,7 @@ def handle_data(self, data): self.remaining_data = item else: self.remaining_data = np.concatenate([self.remaining_data, item]) - - self.raw_data_file.append_item(data, scan_parameters=self.scan_parameters._asdict(), flush=True) + super(EudaqExtTriggerScan, self).handle_data(data=data, new_file=new_file, flush=flush) if __name__ == "__main__": diff --git a/pybar/scans/scan_ext_trigger.py b/pybar/scans/scan_ext_trigger.py index 66c230059..148f29c03 100644 --- a/pybar/scans/scan_ext_trigger.py +++ b/pybar/scans/scan_ext_trigger.py @@ -1,8 +1,10 @@ import logging -import numpy as np -import progressbar from time import time from threading import Timer +from contextlib import contextmanager + +import progressbar +import numpy as np from pybar.analysis.analyze_raw_data import AnalyzeRawData from pybar.fei4.register_utils import invert_pixel_mask, make_box_pixel_mask_from_col_row @@ -19,6 +21,8 @@ class ExtTriggerScan(Fei4RunBase): Set up trigger in DUT configuration file (e.g. dut_configuration_mio.yaml). ''' _default_run_conf = { + "broadcast_commands": True, + "threaded_scan": False, "trig_count": 0, # FE-I4 trigger count, number of consecutive BCs, 0 means 16, from 0 to 15 "trigger_latency": 232, # FE-I4 trigger latency, in BCs, external scintillator / TLU / HitOR: 232, USBpix self-trigger: 220 "trigger_delay": 8, # trigger delay, in BCs @@ -30,7 +34,7 @@ class ExtTriggerScan(Fei4RunBase): "no_data_timeout": 10, # no data timeout after which the scan will be aborted, in seconds "scan_timeout": 60, # timeout for scan after which the scan will be stopped, in seconds "max_triggers": 10000, # maximum triggers after which the scan will be stopped, if 0, no maximum triggers are set - "enable_tdc": False, # if True, enables TDC (use RX2) + "enable_tdc": False, # if True, enables TDC "reset_rx_on_error": False # long scans have a high propability for ESD related data transmission errors; recover and continue here } @@ -70,33 +74,35 @@ def scan(self): self.register_utils.set_command(lvl1_command) with self.readout(no_data_timeout=self.no_data_timeout, **self.scan_parameters._asdict()): - got_data = False - start = time() - while not self.stop_run.wait(1.0): - if not got_data: - if self.fifo_readout.data_words_per_second() > 0: - got_data = True - logging.info('Taking data...') - if self.max_triggers: - self.progressbar = progressbar.ProgressBar(widgets=['', progressbar.Percentage(), ' ', progressbar.Bar(marker='*', left='|', right='|'), ' ', progressbar.AdaptiveETA()], maxval=self.max_triggers, poll=10, term_width=80).start() - else: - self.progressbar = progressbar.ProgressBar(widgets=['', progressbar.Percentage(), ' ', progressbar.Bar(marker='*', left='|', right='|'), ' ', progressbar.Timer()], maxval=self.scan_timeout, poll=10, term_width=80).start() - else: - triggers = self.dut['TLU']['TRIGGER_COUNTER'] - try: - if self.max_triggers: - self.progressbar.update(triggers) - else: - self.progressbar.update(time() - start) - except ValueError: - pass - if self.max_triggers and triggers >= self.max_triggers: - self.progressbar.finish() - self.stop(msg='Trigger limit was reached: %i' % self.max_triggers) + with self.trigger(): + got_data = False + start = time() + while not self.stop_run.wait(1.0): + if not got_data: + if self.data_words_per_second() > 0: + got_data = True + logging.info('Taking data...') + if self.max_triggers: + self.progressbar = progressbar.ProgressBar(widgets=['', progressbar.Percentage(), ' ', progressbar.Bar(marker='*', left='|', right='|'), ' ', progressbar.AdaptiveETA()], maxval=self.max_triggers, poll=10, term_width=80).start() + else: + self.progressbar = progressbar.ProgressBar(widgets=['', progressbar.Percentage(), ' ', progressbar.Bar(marker='*', left='|', right='|'), ' ', progressbar.Timer()], maxval=self.scan_timeout, poll=10, term_width=80).start() + else: + triggers = self.dut['TLU']['TRIGGER_COUNTER'] + try: + if self.max_triggers: + self.progressbar.update(triggers) + else: + self.progressbar.update(time() - start) + except ValueError: + pass + if self.max_triggers and triggers >= self.max_triggers: + self.progressbar.finish() + self.stop(msg='Trigger limit was reached: %i' % self.max_triggers) logging.info('Total amount of triggers collected: %d', self.dut['TLU']['TRIGGER_COUNTER']) def analyze(self): with AnalyzeRawData(raw_data_file=self.output_filename, create_pdf=True) as analyze_raw_data: + analyze_raw_data.trigger_data_format = self.dut['TLU']['DATA_FORMAT'] analyze_raw_data.create_source_scan_hist = True analyze_raw_data.create_cluster_size_hist = True analyze_raw_data.create_cluster_tot_hist = True @@ -110,15 +116,30 @@ def analyze(self): analyze_raw_data.interpreter.print_summary() analyze_raw_data.plot_histograms() - def start_readout(self, *args, **kwargs): - super(ExtTriggerScan, self).start_readout(*args, **kwargs) + @contextmanager + def trigger(self): + self.start_trigger() + try: + yield + finally: + try: + self.stop_trigger() + except: + # in case something fails, call this on last resort + self.scan_timeout_timer.cancel() + self.connect_cancel(["abort"]) + + def start_trigger(self, *args, **kwargs): + self.connect_cancel(["stop"]) self.dut['TDC']['ENABLE'] = self.enable_tdc self.dut['TLU']['TRIGGER_COUNTER'] = 0 if self.max_triggers: self.dut['TLU']['MAX_TRIGGERS'] = self.max_triggers else: self.dut['TLU']['MAX_TRIGGERS'] = 0 # infinity triggers - self.dut['CMD']['EN_EXT_TRIGGER'] = True + self.dut['TX']['EN_EXT_TRIGGER'] = True + with self.synchronized(): + self.dut['TLU']['TRIGGER_ENABLE'] = True def timeout(): try: @@ -131,11 +152,13 @@ def timeout(): if self.scan_timeout: self.scan_timeout_timer.start() - def stop_readout(self, timeout=10.0): + def stop_trigger(self, timeout=10.0): self.scan_timeout_timer.cancel() + with self.synchronized(): + self.dut['TLU']['TRIGGER_ENABLE'] = False + self.dut['TX']['EN_EXT_TRIGGER'] = False self.dut['TDC']['ENABLE'] = False - self.dut['CMD']['EN_EXT_TRIGGER'] = False - super(ExtTriggerScan, self).stop_readout(timeout=timeout) + self.connect_cancel(["abort"]) if __name__ == "__main__": diff --git a/pybar/scans/scan_ext_trigger_gdac.py b/pybar/scans/scan_ext_trigger_gdac.py index 7852bef73..498fe2c14 100644 --- a/pybar/scans/scan_ext_trigger_gdac.py +++ b/pybar/scans/scan_ext_trigger_gdac.py @@ -49,8 +49,8 @@ def scan(self): ExtTriggerScan.scan(self) self.stop_run.clear() - def handle_data(self, data): - self.raw_data_file.append_item(data, scan_parameters=self.scan_parameters._asdict(), new_file=True, flush=True) + def handle_data(self, data, new_file=True, flush=True): + super(ExtTriggerGdacScan, self).handle_data(data=data, new_file=new_file, flush=flush) def get_gdacs_from_interpolated_calibration(self, calibration_file, thresholds): logging.info('Interpolate GDAC calibration for the thresholds %s', str(thresholds)) diff --git a/pybar/scans/scan_ext_trigger_stop_mode.py b/pybar/scans/scan_ext_trigger_stop_mode.py index 075bc6437..3c0a960a0 100644 --- a/pybar/scans/scan_ext_trigger_stop_mode.py +++ b/pybar/scans/scan_ext_trigger_stop_mode.py @@ -1,6 +1,7 @@ import logging from time import time from threading import Timer +from contextlib import contextmanager import progressbar import numpy as np @@ -36,10 +37,11 @@ class StopModeExtTriggerScan(Fei4RunBase): Set up trigger in DUT configuration file (e.g. dut_configuration_mio.yaml). ''' _default_run_conf = { + "broadcast_commands": True, "trigger_latency": 5, # FE global register Trig_Lat. The lower the value the longer the hit data will be stored in data buffer "trigger_delay": 192, # delay between trigger and stop mode command "readout_delay": 2000, # delay after trigger to record hits, the lower the faster the readout; total readout time per track is about (800 + (1300 + readout_delay) * bcid_window) * 25 ns - "trig_count": 100, # Number of consecurive time slices to be read, from 1 to 256 + "trig_count": 100, # Number of consecurive time slices to be read, from 1 to 256; the number is read from raw data file during analysis. "col_span": [1, 80], # defining active column interval, 2-tuple, from 1 to 80 "row_span": [1, 336], # defining active row interval, 2-tuple, from 1 to 336 "overwrite_enable_mask": False, # if True, use col_span and row_span to define an active region regardless of the Enable pixel register. If False, use col_span and row_span to define active region by also taking Enable pixel register into account. @@ -118,9 +120,9 @@ def scan(self): self.register.get_commands("GlobalPulse", Width=0)[0], self.register.get_commands("zeros", length=100)[0])) - self.dut['CMD']['CMD_REPEAT'] = self.trig_count - self.dut['CMD']['START_SEQUENCE_LENGTH'] = len(start_sequence) - self.dut['CMD']['STOP_SEQUENCE_LENGTH'] = len(stop_sequence) + 1 + self.dut['TX']['CMD_REPEAT'] = self.trig_count + self.dut['TX']['START_SEQUENCE_LENGTH'] = len(start_sequence) + self.dut['TX']['STOP_SEQUENCE_LENGTH'] = len(stop_sequence) + 1 # preload the command to be send for each trigger command = self.register_utils.concatenate_commands((start_sequence, one_latency_read, stop_sequence)) @@ -128,49 +130,67 @@ def scan(self): self.register_utils.set_command(command) with self.readout(no_data_timeout=self.no_data_timeout, **self.scan_parameters._asdict()): - got_data = False - start = time() - while not self.stop_run.wait(1.0): - if not got_data: - if self.fifo_readout.data_words_per_second() > 0: - got_data = True - logging.info('Taking data...') - if self.max_triggers: - self.progressbar = progressbar.ProgressBar(widgets=['', progressbar.Percentage(), ' ', progressbar.Bar(marker='*', left='|', right='|'), ' ', progressbar.AdaptiveETA()], maxval=self.max_triggers, poll=10, term_width=80).start() - else: - self.progressbar = progressbar.ProgressBar(widgets=['', progressbar.Percentage(), ' ', progressbar.Bar(marker='*', left='|', right='|'), ' ', progressbar.Timer()], maxval=self.scan_timeout, poll=10, term_width=80).start() - else: - triggers = self.dut['TLU']['TRIGGER_COUNTER'] - try: - if self.max_triggers: - self.progressbar.update(triggers) - else: - self.progressbar.update(time() - start) - except ValueError: - pass - if self.max_triggers and triggers >= self.max_triggers: - self.progressbar.finish() - self.stop(msg='Trigger limit was reached: %i' % self.max_triggers) + with self.trigger(): + got_data = False + start = time() + while not self.stop_run.wait(1.0): + if not got_data: + if self.data_words_per_second() > 0: + got_data = True + logging.info('Taking data...') + if self.max_triggers: + self.progressbar = progressbar.ProgressBar(widgets=['', progressbar.Percentage(), ' ', progressbar.Bar(marker='*', left='|', right='|'), ' ', progressbar.AdaptiveETA()], maxval=self.max_triggers, poll=10, term_width=80).start() + else: + self.progressbar = progressbar.ProgressBar(widgets=['', progressbar.Percentage(), ' ', progressbar.Bar(marker='*', left='|', right='|'), ' ', progressbar.Timer()], maxval=self.scan_timeout, poll=10, term_width=80).start() + else: + triggers = self.dut['TLU']['TRIGGER_COUNTER'] + try: + if self.max_triggers: + self.progressbar.update(triggers) + else: + self.progressbar.update(time() - start) + except ValueError: + pass + if self.max_triggers and triggers >= self.max_triggers: + self.progressbar.finish() + self.stop(msg='Trigger limit was reached: %i' % self.max_triggers) logging.info('Total amount of triggers collected: %d', self.dut['TLU']['TRIGGER_COUNTER']) def analyze(self): with AnalyzeRawData(raw_data_file=self.output_filename, create_pdf=True) as analyze_raw_data: analyze_raw_data.create_hit_table = True - analyze_raw_data.trig_count = self.trig_count # set number of BCID to overwrite the number deduced from the raw data file + analyze_raw_data.trigger_data_format = self.dut['TLU']['DATA_FORMAT'] analyze_raw_data.create_source_scan_hist = True - analyze_raw_data.trigger_data_format = 1 # time stamp only analyze_raw_data.set_stop_mode = True analyze_raw_data.align_at_trigger = True analyze_raw_data.interpreter.set_warning_output(False) - analyze_raw_data.interpret_word_table(use_settings_from_file=False) + analyze_raw_data.interpret_word_table() analyze_raw_data.interpreter.print_summary() analyze_raw_data.plot_histograms() - def start_readout(self, *args, **kwargs): - super(StopModeExtTriggerScan, self).start_readout(*args, **kwargs) + @contextmanager + def trigger(self): + self.start_trigger() + try: + yield + finally: + try: + self.stop_trigger() + except: + # in case something fails, call this on last resort + self.scan_timeout_timer.cancel() + self.connect_cancel(["abort"]) + + def start_trigger(self): + self.connect_cancel(["stop"]) self.dut['TLU']['TRIGGER_COUNTER'] = 0 - self.dut['TLU']['MAX_TRIGGERS'] = self.max_triggers - self.dut['CMD']['EN_EXT_TRIGGER'] = True + if self.max_triggers: + self.dut['TLU']['MAX_TRIGGERS'] = self.max_triggers + else: + self.dut['TLU']['MAX_TRIGGERS'] = 0 # infinity triggers + self.dut['TX']['EN_EXT_TRIGGER'] = True + with self.synchronized(): + self.dut['TLU']['TRIGGER_ENABLE'] = True def timeout(): try: @@ -183,10 +203,12 @@ def timeout(): if self.scan_timeout: self.scan_timeout_timer.start() - def stop_readout(self, timeout=10.0): + def stop_trigger(self): self.scan_timeout_timer.cancel() - self.dut['CMD']['EN_EXT_TRIGGER'] = False - super(StopModeExtTriggerScan, self).stop_readout(timeout=timeout) + with self.synchronized(): + self.dut['TLU']['TRIGGER_ENABLE'] = False + self.dut['TX']['EN_EXT_TRIGGER'] = False + self.connect_cancel(["abort"]) if __name__ == "__main__": diff --git a/pybar/scans/scan_fei4_self_trigger.py b/pybar/scans/scan_fei4_self_trigger.py index e88895488..d77cf6f6d 100644 --- a/pybar/scans/scan_fei4_self_trigger.py +++ b/pybar/scans/scan_fei4_self_trigger.py @@ -1,8 +1,10 @@ import logging from time import time -import numpy as np -import progressbar from threading import Timer +from contextlib import contextmanager + +import progressbar +import numpy as np from pybar.analysis.analyze_raw_data import AnalyzeRawData from pybar.fei4.register_utils import invert_pixel_mask, make_box_pixel_mask_from_col_row @@ -10,12 +12,14 @@ from pybar.run_manager import RunManager -class FEI4SelfTriggerScan(Fei4RunBase): +class Fei4SelfTriggerScan(Fei4RunBase): '''FE-I4 self-trigger scan Implementation of the FE-I4 self-trigger scan, internally using HitOR for self-triggering. ''' _default_run_conf = { + "broadcast_commands": True, + "threaded_scan": False, "trig_count": 4, # FE-I4 trigger count, number of consecutive BCs, 0 means 16, from 0 to 15 "trigger_latency": 239, # FE-I4 trigger latency, in BCs, external scintillator / TLU / HitOR: 232, USBpix self-trigger: 220, from 0 to 255 "col_span": [1, 80], # defining active column interval, 2-tuple, from 1 to 80 @@ -58,19 +62,20 @@ def configure(self): def scan(self): with self.readout(no_data_timeout=self.no_data_timeout): - got_data = False - start = time() - while not self.stop_run.wait(1.0): - if not got_data: - if self.fifo_readout.data_words_per_second() > 0: - got_data = True - logging.info('Taking data...') - self.progressbar = progressbar.ProgressBar(widgets=['', progressbar.Percentage(), ' ', progressbar.Bar(marker='*', left='|', right='|'), ' ', progressbar.Timer()], maxval=self.scan_timeout, poll=10, term_width=80).start() - else: - try: - self.progressbar.update(time() - start) - except ValueError: - pass + with self.trigger(): + got_data = False + start = time() + while not self.stop_run.wait(1.0): + if not got_data: + if self.data_words_per_second() > 0: + got_data = True + logging.info('Taking data...') + self.progressbar = progressbar.ProgressBar(widgets=['', progressbar.Percentage(), ' ', progressbar.Bar(marker='*', left='|', right='|'), ' ', progressbar.Timer()], maxval=self.scan_timeout, poll=10, term_width=80).start() + else: + try: + self.progressbar.update(time() - start) + except ValueError: + pass def analyze(self): with AnalyzeRawData(raw_data_file=self.output_filename, create_pdf=True) as analyze_raw_data: @@ -92,9 +97,23 @@ def set_self_trigger(self, enable=True): commands.extend(self.register.get_commands("RunMode")) self.register_utils.send_commands(commands) - def start_readout(self, *args, **kwargs): - super(FEI4SelfTriggerScan, self).start_readout(*args, **kwargs) - self.set_self_trigger(True) + @contextmanager + def trigger(self): + self.start_trigger() + try: + yield + finally: + try: + self.stop_trigger() + except: + # in case something fails, call this on last resort + self.scan_timeout_timer.cancel() + self.connect_cancel(["abort"]) + + def start_trigger(self): + self.connect_cancel(["stop"]) + with self.synchronized(): + self.set_self_trigger(enable=True) def timeout(): try: @@ -107,10 +126,12 @@ def timeout(): if self.scan_timeout: self.scan_timeout_timer.start() - def stop_readout(self, timeout=10.0): + def stop_trigger(self): self.scan_timeout_timer.cancel() - self.set_self_trigger(False) - super(FEI4SelfTriggerScan, self).stop_readout(timeout=timeout) + with self.synchronized(): + self.set_self_trigger(enable=False) + self.connect_cancel(["abort"]) + if __name__ == "__main__": - RunManager('../configuration.yaml').run_run(FEI4SelfTriggerScan) + RunManager('../configuration.yaml').run_run(Fei4SelfTriggerScan) diff --git a/pybar/scans/scan_hit_delay.py b/pybar/scans/scan_hit_delay.py index 32d8e8f35..da00817e9 100644 --- a/pybar/scans/scan_hit_delay.py +++ b/pybar/scans/scan_hit_delay.py @@ -44,6 +44,9 @@ from pybar.analysis.plotting.plotting import plot_scurves, plot_three_way +warnings.simplefilter("ignore", OptimizeWarning) # deactivate : Covariance warning + + def scurve(x, offset, mu, sigma): return offset + 0.5 * erf((x - mu) / (np.sqrt(2) * sigma)) + 0.5 @@ -339,6 +342,7 @@ class HitDelayScan(Fei4RunBase): Implementation of a hit delay scan. ''' _default_run_conf = { + "broadcast_commands": True, "mask_steps": 3, # mask steps, be carefull PlsrDAC injects different charge for different mask steps "n_injections": 20, # number of injections per PlsrDAC step "scan_parameters": [('PlsrDAC', range(21, 801, 15)), ('PlsrDelay', range(1, 63))], # make sure to set the lowest PlsrDAC to the threshold position! diff --git a/pybar/scans/scan_init.py b/pybar/scans/scan_init.py index d145e6ebd..c2b9dd7f5 100644 --- a/pybar/scans/scan_init.py +++ b/pybar/scans/scan_init.py @@ -7,16 +7,20 @@ class InitScan(Fei4RunBase): '''Init scan ''' - _default_run_conf = {} + _default_run_conf = { + "broadcast_commands": False, + "threaded_scan": False + } def configure(self): pass def scan(self): - logging.info('Init run...') + pass def analyze(self): pass + if __name__ == "__main__": RunManager('../configuration.yaml').run_run(InitScan) diff --git a/pybar/scans/scan_m26_telescope.py b/pybar/scans/scan_m26_telescope.py index a74253a63..fba657435 100644 --- a/pybar/scans/scan_m26_telescope.py +++ b/pybar/scans/scan_m26_telescope.py @@ -3,6 +3,7 @@ import inspect from time import time, sleep from threading import Timer +from contextlib import contextmanager import progressbar import numpy as np @@ -17,15 +18,18 @@ class M26TelescopeScan(Fei4RunBase): - '''External trigger scan with FE-I4 and up to 6 Mimosa26 telescope planes. - - For use with external scintillator (user RX0), TLU (use RJ45), FE-I4 HitOR (USBpix self-trigger). + '''External trigger scan with a single FE-I4 and up to 6 Mimosa26 telescope planes. Note: - Set up trigger in DUT configuration file (e.g. dut_configuration_mmc3_m26_eth.yaml). - Only Agilent E3644a power supply is supported. + - Remove not used Mimosa26 planes by commenting out the drivers in the DUT file (i.e. dut_mmc3_m26_eth.yaml). + - Set up trigger in DUT configuration file (i.e. dut_configuration_mmc3_m26_eth.yaml). + - Enable/disable FEI4 ROI by setting "enable_roi" to True/False. + - Only Agilent E3644a power supplys are supported. Set "remote" to True to enable remote control. ''' _default_run_conf = { + "broadcast_commands": False, + "threaded_scan": False, + "reset_rx_on_error": True, # long scans have a high propability for ESD related data transmission errors; recover and continue "trig_count": 0, # FE-I4 trigger count, number of consecutive BCs, 0 means 16, from 0 to 15 "trigger_latency": 232, # FE-I4 trigger latency, in BCs, external scintillator / TLU / HitOR: 232, USBpix self-trigger: 220 "trigger_delay": 8, # trigger delay, in BCs @@ -37,8 +41,8 @@ class M26TelescopeScan(Fei4RunBase): "no_data_timeout": 120, # no data timeout after which the scan will be aborted, in seconds "scan_timeout": 60, # timeout for scan after which the scan will be stopped, in seconds "max_triggers": 0, # maximum triggers after which the scan will be stopped, if 0, no maximum triggers are set - "reset_rx_on_error": True, # long scans have a high propability for ESD related data transmission errors; recover and continue here - "remote": True # if True, Powersupply remote is enabled + "enable_roi": False, # if True, use additional FEI4 ROI plane + "remote": False # if True, Powersupply remote is enabled } def init_dut(self): @@ -46,13 +50,13 @@ def init_dut(self): status = self.dut['Powersupply'].get_enable() sleep(0.15) status = status.replace("\n", "").replace("\r", "") - status = int(status) #convert string to float in order to compare values! + status = int(status) # convert string to float in order to compare values! if status == 1: - logging.info("Output of powersupply is ON, status: %s"%status) + logging.info("Output of powersupply is ON, status: %s" % status) else: logging.info("Output of powersupply is OFF, status: %s" % status) # TODO: STOP READOUT!!! - #abort(msg='Scan timeout was reached') - #stop_current_run(msg='OFF') + # abort(msg='Scan timeout was reached') + # stop_current_run(msg='OFF') current = self.dut['Powersupply'].get_current() current = current.replace("\n", "").replace("\r", "") logging.info('Current: %s A', current) @@ -61,95 +65,98 @@ def init_dut(self): logging.info('No remote enabled') map(lambda channel: channel.reset(), self.dut.get_modules('m26_rx')) - self.dut['jtag'].reset() + self.dut['JTAG'].reset() - if 'force_config_mimosa26' in self._conf and not self._conf['force_config_mimosa26'] and self.remote and current >= 3.3: #check if force_config is False + if 'force_config_mimosa26' in self._conf and not self._conf['force_config_mimosa26'] and self.remote and current >= 3.3: # check if force_config is False logging.info('Skipping m26 configuration, m26 is already configured') else: if 'm26_configuration' in self._conf and self._conf['m26_configuration']: - m26_config_file = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))), self._conf['m26_configuration']) + m26_config_file = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))), self._conf['m26_configuration']) logging.info('Loading m26 configuration file %s', m26_config_file) self.dut.set_configuration(m26_config_file) - IR={"BSR_ALL":'00101',"DEV_ID_ALL":'01110',"BIAS_DAC_ALL":'01111',"LINEPAT0_REG_ALL":'10000', - "DIS_DISCRI_ALL":'10001',"SEQUENCER_PIX_REG_ALL":'10010',"CONTROL_PIX_REG_ALL":'10011', - "LINEPAT1_REG_ALL":'10100',"SEQUENCER_SUZE_REG_ALL":'10101',"HEADER_REG_ALL":'10110', - "CONTROL_SUZE_REG_ALL":'10111', - "CTRL_8b10b_REG0_ALL":'11000',"CTRL_8b10b_REG1_ALL":'11001',"RO_MODE1_ALL":'11101', - "RO_MODE0_ALL":'11110', - "BYPASS_ALL":'11111'} - ## write JTAG - irs = ["BIAS_DAC_ALL","BYPASS_ALL","BSR_ALL","RO_MODE0_ALL","RO_MODE1_ALL", - "DIS_DISCRI_ALL","LINEPAT0_REG_ALL","LINEPAT1_REG_ALL","CONTROL_PIX_REG_ALL","SEQUENCER_PIX_REG_ALL", - "HEADER_REG_ALL","CONTROL_SUZE_REG_ALL","SEQUENCER_SUZE_REG_ALL","CTRL_8b10b_REG0_ALL", - "CTRL_8b10b_REG1_ALL"] - for i,ir in enumerate(irs): + IR = {'BSR_ALL': '00101', 'DEV_ID_ALL': '01110', 'BIAS_DAC_ALL': '01111', 'LINEPAT0_REG_ALL': '10000', + 'DIS_DISCRI_ALL': '10001', 'SEQUENCER_PIX_REG_ALL': '10010', 'CONTROL_PIX_REG_ALL': '10011', + 'LINEPAT1_REG_ALL': '10100', 'SEQUENCER_SUZE_REG_ALL': '10101', 'HEADER_REG_ALL': '10110', + 'CONTROL_SUZE_REG_ALL': '10111', + 'CTRL_8b10b_REG0_ALL': '11000', 'CTRL_8b10b_REG1_ALL': '11001', 'RO_MODE1_ALL': '11101', + 'RO_MODE0_ALL': '11110', + 'BYPASS_ALL': '11111'} + # # write JTAG + irs = ['BIAS_DAC_ALL', 'BYPASS_ALL', 'BSR_ALL', 'RO_MODE0_ALL', 'RO_MODE1_ALL', + 'DIS_DISCRI_ALL', 'LINEPAT0_REG_ALL', 'LINEPAT1_REG_ALL', 'CONTROL_PIX_REG_ALL', 'SEQUENCER_PIX_REG_ALL', + 'HEADER_REG_ALL', 'CONTROL_SUZE_REG_ALL', 'SEQUENCER_SUZE_REG_ALL', 'CTRL_8b10b_REG0_ALL', + 'CTRL_8b10b_REG1_ALL'] + for ir in irs: logging.info('Programming M26 JATG configuration reg %s', ir) logging.debug(self.dut[ir][:]) - self.dut['jtag'].scan_ir([BitLogic(IR[ir])]*6) - ret = self.dut['jtag'].scan_dr([self.dut[ir][:]])[0] + self.dut['JTAG'].scan_ir([BitLogic(IR[ir])] * 6) + ret = self.dut['JTAG'].scan_dr([self.dut[ir][:]])[0] if self.remote: current = self.dut['Powersupply'].get_current() current = current.replace("\n", "").replace("\r", "") logging.info('Current: %s A', current) - ## read JTAG and check - irs=["DEV_ID_ALL","BSR_ALL","BIAS_DAC_ALL","RO_MODE1_ALL","RO_MODE0_ALL", - "DIS_DISCRI_ALL","LINEPAT0_REG_ALL","LINEPAT1_REG_ALL","CONTROL_PIX_REG_ALL", - "SEQUENCER_PIX_REG_ALL", - "HEADER_REG_ALL","CONTROL_SUZE_REG_ALL","SEQUENCER_SUZE_REG_ALL","CTRL_8b10b_REG0_ALL", - "CTRL_8b10b_REG1_ALL","BYPASS_ALL"] - ret={} - for i,ir in enumerate(irs): + + # # read JTAG and check + irs = ['DEV_ID_ALL', 'BSR_ALL', 'BIAS_DAC_ALL', 'RO_MODE1_ALL', 'RO_MODE0_ALL', + 'DIS_DISCRI_ALL', 'LINEPAT0_REG_ALL', 'LINEPAT1_REG_ALL', 'CONTROL_PIX_REG_ALL', + 'SEQUENCER_PIX_REG_ALL', + 'HEADER_REG_ALL', 'CONTROL_SUZE_REG_ALL', 'SEQUENCER_SUZE_REG_ALL', 'CTRL_8b10b_REG0_ALL', + 'CTRL_8b10b_REG1_ALL', 'BYPASS_ALL'] + ret = {} + for ir in irs: logging.info('Reading M26 JATG configuration reg %s', ir) - self.dut['jtag'].scan_ir([BitLogic(IR[ir])]*6) - ret[ir]= self.dut['jtag'].scan_dr([self.dut[ir][:]])[0] + self.dut['JTAG'].scan_ir([BitLogic(IR[ir])] * 6) + ret[ir] = self.dut['JTAG'].scan_dr([self.dut[ir][:]])[0] if self.remote: current = self.dut['Powersupply'].get_current() current = current.replace("\n", "").replace("\r", "") logging.info('Current: %s A', current) - ## check - for k,v in ret.iteritems(): - if k=="CTRL_8b10b_REG1_ALL": + + # # check + for k, v in ret.iteritems(): + if k == "CTRL_8b10b_REG1_ALL": pass - elif k=="BSR_ALL": - pass #TODO mask clock bits and check others - elif self.dut[k][:]!=v: - logging.error("JTAG data does not match %s get=%s set=%s"%(k,v,self.dut[k][:])) + elif k == "BSR_ALL": + pass # TODO mask clock bits and check others + elif self.dut[k][:] != v: + logging.error("JTAG data does not match %s get=%s set=%s" % (k, v, self.dut[k][:])) else: - logging.info("Checking M26 JTAG %s ok"%k) + logging.info("Checking M26 JTAG %s ok" % k) if self.remote: current = self.dut['Powersupply'].get_current() current = current.replace("\n", "").replace("\r", "") logging.info('Current: %s A', current) - #START procedure + + # START procedure logging.info('Starting M26') - temp=self.dut['RO_MODE0_ALL'][:] - #disable extstart - for reg in self.dut["RO_MODE0_ALL"]["RO_MODE0"]: - reg['En_ExtStart']=0 - reg['JTAG_Start']=0 - self.dut['jtag'].scan_ir([BitLogic(IR['RO_MODE0_ALL'])]*6) - self.dut['jtag'].scan_dr([self.dut['RO_MODE0_ALL'][:]]) - #JTAG start - for reg in self.dut["RO_MODE0_ALL"]["RO_MODE0"]: - reg['JTAG_Start']=1 - self.dut['jtag'].scan_ir([BitLogic(IR['RO_MODE0_ALL'])]*6) - self.dut['jtag'].scan_dr([self.dut['RO_MODE0_ALL'][:]]) - for reg in self.dut["RO_MODE0_ALL"]["RO_MODE0"]: - reg['JTAG_Start']=0 - self.dut['jtag'].scan_ir([BitLogic(IR['RO_MODE0_ALL'])]*6) - self.dut['jtag'].scan_dr([self.dut['RO_MODE0_ALL'][:]]) - #write original configuration - self.dut['RO_MODE0_ALL'][:]=temp - self.dut['jtag'].scan_ir([BitLogic(IR['RO_MODE0_ALL'])]*6) - self.dut['jtag'].scan_dr([self.dut['RO_MODE0_ALL'][:]]) - #readback? - self.dut['jtag'].scan_ir([BitLogic(IR['RO_MODE0_ALL'])]*6) - self.dut['jtag'].scan_dr([self.dut['RO_MODE0_ALL'][:]]*6) + temp = self.dut['RO_MODE0_ALL'][:] + # disable extstart + for reg in self.dut['RO_MODE0_ALL']['RO_MODE0']: + reg['En_ExtStart'] = 0 + reg['JTAG_Start'] = 0 + self.dut['JTAG'].scan_ir([BitLogic(IR['RO_MODE0_ALL'])] * 6) + self.dut['JTAG'].scan_dr([self.dut['RO_MODE0_ALL'][:]]) + # JTAG start + for reg in self.dut['RO_MODE0_ALL']['RO_MODE0']: + reg['JTAG_Start'] = 1 + self.dut['JTAG'].scan_ir([BitLogic(IR['RO_MODE0_ALL'])] * 6) + self.dut['JTAG'].scan_dr([self.dut['RO_MODE0_ALL'][:]]) + for reg in self.dut['RO_MODE0_ALL']['RO_MODE0']: + reg['JTAG_Start'] = 0 + self.dut['JTAG'].scan_ir([BitLogic(IR['RO_MODE0_ALL'])] * 6) + self.dut['JTAG'].scan_dr([self.dut['RO_MODE0_ALL'][:]]) + # write original configuration + self.dut['RO_MODE0_ALL'][:] = temp + self.dut['JTAG'].scan_ir([BitLogic(IR['RO_MODE0_ALL'])] * 6) + self.dut['JTAG'].scan_dr([self.dut['RO_MODE0_ALL'][:]]) + # readback? + self.dut['JTAG'].scan_ir([BitLogic(IR['RO_MODE0_ALL'])] * 6) + self.dut['JTAG'].scan_dr([self.dut['RO_MODE0_ALL'][:]] * 6) if self.remote: current = self.dut['Powersupply'].get_current() @@ -187,81 +194,88 @@ def configure(self): commands.extend(self.register.get_commands("WrRegister", name=["Trig_Lat", "Trig_Count"])) commands.extend(self.register.get_commands("RunMode")) self.register_utils.send_commands(commands) - self.dut['TLU']['RESET']=1 - for plane in range(1,7): - self.dut['M26_RX%d'%plane].reset() - self.dut['M26_RX%d'%plane]['TIMESTAMP_HEADER']=1 def scan(self): # preload command lvl1_command = self.register.get_commands("zeros", length=self.trigger_delay)[0] + self.register.get_commands("LV1")[0] + self.register.get_commands("zeros", length=self.trigger_rate_limit)[0] self.register_utils.set_command(lvl1_command) - with self.readout(no_data_timeout=self.no_data_timeout, **self.scan_parameters._asdict()): - got_data = False - start = time() - while not self.stop_run.wait(1.0): - if not got_data: - if self.fifo_readout.data_words_per_second() > 0: - got_data = True - logging.info('Taking data...') - if self.max_triggers: - self.progressbar = progressbar.ProgressBar(widgets=['', progressbar.Percentage(), ' ', progressbar.Bar(marker='*', left='|', right='|'), ' ', progressbar.AdaptiveETA()], maxval=self.max_triggers, poll=10, term_width=80).start() - else: - self.progressbar = progressbar.ProgressBar(widgets=['', progressbar.Percentage(), ' ', progressbar.Bar(marker='*', left='|', right='|'), ' ', progressbar.Timer()], maxval=self.scan_timeout, poll=10, term_width=80).start() - else: - triggers = self.dut['TLU']['TRIGGER_COUNTER'] - try: - if self.max_triggers: - self.progressbar.update(triggers) - else: - self.progressbar.update(time() - start) - except ValueError: - pass - if self.max_triggers and triggers >= self.max_triggers: - self.progressbar.finish() - self.stop(msg='Trigger limit was reached: %i' % self.max_triggers) + with self.readout(no_data_timeout=self.no_data_timeout, enabled_fe_channels=self._enabled_fe_channels if self.enable_roi else [], enabled_m26_channels=[rx.name for rx in self.dut.get_modules('m26_rx')]): + with self.trigger(): + got_data = False + start = time() + while not self.stop_run.wait(1.0): + if not got_data: + if self.data_words_per_second() > 0: + got_data = True + logging.info('Taking data...') + if self.max_triggers: + self.progressbar = progressbar.ProgressBar(widgets=['', progressbar.Percentage(), ' ', progressbar.Bar(marker='*', left='|', right='|'), ' ', progressbar.AdaptiveETA()], maxval=self.max_triggers, poll=10, term_width=80).start() + else: + self.progressbar = progressbar.ProgressBar(widgets=['', progressbar.Percentage(), ' ', progressbar.Bar(marker='*', left='|', right='|'), ' ', progressbar.Timer()], maxval=self.scan_timeout, poll=10, term_width=80).start() + else: + triggers = self.dut['TLU']['TRIGGER_COUNTER'] + try: + if self.max_triggers: + self.progressbar.update(triggers) + else: + self.progressbar.update(time() - start) + except ValueError: + pass + if self.max_triggers and triggers >= self.max_triggers: + self.progressbar.finish() + self.stop(msg='Trigger limit was reached: %i' % self.max_triggers) logging.info('Total amount of triggers collected: %d', self.dut['TLU']['TRIGGER_COUNTER']) def analyze(self): pass - #with AnalyzeRawData(raw_data_file=self.output_filename, create_pdf=True) as analyze_raw_data: - # analyze_raw_data.create_source_scan_hist = True - # analyze_raw_data.create_cluster_size_hist = True - # analyze_raw_data.create_cluster_tot_hist = True - # analyze_raw_data.align_at_trigger = True - # analyze_raw_data.interpreter.set_warning_output(False) - # analyze_raw_data.interpret_word_table() - # analyze_raw_data.interpreter.print_summary() - # analyze_raw_data.plot_histograms() +# with AnalyzeRawData(raw_data_file=self.output_filename, create_pdf=True) as analyze_raw_data: +# analyze_raw_data.trigger_data_format = self.dut['TLU']['DATA_FORMAT'] +# analyze_raw_data.create_source_scan_hist = True +# analyze_raw_data.create_cluster_size_hist = True +# analyze_raw_data.create_cluster_tot_hist = True +# analyze_raw_data.align_at_trigger = True +# analyze_raw_data.interpreter.set_warning_output(False) +# analyze_raw_data.interpret_word_table() +# analyze_raw_data.interpreter.print_summary() +# analyze_raw_data.plot_histograms() + + @contextmanager + def trigger(self): + self.start_trigger() + try: + yield + finally: + try: + self.stop_trigger() + except: + # in case something fails, call this on last resort + self.scan_timeout_timer.cancel() + self.connect_cancel(["abort"]) - def start_readout(self, *args, **kwargs): - super(M26TelescopeScan, self).start_readout(*args, **kwargs) - self.dut['TLU']['RESET']=1 - self.dut['TLU']['TRIGGER_MODE']=3 - self.dut['TLU']['TRIGGER_LOW_TIMEOUT']=200 - self.dut['TLU']['TRIGGER_HANDSHAKE_ACCEPT_WAIT_CYCLES']=20 - self.dut['TLU']['DATA_FORMAT']=2 - self.dut['TLU']['TRIGGER_DATA_DELAY']=8 + def start_trigger(self): + self.connect_cancel(["stop"]) + self.dut['TLU']['RESET'] = 1 + self.dut['TLU']['TRIGGER_MODE'] = 3 + self.dut['TLU']['TRIGGER_LOW_TIMEOUT'] = 200 + self.dut['TLU']['TRIGGER_HANDSHAKE_ACCEPT_WAIT_CYCLES'] = 20 + self.dut['TLU']['DATA_FORMAT'] = 2 + self.dut['TLU']['TRIGGER_DATA_DELAY'] = 8 self.dut['TLU']['TRIGGER_COUNTER'] = 0 self.dut['TLU']['TRIGGER_VETO_SELECT'] = 0 self.dut['TLU']['EN_TLU_VETO'] = 0 - self.dut['M26_RX1'].set_en(True) - self.dut['M26_RX2'].set_en(True) - self.dut['M26_RX3'].set_en(True) - self.dut['M26_RX4'].set_en(True) - self.dut['M26_RX5'].set_en(True) - self.dut['M26_RX6'].set_en(True) - if self.max_triggers: self.dut['TLU']['MAX_TRIGGERS'] = self.max_triggers else: self.dut['TLU']['MAX_TRIGGERS'] = 0 # infinity triggers - # remove the following line if no FE-I4 connected - self.dut['CMD']['EN_EXT_TRIGGER'] = True + if self.enable_roi: + self.dut['TX']['EN_EXT_TRIGGER'] = True + else: + self.dut['TX']['EN_EXT_TRIGGER'] = False # this will turn on trigger/TLU FSM - self.dut['TLU']['TRIGGER_ENABLE'] = True + with self.synchronized(): + self.dut['TLU']['TRIGGER_ENABLE'] = True def timeout(): try: @@ -274,17 +288,12 @@ def timeout(): if self.scan_timeout: self.scan_timeout_timer.start() - def stop_readout(self, timeout=10.0): + def stop_trigger(self): self.scan_timeout_timer.cancel() - self.dut['TLU']['TRIGGER_ENABLE'] = False - self.dut['CMD']['EN_EXT_TRIGGER'] = False - self.dut['M26_RX1'].set_en(False) - self.dut['M26_RX2'].set_en(False) - self.dut['M26_RX3'].set_en(False) - self.dut['M26_RX4'].set_en(False) - self.dut['M26_RX5'].set_en(False) - self.dut['M26_RX6'].set_en(False) - super(M26TelescopeScan, self).stop_readout(timeout=timeout) + with self.synchronized(): + self.dut['TLU']['TRIGGER_ENABLE'] = False + self.dut['TX']['EN_EXT_TRIGGER'] = False + self.connect_cancel(["abort"]) if __name__ == "__main__": diff --git a/pybar/scans/scan_threshold.py b/pybar/scans/scan_threshold.py index bcd3cfc96..6f721a666 100644 --- a/pybar/scans/scan_threshold.py +++ b/pybar/scans/scan_threshold.py @@ -13,6 +13,8 @@ class ThresholdScan(Fei4RunBase): Implementation of a standard threshold scan. ''' _default_run_conf = { + "broadcast_commands": True, + "threaded_scan": False, "mask_steps": 3, # mask steps, be carefull PlsrDAC injects different charge for different mask steps "n_injections": 100, # number of injections per PlsrDAC step "scan_parameters": [('PlsrDAC', [None, 100])], # the PlsrDAC range @@ -77,5 +79,6 @@ def analyze(self): analyze_raw_data.interpreter.print_summary() analyze_raw_data.plot_histograms() + if __name__ == "__main__": RunManager('../configuration.yaml').run_run(ThresholdScan) diff --git a/pybar/scans/scan_threshold_fast.py b/pybar/scans/scan_threshold_fast.py index 7c7df486f..cf610723e 100644 --- a/pybar/scans/scan_threshold_fast.py +++ b/pybar/scans/scan_threshold_fast.py @@ -1,14 +1,14 @@ import logging + import numpy as np from pybar_fei4_interpreter.analysis_utils import hist_2d_index - from pybar.analysis.analyze_raw_data import AnalyzeRawData from pybar.fei4.register_utils import invert_pixel_mask from pybar.fei4_run_base import Fei4RunBase from pybar.fei4.register_utils import scan_loop from pybar.run_manager import RunManager -from pybar.daq.readout_utils import get_col_row_array_from_data_record_array, convert_data_array, is_data_record, data_array_from_data_iterable +from pybar.daq.readout_utils import get_col_row_array_from_data_record_array, convert_data_array, is_data_record, data_array_from_data_iterable, logical_and class FastThresholdScan(Fei4RunBase): @@ -17,6 +17,8 @@ class FastThresholdScan(Fei4RunBase): Implementation of a fast threshold scan checking for start and end of s-curve. ''' _default_run_conf = { + "broadcast_commands": True, + "threaded_scan": False, "n_injections": 100, # number of injections per PlsrDAC step "scan_parameters": [('PlsrDAC', (None, 100))], # the PlsrDAC range "mask_steps": 3, # mask steps, be carefull PlsrDAC injects different charge for different mask steps @@ -96,7 +98,7 @@ def scan(self): commands.extend(self.register.get_commands("WrRegister", name=['PlsrDAC'])) self.register_utils.send_commands(commands) - with self.readout(PlsrDAC=self.scan_parameter_value, reset_sram_fifo=True, fill_buffer=True, clear_buffer=True, callback=self.handle_data if self.record_data else None): + with self.readout(PlsrDAC=self.scan_parameter_value, fill_buffer=True, callback=self.handle_data if self.record_data else None): cal_lvl1_command = self.register.get_commands("CAL")[0] + self.register.get_commands("zeros", length=40)[0] + self.register.get_commands("LV1")[0] scan_loop(self, cal_lvl1_command, repeat_command=self.n_injections, use_delay=True, mask_steps=self.mask_steps, enable_mask_steps=self.enable_mask_steps, enable_double_columns=enable_double_columns, same_mask_for_all_dc=True, eol_function=None, digital_injection=False, enable_shift_masks=self.enable_shift_masks, disable_shift_masks=self.disable_shift_masks, restore_shift_masks=False, mask=invert_pixel_mask(self.register.get_pixel_register_value('Enable')) if self.use_enable_mask else None, double_column_correction=self.pulser_dac_correction) @@ -106,7 +108,7 @@ def scan(self): if not self.stop_condition_triggered and self.record_data: logging.info('Testing for stop condition: %s %d', 'PlsrDAC', self.scan_parameter_value) - col, row = convert_data_array(data_array_from_data_iterable(self.fifo_readout.data), filter_func=is_data_record, converter_func=get_col_row_array_from_data_record_array) + col, row = convert_data_array(array=self.read_data(), filter_func=is_data_record, converter_func=get_col_row_array_from_data_record_array) if np.any(np.logical_and(col < 1, col > 80)) or np.any(np.logical_and(row < 1, row > 336)): # filter bad data records that can happen logging.warning('There are undefined %d data records (e.g. random data)', np.count_nonzero(np.logical_and(col < 1, col > 80)) + np.count_nonzero(np.logical_and(row < 1, row > 336))) col, row = col[np.logical_and(col > 0, col <= 80)], row[np.logical_and(row > 0, row <= 336)] @@ -169,5 +171,6 @@ def scan_condition(self, occupancy_array): logging.info("Triggering start condition: %d pixel(s) with more than 0 hits >= %d pixel(s)", pixels_with_hits_count, start_pixel_cnt) self.start_condition_triggered = True + if __name__ == "__main__": RunManager('../configuration.yaml').run_run(FastThresholdScan) diff --git a/pybar/scans/test_register.py b/pybar/scans/test_register.py index a5116be8c..a8e25e71b 100644 --- a/pybar/scans/test_register.py +++ b/pybar/scans/test_register.py @@ -25,9 +25,12 @@ class RegisterTest(Fei4RunBase): Register at address 40 will always fail (ADC output value). ''' _default_run_conf = { + "broadcast_commands": False, + "threaded_scan": False, "read_sn": True, "test_global": True, - "test_pixel": True + "test_pixel": True, + "fail_on_error": False } def configure(self): @@ -39,12 +42,12 @@ def scan(self): if self.test_global: global_register_errors = test_global_register(self) - if global_register_errors: + if global_register_errors and self.fail_on_error: raise Exception('Global register test finished with %d errors' % global_register_errors) if self.test_pixel: pixel_register_errors = self.test_pixel_register() - if pixel_register_errors: + if pixel_register_errors and self.fail_on_error: raise Exception('Pixel register test finished with %d errors' % pixel_register_errors) def analyze(self): @@ -58,7 +61,7 @@ def test_pixel_register(self, pix_regs=["EnableDigInj", "Imon", "Enable", "C_Hig commands = [] commands.extend(self.register.get_commands("ConfMode")) self.register_utils.send_commands(commands) - self.fifo_readout.reset_sram_fifo() + self.fifo_readout.reset_fifo() pixel_register_errors = 0 @@ -74,5 +77,6 @@ def test_pixel_register(self, pix_regs=["EnableDigInj", "Imon", "Enable", "C_Hig plots.close() return pixel_register_errors + if __name__ == "__main__": RunManager('../configuration.yaml').run_run(RegisterTest) diff --git a/pybar/scans/test_tdc.py b/pybar/scans/test_tdc.py index 9abd4e35b..418ce4e3a 100644 --- a/pybar/scans/test_tdc.py +++ b/pybar/scans/test_tdc.py @@ -27,6 +27,8 @@ class TdcTest(Fei4RunBase): '''Test TDC scan ''' _default_run_conf = { + "broadcast_commands": True, + "threaded_scan": False, "n_pulses": 10000, "pulse_period": '1E-6', # s "test_tdc_values": False, @@ -50,13 +52,12 @@ def scan(self): if self.test_tdc_values: x, y, y_err = [], [], [] tdc_hist = None - - self.fifo_readout.reset_sram_fifo() # clear fifo data for pulse_width in [i for j in (range(10, 100, 5), range(100, 400, 10)) for i in j]: - logging.info('Test TDC for a pulse with of %d', pulse_width) - self.start_pulser(pulse_width, self.n_pulses) - time.sleep(self.n_pulses * pulse_width * 1e-9 + 0.1) - data = self.fifo_readout.read_data() + with self.readout(fill_buffer=True, callback=None): + logging.info('Test TDC for a pulse with of %d', pulse_width) + self.start_pulser(pulse_width, self.n_pulses) + time.sleep(self.n_pulses * pulse_width * 1e-9 + 0.1) + data = self.read_data(fe_word_filter=False) if data[is_tdc_word(data)].shape[0] != 0: tdc_values = np.bitwise_and(data[is_tdc_word(data)], 0x00000FFF) tdc_counter = np.bitwise_and(data[is_tdc_word(data)], 0x000FF000) @@ -86,13 +87,13 @@ def scan(self): if self.test_trigger_delay: x, y, y_err, y2, y2_err = [], [], [], [], [] - self.fifo_readout.reset_sram_fifo() # clear fifo data for pulse_delay in [i for j in (range(0, 100, 5), range(100, 500, 500)) for i in j]: - logging.info('Test TDC for a pulse delay of %d', pulse_delay) - for _ in range(10): - self.start_pulser(pulse_width=100, n_pulses=1, pulse_delay=pulse_delay) - time.sleep(0.1) - data = self.fifo_readout.read_data() + with self.readout(reset_fifo=True, fill_buffer=True, callback=None): + logging.info('Test TDC for a pulse delay of %d', pulse_delay) + for _ in range(10): + self.start_pulser(pulse_width=100, n_pulses=1, pulse_delay=pulse_delay) + time.sleep(0.1) + data = self.read_data(fe_word_filter=False) if data[is_tdc_word(data)].shape[0] != 0: if len(is_tdc_word(data)) != 10: logging.warning('%d TDC words instead of %d ', len(is_tdc_word(data)), 10) @@ -115,5 +116,6 @@ def scan(self): def analyze(self): pass + if __name__ == "__main__": RunManager('../configuration.yaml').run_run(TdcTest) diff --git a/pybar/scans/tune_fdac.py b/pybar/scans/tune_fdac.py index a61be4352..43ab77072 100644 --- a/pybar/scans/tune_fdac.py +++ b/pybar/scans/tune_fdac.py @@ -6,7 +6,7 @@ from pybar.fei4_run_base import Fei4RunBase from pybar.fei4.register_utils import scan_loop from pybar.run_manager import RunManager -from pybar.daq.readout_utils import convert_data_array, is_data_record, is_fe_word, logical_and, data_array_from_data_iterable, get_col_row_tot_array_from_data_record_array +from pybar.daq.readout_utils import convert_data_array, is_data_record, logical_and, data_array_from_data_iterable, get_col_row_tot_array_from_data_record_array from pybar.analysis.plotting.plotting import plot_three_way @@ -22,13 +22,14 @@ class FdacTuning(Fei4RunBase): Use pybar.scans.tune_fei4 for full FE-I4 tuning. ''' _default_run_conf = { + "broadcast_commands": False, + "threaded_scan": False, "scan_parameters": [('FDAC', None)], "target_charge": 280, "target_tot": 5, "fdac_tune_bits": range(3, -1, -1), "n_injections_fdac": 30, "plot_intermediate_steps": False, - "plots_filename": None, "enable_shift_masks": ["Enable", "C_High", "C_Low"], # enable masks shifted during scan "disable_shift_masks": [], # disable masks shifted during scan "pulser_dac_correction": False, # PlsrDAC correction for each double column @@ -56,13 +57,10 @@ def configure(self): commands.extend(self.register.get_commands("RunMode")) self.register_utils.send_commands(commands) - def scan(self): - if not self.plots_filename: - self.plots_filename = PdfPages(self.output_filename + '.pdf') - self.close_plots = True - else: - self.close_plots = False + self.plots_filename = PdfPages(self.output_filename + '.pdf') + self.close_plots = True + def scan(self): enable_mask_steps = [] cal_lvl1_command = self.register.get_commands("CAL")[0] + self.register.get_commands("zeros", length=40)[0] + self.register.get_commands("LV1")[0] @@ -77,6 +75,8 @@ def scan(self): self.fdac_mask_best = self.register.get_pixel_register_value("FDAC") fdac_tune_bits = self.fdac_tune_bits[:] for scan_parameter_value, fdac_bit in enumerate(fdac_tune_bits): + if self.stop_run.is_set(): + break if additional_scan: self.set_fdac_bit(fdac_bit) logging.info('FDAC setting: bit %d = 1', fdac_bit) @@ -86,7 +86,7 @@ def scan(self): self.write_fdac_config() - with self.readout(FDAC=scan_parameter_value, reset_sram_fifo=True, fill_buffer=True, clear_buffer=True, callback=self.handle_data): + with self.readout(FDAC=scan_parameter_value, fill_buffer=True): scan_loop(self, command=cal_lvl1_command, repeat_command=self.n_injections_fdac, @@ -102,7 +102,8 @@ def scan(self): mask=None, double_column_correction=self.pulser_dac_correction) - col_row_tot = np.column_stack(convert_data_array(data_array_from_data_iterable(self.fifo_readout.data), filter_func=logical_and(is_fe_word, is_data_record), converter_func=get_col_row_tot_array_from_data_record_array)) + data = convert_data_array(array=self.read_data(), filter_func=is_data_record, converter_func=get_col_row_tot_array_from_data_record_array) + col_row_tot = np.column_stack(data) tot_array = np.histogramdd(col_row_tot, bins=(80, 336, 16), range=[[1, 80], [1, 336], [0, 15]])[0] tot_mean_array = np.average(tot_array, axis=2, weights=range(0, 16)) * sum(range(0, 16)) / self.n_injections_fdac select_better_pixel_mask = abs(tot_mean_array - self.target_tot) <= abs(self.tot_mean_best - self.target_tot) @@ -166,5 +167,6 @@ def set_start_fdac(self): start_fdac_setting = start_fdac_setting & ~(1 << bit_position) self.register.set_pixel_register_value("FDAC", start_fdac_setting) + if __name__ == "__main__": RunManager('../configuration.yaml').run_run(FdacTuning) diff --git a/pybar/scans/tune_feedback.py b/pybar/scans/tune_feedback.py index fb1a8ab43..1725c46e7 100644 --- a/pybar/scans/tune_feedback.py +++ b/pybar/scans/tune_feedback.py @@ -6,7 +6,7 @@ from pybar.fei4_run_base import Fei4RunBase from pybar.fei4.register_utils import scan_loop, make_pixel_mask from pybar.run_manager import RunManager -from pybar.daq.readout_utils import convert_data_array, is_data_record, is_fe_word, logical_and, data_array_from_data_iterable, get_col_row_tot_array_from_data_record_array +from pybar.daq.readout_utils import convert_data_array, is_data_record, logical_and, data_array_from_data_iterable, get_col_row_tot_array_from_data_record_array from pybar.analysis.plotting.plotting import plot_tot @@ -20,6 +20,8 @@ class FeedbackTuning(Fei4RunBase): Use pybar.scans.tune_fei4 for full FE-I4 tuning. ''' _default_run_conf = { + "broadcast_commands": False, + "threaded_scan": False, "scan_parameters": [('PrmpVbpf', None)], "target_charge": 280, "target_tot": 5, @@ -28,7 +30,6 @@ class FeedbackTuning(Fei4RunBase): "max_delta_tot": 0.1, "enable_mask_steps_feedback": [0], # mask steps to do per PrmpVbpf setting "plot_intermediate_steps": False, - "plots_filename": None, "enable_shift_masks": ["Enable", "C_High", "C_Low"], # enable masks shifted during scan "disable_shift_masks": [], # disable masks shifted during scan "pulser_dac_correction": False, # PlsrDAC correction for each double column @@ -57,13 +58,10 @@ def configure(self): commands.extend(self.register.get_commands("RunMode")) self.register_utils.send_commands(commands) - def scan(self): - if not self.plots_filename: - self.plots_filename = PdfPages(self.output_filename + '.pdf') - self.close_plots = True - else: - self.close_plots = False + self.plots_filename = PdfPages(self.output_filename + '.pdf') + self.close_plots = True + def scan(self): def bits_set(int_type): int_type = int(int_type) position = 0 @@ -97,6 +95,8 @@ def bits_set(int_type): feedback_best = self.register.get_global_register_value("PrmpVbpf") feedback_tune_bits = self.feedback_tune_bits[:] for feedback_bit in feedback_tune_bits: + if self.stop_run.is_set(): + break if additional_scan: self.set_prmp_vbpf_bit(feedback_bit, bit_value=1) logging.info('PrmpVbpf setting: %d, set bit %d = 1', self.register.get_global_register_value("PrmpVbpf"), feedback_bit) @@ -106,7 +106,7 @@ def bits_set(int_type): scan_parameter_value = self.register.get_global_register_value("PrmpVbpf") - with self.readout(PrmpVbpf=scan_parameter_value, reset_sram_fifo=True, fill_buffer=True, clear_buffer=True, callback=self.handle_data): + with self.readout(PrmpVbpf=scan_parameter_value, fill_buffer=True): scan_loop(self, command=cal_lvl1_command, repeat_command=self.n_injections_feedback, @@ -122,7 +122,8 @@ def bits_set(int_type): mask=None, double_column_correction=self.pulser_dac_correction) - col_row_tot_array = np.column_stack(convert_data_array(data_array_from_data_iterable(self.fifo_readout.data), filter_func=logical_and(is_fe_word, is_data_record), converter_func=get_col_row_tot_array_from_data_record_array)) + data = convert_data_array(array=self.read_data(), filter_func=is_data_record, converter_func=get_col_row_tot_array_from_data_record_array) + col_row_tot_array = np.column_stack(data) occupancy_array, _, _ = np.histogram2d(col_row_tot_array[:, 0], col_row_tot_array[:, 1], bins=(80, 336), range=[[1, 80], [1, 336]]) occupancy_array = np.ma.array(occupancy_array, mask=np.logical_not(np.ma.make_mask(select_mask_array))) # take only selected pixel into account by creating a mask occupancy_array = np.ma.masked_where(occupancy_array > self.n_injections_feedback, occupancy_array) @@ -177,7 +178,7 @@ def bits_set(int_type): self.feedback_best = self.register.get_global_register_value("PrmpVbpf") - if abs(mean_tot - self.target_tot) > 2 * self.max_delta_tot: + if abs(mean_tot - self.target_tot) > 2 * self.max_delta_tot and not self.stop_run.is_set(): if np.all((((self.feedback_best & (1 << np.arange(self.register.global_registers['PrmpVbpf']['bitlength'])))) > 0).astype(int)[self.feedback_tune_bits] == 1): if self.fail_on_warning: raise RuntimeWarning('Selected Feedback bits reached maximum value') @@ -190,7 +191,7 @@ def bits_set(int_type): logging.warning('Selected Feedback bits reached minimum value') else: if self.fail_on_warning: - raise RuntimeWarning('Global feedback tuning failed. Delta ToT = %.2f > %.2f. PrmpVbpf = %d' %(abs(mean_tot - self.target_tot), self.max_delta_tot, self.register.get_global_register_value("PrmpVbpf"))) + raise RuntimeWarning('Global feedback tuning failed. Delta ToT = %.2f > %.2f. PrmpVbpf = %d' % (abs(mean_tot - self.target_tot), self.max_delta_tot, self.register.get_global_register_value("PrmpVbpf"))) else: logging.warning('Global feedback tuning failed. Delta ToT = %.2f > %.2f. PrmpVbpf = %d', abs(mean_tot - self.target_tot), self.max_delta_tot, self.register.get_global_register_value("PrmpVbpf")) else: @@ -200,7 +201,7 @@ def analyze(self): # set here because original value is restored after scan() self.register.set_global_register_value("PrmpVbpf", self.feedback_best) - plot_tot(hist=self.tot_hist, title='ToT distribution after feedback tuning (PrmpVbpf %d)' % self.scan_parameters.PrmpVbpf, filename=self.plots_filename) + plot_tot(hist=self.tot_hist, title='ToT distribution after feedback tuning (PrmpVbpf %d)' % self.feedback_best, filename=self.plots_filename) if self.close_plots: self.plots_filename.close() diff --git a/pybar/scans/tune_fei4.py b/pybar/scans/tune_fei4.py index a57fe6fb2..00e7abf14 100644 --- a/pybar/scans/tune_fei4.py +++ b/pybar/scans/tune_fei4.py @@ -1,7 +1,5 @@ import logging -from matplotlib.backends.backend_pdf import PdfPages - from pybar.run_manager import RunManager from pybar.scans.tune_gdac import GdacTuning from pybar.scans.tune_feedback import FeedbackTuning @@ -30,6 +28,8 @@ class Fei4Tuning(GdacTuning, TdacTuning, FeedbackTuning, FdacTuning): *) measurements from IBL wafer probing ''' _default_run_conf = { + "broadcast_commands": False, + "threaded_scan": False, # tuning parameters "target_threshold": 30, # target threshold "target_charge": 280, # target charge @@ -61,9 +61,7 @@ class Fei4Tuning(GdacTuning, TdacTuning, FeedbackTuning, FdacTuning): "pulser_dac_correction": False, # PlsrDAC correction for each double column "scan_parameters": [('GDAC', -1), ('TDAC', -1), ('PrmpVbpf', -1), ('FDAC', -1), ('global_step', 0), ('local_step', 0)], # plotting - "make_plots": True, # plots for all scan steps are created "plot_intermediate_steps": False, # plot intermediate steps (takes time) - "plots_filename": None, # file name to store the plot to, if None show on screen # other "mask_steps": 3, # mask steps, be carefull PlsrDAC injects different charge for different mask steps "same_mask_for_all_dc": True # Increases scan speed, should be deactivated for very noisy FE @@ -72,7 +70,7 @@ class Fei4Tuning(GdacTuning, TdacTuning, FeedbackTuning, FdacTuning): def configure(self): super(Fei4Tuning, self).configure() - # overwrite pixel registers and set them to center postion before a global tuning + # overwrite pixel registers and set them to center postion before a global tuning if self.reset_local_dacs and self.global_iterations: commands = [] commands.extend(self.register.get_commands("ConfMode")) @@ -87,6 +85,7 @@ def configure(self): commands.extend(self.register.get_commands("RunMode")) self.register_utils.send_commands(commands) + self.close_plots = False def scan(self): '''Metascript that calls other scripts to tune the FE. @@ -121,19 +120,18 @@ def scan(self): if self.local_iterations is None: self.local_iterations = -1 - if self.make_plots: - self.plots_filename = PdfPages(self.output_filename + '.pdf') - else: - self.plots_filename = None - for iteration in range(0, self.global_iterations): # tune iteratively with decreasing range to save time + if self.stop_run.is_set(): + break logging.info("Global tuning step %d / %d", iteration + 1, self.global_iterations) self.set_scan_parameters(global_step=self.scan_parameters.global_step + 1) GdacTuning.scan(self) + if self.stop_run.is_set(): + break self.set_scan_parameters(global_step=self.scan_parameters.global_step + 1) FeedbackTuning.scan(self) - if self.global_iterations >= 0: + if self.global_iterations >= 0 and not self.stop_run.is_set(): self.set_scan_parameters(global_step=self.scan_parameters.global_step + 1) GdacTuning.scan(self) @@ -144,13 +142,17 @@ def scan(self): logging.info("Results of global feedback tuning: PrmpVbpf = %d", PrmpVbpf) for iteration in range(0, self.local_iterations): + if self.stop_run.is_set(): + break logging.info("Local tuning step %d / %d", iteration + 1, self.local_iterations) self.set_scan_parameters(local_step=self.scan_parameters.local_step + 1) TdacTuning.scan(self) + if self.stop_run.is_set(): + break self.set_scan_parameters(local_step=self.scan_parameters.local_step + 1) FdacTuning.scan(self) - if self.local_iterations >= 0: + if self.local_iterations >= 0 and not self.stop_run.is_set(): self.set_scan_parameters(local_step=self.scan_parameters.local_step + 1) TdacTuning.scan(self) @@ -165,15 +167,15 @@ def analyze(self): if self.local_iterations >= 0: TdacTuning.analyze(self) - if self.make_plots: - if self.local_iterations > 0: - plot_three_way(hist=self.tot_mean_best.transpose(), title="Mean ToT after last FDAC tuning", x_axis_title='Mean ToT', filename=self.plots_filename) - plot_three_way(hist=self.register.get_pixel_register_value("FDAC").transpose(), title="FDAC distribution after last FDAC tuning", x_axis_title='FDAC', filename=self.plots_filename, maximum=16) - if self.local_iterations >= 0: - plot_three_way(hist=self.occupancy_best.transpose(), title="Occupancy after tuning", x_axis_title='Occupancy', filename=self.plots_filename, maximum=100) - plot_three_way(hist=self.register.get_pixel_register_value("TDAC").transpose(), title="TDAC distribution after complete tuning", x_axis_title='TDAC', filename=self.plots_filename, maximum=32) + if self.local_iterations > 0: + plot_three_way(hist=self.tot_mean_best.transpose(), title="Mean ToT after last FDAC tuning", x_axis_title='Mean ToT', filename=self.plots_filename) + plot_three_way(hist=self.register.get_pixel_register_value("FDAC").transpose(), title="FDAC distribution after last FDAC tuning", x_axis_title='FDAC', filename=self.plots_filename, maximum=16) + if self.local_iterations >= 0: + plot_three_way(hist=self.occupancy_best.transpose(), title="Occupancy after tuning", x_axis_title='Occupancy', filename=self.plots_filename, maximum=100) + plot_three_way(hist=self.register.get_pixel_register_value("TDAC").transpose(), title="TDAC distribution after complete tuning", x_axis_title='TDAC', filename=self.plots_filename, maximum=32) + + self.plots_filename.close() - self.plots_filename.close() if __name__ == "__main__": RunManager('../configuration.yaml').run_run(Fei4Tuning) diff --git a/pybar/scans/tune_gdac.py b/pybar/scans/tune_gdac.py index 6f11dbf3a..55ce53c8b 100644 --- a/pybar/scans/tune_gdac.py +++ b/pybar/scans/tune_gdac.py @@ -6,7 +6,7 @@ from pybar.fei4_run_base import Fei4RunBase from pybar.fei4.register_utils import scan_loop, make_pixel_mask from pybar.run_manager import RunManager -from pybar.daq.readout_utils import convert_data_array, is_data_record, is_fe_word, logical_and, data_array_from_data_iterable, get_col_row_array_from_data_record_array +from pybar.daq.readout_utils import convert_data_array, is_data_record, logical_and, data_array_from_data_iterable, get_col_row_array_from_data_record_array from pybar.analysis.plotting.plotting import plot_three_way @@ -20,6 +20,8 @@ class GdacTuning(Fei4RunBase): Use pybar.scans.tune_fei4 for full FE-I4 tuning. ''' _default_run_conf = { + "broadcast_commands": False, + "threaded_scan": False, "scan_parameters": [('GDAC', None)], "target_threshold": 30, # target threshold in PlsrDAC to tune to "gdac_tune_bits": range(7, -1, -1), # GDAC bits to change during tuning @@ -28,7 +30,6 @@ class GdacTuning(Fei4RunBase): "max_delta_threshold": 5, # minimum difference to the target_threshold to abort the tuning "enable_mask_steps_gdac": [0], # mask steps to do per GDAC setting "plot_intermediate_steps": False, # plot intermediate steps (takes time) - "plots_filename": None, # file name to store the plot to, if None show on screen "enable_shift_masks": ["Enable", "C_High", "C_Low"], # enable masks shifted during scan "disable_shift_masks": [], # disable masks shifted during scan "pulser_dac_correction": False, # PlsrDAC correction for each double column @@ -57,12 +58,10 @@ def configure(self): commands.extend(self.register.get_commands("RunMode")) self.register_utils.send_commands(commands) + self.plots_filename = PdfPages(self.output_filename + '.pdf') + self.close_plots = True + def scan(self): - if not self.plots_filename: - self.plots_filename = PdfPages(self.output_filename + '.pdf') - self.close_plots = True - else: - self.close_plots = False cal_lvl1_command = self.register.get_commands("CAL")[0] + self.register.get_commands("zeros", length=40)[0] + self.register.get_commands("LV1")[0] self.write_target_threshold() @@ -83,8 +82,6 @@ def bits_set(int_type): # calculate selected pixels from the mask and the disabled columns select_mask_array = np.zeros(shape=(80, 336), dtype=np.uint8) - self.occ_array_sel_pixels_best = select_mask_array.copy() - self.occ_array_desel_pixels_best = select_mask_array.copy() if not self.enable_mask_steps_gdac: self.enable_mask_steps_gdac = range(self.mask_steps) for mask_step in self.enable_mask_steps_gdac: @@ -95,14 +92,18 @@ def bits_set(int_type): additional_scan = True additional_scan_ongoing = False - occupancy_best = 0.0 last_good_gdac_bit = self.gdac_tune_bits[0] last_good_gdac_scan_step = 0 gdac_tune_bits_permutation = 0 - gdac_best = self.register_utils.get_gdac() + gdac_values = [] + gdac_occupancy = [] + gdac_occ_array_sel_pixels = [] + gdac_occ_array_desel_pixels = [] gdac_tune_bits = self.gdac_tune_bits[:] min_gdac_with_occupancy = None for gdac_scan_step, gdac_bit in enumerate(gdac_tune_bits): + if self.stop_run.is_set(): + break if additional_scan: self.set_gdac_bit(gdac_bit, bit_value=1, send_command=True) scan_parameter_value = (self.register.get_global_register_value("Vthin_AltCoarse") << 8) + self.register.get_global_register_value("Vthin_AltFine") @@ -112,7 +113,7 @@ def bits_set(int_type): scan_parameter_value = (self.register.get_global_register_value("Vthin_AltCoarse") << 8) + self.register.get_global_register_value("Vthin_AltFine") logging.info('GDAC setting: %d, set bit %d = 0', scan_parameter_value, gdac_bit) - with self.readout(GDAC=scan_parameter_value, reset_sram_fifo=True, fill_buffer=True, clear_buffer=True, callback=self.handle_data): + with self.readout(GDAC=scan_parameter_value, fill_buffer=True): scan_loop(self, command=cal_lvl1_command, repeat_command=self.n_injections_gdac, @@ -128,18 +129,20 @@ def bits_set(int_type): mask=None, double_column_correction=self.pulser_dac_correction) - occupancy_array, _, _ = np.histogram2d(*convert_data_array(data_array_from_data_iterable(self.fifo_readout.data), filter_func=logical_and(is_fe_word, is_data_record), converter_func=get_col_row_array_from_data_record_array), bins=(80, 336), range=[[1, 80], [1, 336]]) + data = convert_data_array(array=self.read_data(), filter_func=is_data_record, converter_func=get_col_row_array_from_data_record_array) + occupancy_array, _, _ = np.histogram2d(*data, bins=(80, 336), range=[[1, 80], [1, 336]]) occ_array_sel_pixels = np.ma.array(occupancy_array, mask=np.logical_not(np.ma.make_mask(select_mask_array))) # take only selected pixel into account by using the mask occ_array_desel_pixels = np.ma.array(occupancy_array, mask=np.ma.make_mask(select_mask_array)) # take only de-selected pixel into account by using the inverted mask median_occupancy = np.ma.median(occ_array_sel_pixels) noise_occupancy = np.ma.median(occ_array_desel_pixels) occupancy_almost_zero = np.allclose(median_occupancy, 0) no_noise = np.allclose(noise_occupancy, 0) - if abs(median_occupancy - self.n_injections_gdac / 2) < abs(occupancy_best - self.n_injections_gdac / 2): - occupancy_best = median_occupancy - gdac_best = self.register_utils.get_gdac() - self.occ_array_sel_pixels_best = occ_array_sel_pixels.copy() - self.occ_array_desel_pixels_best = occ_array_desel_pixels.copy() + gdac_values.append(self.register_utils.get_gdac()) + gdac_occupancy.append(median_occupancy) + gdac_occ_array_sel_pixels.append(occ_array_sel_pixels.copy()) + gdac_occ_array_desel_pixels.append(occ_array_desel_pixels.copy()) + self.occ_array_sel_pixels_best = occ_array_sel_pixels.copy() + self.occ_array_desel_pixels_best = occ_array_desel_pixels.copy() if self.plot_intermediate_steps: plot_three_way(self.occ_array_sel_pixel.transpose(), title="Occupancy (GDAC " + str(scan_parameter_value) + " with tuning bit " + str(gdac_bit) + ")", x_axis_title='Occupancy', filename=self.plots_filename, maximum=self.n_injections_gdac) @@ -183,7 +186,7 @@ def bits_set(int_type): else: gdac_tune_bits_permutation += 1 else: - gdac_tune_bits_permutation_header = map(int,bin(gdac_tune_bits_permutation)[2:].zfill(last_good_gdac_scan_step)) + gdac_tune_bits_permutation_header = map(int, bin(gdac_tune_bits_permutation)[2:].zfill(last_good_gdac_scan_step)) for gdac_permutation_bit, gdac_permutation_bit_value in enumerate(gdac_tune_bits_permutation_header): self.set_gdac_bit(self.gdac_tune_bits[gdac_permutation_bit], bit_value=gdac_permutation_bit_value, send_command=False) gdac_tune_bits.extend(self.gdac_tune_bits[last_good_gdac_scan_step + 1:]) @@ -213,14 +216,29 @@ def bits_set(int_type): logging.info('Keep bit 0 = 0') # select best GDAC value - if abs(occupancy_best - self.n_injections_gdac / 2) < abs(median_occupancy - self.n_injections_gdac / 2): + occupancy_sorted = np.array(gdac_occupancy)[np.argsort(np.array(gdac_values))] + gdac_sorted = np.sort(gdac_values) + try: + diff_occupancy = occupancy_sorted[1:] - occupancy_sorted[:-1] + gdac_min_idx = np.where(diff_occupancy > 0)[0][-1] + except IndexError: + gdac_min_idx = None + occupancy_sorted_sel = occupancy_sorted[gdac_min_idx:] + gdac_sorted_sel = gdac_sorted[gdac_min_idx:] + gdac_best_idx = np.abs(np.array(occupancy_sorted_sel) - self.n_injections_gdac / 2).argmin() + gdac_best = gdac_sorted_sel[gdac_best_idx] + occupancy_best = occupancy_sorted_sel[gdac_best_idx] + if gdac_best != self.register_utils.get_gdac(): logging.info("Binary search converged to non-optimal value, apply best GDAC value, change GDAC from %d to %d", self.register_utils.get_gdac(), gdac_best) median_occupancy = occupancy_best self.register_utils.set_gdac(gdac_best, send_command=False) + # for plotting + self.occ_array_sel_pixels_best = np.array(gdac_occ_array_sel_pixels)[np.argsort(np.array(gdac_values))][gdac_best_idx] + self.occ_array_desel_pixels_best = np.array(gdac_occ_array_sel_pixels)[np.argsort(np.array(gdac_values))][gdac_best_idx] self.gdac_best = self.register_utils.get_gdac() - if abs(median_occupancy - self.n_injections_gdac / 2) > self.max_delta_threshold: + if abs(median_occupancy - self.n_injections_gdac / 2) > self.max_delta_threshold and not self.stop_run.is_set(): if np.all((((self.gdac_best & (1 << np.arange(self.register.global_registers['Vthin_AltFine']['bitlength'] + self.register.global_registers['Vthin_AltFine']['bitlength'])))) > 0).astype(int)[self.gdac_tune_bits] == 1): if self.fail_on_warning: raise RuntimeWarning('Selected GDAC bits reached maximum value') @@ -233,7 +251,7 @@ def bits_set(int_type): logging.warning('Selected GDAC bits reached minimum value') else: if self.fail_on_warning: - raise RuntimeWarning('Global threshold tuning failed. Delta threshold = %.2f > %.2f. Vthin_AltCoarse / Vthin_AltFine = %d / %d' %(abs(median_occupancy - self.n_injections_gdac / 2), self.max_delta_threshold, self.register.get_global_register_value("Vthin_AltCoarse"), self.register.get_global_register_value("Vthin_AltFine"))) + raise RuntimeWarning('Global threshold tuning failed. Delta threshold = %.2f > %.2f. Vthin_AltCoarse / Vthin_AltFine = %d / %d' % (abs(median_occupancy - self.n_injections_gdac / 2), self.max_delta_threshold, self.register.get_global_register_value("Vthin_AltCoarse"), self.register.get_global_register_value("Vthin_AltFine"))) else: logging.warning('Global threshold tuning failed. Delta threshold = %.2f > %.2f. Vthin_AltCoarse / Vthin_AltFine = %d / %d', abs(median_occupancy - self.n_injections_gdac / 2), self.max_delta_threshold, self.register.get_global_register_value("Vthin_AltCoarse"), self.register.get_global_register_value("Vthin_AltFine")) else: @@ -243,9 +261,8 @@ def analyze(self): # set here because original value is restored after scan() self.register_utils.set_gdac(self.gdac_best, send_command=False) - plot_three_way(self.occ_array_sel_pixels_best.transpose(), title="Occupancy after GDAC tuning of selected pixels (GDAC " + str(self.scan_parameters.GDAC) + ")", x_axis_title='Occupancy', filename=self.plots_filename, maximum=self.n_injections_gdac) - - plot_three_way(self.occ_array_desel_pixels_best.transpose(), title="Occupancy after GDAC tuning of not selected pixels (GDAC " + str(self.scan_parameters.GDAC) + ")", x_axis_title='Occupancy', filename=self.plots_filename, maximum=self.n_injections_gdac) + plot_three_way(self.occ_array_sel_pixels_best.transpose(), title="Occupancy after GDAC tuning of selected pixels (GDAC " + str(self.gdac_best) + ")", x_axis_title='Occupancy', filename=self.plots_filename, maximum=self.n_injections_gdac) + plot_three_way(self.occ_array_desel_pixels_best.transpose(), title="Occupancy after GDAC tuning of not selected pixels (GDAC " + str(self.gdac_best) + ")", x_axis_title='Occupancy', filename=self.plots_filename, maximum=self.n_injections_gdac) if self.close_plots: self.plots_filename.close() diff --git a/pybar/scans/tune_gdac_standard.py b/pybar/scans/tune_gdac_standard.py index a194dbbda..82837a8a0 100644 --- a/pybar/scans/tune_gdac_standard.py +++ b/pybar/scans/tune_gdac_standard.py @@ -6,7 +6,7 @@ from pybar.fei4_run_base import Fei4RunBase from pybar.fei4.register_utils import scan_loop, make_pixel_mask from pybar.run_manager import RunManager -from pybar.daq.readout_utils import convert_data_array, is_data_record, is_fe_word, logical_and, data_array_from_data_iterable, get_col_row_array_from_data_record_array +from pybar.daq.readout_utils import convert_data_array, is_data_record, logical_and, data_array_from_data_iterable, get_col_row_array_from_data_record_array from pybar.analysis.plotting.plotting import plot_three_way @@ -20,6 +20,8 @@ class GdacTuningStandard(Fei4RunBase): Use pybar.scans.tune_fei4 for full FE-I4 tuning. ''' _default_run_conf = { + "broadcast_commands": False, + "threaded_scan": False, "scan_parameters": [('GDAC', [255, 40])], "step_size": -1, # step size of the GDAC during scan "target_threshold": 30, # target threshold in PlsrDAC to tune to @@ -27,7 +29,6 @@ class GdacTuningStandard(Fei4RunBase): "max_delta_threshold": 5, # minimum difference to the target_threshold to abort the tuning "enable_mask_steps_gdac": [0], # mask steps to do per GDAC setting "plot_intermediate_steps": False, # plot intermediate steps (takes time) - "plots_filename": None, # file name to store the plot to, if None show on screen "enable_shift_masks": ["Enable", "C_High", "C_Low"], # enable masks shifted during scan "disable_shift_masks": [], # disable masks shifted during scan "pulser_dac_correction": False, # PlsrDAC correction for each double column @@ -56,13 +57,10 @@ def configure(self): commands.extend(self.register.get_commands("RunMode")) self.register_utils.send_commands(commands) - def scan(self): - if not self.plots_filename: - self.plots_filename = PdfPages(self.output_filename + '.pdf') - self.close_plots = True - else: - self.close_plots = False + self.plots_filename = PdfPages(self.output_filename + '.pdf') + self.close_plots = True + def scan(self): cal_lvl1_command = self.register.get_commands("CAL")[0] + self.register.get_commands("zeros", length=40)[0] + self.register.get_commands("LV1")[0] self.write_target_threshold() @@ -98,12 +96,14 @@ def bits_set(int_type): logging.info('Deselect double column %d' % column) select_mask_array[column, :] = 0 - occupancy_best = 0.0 - median_occupancy_last_step = 0.0 - gdac_best = self.register_utils.get_gdac() - for gdac_scan_step, scan_parameter_value in enumerate(scan_parameter_range): + gdac_values = [] + gdac_occupancy = [] + gdac_occ_array_sel_pixels = [] + gdac_occ_array_desel_pixels = [] + median_occupancy_last_step = None + for scan_parameter_value in scan_parameter_range: self.register_utils.set_gdac(scan_parameter_value) - with self.readout(GDAC=scan_parameter_value, reset_sram_fifo=True, fill_buffer=True, clear_buffer=True, callback=self.handle_data): + with self.readout(GDAC=scan_parameter_value, fill_buffer=True): scan_loop(self, command=cal_lvl1_command, repeat_command=self.n_injections_gdac, @@ -119,34 +119,51 @@ def bits_set(int_type): mask=None, double_column_correction=self.pulser_dac_correction) - occupancy_array, _, _ = np.histogram2d(*convert_data_array(data_array_from_data_iterable(self.fifo_readout.data), filter_func=logical_and(is_fe_word, is_data_record), converter_func=get_col_row_array_from_data_record_array), bins=(80, 336), range=[[1, 80], [1, 336]]) + data = convert_data_array(array=self.read_data(), filter_func=is_data_record, converter_func=get_col_row_array_from_data_record_array) + occupancy_array, _, _ = np.histogram2d(*data, bins=(80, 336), range=[[1, 80], [1, 336]]) occ_array_sel_pixels = np.ma.array(occupancy_array, mask=np.logical_not(np.ma.make_mask(select_mask_array))) # take only selected pixel into account by using the mask occ_array_desel_pixels = np.ma.array(occupancy_array, mask=np.ma.make_mask(select_mask_array)) # take only de-selected pixel into account by using the inverted mask median_occupancy = np.ma.median(occ_array_sel_pixels) noise_occupancy = np.ma.median(occ_array_desel_pixels) occupancy_almost_zero = np.allclose(median_occupancy, 0) no_noise = np.allclose(noise_occupancy, 0) - if no_noise and not occupancy_almost_zero and abs(median_occupancy - self.n_injections_gdac / 2) < abs(occupancy_best - self.n_injections_gdac / 2): - occupancy_best = median_occupancy - gdac_best = self.register_utils.get_gdac() - self.occ_array_sel_pixels_best = occ_array_sel_pixels.copy() - self.occ_array_desel_pixels_best = occ_array_desel_pixels.copy() + gdac_values.append(self.register_utils.get_gdac()) + gdac_occupancy.append(median_occupancy) + gdac_occ_array_sel_pixels.append(occ_array_sel_pixels.copy()) + gdac_occ_array_desel_pixels.append(occ_array_desel_pixels.copy()) + self.occ_array_sel_pixels_best = occ_array_sel_pixels.copy() + self.occ_array_desel_pixels_best = occ_array_desel_pixels.copy() if self.plot_intermediate_steps: plot_three_way(self.occ_array_sel_pixel.transpose(), title="Occupancy (GDAC " + str(scan_parameter_value) + ")", x_axis_title='Occupancy', filename=self.plots_filename, maximum=self.n_injections_gdac) - if no_noise and not occupancy_almost_zero and median_occupancy >= median_occupancy_last_step and median_occupancy >= self.n_injections_gdac / 2: + # abort early if threshold is found + if no_noise and not occupancy_almost_zero and (median_occupancy_last_step is not None and median_occupancy >= median_occupancy_last_step) and median_occupancy >= self.n_injections_gdac / 2: break + if no_noise and not occupancy_almost_zero: median_occupancy_last_step = median_occupancy else: median_occupancy_last_step = 0.0 - self.register_utils.set_gdac(gdac_best, send_command=False) + # select best GDAC value + occupancy_sorted = np.array(gdac_occupancy)[np.argsort(np.array(gdac_values))] + gdac_sorted = np.sort(gdac_values) + gdac_min_idx = np.where(occupancy_sorted >= self.n_injections_gdac / 2)[0][-1] + occupancy_sorted_sel = occupancy_sorted[gdac_min_idx:] + gdac_sorted_sel = gdac_sorted[gdac_min_idx:] + gdac_best_idx = np.abs(np.array(occupancy_sorted_sel) - self.n_injections_gdac / 2).argmin() + gdac_best = gdac_sorted_sel[gdac_best_idx] + occupancy_best = occupancy_sorted_sel[gdac_best_idx] median_occupancy = occupancy_best + self.register_utils.set_gdac(gdac_best, send_command=False) + # for plotting + self.occ_array_sel_pixels_best = np.array(gdac_occ_array_sel_pixels)[np.argsort(np.array(gdac_values))][gdac_best_idx] + self.occ_array_desel_pixels_best = np.array(gdac_occ_array_sel_pixels)[np.argsort(np.array(gdac_values))][gdac_best_idx] + self.gdac_best = self.register_utils.get_gdac() - if abs(median_occupancy - self.n_injections_gdac / 2) > self.max_delta_threshold: + if abs(median_occupancy - self.n_injections_gdac / 2) > self.max_delta_threshold and not self.stop_run.is_set(): if np.all((((self.gdac_best & (1 << np.arange(self.register.global_registers['Vthin_AltFine']['bitlength'] + self.register.global_registers['Vthin_AltFine']['bitlength'])))) > 0).astype(int) == 0): if self.fail_on_warning: raise RuntimeWarning('Selected GDAC bits reached minimum value') @@ -154,7 +171,7 @@ def bits_set(int_type): logging.warning('Selected GDAC bits reached minimum value') else: if self.fail_on_warning: - raise RuntimeWarning('Global threshold tuning failed. Delta threshold = %.2f > %.2f. Vthin_AltCoarse / Vthin_AltFine = %d / %d' %(abs(median_occupancy - self.n_injections_gdac / 2), self.max_delta_threshold, self.register.get_global_register_value("Vthin_AltCoarse"), self.register.get_global_register_value("Vthin_AltFine"))) + raise RuntimeWarning('Global threshold tuning failed. Delta threshold = %.2f > %.2f. Vthin_AltCoarse / Vthin_AltFine = %d / %d' % (abs(median_occupancy - self.n_injections_gdac / 2), self.max_delta_threshold, self.register.get_global_register_value("Vthin_AltCoarse"), self.register.get_global_register_value("Vthin_AltFine"))) else: logging.warning('Global threshold tuning failed. Delta threshold = %.2f > %.2f. Vthin_AltCoarse / Vthin_AltFine = %d / %d', abs(median_occupancy - self.n_injections_gdac / 2), self.max_delta_threshold, self.register.get_global_register_value("Vthin_AltCoarse"), self.register.get_global_register_value("Vthin_AltFine")) else: @@ -164,9 +181,9 @@ def analyze(self): # set here because original value is restored after scan() self.register_utils.set_gdac(self.gdac_best, send_command=False) - plot_three_way(self.occ_array_sel_pixels_best.transpose(), title="Occupancy after GDAC tuning of selected pixels (GDAC " + str(self.scan_parameters.GDAC) + ")", x_axis_title='Occupancy', filename=self.plots_filename, maximum=self.n_injections_gdac) + plot_three_way(self.occ_array_sel_pixels_best.transpose(), title="Occupancy after GDAC tuning of selected pixels (GDAC " + str(self.gdac_best) + ")", x_axis_title='Occupancy', filename=self.plots_filename, maximum=self.n_injections_gdac) - plot_three_way(self.occ_array_desel_pixels_best.transpose(), title="Occupancy after GDAC tuning of not selected pixels (GDAC " + str(self.scan_parameters.GDAC) + ")", x_axis_title='Occupancy', filename=self.plots_filename, maximum=self.n_injections_gdac) + plot_three_way(self.occ_array_desel_pixels_best.transpose(), title="Occupancy after GDAC tuning of not selected pixels (GDAC " + str(self.gdac_best) + ")", x_axis_title='Occupancy', filename=self.plots_filename, maximum=self.n_injections_gdac) if self.close_plots: self.plots_filename.close() diff --git a/pybar/scans/tune_hot_pixels.py b/pybar/scans/tune_hot_pixels.py index 5f15a3dd0..cd108ef25 100644 --- a/pybar/scans/tune_hot_pixels.py +++ b/pybar/scans/tune_hot_pixels.py @@ -2,19 +2,21 @@ import numpy as np -from pybar.scans.scan_fei4_self_trigger import FEI4SelfTriggerScan +from pybar.scans.scan_fei4_self_trigger import Fei4SelfTriggerScan from pybar.analysis.analyze_raw_data import AnalyzeRawData from pybar.fei4.register_utils import invert_pixel_mask from pybar.run_manager import RunManager from pybar.analysis.plotting.plotting import plot_occupancy, plot_fancy_occupancy -class HotPixelTuning(FEI4SelfTriggerScan): +class HotPixelTuning(Fei4SelfTriggerScan): '''FE-I4 hot pixels tuning Masking hot pixels based on FEI4 self-trigger scan. ''' _default_run_conf = { + "broadcast_commands": False, + "threaded_scan": False, "trig_count": 4, # FE-I4 trigger count, number of consecutive BCs, 0 means 16, from 0 to 15 "trigger_latency": 239, # FE-I4 trigger latency, in BCs, external scintillator / TLU / HitOR: 232, USBpix self-trigger: 220, from 0 to 255 "col_span": [1, 80], # defining active column interval, 2-tuple, from 1 to 80 diff --git a/pybar/scans/tune_merged_pixels.py b/pybar/scans/tune_merged_pixels.py index 8a8d9dc78..4f32bb0c6 100644 --- a/pybar/scans/tune_merged_pixels.py +++ b/pybar/scans/tune_merged_pixels.py @@ -68,5 +68,6 @@ def analyze(self): mask_name = self.register.pixel_registers[mask]['name'] plot_occupancy(self.register.get_pixel_register_value(mask).T, title='%s Mask' % mask_name, z_max=1, filename=analyze_raw_data.output_pdf) + if __name__ == "__main__": RunManager('../configuration.yaml').run_run(MergedPixelsTuning) diff --git a/pybar/scans/tune_noise_occupancy.py b/pybar/scans/tune_noise_occupancy.py index 9b3bea2ea..9e5c4b717 100644 --- a/pybar/scans/tune_noise_occupancy.py +++ b/pybar/scans/tune_noise_occupancy.py @@ -21,6 +21,8 @@ class NoiseOccupancyTuning(Fei4RunBase): To achieve a broader TDAC distribution it is necessary to decrease TdacVbp. ''' _default_run_conf = { + "broadcast_commands": True, + "threaded_scan": False, "occupancy_limit": 1 * 10 ** (-5), # the lower the number the higher the constraints on noise occupancy; 0 will mask any pixel with occupancy greater than zero "n_triggers": 10000000, # total number of triggers which will be sent to the FE. From 1 to 4294967295 (32-bit unsigned int). "trig_count": 1, # FE-I4 trigger count, number of consecutive BCs, 0 means 16, from 0 to 15 @@ -81,7 +83,7 @@ def scan(self): self.total_scan_time = int(lvl1_command.length() * 25 * (10 ** -9) * self.n_triggers) logging.info('Estimated scan time: %ds', self.total_scan_time) - with self.readout(reset_sram_fifo=False, clear_buffer=True, callback=self.handle_data, errback=self.handle_err, no_data_timeout=self.no_data_timeout): + with self.readout(no_data_timeout=self.no_data_timeout): got_data = False start = time() self.register_utils.send_command(lvl1_command, repeat=self.n_triggers, wait_for_finish=False, set_length=True, clear_memory=False) @@ -91,7 +93,7 @@ def scan(self): self.progressbar.finish() self.stop('Finished sending %d triggers' % self.n_triggers) if not got_data: - if self.fifo_readout.data_words_per_second() > 0: + if self.data_words_per_second() > 0: got_data = True logging.info('Taking data...') self.progressbar = progressbar.ProgressBar(widgets=['', progressbar.Percentage(), ' ', progressbar.Bar(marker='*', left='|', right='|'), ' ', progressbar.Timer()], maxval=self.total_scan_time, poll=10, term_width=80).start() @@ -141,5 +143,6 @@ def analyze(self): mask_name = self.register.pixel_registers[mask]['name'] plot_occupancy(self.register.get_pixel_register_value(mask).T, title='%s Mask' % mask_name, z_max=1, filename=analyze_raw_data.output_pdf) + if __name__ == "__main__": RunManager('../configuration.yaml').run_run(NoiseOccupancyTuning) diff --git a/pybar/scans/tune_stuck_pixel.py b/pybar/scans/tune_stuck_pixel.py index a28ac083b..d10d5011c 100644 --- a/pybar/scans/tune_stuck_pixel.py +++ b/pybar/scans/tune_stuck_pixel.py @@ -13,6 +13,8 @@ class StuckPixelScan(DigitalScan): '''Stuck pixel scan to detect and disable stuck pixels (Hitbus/HitOR always high). ''' _default_run_conf = { + "broadcast_commands": False, + "threaded_scan": False, "mask_steps": 3, # mask steps "n_injections": 100, # number of injections "use_enable_mask": False, # if True, use Enable mask during scan, if False, all pixels will be enabled @@ -42,30 +44,28 @@ def analyze(self): analyze_raw_data.interpreter.print_summary() occ_hist = analyze_raw_data.out_file_h5.root.HistOcc[:, :, 0].T - self.occ_mask = np.zeros(shape=occ_hist.shape, dtype=np.dtype('>u1')) + occ_mask = np.zeros(shape=occ_hist.shape, dtype=np.dtype('>u1')) # noisy pixels are set to 1 - self.occ_mask[occ_hist < self.n_injections] = 1 + occ_mask[occ_hist < self.n_injections] = 1 # make inverse - self.inv_occ_mask = invert_pixel_mask(self.occ_mask) - self.disable_for_mask = self.disable_for_mask + inv_occ_mask = invert_pixel_mask(occ_mask) if self.overwrite_mask: for mask in self.disable_for_mask: - self.register.set_pixel_register_value(mask, self.inv_occ_mask) + self.register.set_pixel_register_value(mask, inv_occ_mask) else: for mask in self.disable_for_mask: - enable_mask = np.logical_and(self.inv_occ_mask, self.register.get_pixel_register_value(mask)) + enable_mask = np.logical_and(inv_occ_mask, self.register.get_pixel_register_value(mask)) self.register.set_pixel_register_value(mask, enable_mask) - self.enable_for_mask = self.enable_for_mask if self.overwrite_mask: for mask in self.enable_for_mask: - self.register.set_pixel_register_value(mask, self.occ_mask) + self.register.set_pixel_register_value(mask, occ_mask) else: for mask in self.enable_for_mask: - disable_mask = np.logical_or(self.occ_mask, self.register.get_pixel_register_value(mask)) + disable_mask = np.logical_or(occ_mask, self.register.get_pixel_register_value(mask)) self.register.set_pixel_register_value(mask, disable_mask) - plot_occupancy(self.occ_mask.T, title='Stuck Pixels', z_max=1, filename=analyze_raw_data.output_pdf) + plot_occupancy(occ_mask.T, title='Stuck Pixels', z_max=1, filename=analyze_raw_data.output_pdf) for mask in self.disable_for_mask: mask_name = self.register.pixel_registers[mask]['name'] plot_occupancy(self.register.get_pixel_register_value(mask).T, title='%s Mask' % mask_name, z_max=1, filename=analyze_raw_data.output_pdf) diff --git a/pybar/scans/tune_tdac.py b/pybar/scans/tune_tdac.py index b7149f2d3..3c86dfbcc 100644 --- a/pybar/scans/tune_tdac.py +++ b/pybar/scans/tune_tdac.py @@ -6,7 +6,7 @@ from pybar.fei4_run_base import Fei4RunBase from pybar.fei4.register_utils import scan_loop from pybar.run_manager import RunManager -from pybar.daq.readout_utils import convert_data_array, is_data_record, is_fe_word, logical_and, data_array_from_data_iterable, get_col_row_array_from_data_record_array +from pybar.daq.readout_utils import convert_data_array, is_data_record, logical_and, data_array_from_data_iterable, get_col_row_array_from_data_record_array from pybar.analysis.plotting.plotting import plot_three_way @@ -20,12 +20,13 @@ class TdacTuning(Fei4RunBase): Use pybar.scans.tune_fei4 for full FE-I4 tuning. ''' _default_run_conf = { + "broadcast_commands": False, + "threaded_scan": False, "scan_parameters": [('TDAC', None)], "target_threshold": 30, "tdac_tune_bits": range(4, -1, -1), "n_injections_tdac": 100, "plot_intermediate_steps": False, - "plots_filename": None, "enable_shift_masks": ["Enable", "C_High", "C_Low"], # enable masks shifted during scan "disable_shift_masks": [], # disable masks shifted during scan "pulser_dac_correction": False, # PlsrDAC correction for each double column @@ -53,13 +54,10 @@ def configure(self): commands.extend(self.register.get_commands("RunMode")) self.register_utils.send_commands(commands) - def scan(self): - if not self.plots_filename: - self.plots_filename = PdfPages(self.output_filename + '.pdf') - self.close_plots = True - else: - self.close_plots = False + self.plots_filename = PdfPages(self.output_filename + '.pdf') + self.close_plots = True + def scan(self): enable_mask_steps = [] cal_lvl1_command = self.register.get_commands("CAL")[0] + self.register.get_commands("zeros", length=40)[0] + self.register.get_commands("LV1")[0] @@ -73,6 +71,8 @@ def scan(self): self.tdac_mask_best = self.register.get_pixel_register_value("TDAC") tdac_tune_bits = self.tdac_tune_bits[:] for scan_parameter_value, tdac_bit in enumerate(tdac_tune_bits): + if self.stop_run.is_set(): + break if additional_scan: self.set_tdac_bit(tdac_bit) logging.info('TDAC setting: bit %d = 1', tdac_bit) @@ -82,7 +82,7 @@ def scan(self): self.write_tdac_config() - with self.readout(TDAC=scan_parameter_value, reset_sram_fifo=True, fill_buffer=True, clear_buffer=True, callback=self.handle_data): + with self.readout(TDAC=scan_parameter_value, fill_buffer=True): scan_loop(self, command=cal_lvl1_command, repeat_command=self.n_injections_tdac, @@ -98,7 +98,8 @@ def scan(self): mask=None, double_column_correction=self.pulser_dac_correction) - occupancy_array, _, _ = np.histogram2d(*convert_data_array(data_array_from_data_iterable(self.fifo_readout.data), filter_func=logical_and(is_fe_word, is_data_record), converter_func=get_col_row_array_from_data_record_array), bins=(80, 336), range=[[1, 80], [1, 336]]) + data = convert_data_array(array=self.read_data(), filter_func=is_data_record, converter_func=get_col_row_array_from_data_record_array) + occupancy_array, _, _ = np.histogram2d(*data, bins=(80, 336), range=[[1, 80], [1, 336]]) select_better_pixel_mask = abs(occupancy_array - self.n_injections_tdac / 2) <= abs(self.occupancy_best - self.n_injections_tdac / 2) pixel_with_too_high_occupancy_mask = occupancy_array > self.n_injections_tdac / 2 self.occupancy_best[select_better_pixel_mask] = occupancy_array[select_better_pixel_mask] @@ -134,7 +135,8 @@ def scan(self): # cal_lvl1_command = self.register.get_commands("CAL")[0] + self.register.get_commands("zeros", length=40)[0] + self.register.get_commands("LV1")[0] + self.register.get_commands("zeros", mask_steps=mask_steps)[0] # self.scan_loop(cal_lvl1_command, repeat_command=self.n_injections_tdac, mask_steps=mask_steps, enable_mask_steps=enable_mask_steps, enable_double_columns=None, same_mask_for_all_dc=True, eol_function=None, digital_injection=False, enable_shift_masks=["Enable", "C_High", "C_Low"], restore_shift_masks=True, mask=None) # self.readout.stop() -# occupancy_array, _, _ = np.histogram2d(*convert_data_array(data_array_from_data_dict_iterable(self.fifo_readout.data), filter_func=is_data_record, converter_func=get_col_row_array_from_data_record_array), bins=(80, 336), range=[[1, 80], [1, 336]]) +# data = convert_data_array(array=self.read_data(), filter_func=is_data_record, converter_func=get_col_row_array_from_data_record_array) +# occupancy_array, _, _ = np.histogram2d(*data, bins=(80, 336), range=[[1, 80], [1, 336]]) # plot_three_way(hist=occupancy_array.transpose(), title="Occupancy check", x_axis_title="Occupancy", filename=plots_filename, maximum = self.n_injections_tdac) # plot_three_way(hist=self.register.get_pixel_register_value("TDAC").transpose(), title="TDAC check distribution after tuning", x_axis_title="TDAC", filename=plots_filename, maximum = 32) @@ -172,5 +174,6 @@ def write_tdac_config(self): commands.extend(self.register.get_commands("WrFrontEnd", same_mask_for_all_dc=False, name=["TDAC"])) self.register_utils.send_commands(commands) + if __name__ == "__main__": RunManager('../configuration.yaml').run_run(TdacTuning) diff --git a/pybar/scans/tune_threshold_baseline.py b/pybar/scans/tune_threshold_baseline.py index f2b25cecf..b362de423 100644 --- a/pybar/scans/tune_threshold_baseline.py +++ b/pybar/scans/tune_threshold_baseline.py @@ -1,10 +1,11 @@ import logging from time import time -import numpy as np -import progressbar from collections import deque -from pybar.daq.readout_utils import get_col_row_array_from_data_record_array, convert_data_array, data_array_from_data_iterable, is_fe_word, is_data_record, logical_and +import progressbar +import numpy as np + +from pybar.daq.readout_utils import get_col_row_array_from_data_record_array, convert_data_array, data_array_from_data_iterable, is_data_record, logical_and # from pybar.daq.readout_utils import data_array_from_data_iterable # from pybar_fei4_interpreter.data_interpreter import PyDataInterpreter # from pybar_fei4_interpreter.data_histograming import PyDataHistograming @@ -23,6 +24,8 @@ class ThresholdBaselineTuning(Fei4RunBase): NOTE: To increase the TDAC range, decrease TdacVbp. ''' _default_run_conf = { + "broadcast_commands": False, + "threaded_scan": False, "occupancy_limit": 1 * 10 ** (-5), # occupancy limit, when reached the TDAC will be decreased (increasing threshold). 0 will mask any pixel with occupancy greater than zero "scan_parameters": [('Vthin_AltFine', (120, None)), ('TDAC_step', None), ('relaxation', 0)], # the Vthin_AltFine range, number of steps (repetition at constant Vthin_AltFine) "increase_threshold": 5, # increasing the global threshold (Vthin_AltFine) after tuning @@ -133,7 +136,7 @@ def scan(self): logging.info('TDAC step %d at Vthin_AltFine %d', tdac_step, reg_val) # logging.info('Estimated scan time: %ds', total_scan_time) - with self.readout(Vthin_AltFine=reg_val, TDAC_step=tdac_step, relaxation=relaxation, reset_sram_fifo=True, fill_buffer=True, clear_buffer=True, callback=self.handle_data): + with self.readout(Vthin_AltFine=reg_val, TDAC_step=tdac_step, relaxation=relaxation, fill_buffer=True): got_data = False start = time() self.register_utils.send_command(lvl1_command, repeat=self.n_triggers, wait_for_finish=False, set_length=True, clear_memory=False) @@ -144,7 +147,7 @@ def scan(self): logging.info('Finished sending %d triggers', self.n_triggers) break if not got_data: - if self.fifo_readout.data_words_per_second() > 0: + if self.data_words_per_second() > 0: got_data = True logging.info('Taking data...') self.progressbar = progressbar.ProgressBar(widgets=['', progressbar.Percentage(), ' ', progressbar.Bar(marker='*', left='|', right='|'), ' ', progressbar.Timer()], maxval=total_scan_time, poll=10, term_width=80).start() @@ -154,7 +157,7 @@ def scan(self): except ValueError: pass # use Numpy for analysis and histogramming - col_arr, row_arr = convert_data_array(data_array_from_data_iterable(self.fifo_readout.data), filter_func=logical_and(is_fe_word, is_data_record), converter_func=get_col_row_array_from_data_record_array) + col_arr, row_arr = convert_data_array(array=self.read_data(), filter_func=is_data_record, converter_func=get_col_row_array_from_data_record_array) occ_hist, _, _ = np.histogram2d(col_arr, row_arr, bins=(80, 336), range=[[1, 80], [1, 336]]) occ_mask = np.zeros(shape=occ_hist.shape, dtype=np.dtype('>u1')) diff --git a/pybar/scans/tune_tlu.py b/pybar/scans/tune_tlu.py index ad0cece89..6d65701e0 100644 --- a/pybar/scans/tune_tlu.py +++ b/pybar/scans/tune_tlu.py @@ -21,6 +21,8 @@ class TluTuning(Fei4RunBase): The TLU has to be started with internal trigger generation (TLUControl -t 1). ''' _default_run_conf = { + "broadcast_commands": True, + "threaded_scan": False, "scan_parameters": [('TRIGGER_DATA_DELAY', range(0, 2**4))], # TRIGGER_DATA_DELAY has 4-bit "sleep": 2 # Time to record the trigger words per delay setting in seconds } @@ -37,10 +39,8 @@ def scan(self): with self.readout(TRIGGER_DATA_DELAY=value): self.dut['TLU']['TRIGGER_ENABLE'] = True -# self.dut['CMD']['EN_EXT_TRIGGER'] = True time.sleep(self.sleep) self.dut['TLU']['TRIGGER_ENABLE'] = False -# self.dut['CMD']['EN_EXT_TRIGGER'] = False if self.dut['TLU']['TRIGGER_COUNTER'] == 0: raise RuntimeError('No triggers collected. Check if TLU is on and the IO is set correctly.') @@ -101,5 +101,6 @@ def analyze(self): plt.legend(loc=0) output_pdf.savefig() + if __name__ == "__main__": RunManager('../configuration.yaml').run_run(TluTuning) diff --git a/pybar/testing/test_analysis.py b/pybar/testing/test_analysis.py index 5a183e462..102afc1eb 100644 --- a/pybar/testing/test_analysis.py +++ b/pybar/testing/test_analysis.py @@ -4,12 +4,11 @@ import os import zlib +import progressbar import tables as tb import numpy as np from numpy.testing import assert_array_equal -import progressbar - from pixel_clusterizer.clusterizer import HitClusterizer from pybar_fei4_interpreter.data_interpreter import PyDataInterpreter @@ -119,7 +118,7 @@ def tearDownClass(cls): # remove created files os.remove(os.path.join(tests_data_folder, 'ext_trigger_scan_tlu_interpreted.h5')) def test_libraries_stability(self): # calls 50 times the constructor and destructor to check the libraries - progress_bar = progressbar.ProgressBar(widgets=['', progressbar.Percentage(), ' ', progressbar.Bar(marker='*', left='|', right='|'), ' ', progressbar.ETA()], maxval=50, term_width=80) + progress_bar = progressbar.ProgressBar(widgets=['', progressbar.Percentage(), ' ', progressbar.Bar(marker='*', left='|', right='|'), ' ', progressbar.AdaptiveETA()], maxval=50, term_width=80) progress_bar.start() for i in range(50): interpreter = PyDataInterpreter() diff --git a/pybar/testing/test_interface.py b/pybar/testing/test_interface.py index 8b2197ee6..365102a3b 100644 --- a/pybar/testing/test_interface.py +++ b/pybar/testing/test_interface.py @@ -1,6 +1,8 @@ ''' Script to check the readout system interface (software + FPGA firmware). A global register test is performed with pyBAR and a simulation of the FPGA + FE-I4. ''' + +import logging import unittest import shutil import mock @@ -8,7 +10,6 @@ import subprocess import time import os -import logging from pybar.run_manager import RunManager from pybar.scans.test_register import RegisterTest diff --git a/pybar/testing/test_interface_data/configuration.yaml b/pybar/testing/test_interface_data/configuration.yaml index 5746b2d5d..af9cc9c80 100644 --- a/pybar/testing/test_interface_data/configuration.yaml +++ b/pybar/testing/test_interface_data/configuration.yaml @@ -1,35 +1,18 @@ -working_dir : # Module data will be written to this path. If not given, use path of this file. Default: not given / empty +dut : dut_mio_sim.yaml +dut_configuration : "" +working_dir : -dut : dut_mio_sim.yaml # DUT hardware configuration (.yaml). Change to dut_mio_gpac.yaml for GPAC support. -dut_configuration : # DUT init configuration (.yaml). Change to dut_configuration_mio_gpac.yaml for GPAC support. - -fe_configuration : # FE configuration file, text (.cfg) or HDF5 (.h5) file. If not given, latest valid configuration (run status FINISHED) will be taken. If a number is given, configuration from run with specified number will be taken. -fe_flavor : fei4a # FEI4 flavor/type for initial configuration. Valid values: 'fei4a' or 'fei4b' -chip_address : # Chip Address for initial configuration, if not given, broadcast bit will be set -module_id : module_test # module identifier / name, sub-folder with given name will be created inside working_dir - -# *** global run configuration *** -# -#run_conf: -# send_data : 'tcp://127.0.0.1:5678' -# comment : '' -# reset_rx_on_error : False -# -# *** scan specific run configuration *** -# -#Fei4Tuning: -# enable_shift_masks : ["Enable", "C_Low", "C_High"] -# target_threshold : 50 # target threshold -# target_charge : 280 # target charge -# target_tot : 5 # target ToT -# global_iterations : 4 -# local_iterations : 3 -# -#AnalogScan: -# scan_parameters : {'PlsrDAC': 280} -# enable_shift_masks : ["Enable", "C_Low", "C_High"] -# -#ThresholdScan: -# scan_parameters : {'PlsrDAC': [0, 100]} -# enable_shift_masks : ["Enable", "C_Low", "C_High"] -# +modules : + module_0 : + activate : True + configuration : # FE configuration file, text (.cfg) or HDF5 (.h5) file. If no value is given, the latest valid configuration (run status 'FINISHED') will be taken. If a number is given, the configuration from the run with the specified number will be taken. + flavor : fei4a # FEI4 flavor/type for initial configuration. Valid values are: 'fei4a', 'fei4b'. + chip_address : 0 # Chip Address for initial configuration. if no value is given, the broadcast bit will be set. + FIFO : SRAM_FIFO # As implemented in the firmware. + RX : DATA_CH4 # As implemented in the firmware. + rx_channel : 4 # As implemented in the firmware. + TX : CMD_CH1_TO_CH4 # As implemented in the firmware. + tx_channel : 0 # As implemented in the firmware. + TDC: TDC_RX2 # As implemented in the firmware. + tdc_channel : 4 # As implemented in the firmware. + TLU : TRIGGER_CH1_TO_CH4 # As implemented in the firmware. diff --git a/pybar/testing/test_interface_data/dut_mio_sim.yaml b/pybar/testing/test_interface_data/dut_mio_sim.yaml index 4860dc20e..ba6dc70d9 100644 --- a/pybar/testing/test_interface_data/dut_mio_sim.yaml +++ b/pybar/testing/test_interface_data/dut_mio_sim.yaml @@ -5,7 +5,8 @@ version : 2.0.0 transfer_layer: - name : USB type : SiSim - timeout : 180 + init : + timeout : 180 # Example of additional lab device transfer layers to be used with pyBAR # - name : Visa @@ -20,23 +21,22 @@ hw_drivers: # interface : USB # base_addr : 0x0 - - name : CH4 + - name : DATA_CH4 type : fei4_rx interface : USB base_addr : 0x18300 -# Uncomment for FEI4QuadModuleAdapterCard - - name : CH3 + - name : DATA_CH3 type : fei4_rx interface : USB base_addr : 0x18400 - - - name : CH2 + + - name : DATA_CH2 type : fei4_rx interface : USB base_addr : 0x18500 - - - name : CH1 + + - name : DATA_CH1 type : fei4_rx interface : USB base_addr : 0x18600 @@ -58,23 +58,23 @@ hw_drivers: # init : # device : Agilent 33250a - - name : CMD + - name : CMD_CH1_TO_CH4 type : cmd_seq interface : USB base_addr : 0x10000 - - name : SRAM + - name : SRAM_FIFO type : sram_fifo interface : USB base_addr : 0x18100 base_data_addr : 0x0001000000000000 - - name : TLU + - name : TRIGGER_CH1_TO_CH4 type : tlu interface : USB base_addr : 0x18200 - - name : TDC + - name : TDC_RX2 type : tdc_s3 interface : USB base_addr : 0x18700 @@ -89,8 +89,6 @@ hw_drivers: interface : USB base_addr : 0x18900 -user_drivers: - registers: - name : ENABLE_CHANNEL type : StdRegister @@ -103,16 +101,16 @@ registers: - name : TLU size : 1 offset : 4 - - name : CH4 + - name : DATA_CH4 size : 1 offset : 3 - - name : CH3 + - name : DATA_CH3 size : 1 offset : 2 - - name : CH2 + - name : DATA_CH2 size : 1 offset : 1 - - name : CH1 + - name : DATA_CH1 size : 1 offset : 0 diff --git a/pybar/testing/test_scans.py b/pybar/testing/test_scans.py deleted file mode 100644 index 539f3b60a..000000000 --- a/pybar/testing/test_scans.py +++ /dev/null @@ -1,217 +0,0 @@ -''' This script checks reliablibility of the readout system. -A fully functional FE-I4 needs to be attched to the hardware and powered (any sensor needs to be depleted). -Otherwise the result is biased by FE-I4. If these testing pass there is a high propability that the hardware -of readout system and the FE-I4 works fine. The testing take about 10 min. - -Note: -Please change the FE-I4 flavor (fe_flavor) according to your FE-I4 inside the testing/test_scans/configuration.yaml file. -''' - -import unittest -import os -import fnmatch -import shutil -import tables as tb -import numpy as np -from Queue import Empty - -from pybar.run_manager import RunManager -from pybar.scans.scan_digital import DigitalScan -from pybar.scans.scan_analog import AnalogScan -from pybar.scans.scan_threshold_fast import FastThresholdScan -from pybar.scans.scan_threshold import ThresholdScan -from pybar.scans.tune_fei4 import Fei4Tuning - -from pybar.fei4.register_utils import parse_pixel_dac_config - -_data_folder = 'test_scans/module_test' # be careful... will be deleted -_configuration_folder = 'test_scans/configuration.yaml' - -# Cut values -_upper_noise_cut = 3.5 -_upper_noise_std_cut = 0.5 -_upper_pixel_fail_cut = 10 -_lower_tdac_median_cut = 15.0 -_upper_tdac_median_cut = 16.0 -_lower_tdac_std_cut = 2.5 -_upper_tdac_std_cut = 6. -_lower_fdac_median_cut = 6.5 -_upper_fdac_median_cut = 8.5 -_lower_fdac_std_cut = 1. -_upper_fdac_std_cut = 2.5 - - -def run_scan(scan, run_conf=None): - run_manager = RunManager(_configuration_folder) - run_manager.run_run(scan, run_conf=run_conf) - error_msg = '' - try: - error_msg = str(run_manager.current_run.err_queue.get(timeout=1)[1]) - except Empty: - pass - return run_manager.current_run._run_status == 'FINISHED', error_msg, run_manager.current_run.output_filename, run_manager.current_run._default_run_conf, run_manager.current_run.__class__.__name__ - - -def find(pattern, path): - result = [] - for root, _, files in os.walk(path): - for name in files: - if fnmatch.fnmatch(name, pattern): - result.append(os.path.join(root, name)) - return result - - -def check_1d_histogram(filename, hist_name, select_mask, result, operation): - ok = True - error_string = hist_name + ' ' - with tb.open_file(filename, 'r') as in_file_h5: - hist = in_file_h5.get_node(in_file_h5.root, hist_name)[:] - for index in range(select_mask[select_mask].shape[0]): - operation_ok = True - if operation[select_mask][index] == '==' and not (hist[select_mask][index] == result[select_mask][index]): - operation_ok = False - elif operation[select_mask][index] == '<=' and not (hist[select_mask][index] <= result[select_mask][index]): - operation_ok = False - elif operation[select_mask][index] == '>=' and not (hist[select_mask][index] >= result[select_mask][index]): - operation_ok = False - elif operation[select_mask][index] == '<' and not (hist[select_mask][index] < result[select_mask][index]): - operation_ok = False - elif operation[select_mask][index] == '>' and not (hist[select_mask][index] > result[select_mask][index]): - operation_ok = False - elif operation[select_mask][index] == '!=' and not (hist[select_mask][index] != result[select_mask][index]): - operation_ok = False - if not operation_ok: - error_string += ' Index %s, %s %s %s' % (index, hist[select_mask][index], operation[select_mask][index], result[select_mask][index]) - ok = False - return ok, error_string - - -def check_hit_map(filename, hist_name, select_mask, result, operation): - failing_pixels = 0 - with tb.open_file(filename, 'r') as in_file_h5: - hist = in_file_h5.get_node(in_file_h5.root, hist_name)[:, :, 0] - if operation == '==' and not np.all(hist[select_mask] == result[select_mask]): - failing_pixels = np.sum(~(hist[select_mask] == result[select_mask])) - elif operation == '<=' and not np.all(hist[select_mask] <= result[select_mask]): - failing_pixels = np.sum(~(hist[select_mask] <= result[select_mask])) - elif operation == '>=' and not np.all(hist[select_mask] >= result[select_mask]): - failing_pixels = np.sum(~(hist[select_mask] >= result[select_mask])) - elif operation == '<' and not np.all(hist[select_mask] < result[select_mask]): - failing_pixels = np.sum(~(hist[select_mask] < result[select_mask])) - elif operation == '>' and not np.all(hist[select_mask] > result[select_mask]): - failing_pixels = np.sum(~(hist[select_mask] > result[select_mask])) - elif operation == '!=' and not np.all(hist[select_mask] != result[select_mask]): - failing_pixels = np.sum(~(hist[select_mask] != result[select_mask])) - return failing_pixels - - -def check_threshold_scan(filename): - with tb.open_file(filename, 'r') as in_file_h5: - hist_threshold, hist_noise = in_file_h5.root.HistThresholdFitted[:], in_file_h5.root.HistNoiseFitted[:] - threshold_mean, threshold_std = np.mean(hist_threshold[hist_threshold != 0]), np.std(hist_threshold[hist_threshold != 0]) - noise_mean, noise_std = np.mean(hist_noise[hist_noise != 0]), np.std(hist_noise[hist_noise != 0]) - return threshold_mean, threshold_std, noise_mean, noise_std - - -def check_tuning_result(filename): - ok = True - error_string = 'FAIL tuning ' - fdac_file = find('*_tuning.dat', _data_folder + '/fdacs')[0] - tdac_file = find('*_tuning.dat', _data_folder + '/tdacs')[0] - tdacs, fdacs = parse_pixel_dac_config(tdac_file)[1:77, :], parse_pixel_dac_config(fdac_file)[1:77, :] - tdac_median, tdac_std = np.median(tdacs), np.std(tdacs) - fdac_median, fdac_std = np.median(fdacs), np.std(fdacs) - - if tdac_median < _lower_tdac_median_cut or tdac_median > _upper_tdac_median_cut: - error_string += ' TDAC median = %2.1f' % tdac_median - ok = False - if tdac_std < _lower_tdac_std_cut or tdac_std > _upper_tdac_std_cut: - error_string += ' TDAC std = %2.1f' % tdac_std - ok = False - if fdac_median < _lower_fdac_median_cut or fdac_median > _upper_fdac_median_cut: - error_string += ' FDAC median = %2.1f' % fdac_median - ok = False - if fdac_std < _lower_fdac_std_cut or fdac_std > _upper_fdac_std_cut: - error_string += ' FDAC std = %2.1f' % fdac_std - ok = False - - return ok, error_string - - -class TestScans(unittest.TestCase): - - @classmethod - def setUpClass(cls): - pass - - @classmethod - def tearDownClass(cls): - shutil.rmtree(_data_folder, ignore_errors=True) - - def test_system_status(self): # does a digital scan and checks the data for errors (event status, number of hits)s - ok, error_msg, output_filename, default_cfg, _ = run_scan(DigitalScan) - if ok: # only analyze if scan finished normal - digital_scan_file = (output_filename + '_interpreted.h5').encode('string-escape') # the digital interpreted data file - # Check event status histogram - operation = np.array(['==', '==', '==', '==', '==', '==', '==', '==', '==', '==', '==', '==', '==', '==', '==', '==']) - select_mask, result = np.ones(11, dtype=np.bool), np.zeros(11, dtype=np.uint32) - select_mask[1], result[1] = True, 40 * default_cfg['mask_steps'] * default_cfg['n_injections'] # all events with no trigger word expected - ok, error_msg = check_1d_histogram(digital_scan_file, 'HistErrorCounter', select_mask, result, operation) - # Check hit histogram - result = np.ones((336, 80), np.uint32) * default_cfg['n_injections'] - select_mask = np.ones((336, 80), dtype=np.bool) - failing_pixel = check_hit_map(digital_scan_file, 'HistOcc', select_mask, result, '==') - if failing_pixel > _upper_pixel_fail_cut: - ok = False - error_msg += ' There are %s pixels without exactly %s hits' % (failing_pixel, default_cfg['n_injections']) - self.assertTrue(ok, msg=error_msg) - - def test_standard_scans(self): # check if the scans work and the data integrity - scans = [DigitalScan, AnalogScan, ThresholdScan, FastThresholdScan] # list of scans to check - ok = True - error_msg = ' ' - for scan in scans: - # Check if scan crashes - run_conf = {'n_injections': 100, 'mask_steps': 1} # Save time by taking less pixel - scan_ok, scan_error_msg, output_filename, _, scan_name = run_scan(scan, run_conf=run_conf) - if not scan_ok: - error_msg += ' FAIL ' + str(scan_name) + ' ' + scan_error_msg - - data_file = (output_filename + '_interpreted.h5').encode('string-escape') # the digital interpreted data file - if 'ThresholdScan' not in scan_name: # check event status histogram of all scans but threshold scans - operation = np.array(['==', '==', '==', '==', '==', '==', '==', '==', '>=', '>=', '>=']) - select_mask, result = np.ones(11, dtype=np.bool), np.zeros(11, dtype=np.uint32) - select_mask[1], result[1] = True, 40 * run_conf['mask_steps'] * run_conf['n_injections'] # all events with no trigger word expected - data_ok, data_error_msg = check_1d_histogram(data_file, 'HistErrorCounter', select_mask, result, operation) - if not data_ok: - error_msg += ' ' + str(scan_name) + ': ' + data_error_msg - else: # check threshold scan results - data_ok = True - threshold_mean, threshold_std, noise_mean, noise_std = check_threshold_scan(data_file) - if noise_mean > _upper_noise_cut or noise_std > _upper_noise_std_cut: - data_ok = False - error_msg += ' ' + str(scan_name) + ': threshold/threshold std./noise/noise std. = %s/%s/%s/%s' % (threshold_mean, threshold_std, noise_mean, noise_std) - - ok &= (scan_ok & data_ok) - self.assertTrue(ok, msg=error_msg) - - def test_tuning(self): # run a full tuning and check results - error_msg = '' - data_ok = False - run_conf = {'global_iterations': 2, 'local_iterations': 1} # Save time by taking less iterations - scan_ok, scan_error_msg, output_filename, _, _ = run_scan(Fei4Tuning, run_conf=run_conf) - scan_file = (output_filename + '_interpreted.h5').encode('string-escape') # the digital interpreted data file - - if not scan_ok: - error_msg += scan_error_msg - else: - data_ok, error_msg_data = check_tuning_result(scan_file) - if not data_ok: - error_msg += error_msg_data - - self.assertTrue(scan_ok & data_ok, msg=error_msg) - - -if __name__ == '__main__': - suite = unittest.TestLoader().loadTestsFromTestCase(TestScans) - unittest.TextTestRunner(verbosity=2).run(suite) diff --git a/pybar/testing/test_scans_data/configuration.yaml b/pybar/testing/test_scans_data/configuration.yaml index d88c00432..400071dd8 100644 --- a/pybar/testing/test_scans_data/configuration.yaml +++ b/pybar/testing/test_scans_data/configuration.yaml @@ -3,8 +3,8 @@ working_dir : # Module data will be written to this path. If not given, use pat dut : dut_mio.yaml # DUT hardware configuration (.yaml). Change to dut_mio_gpac.yaml for GPAC support. dut_configuration : dut_configuration_mio.yaml # DUT init configuration (.yaml). Change to dut_configuration_mio_gpac.yaml for GPAC support. -fe_configuration : # FE configuration file, text (.cfg) or HDF5 (.h5) file. If not given, latest valid configuration (run status FINISHED) will be taken. If a number is given, configuration from run with specified number will be taken. -fe_flavor : fei4a # FEI4 flavor/type for initial configuration. Valid values: 'fei4a' or 'fei4b' +configuration : # FE configuration file, text (.cfg) or HDF5 (.h5) file. If not given, latest valid configuration (run status FINISHED) will be taken. If a number is given, configuration from run with specified number will be taken. +flavor : fei4a # FEI4 flavor/type for initial configuration. Valid values: 'fei4a' or 'fei4b' chip_address : # Chip Address for initial configuration, if not given, broadcast bit will be set module_id : module_test # module identifier / name, sub-folder with given name will be created inside working_dir diff --git a/pybar/utils/utils.py b/pybar/utils/utils.py index c3c0562ef..0749e0e9a 100644 --- a/pybar/utils/utils.py +++ b/pybar/utils/utils.py @@ -5,6 +5,7 @@ import collections import itertools # import array + import numpy as np # from bitarray import bitarray @@ -306,3 +307,32 @@ def str2bool(value): raise ValueError('Cannot convert to boolean: unknown string %s' % value) except AttributeError: # not a string return bool(value) + + +def groupby_dict(dictionary, key): + ''' Group dict of dicts by key. + ''' + return dict((k, list(g)) for k, g in itertools.groupby(sorted(dictionary.keys(), key=lambda name: dictionary[name][key]), key=lambda name: dictionary[name][key])) + + +def dict_compare(d1, d2): + '''Comparing two dictionaries. + + Note: https://stackoverflow.com/questions/4527942/comparing-two-dictionaries-in-python + ''' + d1_keys = set(d1.keys()) + d2_keys = set(d2.keys()) + intersect_keys = d1_keys.intersection(d2_keys) + added = d1_keys - d2_keys + removed = d2_keys - d1_keys + modified = {o : (d1[o], d2[o]) for o in intersect_keys if d1[o] != d2[o]} + same = set(o for o in intersect_keys if d1[o] == d2[o]) + return added, removed, modified, same + + +def zip_nofill(*iterables): + '''Zipping iterables without fillvalue. + + Note: https://stackoverflow.com/questions/38054593/zip-longest-without-fillvalue + ''' + return (tuple([entry for entry in iterable if entry is not None]) for iterable in itertools.izip_longest(*iterables, fillvalue=None)) diff --git a/requirements.txt b/requirements.txt index ad2905a58..9144345e5 100644 --- a/requirements.txt +++ b/requirements.txt @@ -9,6 +9,7 @@ progressbar-latest>=2.4 tables pyyaml scipy +contextlib2 # for multi with context manager # Additional functionality (lab devices, unit tests, Online Monitor) pyvisa # interface to lab devices diff --git a/setup.py b/setup.py index 984832786..8362f4c87 100755 --- a/setup.py +++ b/setup.py @@ -34,7 +34,7 @@ description='pyBAR - Bonn ATLAS Readout in Python', url='https://github.com/SiLab-Bonn/pyBAR', license='BSD 3-Clause ("BSD New" or "BSD Simplified") License', - long_description='PyBAR is a versatile readout and test system for the ATLAS FE-I4(A/B) pixel readout chip.\nIt uses the basil framework to access the readout hardware. PyBAR\'s FPGA firmware and host software includes support for different hardware platforms.', + long_description='PyBAR is a versatile readout and test system for the ATLAS FEI4 pixel readout chip.\nIt uses the Basil framework to access the readout hardware. PyBAR\'s FPGA firmware and host software includes support for different hardware platforms.', author=author, maintainer=author, author_email=author_email,