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