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 : }
|