LCOV - code coverage report
Current view: top level - wibmod/src/WIB1 - WIB_FEMB.cpp (source / functions) Coverage Total Hit
Test: code.result Lines: 0.0 % 671 0
Test Date: 2026-10-11 15:05:20 Functions: 0.0 % 16 0

            Line data    Source code
       1              : #include "wibmod/WIB1/ADC_ASIC_reg_mapping.hh"
       2              : #include "wibmod/WIB1/ASIC_reg_mapping.hh"
       3              : #include "wibmod/WIB1/FE_ASIC_reg_mapping.hh"
       4              : #include "wibmod/WIB1/WIB.hh"
       5              : #include "wibmod/WIB1/WIBException.hh"
       6              : #include <bitset>
       7              : #include <iomanip>
       8              : #include <iostream>
       9              : #include <sstream>
      10              : #include <unistd.h>
      11              : 
      12              : #define sleep(x) usleep((useconds_t)x * 1e6)
      13              : 
      14              : /** \brief Setup FEMB in real or pulser data mode
      15              :  *
      16              :  *  Sets up iFEMB (index from 1)
      17              :  *  fe_config: list of options to configure the FE ASICs:
      18              :  *          Gain: 0,1,2,3 for 4.7, 7.8, 14, 25 mV/fC, respectively
      19              :  *          Shaping Time: 0,1,2,3 for 0.5, 1, 2, 3 us, respectively
      20              :  *          High Baseline: 0 for 200 mV, 1 for 900 mV, 2 for 200 mV on collection and 900 mV on induction
      21              :  *          High Leakage: 0 for 100 pA, 1 for 500 pA
      22              :  *          Leakage x 10: if 1, multiply leakage times 10
      23              :  *          AC Coupling : 0 for DC coupling, 1 for AC coupling (between FE and ADC)
      24              :  *          Buffer: 0 for disable and bypass, 1 for use (between FE and ADC)
      25              :  *          Use External Clock: 0 ADC use internal clock, 1 ADC use FPGA clocking (almost always want 1)
      26              :  *  clk_phases: a list of 16 bit values to try for the ADC clock phases.
      27              :  *      Tries these values until the sync check bits are all 0, and hunts
      28              :  *        for good values if these all fail.
      29              :  *      The most significant byte is ADC_ASIC_CLK_PHASE_SELECT (register 6)
      30              :  *        while the least significant byte is ADC_ASIC_CLK_PHASE_SELECT (register 15)
      31              :  *  pls_mode: pulser mode select: 0 off, 1 FE ASIC internal pulser, 2 FPGA pulser
      32              :  *  pls_dac_val: pulser DAC value (amplitude)
      33              :  *      6-bits in ASIC test pulse mode, 5-bits in FPGA test pulse mode
      34              :  *  start_frame_mode_sel: 1 to make data frame start the way BU WIB firmware expects
      35              :  *  start_frame_swap: 1 to reverse the start bits
      36              :  */
      37              : void
      38            0 : WIB::ConfigFEMB(uint8_t iFEMB,
      39              :                 std::vector<uint32_t> fe_config,
      40              :                 std::vector<uint16_t> clk_phases,
      41              :                 uint8_t pls_mode,
      42              :                 uint8_t pls_dac_val,
      43              :                 uint8_t start_frame_mode_sel,
      44              :                 uint8_t start_frame_swap)
      45              : {
      46              : 
      47            0 :   if (iFEMB < 1 || iFEMB > 4) {
      48            0 :     BUException::WIB_BAD_ARGS e;
      49            0 :     std::stringstream expstr;
      50            0 :     expstr << "ConfigFEMB: iFEMB should be between 1 and 4: " << int(iFEMB);
      51            0 :     e.Append(expstr.str().c_str());
      52            0 :     throw e;
      53            0 :   }
      54            0 :   if (pls_mode > 2) {
      55            0 :     BUException::WIB_BAD_ARGS e;
      56            0 :     std::stringstream expstr;
      57            0 :     expstr << "ConfigFEMB: pls_dac_mode is allowed to be 0 (off), 1 (FPGA), 2 (internal), but is: " << int(pls_mode);
      58            0 :     e.Append(expstr.str().c_str());
      59            0 :     throw e;
      60            0 :   }
      61            0 :   if (start_frame_mode_sel > 1 || start_frame_swap > 1) {
      62            0 :     BUException::WIB_BAD_ARGS e;
      63            0 :     std::stringstream expstr;
      64            0 :     expstr << "ConfigFEMB: start_frame_mode_sel and start_frame_swap must be 0 or 1";
      65            0 :     e.Append(expstr.str().c_str());
      66            0 :     throw e;
      67            0 :   }
      68              : 
      69            0 :   if (fe_config.size() != 8) {
      70              : 
      71            0 :     BUException::WIB_BAD_ARGS e;
      72            0 :     std::stringstream expstr;
      73            0 :     expstr << "Error: Expecting 9 Front End configuration options:" << std::endl
      74            0 :            << "\t0: Gain" << std::endl
      75            0 :            << "\t1: Shaping Time" << std::endl
      76            0 :            << "\t2: High Baseline" << std::endl
      77            0 :            << "\t3: High Leakage" << std::endl
      78            0 :            << "\t4: Leakage x 10" << std::endl
      79            0 :            << "\t5: AC Coupling" << std::endl
      80            0 :            << "\t6: Buffer" << std::endl
      81            0 :            << "\t7: Use External Clock" << std::endl;
      82            0 :     e.Append(expstr.str().c_str());
      83            0 :     throw e;
      84            0 :   } else {
      85            0 :     std::cout << "Front End configuration options:" << std::endl
      86            0 :               << "\t0:" << std::setw(22) << std::setfill(' ') << "Gain " << fe_config[0] << std::endl
      87            0 :               << "\t1:" << std::setw(22) << std::setfill(' ') << "Shaping Time " << fe_config[1] << std::endl
      88            0 :               << "\t2:" << std::setw(22) << std::setfill(' ') << "High Baseline " << fe_config[2] << std::endl
      89            0 :               << "\t3:" << std::setw(22) << std::setfill(' ') << "High Leakage " << fe_config[3] << std::endl
      90            0 :               << "\t4:" << std::setw(22) << std::setfill(' ') << "Leakage x 10 " << fe_config[4] << std::endl
      91            0 :               << "\t5:" << std::setw(22) << std::setfill(' ') << "AC Coupling " << fe_config[5] << std::endl
      92            0 :               << "\t6:" << std::setw(22) << std::setfill(' ') << "Buffer " << fe_config[6] << std::endl
      93            0 :               << "\t8:" << std::setw(22) << std::setfill(' ') << "Use External Clock " << fe_config[7] << std::endl;
      94              :   }
      95              : 
      96            0 :   std::cout << "Pulser Mode: " << int(pls_mode) << " and DAC Value: " << int(pls_dac_val) << std::endl;
      97              : 
      98              :   // get this register so we can leave it in the state it started in
      99            0 :   uint32_t slow_control_dnd = Read("SYSTEM.SLOW_CONTROL_DND");
     100            0 :   Write("SYSTEM.SLOW_CONTROL_DND", 1);
     101              : 
     102            0 :   if (ReadFEMB(iFEMB, "VERSION_ID") == ReadFEMB(iFEMB, "SYS_RESET")) { // can't read register if equal
     103            0 :     if (ContinueOnFEMBRegReadError) {
     104            0 :       std::cout << "Error: Can't read registers from FEMB " << int(iFEMB) << std::endl;
     105            0 :       return;
     106              :     }
     107            0 :     BUException::FEMB_REG_READ_ERROR e;
     108            0 :     std::stringstream expstr;
     109            0 :     expstr << " for FEMB: " << int(iFEMB);
     110            0 :     e.Append(expstr.str().c_str());
     111            0 :     throw e;
     112            0 :   }
     113              : 
     114            0 :   WriteFEMB(iFEMB, "REG_RESET", 1);
     115            0 :   sleep(1);
     116              : 
     117            0 :   WriteFEMB(iFEMB, "START_FRAME_MODE_SELECT", start_frame_mode_sel);
     118            0 :   sleep(1);
     119            0 :   WriteFEMB(iFEMB, "START_FRAME_SWAP", start_frame_swap);
     120              : 
     121            0 :   if (fe_config[7]) { // use external clock
     122            0 :     SetupFEMBExtClock(iFEMB);
     123              :   }
     124            0 :   sleep(0.05);
     125              : 
     126            0 :   WriteFEMB(iFEMB, "TIME_STAMP_RESET", 1);
     127            0 :   WriteFEMB(iFEMB, "TIME_STAMP_RESET", 1);
     128              : 
     129              :   // These are all Jack's WIB addresses, need to figure out Dan's addresses for functionality
     130              :   ////Sync Time stamp /WIB
     131              :   // Write(1, 0);
     132              :   // Write(1, 0);
     133              :   // Write(1, 2);
     134              :   // Write(1, 2);
     135              :   // Write(1, 0);
     136              :   // Write(1, 0);
     137              :   //
     138              :   ////Reset Error /WIB
     139              :   // Write(18, 0x8000);
     140              :   // Write(18, 0x8000);
     141              : 
     142              :   // Reset SPI
     143              :   //
     144            0 :   sleep(0.005);
     145            0 :   WriteFEMB(iFEMB, "ADC_ASIC_RESET", 0x1);
     146            0 :   sleep(0.005);
     147            0 :   WriteFEMB(iFEMB, "ADC_ASIC_RESET", 0x1);
     148            0 :   sleep(0.005);
     149            0 :   WriteFEMB(iFEMB, "FE_ASIC_RESET", 0x1);
     150            0 :   sleep(0.005);
     151            0 :   WriteFEMB(iFEMB, "FE_ASIC_RESET", 0x1);
     152            0 :   sleep(0.005);
     153              : 
     154              :   // Set ADC latch_loc
     155            0 :   uint32_t REG_LATCHLOC1_4_data = 0x04040404;
     156            0 :   uint32_t REG_LATCHLOC5_8_data = 0x04040404;
     157              : 
     158            0 :   WriteFEMB(iFEMB, "ADC_LATCH_LOC_0TO3", REG_LATCHLOC1_4_data);
     159            0 :   WriteFEMB(iFEMB, "ADC_LATCH_LOC_4TO7", REG_LATCHLOC5_8_data);
     160              : 
     161              :   // Setup pulser
     162            0 :   uint8_t internal_daq_value = 0;
     163            0 :   if (pls_mode == 1) // internal, FE ASIC, 6 bits
     164              :   {
     165            0 :     if (pls_dac_val >= 63) {
     166            0 :       BUException::WIB_BAD_ARGS e;
     167            0 :       std::stringstream expstr;
     168            0 :       expstr << "ConfigFEMB: pls_dac_val is 6 bits for internal DAC, must be 0-63, but is: " << int(pls_dac_val);
     169            0 :       e.Append(expstr.str().c_str());
     170            0 :       throw e;
     171            0 :     }
     172            0 :     internal_daq_value = pls_dac_val;
     173            0 :     SetupInternalPulser(iFEMB);
     174            0 :   } else if (pls_mode == 2) // external, FPGA, 5 bits
     175              :   {
     176            0 :     if (pls_dac_val >= 32) {
     177            0 :       BUException::WIB_BAD_ARGS e;
     178            0 :       std::stringstream expstr;
     179            0 :       expstr << "ConfigFEMB: pls_dac_val is 5 bits for FPGA DAC, must be 0-31, but is: " << int(pls_dac_val);
     180            0 :       e.Append(expstr.str().c_str());
     181            0 :       throw e;
     182            0 :     }
     183            0 :     SetupFPGAPulser(iFEMB, pls_dac_val);
     184              :   }
     185              : 
     186              :   // Setup ASICs
     187            0 :   SetupFEMBASICs(iFEMB,
     188            0 :                  fe_config[0],
     189            0 :                  fe_config[1],
     190            0 :                  fe_config[2],
     191            0 :                  fe_config[3],
     192            0 :                  fe_config[4],
     193            0 :                  fe_config[5],
     194            0 :                  fe_config[6],
     195            0 :                  fe_config[7],
     196              :                  pls_mode,
     197              :                  internal_daq_value);
     198            0 :   std::cout << "FEMB " << int(iFEMB) << " Successful SPI config" << std::endl;
     199              : 
     200              :   // Try to sync ADCs
     201            0 :   if (clk_phases.size() == 0) {
     202            0 :     clk_phases.push_back(0xFFFF);
     203              :   }
     204            0 :   if (!TryFEMBPhases(iFEMB, clk_phases)) {
     205            0 :     if (ContinueIfListOfFEMBClockPhasesDontSync) {
     206            0 :       std::cout << "Warning: FEMB " << int(iFEMB)
     207            0 :                 << " ADC FIFO not synced from expected phases, trying to hunt for phases" << std::endl;
     208            0 :       if (!HuntFEMBPhase(iFEMB, clk_phases.at(0))) {
     209            0 :         if (ContinueOnFEMBSyncError) {
     210            0 :           std::cout << "Error: FEMB " << int(iFEMB) << " ADC FIFO could not be synced even after hunting" << std::endl;
     211              :         } else {
     212            0 :           uint16_t adc_fifo_sync = (ReadFEMB(iFEMB, 6) & 0xFFFF0000) >> 16;
     213            0 :           BUException::FEMB_ADC_SYNC_ERROR e;
     214            0 :           std::stringstream expstr;
     215            0 :           expstr << " after hunting. ";
     216            0 :           expstr << " FEMB: " << int(iFEMB);
     217            0 :           expstr << " sync: " << std::bitset<16>(adc_fifo_sync);
     218            0 :           expstr << " phases: ";
     219            0 :           expstr << std::hex << std::setfill('0') << std::setw(2) << ReadFEMB(iFEMB, "ADC_ASIC_CLK_PHASE_SELECT");
     220            0 :           expstr << std::hex << std::setfill('0') << std::setw(2) << ReadFEMB(iFEMB, "ADC_ASIC_CLK_PHASE_SELECT_2");
     221            0 :           e.Append(expstr.str().c_str());
     222            0 :           throw e;
     223            0 :         }
     224              :       } // if ! HuntFEMBPhase
     225              :     } // if ContinueIfListOfFEMBClockPhasesDontSync
     226              :     else // ContinueIfListOfFEMBClockPhasesDontSync
     227              :     {
     228            0 :       uint16_t adc_fifo_sync = (ReadFEMB(iFEMB, 6) & 0xFFFF0000) >> 16;
     229            0 :       BUException::FEMB_ADC_SYNC_ERROR e;
     230            0 :       std::stringstream expstr;
     231            0 :       expstr << " after trying all in list. ";
     232            0 :       expstr << " FEMB: " << int(iFEMB);
     233            0 :       expstr << " sync: " << std::bitset<16>(adc_fifo_sync);
     234            0 :       expstr << " phases tried: " << std::endl;
     235            0 :       for (size_t iclk_phase = 0; iclk_phase < clk_phases.size(); iclk_phase++) {
     236            0 :         expstr << "    " << std::hex << std::setfill('0') << std::setw(4) << clk_phases[iclk_phase] << std::endl;
     237              :       }
     238            0 :       e.Append(expstr.str().c_str());
     239            0 :       throw e;
     240            0 :     } // else ContinueIfListOfFEMBClockPhasesDontSync
     241              :   } // if ! TryFEMBPhases
     242            0 :   uint16_t adc_fifo_sync = (ReadFEMB(iFEMB, 6) & 0xFFFF0000) >> 16;
     243            0 :   std::cout << "FEMB " << int(iFEMB) << " Final ADC FIFO sync: " << std::bitset<16>(adc_fifo_sync) << std::endl;
     244            0 :   std::cout << "FEMB " << int(iFEMB) << " Final Clock Phases: " << std::hex << std::setfill('0') << std::setw(2)
     245            0 :             << ReadFEMB(iFEMB, "ADC_ASIC_CLK_PHASE_SELECT") << std::hex << std::setfill('0') << std::setw(2)
     246            0 :             << ReadFEMB(iFEMB, "ADC_ASIC_CLK_PHASE_SELECT_2") << std::endl;
     247              : 
     248              :   // time stamp reset
     249            0 :   WriteFEMB(iFEMB, "TIME_STAMP_RESET", 1);
     250            0 :   WriteFEMB(iFEMB, "TIME_STAMP_RESET", 1);
     251              : 
     252              :   // These are all Jack's WIB addresses, need to figure out Dan's addresses for functionality
     253              :   ////Sync Time stamp /WIB
     254              :   // Write(1, 0);
     255              :   // Write(1, 0);
     256              :   // Write(1, 2);
     257              :   // Write(1, 2);
     258              :   // Write(1, 0);
     259              :   // Write(1, 0);
     260              :   //
     261              :   ////Reset Error /WIB
     262              :   // Write(18, 0x8000);
     263              :   // Write(18, 0x8000);
     264              : 
     265            0 :   Write("SYSTEM.SLOW_CONTROL_DND", slow_control_dnd);
     266              : }
     267              : 
     268              : /** \brief Setup FEMB in fake data mode
     269              :  *
     270              :  *  Sets up iFEMB (index from 1) in fake data mode
     271              :  *  fake_mode: 0 for real data, 1 for fake word, 2 for fake waveform, 3 for channel indicator (FEMB, chip, channel),
     272              :  *          4 for channel indicator (counter, chip, channel)
     273              :  *  fake_word: 12 bit wrd to use when in fake word mode
     274              :  *  femb_number: femb number to use in fake_mode 3, 4 bits
     275              :  *  fake_samples: vector of samples to use in fake_mode 2
     276              :  */
     277              : void
     278            0 : WIB::ConfigFEMBFakeData(uint8_t iFEMB,
     279              :                         uint8_t fake_mode,
     280              :                         uint32_t fake_word,
     281              :                         uint8_t femb_number,
     282              :                         std::vector<uint32_t> fake_samples,
     283              :                         uint8_t start_frame_mode_sel,
     284              :                         uint8_t start_frame_swap)
     285              : {
     286              : 
     287            0 :   if (iFEMB < 1 || iFEMB > 4) {
     288            0 :     BUException::WIB_BAD_ARGS e;
     289            0 :     std::stringstream expstr;
     290            0 :     expstr << "ConfigFEMBFakeData: iFEMB should be between 1 and 4: " << int(iFEMB);
     291            0 :     e.Append(expstr.str().c_str());
     292            0 :     throw e;
     293            0 :   }
     294            0 :   if (start_frame_mode_sel > 1 || start_frame_swap > 1) {
     295            0 :     BUException::WIB_BAD_ARGS e;
     296            0 :     std::stringstream expstr;
     297            0 :     expstr << "ConfigFEMBFakeData: start_frame_mode_sel and start_frame_swap must be 0 or 1";
     298            0 :     e.Append(expstr.str().c_str());
     299            0 :     throw e;
     300            0 :   }
     301            0 :   if (fake_mode == 1 && fake_word > 0xFFF) {
     302            0 :     BUException::WIB_BAD_ARGS e;
     303            0 :     std::stringstream expstr;
     304            0 :     expstr << "ConfigFEMBFakeData: fake_word must be only 12 bits i.e. <= 4095, is: " << fake_word;
     305            0 :     e.Append(expstr.str().c_str());
     306            0 :     throw e;
     307            0 :   }
     308            0 :   if (fake_mode == 2 && fake_samples.size() != 256) {
     309            0 :     BUException::WIB_BAD_ARGS e;
     310            0 :     std::stringstream expstr;
     311            0 :     expstr << "ConfigFEMBFakeData: femb_samples must be 255 long, is: " << fake_samples.size();
     312            0 :     e.Append(expstr.str().c_str());
     313            0 :     throw e;
     314            0 :   }
     315            0 :   if (fake_mode == 3 && femb_number > 0xF) {
     316            0 :     BUException::WIB_BAD_ARGS e;
     317            0 :     std::stringstream expstr;
     318            0 :     expstr << "ConfigFEMBFakeData: femb_number must be only 4 bits i.e. <= 15, is: " << int(femb_number);
     319            0 :     e.Append(expstr.str().c_str());
     320            0 :     throw e;
     321            0 :   }
     322              : 
     323              :   // get this register so we can leave it in the state it started in
     324            0 :   uint32_t slow_control_dnd = Read("SYSTEM.SLOW_CONTROL_DND");
     325            0 :   Write("SYSTEM.SLOW_CONTROL_DND", 1);
     326              : 
     327            0 :   WriteFEMB(iFEMB, "REG_RESET", 1);
     328            0 :   sleep(1);
     329              : 
     330            0 :   WriteFEMB(iFEMB, "STREAM_AND_ADC_DATA_EN", 0);
     331            0 :   sleep(1);
     332              : 
     333            0 :   WriteFEMB(iFEMB, "START_FRAME_MODE_SELECT", start_frame_mode_sel);
     334            0 :   sleep(1);
     335            0 :   WriteFEMB(iFEMB, "START_FRAME_SWAP", start_frame_swap);
     336            0 :   sleep(0.05);
     337              : 
     338              :   // time stamp reset
     339            0 :   WriteFEMB(iFEMB, "TIME_STAMP_RESET", 1);
     340            0 :   WriteFEMB(iFEMB, "TIME_STAMP_RESET", 1);
     341              : 
     342              :   // Now do the Fake data mode setup
     343            0 :   if (fake_mode == 1) {
     344            0 :     WriteFEMB(iFEMB, "DATA_TEST_PATTERN", fake_word);
     345              :   }
     346            0 :   if (fake_mode == 2) {
     347              :     // Put waveform in FEMB registers
     348            0 :     for (size_t iSample = 0; iSample < 256; iSample++) {
     349            0 :       WriteFEMB(iFEMB, 0x300 + iSample, fake_samples.at(iSample));
     350            0 :       sleep(0.005);
     351              :     }
     352              :   }
     353            0 :   if (fake_mode == 3) {
     354            0 :     WriteFEMB(iFEMB, "FEMB_NUMBER", femb_number);
     355              :   }
     356            0 :   WriteFEMB(iFEMB, "FEMB_TST_SEL", fake_mode);
     357              : 
     358              :   // time stamp reset
     359            0 :   WriteFEMB(iFEMB, "TIME_STAMP_RESET", 1);
     360            0 :   WriteFEMB(iFEMB, "TIME_STAMP_RESET", 1);
     361              : 
     362            0 :   WriteFEMB(iFEMB, "STREAM_AND_ADC_DATA_EN", 9);
     363              : 
     364            0 :   Write("SYSTEM.SLOW_CONTROL_DND", slow_control_dnd);
     365            0 : }
     366              : 
     367              : /** \brief Setup FEMB External Clock
     368              :  *
     369              :  *  Sets up iFEMB (index from 1) external clock parameters
     370              :  */
     371              : void
     372            0 : WIB::SetupFEMBExtClock(uint8_t iFEMB)
     373              : {
     374              : 
     375              :   // EXTERNAL CLOCK VARIABLES
     376            0 :   uint32_t clk_period = 5; // ns
     377            0 :   uint32_t clk_dis = 0;    // 0 --> enable, 1 disable
     378            0 :   uint32_t d14_rst_oft = 0 / clk_period;
     379            0 :   uint32_t d14_rst_wdt = (45 / clk_period);
     380            0 :   uint32_t d14_rst_inv = 1;
     381            0 :   uint32_t d14_read_oft = 480 / clk_period;
     382            0 :   uint32_t d14_read_wdt = 20 / clk_period;
     383            0 :   uint32_t d14_read_inv = 1;
     384            0 :   uint32_t d14_idxm_oft = 230 / clk_period;
     385            0 :   uint32_t d14_idxm_wdt = 270 / clk_period;
     386            0 :   uint32_t d14_idxm_inv = 0;
     387            0 :   uint32_t d14_idxl_oft = 480 / clk_period;
     388            0 :   uint32_t d14_idxl_wdt = 20 / clk_period;
     389            0 :   uint32_t d14_idxl_inv = 0;
     390            0 :   uint32_t d14_idl0_oft = 50 / clk_period;
     391            0 :   uint32_t d14_idl0_wdt = (190 / clk_period) - 1;
     392            0 :   uint32_t d14_idl1_oft = 480 / clk_period;
     393            0 :   uint32_t d14_idl1_wdt = 20 / clk_period;
     394            0 :   uint32_t d14_idl_inv = 0;
     395              : 
     396            0 :   uint32_t d58_rst_oft = 0 / clk_period;
     397            0 :   uint32_t d58_rst_wdt = (45 / clk_period);
     398            0 :   uint32_t d58_rst_inv = 1;
     399            0 :   uint32_t d58_read_oft = 480 / clk_period;
     400            0 :   uint32_t d58_read_wdt = 20 / clk_period;
     401            0 :   uint32_t d58_read_inv = 1;
     402            0 :   uint32_t d58_idxm_oft = 230 / clk_period;
     403            0 :   uint32_t d58_idxm_wdt = 270 / clk_period;
     404            0 :   uint32_t d58_idxm_inv = 0;
     405            0 :   uint32_t d58_idxl_oft = 480 / clk_period;
     406            0 :   uint32_t d58_idxl_wdt = 20 / clk_period;
     407            0 :   uint32_t d58_idxl_inv = 0;
     408            0 :   uint32_t d58_idl0_oft = 50 / clk_period;
     409            0 :   uint32_t d58_idl0_wdt = (190 / clk_period) - 1;
     410            0 :   uint32_t d58_idl1_oft = 480 / clk_period;
     411            0 :   uint32_t d58_idl1_wdt = 20 / clk_period;
     412            0 :   uint32_t d58_idl_inv = 0;
     413              : 
     414              :   // external clock phase -- Version 320
     415              :   /*uint32_t d14_read_step = 7;
     416              :   uint32_t d14_read_ud   = 0;
     417              :   uint32_t d14_idxm_step = 3;
     418              :   uint32_t d14_idxm_ud   = 0;
     419              :   uint32_t d14_idxl_step = 1;
     420              :   uint32_t d14_idxl_ud   = 1;
     421              :   uint32_t d14_idl0_step = 5;
     422              :   uint32_t d14_idl0_ud   = 0;
     423              :   uint32_t d14_idl1_step = 2;
     424              :   uint32_t d14_idl1_ud   = 0;
     425              :   uint32_t d14_phase_en  = 1;
     426              : 
     427              :   uint32_t d58_read_step = 1;
     428              :   uint32_t d58_read_ud   = 1;
     429              :   uint32_t d58_idxm_step = 0;
     430              :   uint32_t d58_idxm_ud   = 0;
     431              :   uint32_t d58_idxl_step = 5;
     432              :   uint32_t d58_idxl_ud   = 1;
     433              :   uint32_t d58_idl0_step = 6;
     434              :   uint32_t d58_idl0_ud   = 0;
     435              :   uint32_t d58_idl1_step = 5;
     436              :   uint32_t d58_idl1_ud   = 0;
     437              :   uint32_t d58_phase_en  = 1;*/
     438              :   // Version 323
     439            0 :   uint32_t d14_read_step = 11;
     440            0 :   uint32_t d14_read_ud = 0;
     441            0 :   uint32_t d14_idxm_step = 9;
     442            0 :   uint32_t d14_idxm_ud = 0;
     443            0 :   uint32_t d14_idxl_step = 7;
     444            0 :   uint32_t d14_idxl_ud = 0;
     445            0 :   uint32_t d14_idl0_step = 12;
     446            0 :   uint32_t d14_idl0_ud = 0;
     447            0 :   uint32_t d14_idl1_step = 10;
     448            0 :   uint32_t d14_idl1_ud = 0;
     449            0 :   uint32_t d14_phase_en = 1;
     450              : 
     451            0 :   uint32_t d58_read_step = 0;
     452            0 :   uint32_t d58_read_ud = 0;
     453            0 :   uint32_t d58_idxm_step = 5;
     454            0 :   uint32_t d58_idxm_ud = 0;
     455            0 :   uint32_t d58_idxl_step = 4;
     456            0 :   uint32_t d58_idxl_ud = 1;
     457            0 :   uint32_t d58_idl0_step = 3;
     458            0 :   uint32_t d58_idl0_ud = 0;
     459            0 :   uint32_t d58_idl1_step = 4;
     460            0 :   uint32_t d58_idl1_ud = 0;
     461            0 :   uint32_t d58_phase_en = 1;
     462              : 
     463              :   // END EXTERNAL CLOCK VARIABLES
     464              : 
     465              :   // config timing
     466            0 :   uint32_t d14_inv =
     467              :     (d14_rst_inv << 0) + (d14_read_inv << 1) + (d14_idxm_inv << 2) + (d14_idxl_inv << 3) + (d14_idl_inv << 4);
     468            0 :   uint32_t d58_inv =
     469              :     (d58_rst_inv << 0) + (d58_read_inv << 1) + (d58_idxm_inv << 2) + (d58_idxl_inv << 3) + (d58_idl_inv << 4);
     470            0 :   uint32_t d_inv = d58_inv + (d14_inv << 5);
     471              : 
     472            0 :   uint32_t addr_data;
     473              : 
     474            0 :   addr_data = clk_dis + (d_inv << 16);
     475            0 :   WriteFEMB(iFEMB, 21, addr_data);
     476              : 
     477            0 :   addr_data = d58_rst_oft + (d14_rst_oft << 16);
     478            0 :   WriteFEMB(iFEMB, 22, addr_data);
     479              : 
     480            0 :   addr_data = d58_rst_wdt + (d14_rst_wdt << 16);
     481            0 :   WriteFEMB(iFEMB, 23, addr_data);
     482              : 
     483            0 :   addr_data = d58_read_oft + (d14_read_oft << 16);
     484            0 :   WriteFEMB(iFEMB, 24, addr_data);
     485              : 
     486            0 :   addr_data = d58_read_wdt + (d14_read_wdt << 16);
     487            0 :   WriteFEMB(iFEMB, 25, addr_data);
     488              : 
     489            0 :   addr_data = d58_idxm_oft + (d14_idxm_oft << 16);
     490            0 :   WriteFEMB(iFEMB, 26, addr_data);
     491              : 
     492            0 :   addr_data = d58_idxm_wdt + (d14_idxm_wdt << 16);
     493            0 :   WriteFEMB(iFEMB, 27, addr_data);
     494              : 
     495            0 :   addr_data = d58_idxl_oft + (d14_idxl_oft << 16);
     496            0 :   WriteFEMB(iFEMB, 28, addr_data);
     497              : 
     498            0 :   addr_data = d58_idxl_wdt + (d14_idxl_wdt << 16);
     499            0 :   WriteFEMB(iFEMB, 29, addr_data);
     500              : 
     501            0 :   addr_data = d58_idl0_oft + (d14_idl0_oft << 16);
     502            0 :   WriteFEMB(iFEMB, 30, addr_data);
     503              : 
     504            0 :   addr_data = d58_idl0_wdt + (d14_idl0_wdt << 16);
     505            0 :   WriteFEMB(iFEMB, 31, addr_data);
     506              : 
     507            0 :   addr_data = d58_idl1_oft + (d14_idl1_oft << 16);
     508            0 :   WriteFEMB(iFEMB, 32, addr_data);
     509              : 
     510            0 :   addr_data = d58_idl1_wdt + (d14_idl1_wdt << 16);
     511            0 :   WriteFEMB(iFEMB, 33, addr_data);
     512              : 
     513              :   // config phase
     514            0 :   for (size_t i = 0; i < 4; i++) {
     515            0 :     addr_data = d14_read_step + (d14_idxm_step << 16);
     516            0 :     WriteFEMB(iFEMB, 35, addr_data);
     517              : 
     518            0 :     addr_data = d14_idxl_step + (d14_idl0_step << 16);
     519            0 :     WriteFEMB(iFEMB, 36, addr_data);
     520              : 
     521            0 :     d14_phase_en = d14_phase_en ^ 1;
     522            0 :     uint32_t d14_ud = d14_read_ud + (d14_idxm_ud << 1) + (d14_idxl_ud << 2) + (d14_idl0_ud << 3) + (d14_idl1_ud << 4) +
     523              :                       (d14_phase_en << 15);
     524            0 :     addr_data = d14_idl1_step + (d14_ud << 16);
     525            0 :     WriteFEMB(iFEMB, 37, addr_data);
     526              : 
     527            0 :     addr_data = d58_read_step + (d58_idxm_step << 16);
     528            0 :     WriteFEMB(iFEMB, 38, addr_data);
     529              : 
     530            0 :     addr_data = d58_idxl_step + (d58_idl0_step << 16);
     531            0 :     WriteFEMB(iFEMB, 39, addr_data);
     532              : 
     533            0 :     d58_phase_en = d58_phase_en ^ 1;
     534            0 :     uint32_t d58_ud = d58_read_ud + (d58_idxm_ud << 1) + (d58_idxl_ud << 2) + (d58_idl0_ud << 3) + (d58_idl1_ud << 4) +
     535            0 :                       (d58_phase_en << 15);
     536            0 :     addr_data = d58_idl1_step + (d58_ud << 16);
     537            0 :     WriteFEMB(iFEMB, 40, addr_data);
     538              :   }
     539            0 :   sleep(0.05);
     540            0 : }
     541              : 
     542              : /** \brief Setup FEMB ASICs
     543              :  *
     544              :  *  Sets up iFEMB (index from 1) ASICs
     545              :  *
     546              :  *  registerList is a list of 71 32bit registers to program the FE and ADC ASICs
     547              :  *
     548              :  *  returns adc sync status 16 bits, one for each serial link between ADC and FPGA. There are 2 per ADC
     549              :  */
     550              : uint16_t
     551            0 : WIB::SetupFEMBASICs(uint8_t iFEMB, std::vector<uint32_t> registerList)
     552              : {
     553              : 
     554            0 :   const size_t REG_SPI_BASE = 512;
     555            0 :   const size_t NREGS = 71;
     556              : 
     557            0 :   if (registerList.size() != NREGS) {
     558            0 :     BUException::FEMB_FIRMWARE_VERSION_MISMATCH e;
     559            0 :     std::stringstream expstr;
     560            0 :     expstr << "SetupFEMBASICs expects : " << NREGS << " argument is: " << registerList.size();
     561            0 :     e.Append(expstr.str().c_str());
     562            0 :     throw e;
     563            0 :   }
     564              : 
     565              :   // turn off HS data before register writes
     566            0 :   WriteFEMB(iFEMB, "STREAM_EN", 0);
     567            0 :   sleep(2);
     568              : 
     569            0 :   for (size_t iReg = 0; iReg < NREGS; iReg++) {
     570            0 :     WriteFEMB(iFEMB, REG_SPI_BASE + iReg, registerList[iReg]);
     571              :   }
     572              : 
     573              :   /////////////////////////////
     574              :   // run the SPI programming
     575              :   /////////////////////////////
     576              : 
     577            0 :   WriteFEMB(iFEMB, "ADC_ASIC_RESET", 1);
     578            0 :   sleep(0.01);
     579            0 :   WriteFEMB(iFEMB, "FE_ASIC_RESET", 1);
     580            0 :   sleep(0.01);
     581            0 :   WriteFEMB(iFEMB, "WRITE_ADC_ASIC_SPI", 1);
     582            0 :   sleep(0.01);
     583            0 :   WriteFEMB(iFEMB, "WRITE_ADC_ASIC_SPI", 1);
     584            0 :   sleep(0.01);
     585            0 :   WriteFEMB(iFEMB, "WRITE_FE_ASIC_SPI", 1);
     586            0 :   sleep(0.01);
     587            0 :   WriteFEMB(iFEMB, "WRITE_FE_ASIC_SPI", 1);
     588            0 :   sleep(0.01);
     589              : 
     590            0 :   uint16_t adc_sync_status = (uint16_t)ReadFEMB(iFEMB, "ADC_ASIC_SYNC_STATUS");
     591              :   /////////////////////////////
     592              :   /////////////////////////////
     593              : 
     594              :   // turn HS link back on
     595            0 :   sleep(2);
     596            0 :   WriteFEMB(iFEMB, "STREAM_EN", 1);
     597              : 
     598            0 :   return adc_sync_status;
     599              : }
     600              : 
     601              : /** \brief Setup FEMB ASICs
     602              :  *
     603              :  *  Sets up iFEMB (index from 1) ASICs
     604              :  *
     605              :  *  gain: 0,1,2,3 for 4.7, 7.8, 14, 25 mV/fC, respectively
     606              :  *  shaping time: 0,1,2,3 for 0.5, 1, 2, 3 us, respectively
     607              :  *  highBaseline is 900mV for 1, 200mV for 0, and appropriately for each plane for 2
     608              :  *  highLeakage is 500pA for true, 100pA for false
     609              :  *  leakagex10 multiplies leakage x10 if true
     610              :  *  acCoupling: FE is AC coupled to ADC if true, DC if false
     611              :  *  buffer: FE to ADC buffer on if true, off and bypassed if false
     612              :  *  useExtClock: ADC uses external (FPGA) clock if true, internal if false
     613              :  *  internalDACControl: 0 for disabled, 1 for internal FE ASIC pulser, 2 for external FPGA pulser
     614              :  *  internalDACValue: 6 bit value for amplitude to use with internal pulser
     615              :  *
     616              :  *  returns adc sync status 16 bits, one for each serial link between ADC and FPGA. There are 2 per ADC
     617              :  */
     618              : uint16_t
     619            0 : WIB::SetupFEMBASICs(uint8_t iFEMB,
     620              :                     uint8_t gain,
     621              :                     uint8_t shape,
     622              :                     uint8_t highBaseline,
     623              :                     bool highLeakage,
     624              :                     bool leakagex10,
     625              :                     bool acCoupling,
     626              :                     bool buffer,
     627              :                     bool useExtClock,
     628              :                     uint8_t internalDACControl,
     629              :                     uint8_t internalDACValue)
     630              : {
     631              : 
     632            0 :   (void)buffer; // to make compiler not complain about unused arguments
     633              : 
     634            0 :   if (gain > 3) {
     635            0 :     BUException::WIB_BAD_ARGS e;
     636            0 :     std::stringstream expstr;
     637            0 :     expstr << "gain should be between 0 and 3, but is: " << int(gain);
     638            0 :     e.Append(expstr.str().c_str());
     639            0 :     throw e;
     640            0 :   }
     641            0 :   if (shape > 3) {
     642            0 :     BUException::WIB_BAD_ARGS e;
     643            0 :     std::stringstream expstr;
     644            0 :     expstr << "shape should be between 0 and 3, but is: " << int(shape);
     645            0 :     e.Append(expstr.str().c_str());
     646            0 :     throw e;
     647            0 :   }
     648              : 
     649            0 :   const size_t REG_SPI_BASE_WRITE = 0x200; // 512
     650            0 :   const size_t REG_SPI_BASE_READ = 0x250;  // 592
     651              :   // 0x48 registers total, 72 in hex
     652              : 
     653            0 :   bool bypassOutputBuffer = true; // if false might blow up protoDUNE
     654            0 :   bool useOutputMonitor = false;  // if true might blow up protoDUNE
     655            0 :   bool useCh16HighPassFilter = false;
     656            0 :   bool monitorBandgapNotTemp = false;
     657            0 :   bool monitorTempBandgapNotSignal = false;
     658            0 :   bool useTestCapacitance = (bool)internalDACControl;
     659              : 
     660              :   // Flip bits of gain
     661            0 :   if (gain == 0x1)
     662              :     gain = 0x2;
     663            0 :   else if (gain == 0x2)
     664            0 :     gain = 0x1;
     665              : 
     666              :   // Shape
     667            0 :   if (shape == 0x0)
     668              :     shape = 0x2; // 0.5 us
     669              :   else if (shape == 0x1)
     670              :     shape = 0x0; // 1 us
     671              :   else if (shape == 0x2)
     672              :     shape = 0x3; // 2 us
     673              :   else if (shape == 0x3)
     674            0 :     shape = 0x1; // 3 us
     675              : 
     676            0 :   FE_ASIC_reg_mapping fe_map;
     677            0 :   if (highBaseline > 1) {
     678              :     // Set them all to high baseline
     679            0 :     fe_map.set_board(useTestCapacitance,
     680              :                      0,
     681              :                      gain,
     682              :                      shape,
     683              :                      useOutputMonitor,
     684              :                      !bypassOutputBuffer,
     685            0 :                      !highLeakage,
     686              :                      monitorBandgapNotTemp,
     687              :                      monitorTempBandgapNotSignal,
     688              :                      useCh16HighPassFilter,
     689              :                      leakagex10,
     690              :                      acCoupling,
     691              :                      internalDACControl,
     692              :                      internalDACValue);
     693              :     // Now just set collection channels to low baseline
     694            0 :     fe_map.set_collection_baseline(1);
     695              :   } else {
     696            0 :     fe_map.set_board(useTestCapacitance,
     697              :                      ~highBaseline,
     698              :                      gain,
     699              :                      shape,
     700              :                      useOutputMonitor,
     701              :                      !bypassOutputBuffer,
     702            0 :                      !highLeakage,
     703              :                      monitorBandgapNotTemp,
     704              :                      monitorTempBandgapNotSignal,
     705              :                      useCh16HighPassFilter,
     706              :                      leakagex10,
     707              :                      acCoupling,
     708              :                      internalDACControl,
     709              :                      internalDACValue);
     710              :   }
     711            0 :   ADC_ASIC_reg_mapping adc_map;
     712            0 :   uint8_t offsetCurrentValue = 0;
     713            0 :   bool pcsr = 0;
     714            0 :   bool pdsr = 0;
     715            0 :   bool adcSleep = 0;
     716            0 :   bool useADCTestInput = 0;
     717            0 :   bool f4 = 0;
     718            0 :   bool f5 = 0;
     719            0 :   bool lsbCurrentStearingPartialNotFull = 0;
     720            0 :   bool clk0 = 0;
     721            0 :   if (useExtClock)
     722              :     clk0 = 1;
     723            0 :   bool clk1 = 0;
     724            0 :   bool freq = 0;
     725            0 :   bool enableOffsetCurrent = 0;
     726            0 :   bool f0 = 0;
     727            0 :   bool f1 = 0;
     728            0 :   bool f2 = 0;
     729            0 :   bool f3 = 0;
     730            0 :   adc_map.set_board(offsetCurrentValue,
     731              :                     pcsr,
     732              :                     pdsr,
     733              :                     adcSleep,
     734              :                     useADCTestInput,
     735              :                     f4,
     736              :                     f5,
     737              :                     lsbCurrentStearingPartialNotFull,
     738              :                     0,
     739              :                     0,
     740              :                     0,
     741              :                     0,
     742              :                     0,
     743              :                     clk0,
     744              :                     clk1,
     745              :                     freq,
     746              :                     enableOffsetCurrent,
     747              :                     f0,
     748              :                     f1,
     749              :                     f2,
     750              :                     f3);
     751            0 :   ASIC_reg_mapping map;
     752            0 :   map.set_board(fe_map, adc_map);
     753            0 :   map.get_regs();
     754            0 :   const std::vector<uint32_t> regs = map.get_regs();
     755            0 :   const size_t nRegs = regs.size();
     756              : 
     757            0 :   uint16_t adc_sync_status = 0xFFFF;
     758              : 
     759            0 :   for (unsigned iSPIWrite = 0; iSPIWrite < 2; iSPIWrite++) {
     760            0 :     WriteFEMB(iFEMB, "STREAM_AND_ADC_DATA_EN", 0); // Turn off STREAM_EN and ADC_DATA_EN
     761            0 :     sleep(0.1);
     762              : 
     763            0 :     std::cout << "ASIC SPI Write Registers..." << std::endl;
     764            0 :     for (size_t iReg = 0; iReg < nRegs; iReg++) {
     765            0 :       WriteFEMB(iFEMB, REG_SPI_BASE_WRITE + iReg, regs[iReg]);
     766            0 :       sleep(0.01);
     767              :     }
     768              : 
     769              :     // run the SPI programming
     770            0 :     sleep(0.1);
     771            0 :     WriteFEMB(iFEMB, "WRITE_ASIC_SPI", 1);
     772            0 :     sleep(0.1);
     773              : 
     774            0 :     if (iSPIWrite == 1) {
     775              :       // Now check readback
     776              :       bool spi_mismatch = false;
     777            0 :       for (unsigned iSPIRead = 0; iSPIRead < 2; iSPIRead++) {
     778            0 :         std::cout << "ASIC SPI Readback..." << std::endl;
     779            0 :         std::vector<uint32_t> regsReadback(nRegs);
     780            0 :         for (size_t iReg = 0; iReg < nRegs; iReg++) {
     781            0 :           uint32_t regReadback = ReadFEMB(iFEMB, REG_SPI_BASE_READ + iReg);
     782            0 :           regsReadback[iReg] = regReadback;
     783            0 :           sleep(0.01);
     784              :         }
     785              : 
     786              :         bool verbose = false;
     787              :         if (verbose)
     788              :           std::cout << "ASIC SPI register number, write val, read val:" << std::endl;
     789              :         spi_mismatch = false;
     790            0 :         for (size_t iReg = 0; iReg < nRegs; iReg++) {
     791            0 :           if (verbose) {
     792              :             std::cout << std::dec << std::setfill(' ') << std::setw(3) << iReg << "  " << std::hex << std::setfill('0')
     793              :                       << std::setw(8) << regs[iReg] << "  " << std::hex << std::setfill('0') << std::setw(8)
     794              :                       << regsReadback[iReg] << std::endl;
     795              :           } // if verbose
     796            0 :           if (regs[iReg] != regsReadback[iReg]) {
     797            0 :             spi_mismatch = true;
     798            0 :             size_t asicFailNum = 0;
     799            0 :             if (iReg > 0)
     800            0 :               asicFailNum = (iReg - 1) / 9;
     801            0 :             std::cout << "FE-ADC ASIC " << asicFailNum << " SPI faled" << std::endl;
     802              :           } // if regs don't match
     803              :         } // for iReg
     804            0 :         if (!spi_mismatch)
     805              :           break;
     806            0 :       } // for iSPIRead
     807            0 :       if (spi_mismatch) {
     808            0 :         if (ContinueOnFEMBSPIError) {
     809            0 :           std::cout << "FEMB ASIC SPI readback mismatch--problems communicating with ASICs for FEMB: " << int(iFEMB)
     810            0 :                     << std::endl;
     811              :         } else {
     812            0 :           BUException::FEMB_SPI_READBACK_MISMATCH e;
     813            0 :           std::stringstream expstr;
     814            0 :           expstr << " for FEMB: " << int(iFEMB);
     815            0 :           e.Append(expstr.str().c_str());
     816            0 :           throw e;
     817            0 :         }
     818              :       } // if spi_mismatch
     819              :     } // if iSPIWrite == 1
     820            0 :     sleep(0.1);
     821              : 
     822            0 :     WriteFEMB(iFEMB, "STREAM_AND_ADC_DATA_EN", 9); // STREAM_EN and ADC_DATA_EN
     823            0 :     sleep(0.05);
     824            0 :     WriteFEMB(iFEMB, "STREAM_AND_ADC_DATA_EN", 9); // STREAM_EN and ADC_DATA_EN
     825            0 :     sleep(0.1);
     826              : 
     827            0 :     adc_sync_status = (uint16_t)ReadFEMB(iFEMB, "ADC_ASIC_SYNC_STATUS");
     828              : 
     829              :     // The real sync check can happen here in Shanshan's code
     830              : 
     831              :   } // for iSPIWrite
     832              : 
     833            0 :   return adc_sync_status;
     834            0 : }
     835              : 
     836              : uint16_t
     837            0 : WIB::SetupASICPulserBits(uint8_t iFEMB)
     838              : {
     839              : 
     840            0 :   const uint32_t REG_SPI_BASE_WRITE = 0x200; // 512
     841            0 :   const uint32_t REG_SPI_BASE_READ = 0x250;  // 592
     842            0 :   uint16_t adc_sync_status = 0xFFFF;
     843              : 
     844            0 :   size_t nASICs = 8;
     845            0 :   unsigned nTries = 3;
     846            0 :   for (unsigned iSPIWrite = 0; iSPIWrite < nTries; iSPIWrite++) {
     847            0 :     WriteFEMB(iFEMB, "STREAM_AND_ADC_DATA_EN", 0); // Turn off STREAM_EN and ADC_DATA_EN
     848            0 :     sleep(0.1);
     849              : 
     850            0 :     std::cout << "ASIC SPI Write Registers..." << std::endl;
     851              : 
     852            0 :     uint8_t value = 0x2;
     853            0 :     uint8_t mask = 0x3;
     854            0 :     uint8_t pos = 24;
     855            0 :     std::vector<uint32_t> vals(nASICs);
     856            0 :     for (size_t iASIC = 0; iASIC < nASICs; iASIC++) {
     857            0 :       uint32_t address = (REG_SPI_BASE_WRITE + 9 * iASIC + 8);
     858            0 :       std::cout << "Writing address " << std::hex << std::setfill('0') << std::setw(8) << address << std::endl;
     859              :       // WriteFEMBBits(iFEMB, address, pos, mask, value);
     860              : 
     861              :       // Bit-wise calculation of register val
     862            0 :       uint32_t shiftVal = value & mask;
     863            0 :       uint32_t regMask = (mask << pos);
     864            0 :       uint32_t initVal = ReadFEMB(iFEMB, address);
     865            0 :       uint32_t newVal = ((initVal & ~(regMask)) | (shiftVal << pos));
     866            0 :       vals[iASIC] = newVal;
     867            0 :       WriteFEMB(iFEMB, address, newVal);
     868              : 
     869            0 :       sleep(0.01);
     870              :     }
     871              : 
     872              :     // run the SPI programming
     873            0 :     sleep(0.1);
     874            0 :     WriteFEMB(iFEMB, "WRITE_ASIC_SPI", 1);
     875            0 :     sleep(0.1);
     876              : 
     877            0 :     if (iSPIWrite == nTries - 1) {
     878              :       // Now check readback
     879              :       bool spi_mismatch = false;
     880            0 :       for (unsigned iSPIRead = 0; iSPIRead < 2; iSPIRead++) {
     881            0 :         std::cout << "ASIC SPI Readback..." << std::endl;
     882            0 :         std::vector<uint32_t> regsReadback(nASICs);
     883            0 :         for (size_t iASIC = 0; iASIC < nASICs; iASIC++) {
     884            0 :           uint32_t regReadback = ReadFEMB(iFEMB, (REG_SPI_BASE_READ + 9 * iASIC + 8));
     885            0 :           regsReadback[iASIC] = regReadback;
     886            0 :           sleep(0.01);
     887              :         }
     888              : 
     889            0 :         std::cout << "ASIC SPI register number, write val, read val:" << std::endl;
     890              :         spi_mismatch = false;
     891            0 :         for (size_t iASIC = 0; iASIC < nASICs; iASIC++) {
     892            0 :           std::cout << std::dec << std::setfill(' ') << std::setw(3) << iASIC << "  " << std::hex << std::setfill('0')
     893            0 :                     << std::setw(8) << vals[iASIC] << "  " << std::hex << std::setfill('0') << std::setw(8)
     894            0 :                     << regsReadback[iASIC] << std::endl;
     895            0 :           if (vals[iASIC] != regsReadback[iASIC]) {
     896            0 :             spi_mismatch = true;
     897            0 :             size_t asicFailNum = 0;
     898            0 :             if (iASIC > 0)
     899            0 :               asicFailNum = (iASIC - 1);
     900            0 :             std::cout << "FE-ADC ASIC " << asicFailNum << " SPI faled" << std::endl;
     901              :           } // if regs don't match
     902              :         } // for iReg
     903            0 :         if (!spi_mismatch)
     904              :           break;
     905            0 :       } // for iSPIRead
     906            0 :       if (spi_mismatch) {
     907            0 :         BUException::WIB_ERROR e;
     908            0 :         e.Append("SPI programming failure");
     909            0 :         throw e;
     910            0 :       } // if spi_mismatch
     911              :     } // if iSPIWrite == 1
     912            0 :     sleep(0.1);
     913              : 
     914            0 :     WriteFEMB(iFEMB, "STREAM_AND_ADC_DATA_EN", 9); // STREAM_EN and ADC_DATA_EN
     915            0 :     sleep(0.05);
     916            0 :     WriteFEMB(iFEMB, "STREAM_AND_ADC_DATA_EN", 9); // STREAM_EN and ADC_DATA_EN
     917            0 :     sleep(0.1);
     918              : 
     919            0 :     adc_sync_status = (uint16_t)ReadFEMB(iFEMB, "ADC_ASIC_SYNC_STATUS");
     920              : 
     921              :     // The real sync check can happen here in Shanshan's code
     922              : 
     923            0 :   } // for iSPIWrite
     924              : 
     925            0 :   return adc_sync_status;
     926              : }
     927              : 
     928              : void
     929            0 : WIB::SetupFPGAPulser(uint8_t iFEMB, uint8_t dac_val)
     930              : {
     931            0 :   std::cout << "FEMB " << int(iFEMB) << " Configuring FPGA pulser with DAC value: " << int(dac_val) << std::endl;
     932              : 
     933            0 :   WriteFEMB(iFEMB, "ASIC_TP_EN", 0);
     934            0 :   WriteFEMB(iFEMB, "FPGA_TP_EN", 1);
     935              : 
     936            0 :   WriteFEMB(iFEMB, "DAC_SELECT", 1);
     937            0 :   WriteFEMB(iFEMB, "TEST_PULSE_AMPLITUDE", dac_val);
     938            0 :   WriteFEMB(iFEMB, "TEST_PULSE_DELAY", 219);
     939            0 :   WriteFEMB(iFEMB, "TEST_PULSE_PERIOD", 497);
     940              : 
     941            0 :   WriteFEMB(iFEMB, "INT_TP_EN", 0);
     942            0 :   WriteFEMB(iFEMB, "EXT_TP_EN", 1);
     943            0 : }
     944              : 
     945              : void
     946            0 : WIB::SetupInternalPulser(uint8_t iFEMB)
     947              : {
     948            0 :   std::cout << "FEMB " << int(iFEMB) << " Configuring internal pulser" << std::endl;
     949              : 
     950            0 :   WriteFEMB(iFEMB, "DAC_SELECT", 0);
     951            0 :   WriteFEMB(iFEMB, "TEST_PULSE_AMPLITUDE", 0);
     952            0 :   WriteFEMB(iFEMB, "TEST_PULSE_DELAY", 219);
     953            0 :   WriteFEMB(iFEMB, "TEST_PULSE_PERIOD", 497);
     954              : 
     955            0 :   WriteFEMB(iFEMB, "INT_TP_EN", 0);
     956            0 :   WriteFEMB(iFEMB, "EXT_TP_EN", 1);
     957              : 
     958            0 :   WriteFEMB(iFEMB, "FPGA_TP_EN", 0);
     959            0 :   WriteFEMB(iFEMB, "ASIC_TP_EN", 1);
     960            0 : }
     961              : 
     962              : void
     963            0 : WIB::WriteFEMBPhase(uint8_t iFEMB, uint16_t clk_phase_data)
     964              : {
     965              : 
     966            0 :   uint32_t clk_phase_data0 = (clk_phase_data >> 8) & 0xFF;
     967            0 :   uint32_t clk_phase_data1 = clk_phase_data & 0xFF;
     968              : 
     969            0 :   uint32_t data;
     970            0 :   uint32_t read_back;
     971            0 :   int count = 0;
     972            0 :   sleep(0.001);
     973            0 :   for (int i = 0; i < 10; ++i) {
     974              : 
     975            0 :     data = (~(clk_phase_data0)) & 0xFF;
     976            0 :     WriteFEMB(iFEMB, 6, data);
     977            0 :     sleep(0.001);
     978            0 :     read_back = ReadFEMB(iFEMB, 6);
     979            0 :     sleep(0.001);
     980            0 :     if ((read_back & 0xFF) == ((~(clk_phase_data0)) & 0xFF)) {
     981              :       break;
     982              :     } else {
     983            0 :       count++;
     984              :     }
     985              :   }
     986            0 :   if (count >= 10) {
     987            0 :     std::cout << "readback val for 0 is different from written data " << std::endl;
     988              :     // Put in system exit?
     989              :   }
     990              :   count = 0;
     991            0 :   for (int i = 0; i < 10; ++i) {
     992              : 
     993            0 :     data = (~(clk_phase_data1)) & 0xFF;
     994            0 :     WriteFEMB(iFEMB, 15, data);
     995            0 :     sleep(0.001);
     996            0 :     read_back = ReadFEMB(iFEMB, 15);
     997            0 :     sleep(0.001);
     998            0 :     if ((read_back & 0xFF) == ((~(clk_phase_data1)) & 0xFF)) {
     999              :       break;
    1000              :     } else {
    1001            0 :       count++;
    1002              :     }
    1003              :   }
    1004            0 :   if (count >= 10) {
    1005            0 :     std::cout << "readback val for 1 is different from written data " << std::endl;
    1006              :     // Put in system exit?
    1007              :   }
    1008              :   count = 0;
    1009            0 :   for (int i = 0; i < 10; ++i) {
    1010              : 
    1011            0 :     data = clk_phase_data0;
    1012            0 :     WriteFEMB(iFEMB, 6, data);
    1013            0 :     sleep(0.001);
    1014              : 
    1015            0 :     read_back = ReadFEMB(iFEMB, 6);
    1016            0 :     sleep(0.001);
    1017            0 :     if ((read_back & 0xFF) == ((clk_phase_data0) & 0xFF)) {
    1018              :       break;
    1019              :     } else {
    1020            0 :       count++;
    1021              :     }
    1022              :   }
    1023            0 :   if (count >= 10) {
    1024            0 :     std::cout << "readback val for 2 is different from written data " << std::endl;
    1025              :     // Put in system exit?
    1026              :   }
    1027              :   count = 0;
    1028            0 :   for (int i = 0; i < 10; ++i) {
    1029              : 
    1030            0 :     data = clk_phase_data1;
    1031            0 :     WriteFEMB(iFEMB, 15, data);
    1032            0 :     sleep(0.001);
    1033              : 
    1034            0 :     read_back = ReadFEMB(iFEMB, 6);
    1035            0 :     sleep(0.001);
    1036            0 :     if ((read_back & 0xFF) == ((clk_phase_data1) & 0xFF)) {
    1037              :       break;
    1038              :     } else {
    1039            0 :       count++;
    1040              :     }
    1041              :   }
    1042            0 :   if (count >= 10) {
    1043            0 :     std::cout << "readback val for 3 is different from written data " << std::endl;
    1044              :     // Put in system exit?
    1045              :   }
    1046            0 : }
    1047              : 
    1048              : bool
    1049            0 : WIB::TryFEMBPhases(uint8_t iFEMB, std::vector<uint16_t> phases)
    1050              : {
    1051              : 
    1052            0 :   size_t nPhases = phases.size();
    1053            0 :   std::cout << "Searching " << nPhases << " sets of phases:" << std::endl;
    1054            0 :   for (size_t ip = 0; ip < nPhases; ++ip) {
    1055            0 :     uint16_t phase = phases.at(ip);
    1056            0 :     std::cout << "Set " << ip << std::endl;
    1057            0 :     std::cout << "\t Phase: " << std::hex << std::setw(4) << phase << std::endl;
    1058              : 
    1059            0 :     WriteFEMBPhase(iFEMB, phase);
    1060              :     // If it made it this far, it found the correct readback val
    1061            0 :     sleep(0.001);
    1062            0 :     uint32_t adc_fifo_sync = (ReadFEMB(iFEMB, 6) & 0xFFFF0000) >> 16;
    1063            0 :     sleep(0.001);
    1064            0 :     adc_fifo_sync = (ReadFEMB(iFEMB, 6) & 0xFFFF0000) >> 16;
    1065            0 :     sleep(0.001);
    1066              : 
    1067            0 :     std::cout << "FEMB " << int(iFEMB) << " ADC FIFO sync: " << std::bitset<16>(adc_fifo_sync) << std::endl;
    1068              : 
    1069            0 :     if (adc_fifo_sync == 0) {
    1070            0 :       std::cout << "FEMB " << int(iFEMB) << " ADC FIFO synced" << std::endl;
    1071            0 :       std::cout << "  phase:   " << std::hex << std::setw(4) << std::setfill('0') << (uint32_t)phase << std::endl;
    1072            0 :       return true;
    1073              :     }
    1074              :   }
    1075              : 
    1076              :   // std::cout << "Could not find successful phase" << std::endl;
    1077              :   return false;
    1078              : }
    1079              : 
    1080              : bool
    1081            0 : WIB::HuntFEMBPhase(uint8_t iFEMB, uint16_t clk_phase_data_start)
    1082              : {
    1083            0 :   uint32_t clk_phase_data0 = (clk_phase_data_start >> 8) & 0xFF;
    1084            0 :   uint32_t clk_phase_data1 = clk_phase_data_start & 0xFF;
    1085            0 :   uint32_t adc_fifo_sync = 1;
    1086              : 
    1087            0 :   uint32_t a_cs[8] = { 0xc000, 0x3000, 0x0c00, 0x0300, 0x00c0, 0x0030, 0x000c, 0x0003 };
    1088              : 
    1089            0 :   uint32_t a_mark[8] = { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 };
    1090              : 
    1091            0 :   uint32_t a_cnt[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
    1092              : 
    1093            0 :   while (adc_fifo_sync) {
    1094            0 :     sleep(0.001);
    1095            0 :     adc_fifo_sync = (ReadFEMB(iFEMB, 6) & 0xFFFF0000) >> 16;
    1096            0 :     sleep(0.001);
    1097            0 :     adc_fifo_sync = (ReadFEMB(iFEMB, 6) & 0xFFFF0000) >> 16;
    1098            0 :     sleep(0.001);
    1099              : 
    1100            0 :     std::cout << "FEMB " << int(iFEMB) << " ADC FIFO sync: " << std::bitset<16>(adc_fifo_sync) << std::endl;
    1101              : 
    1102            0 :     if (adc_fifo_sync == 0) {
    1103            0 :       std::cout << "FEMB " << int(iFEMB) << " Successful SPI config and ADC FIFO synced" << std::endl;
    1104              :       // std::cout << "  ADC_ASIC_CLK_PHASE_SELECT:   " << std::hex << std::setw(2) << std::setfill('0') <<
    1105              :       // clk_phase_data0 << std::endl; std::cout << "  ADC_ASIC_CLK_PHASE_SELECT_2: " << std::hex << std::setw(2) <<
    1106              :       // std::setfill('0') << clk_phase_data1 << std::endl;
    1107            0 :       std::cout << "  phase:   " << std::hex << std::setw(2) << std::setfill('0') << clk_phase_data0;
    1108            0 :       std::cout << std::hex << std::setw(2) << std::setfill('0') << clk_phase_data1 << std::endl;
    1109            0 :       return true;
    1110              :     } else {
    1111            0 :       std::cout << "ERROR: sync not zero: " << std::bitset<16>(adc_fifo_sync) << std::endl;
    1112            0 :       for (int i = 0; i < 8; ++i) {
    1113            0 :         uint32_t a = adc_fifo_sync & a_cs[i];
    1114            0 :         uint32_t a_mark_xor = 0;
    1115            0 :         if (a != 0) {
    1116            0 :           a_cnt[i]++;
    1117            0 :           a_mark_xor = a_mark[i] ^ 0xFF;
    1118            0 :           if (a_cnt[i] == 1 || a_cnt[i] == 3) {
    1119            0 :             clk_phase_data0 = ((clk_phase_data0 & a_mark[i]) ^ a_mark[i]) + (clk_phase_data0 & a_mark_xor);
    1120            0 :           } else if (a_cnt[i] == 2 || a_cnt[i] == 4) {
    1121            0 :             clk_phase_data1 = ((clk_phase_data1 & a_mark[i]) ^ a_mark[i]) + (clk_phase_data1 & a_mark_xor);
    1122            0 :           } else if (a_cnt[i] >= 5) {
    1123              :             return false;
    1124              :           }
    1125              :         } else {
    1126            0 :           continue;
    1127              :         }
    1128              :       }
    1129            0 :       uint16_t clk_phase_to_write = 0;
    1130            0 :       clk_phase_to_write |= (clk_phase_data0 & 0xFF) << 8;
    1131            0 :       clk_phase_to_write |= clk_phase_data1;
    1132            0 :       WriteFEMBPhase(iFEMB, clk_phase_to_write);
    1133              :     }
    1134              :   }
    1135              :   return false;
    1136              : }
    1137              : 
    1138              : void
    1139            0 : WIB::ConfigFEMBMode(uint8_t iFEMB,
    1140              :                     uint32_t pls_cs,
    1141              :                     uint32_t dac_sel,
    1142              :                     uint32_t fpga_dac,
    1143              :                     uint32_t asic_dac,
    1144              :                     uint32_t mon_cs = 0)
    1145              : {
    1146            0 :   uint32_t tp_sel;
    1147            0 :   if (mon_cs == 0) {
    1148            0 :     tp_sel = ((asic_dac & 0x01) << 1) + (fpga_dac & 0x01) + ((dac_sel & 0x1) << 8);
    1149              :   } else {
    1150              :     tp_sel = 0x402;
    1151              :   }
    1152            0 :   WriteFEMB(iFEMB, 16, tp_sel & 0x0000FFFF);
    1153            0 :   WriteFEMB(iFEMB, 18, 0x11);
    1154            0 :   uint32_t pls_cs_value = 0x00;
    1155            0 :   if (pls_cs == 0)
    1156              :     pls_cs_value = 0x11; // disable all
    1157            0 :   else if (pls_cs == 1)
    1158              :     pls_cs_value = 0x10; // internal pls
    1159            0 :   else if (pls_cs == 2)
    1160            0 :     pls_cs_value = 0x01; // external pls
    1161              : 
    1162            0 :   WriteFEMB(iFEMB, 18, pls_cs_value);
    1163            0 : }
    1164              : 
    1165              : void
    1166            0 : WIB::SetContinueOnFEMBRegReadError(bool enable)
    1167              : {
    1168            0 :   ContinueOnFEMBRegReadError = enable;
    1169            0 : }
    1170              : 
    1171              : void
    1172            0 : WIB::SetContinueOnFEMBSPIError(bool enable)
    1173              : {
    1174            0 :   ContinueOnFEMBSPIError = enable;
    1175            0 : }
    1176              : 
    1177              : void
    1178            0 : WIB::SetContinueOnFEMBSyncError(bool enable)
    1179              : {
    1180            0 :   ContinueOnFEMBSyncError = enable;
    1181            0 : }
    1182              : 
    1183              : void
    1184            0 : WIB::SetContinueIfListOfFEMBClockPhasesDontSync(bool enable)
    1185              : {
    1186            0 :   ContinueIfListOfFEMBClockPhasesDontSync = enable;
    1187            0 : }
        

Generated by: LCOV version 2.0-1