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 % 674 0
Test Date: 2025-12-21 13:07:08 Functions: 0.0 % 16 0

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

Generated by: LCOV version 2.0-1