spirack 0.2.9__tar.gz → 0.2.12__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (32) hide show
  1. {spirack-0.2.9 → spirack-0.2.12}/PKG-INFO +1 -1
  2. spirack-0.2.12/spirack/D4a_module.py +1155 -0
  3. spirack-0.2.12/spirack/version.py +1 -0
  4. {spirack-0.2.9 → spirack-0.2.12}/spirack.egg-info/PKG-INFO +1 -1
  5. {spirack-0.2.9 → spirack-0.2.12}/spirack.egg-info/SOURCES.txt +1 -0
  6. spirack-0.2.9/spirack/version.py +0 -1
  7. {spirack-0.2.9 → spirack-0.2.12}/LICENSE +0 -0
  8. {spirack-0.2.9 → spirack-0.2.12}/README.md +0 -0
  9. {spirack-0.2.9 → spirack-0.2.12}/setup.cfg +0 -0
  10. {spirack-0.2.9 → spirack-0.2.12}/setup.py +0 -0
  11. {spirack-0.2.9 → spirack-0.2.12}/spirack/B1b_module.py +0 -0
  12. {spirack-0.2.9 → spirack-0.2.12}/spirack/B2b_module.py +0 -0
  13. {spirack-0.2.9 → spirack-0.2.12}/spirack/D4_module.py +0 -0
  14. {spirack-0.2.9 → spirack-0.2.12}/spirack/D4b_module.py +0 -0
  15. {spirack-0.2.9 → spirack-0.2.12}/spirack/D5a_module.py +0 -0
  16. {spirack-0.2.9 → spirack-0.2.12}/spirack/D5b_module.py +0 -0
  17. {spirack-0.2.9 → spirack-0.2.12}/spirack/F1d_module.py +0 -0
  18. {spirack-0.2.9 → spirack-0.2.12}/spirack/M2j_module.py +0 -0
  19. {spirack-0.2.9 → spirack-0.2.12}/spirack/M2p_module.py +0 -0
  20. {spirack-0.2.9 → spirack-0.2.12}/spirack/P2d_module.py +0 -0
  21. {spirack-0.2.9 → spirack-0.2.12}/spirack/S4g_module.py +0 -0
  22. {spirack-0.2.9 → spirack-0.2.12}/spirack/S5i_module.py +0 -0
  23. {spirack-0.2.9 → spirack-0.2.12}/spirack/S5k_module.py +0 -0
  24. {spirack-0.2.9 → spirack-0.2.12}/spirack/S5l_module.py +0 -0
  25. {spirack-0.2.9 → spirack-0.2.12}/spirack/U1c_module.py +0 -0
  26. {spirack-0.2.9 → spirack-0.2.12}/spirack/U2_module.py +0 -0
  27. {spirack-0.2.9 → spirack-0.2.12}/spirack/__init__.py +0 -0
  28. {spirack-0.2.9 → spirack-0.2.12}/spirack/chip_mode.py +0 -0
  29. {spirack-0.2.9 → spirack-0.2.12}/spirack/spi_rack.py +0 -0
  30. {spirack-0.2.9 → spirack-0.2.12}/spirack.egg-info/dependency_links.txt +0 -0
  31. {spirack-0.2.9 → spirack-0.2.12}/spirack.egg-info/requires.txt +0 -0
  32. {spirack-0.2.9 → spirack-0.2.12}/spirack.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: spirack
3
- Version: 0.2.9
3
+ Version: 0.2.12
4
4
  Summary: Drivers for the QuTech SPI-rack
5
5
  Home-page: https://github.com/mtiggelman/SPI-rack
6
6
  Author: Marijn Tiggelman
@@ -0,0 +1,1155 @@
1
+ """ADC module D4a interface
2
+
3
+ SPI Rack interface code for the D4 module.
4
+
5
+ Example:
6
+ Example use: ::
7
+ D4a = spirack.D4a_modules(SPI_Rack1, 5)
8
+
9
+ Code version: 10
10
+ """
11
+
12
+ from .chip_mode import AD7175_MODE, AD7175_SPEED # for ADC
13
+ from .chip_mode import HCT595_MODE, HCT595_SPEED # for SR (shift register)
14
+ from .chip_mode import BICPINS_SPEED # for GPIO
15
+ import time
16
+
17
+ class D4a_module(object):
18
+ """D4a module interface class
19
+
20
+ This class does the low level interfacing with the D4a module. When creating
21
+ an instance, it requires a SPI_rack class passed as a parameter.
22
+
23
+ The module contains two independent 24-bit analog to digital converters. They
24
+ can be individually configured and triggered. The filter settings determine
25
+ the data rate and resolution. For an overview of settings, see the website.
26
+
27
+ Attributes:
28
+ module (int): module number set by the user (must coincide with hardware)
29
+ filter_setting (int): current filter setting
30
+ filter_type (string): filter type, either sinc3 or sinc5
31
+ """
32
+
33
+ def __init__(self, spi_rack, module, switch_delay = 0.1, initialize = 1):
34
+ """Inits D4a module class
35
+
36
+ The D4a_module class needs an SPI_rack object at initiation. All
37
+ communication will run via that class. At initialization the ADC filters
38
+ will be set to 'sinc3' at 16.67 SPS.
39
+
40
+ Args:
41
+ spi_rack (SPI_rack object): SPI_rack class object via which the communication runs
42
+ module (int): module number set on the hardware
43
+ """
44
+ self.file = os.path.abspath(__file__)
45
+ print("D4a initialized.\nPath to D4a file is", self.file,"\n") # debug only
46
+
47
+ self.module = module
48
+ self.spi_rack = spi_rack
49
+
50
+ self.reg = AD7175_registers
51
+
52
+ self.filter_setting = None
53
+ self.filter_type = None
54
+
55
+ # remote_settings is a byte containing settings
56
+ # for overload (OL), feedback (FB) and the muxes (1P4T switches).
57
+ # The bit order corresponds to the connectivity of the Shift-Regsiter outputs
58
+ # Bits are:
59
+ #
60
+ # 7 (msb) 6 5 4 3 2 1 0 (lsb)
61
+ #
62
+ # SWB_A0 SWB_A1_0 B_OL SWB_A1_1 SWT_A1_1 SWT_A0 SWT_A1_0 T_OL
63
+ # "Bottom" "Bottom" "Bottom" "Bottom" "Top" "Top" "Top" "Top"
64
+ # 1 0 0 0 0 1 0 0
65
+ #
66
+ self.remote_settings = 0x42 # 0b 0100 0010
67
+ self.spi_rack.write_data(self.module, 2, HCT595_MODE, HCT595_SPEED, bytearray([self.remote_settings]))
68
+
69
+ self.bic_sync_value = 0 # initializing to no sync given
70
+
71
+ self._default_setup() # cont. mode, single cycle, chnn 0 and set-up 0, AIN3-vs-AIN2
72
+
73
+ for adc in range(0, 2):
74
+
75
+ # Check communication with the ADC
76
+ print("\nChecking communication with ADC",adc,":")
77
+ Received_ID = self.get_ADC_ID(adc)
78
+ print(" ADC ID is",Received_ID,
79
+ ",",hex(Received_ID),".\n",
80
+ " The expected value is 3294 , 0xCDX.")
81
+
82
+ # Set filter to sinc3 and 20
83
+ self.set_filter(adc, 'sinc3', 20)
84
+
85
+ # Disable sync mode
86
+ self.configure_sync_mode(adc, 0)
87
+
88
+ # Turn off over-load indicators
89
+ self.config_led(adc, 0)
90
+
91
+ self.SR_OEb = 0 # initializing the SR output_enable\ to 'enabled'
92
+ self.set_output_enable(self.SR_OEb)
93
+
94
+ def continuous_conversion_trig_and_read(self, adc):
95
+ """Perform a conversion
96
+
97
+ Performs a conversion on the given ADC. It will both trigger the ADC and
98
+ wait for the result. Because of this it will block all other operations.
99
+
100
+ Args:
101
+ adc (int:0-1): ADC to perform the conversion
102
+ """
103
+ self.launch_continuous_conversion(adc)
104
+ return self.get_finalized_result(adc)
105
+
106
+ def single_conversion_trig_and_read(self, adc):
107
+ """Perform a true-single conversion
108
+
109
+ Performs a conversion on the given ADC. It will both trigger the ADC for one
110
+ conversion only (single- vs. continuous-mode ) and wait for its result.
111
+ Because of this it will block all other operations.
112
+
113
+ Args:
114
+ adc (int:0-1): ADC to perform the conversion
115
+ """
116
+ self.launch_one_conversion(adc)
117
+ return self.get_finalized_result(adc)
118
+
119
+ def launch_continuous_conversion(self, adc):
120
+ """Triggers a continuous conversion
121
+
122
+ Triggers a conversion on the given ADC. Does not wait for the result. This
123
+ should be used if multiple devices/adcs need to convert in parallel. After the conversion
124
+ is done it will immediately continue doing conversions and updating the
125
+ output.
126
+
127
+ Args:
128
+ adc (int:0-1): ADC to perform the conversion
129
+ """
130
+ self._write_data_16(adc, self.reg.adcMODE_REG,
131
+ (0<<self.reg.MODE) |
132
+ (1<<self.reg.SING_CYC))
133
+
134
+ def launch_one_conversion(self, adc):
135
+ """Triggers a single conversion
136
+
137
+ Args:
138
+ adc (int:0-1): ADC to perform the conversion
139
+ """
140
+ self._write_data_16(adc, self.reg.adcMODE_REG,
141
+ (1<<self.reg.MODE) |
142
+ (1<<self.reg.SING_CYC))
143
+
144
+ def get_finalized_result(self, adc):
145
+ """Returns the result of a conversion
146
+
147
+ Returns the result from an executed conversion. The function will wait until the
148
+ result is present, therefore it will block all other operations.
149
+
150
+ It will return the last conversion result. If the time between the launching the conversion
151
+ and reading the result is too long, the result may be of a second/third conversion. (in
152
+ continuous mode, where the ADC keeps converting and updating the data output)
153
+
154
+ Args:
155
+ adc (int:0-1): ADC to readout
156
+ Returns:
157
+ ADC measured voltage (float)
158
+ """
159
+ self.wait_for_data(adc)
160
+ raw_res = self.force_immediate_read_out(adc)
161
+ checked_res = self.overload_check(adc, raw_res)
162
+ return checked_res
163
+
164
+ def wait_for_data(self, adc):
165
+ """Pauses further execution until current conversion is completed
166
+ """
167
+ running = True
168
+ while running:
169
+ status = self._read_RDYb_bit(adc)
170
+ # if new data available:
171
+ if status == 0:
172
+ running = False
173
+ return
174
+
175
+ def _read_RDYb_bit(self, adc):
176
+ """reads out the RDYb bit from the specified ADC
177
+ """
178
+ status = self._read_data(adc, self.reg.STATUS_REG, 1)
179
+ RDYb = status[0]&0x80
180
+ return RDYb
181
+
182
+ def force_immediate_read_out(self, adc):
183
+ """Reads the ADC data output register, regardless of its RDY/complete status
184
+
185
+ Get raw data, shift it to correct place, and convert to voltage
186
+ Args:
187
+ adc (int:0-1): ADC to readout
188
+ Returns:
189
+ ADC measured voltage (float)
190
+ force_read_out = force_get_results
191
+ """
192
+ raw_data = self._read_data(adc, self.reg.DATA_REG, 3)
193
+ raw_data = raw_data[1:]
194
+ raw_data_val = raw_data[0] << 16 | raw_data[1] << 8 | raw_data[2]
195
+ return self.calculate_ADC_voltage_from_ADC_binary(raw_data_val)
196
+
197
+
198
+ def calculate_ADC_voltage_from_ADC_binary(self, bin_data):
199
+ """
200
+
201
+ """
202
+ return (bin_data * 2 * 0.875 / 2**22) - 3.5 # D4a v2-1 using a 3.5V reference
203
+
204
+
205
+ def overload_check(self, adc, raw_res):
206
+ """
207
+
208
+ """
209
+ if (raw_res > 3.999999 or raw_res < -3.994):
210
+ # Indicate overload condition to user:
211
+ # print warning, turn on LED until reset by user, and replace result
212
+ print(" Warning: result", raw_res,"is outside the supported range.\n Data will be replaced by '999'")
213
+ self.config_led(adc, 1)
214
+ return 999
215
+ else:
216
+ return raw_res
217
+
218
+
219
+ def config_led(self, led, on_off):
220
+ """
221
+ """
222
+ if led not in range(2):
223
+ raise ValueError('LED number {} does not exist. Possible values are 0 and 1.'.format(adc))
224
+ if on_off not in range(2):
225
+ raise ValueError('Value {} is not legal for LED setting. Requiring a Bool value.'.format(on_off))
226
+
227
+ if (led==0):
228
+ # Setting the 'Top' mux
229
+ self.remote_settings &= 0xfe # reset SR bit 0 (T_OL)
230
+ mux_new_settings = on_off<<0 # shift new val to bit 0
231
+ elif (led==1):
232
+ # Setting the 'Bottom' mux
233
+ self.remote_settings &= 0xDf # reset SR bit 5 (B_OL)
234
+ mux_new_settings = on_off<<5 # shift new val to bit 5
235
+ self.remote_settings |= mux_new_settings
236
+ self.spi_rack.write_data(self.module, 2, HCT595_MODE, HCT595_SPEED, bytearray([self.remote_settings]))
237
+
238
+ def select_measurement_type(self, adc, measurement_type):
239
+ """Sets the D4a input-path mux
240
+ (connects the selected signal to the selected ADC)
241
+ and updates the 'remote_settings' byte
242
+
243
+ Options are 0 - GND, 1 - cal ref level , 2 - internal header pin, 3 - front-panel connector
244
+
245
+ Formerly called 'config_mux' (a.k.a. 'connect_signals_to_adc')
246
+ """
247
+ # input checks
248
+ if adc not in range(2):
249
+ raise ValueError('ADC number {} does not exist. Possible values are 0 and 1.'.format(adc))
250
+
251
+ self.measurement_types = ['single-ended calibration','differential calibration',
252
+ 'single-ended measurement','grounding',
253
+ 'back-panel single-ended measurement','back-panel complementary single-ended measurement',
254
+ 'back-panel differential measurement',
255
+ 'test_msb_is_1','test_lsb_is_1']
256
+ if measurement_type not in self.measurement_types:
257
+ raise ValueError('Measurement type \'{}\' does not exist. \nPossible values are {}.'.format(measurement_type,self.measurement_types))
258
+
259
+ print("select_measurement_type:",
260
+ "\n Instruction was given for ADC",adc,
261
+ "\n Initial SR remote_settings is",self.remote_settings,
262
+ "\n (as bits:",bin(self.remote_settings),")") # debug
263
+
264
+ if (adc==0):
265
+ # Setting the 'Top' mux
266
+ if (measurement_type=='test_lsb_is_1'):
267
+ self.remote_settings = 0x01 # testing only (used for debug)
268
+ if (measurement_type=='test_msb_is_1'):
269
+ self.remote_settings = 0x08 # testing only (used for debug)
270
+ if (measurement_type=='single-ended calibration'):
271
+ #SWT_A0,A1_0,A1_1: 0 0 0
272
+ self.remote_settings &= 0xfb # config SWT_A0 (bit 2)
273
+ self.remote_settings &= 0xfd # config SWT_A1_0 (bit 1)
274
+ self.remote_settings &= 0xf7 # config SWT_A1_1 (bit 3)
275
+ if (measurement_type=='differential calibration'):
276
+ #SWT_A0,A1_0,A1_1: 0 0 1
277
+ self.remote_settings &= 0xfb # config SWT_A0 (bit 2)
278
+ self.remote_settings &= 0xfd # config SWT_A1_0 (bit 1)
279
+ self.remote_settings |= 0x08 # config SWT_A1_1 (bit 3)
280
+ if (measurement_type=='single-ended measurement'):
281
+ #SWT_A0,A1_0,A1_1: 0 1 0
282
+ self.remote_settings &= 0xfb # config SWT_A0 (bit 2)
283
+ self.remote_settings |= 0x02 # config SWT_A1_0 (bit 1)
284
+ self.remote_settings &= 0xf7 # config SWT_A1_1 (bit 3)
285
+ if (measurement_type=='grounding'):
286
+ #SWT_A0,A1_0,A1_1: 1 0 0
287
+ self.remote_settings |= 0x04 # config SWT_A0 (bit 2)
288
+ self.remote_settings &= 0xfd # config SWT_A1_0 (bit 1)
289
+ self.remote_settings &= 0xf7 # config SWT_A1_1 (bit 3)
290
+ if (measurement_type=='back-panel single-ended measurement'):
291
+ #SWT_A0,A1_0,A1_1: 1 1 0
292
+ self.remote_settings |= 0x04 # config SWT_A0 (bit 2)
293
+ self.remote_settings |= 0x02 # config SWT_A1_0 (bit 1)
294
+ self.remote_settings &= 0xf7 # config SWT_A1_1 (bit 3)
295
+ if (measurement_type=='back-panel complementary single-ended measurement'):
296
+ #SWT_A0,A1_0,A1_1: 1 0 1
297
+ self.remote_settings |= 0x04 # config SWT_A0 (bit 2)
298
+ self.remote_settings &= 0xfd # config SWT_A1_0 (bit 1)
299
+ self.remote_settings |= 0x08 # config SWT_A1_1 (bit 3)
300
+ if (measurement_type=='back-panel differential measurement'):
301
+ #SWT_A0,A1_0,A1_1: 1 1 1
302
+ self.remote_settings |= 0x04 # config SWT_A0 (bit 2)
303
+ self.remote_settings |= 0x02 # config SWT_A1_0 (bit 1)
304
+ self.remote_settings |= 0x08 # config SWT_A1_1 (bit 3)
305
+ if (adc==1):
306
+ # Setting the 'Bottom' mux
307
+ if (measurement_type=='test_lsb_is_1'):
308
+ self.remote_settings = 0x10 # testing only (used for debug)
309
+ if (measurement_type=='test_msb_is_1'):
310
+ self.remote_settings = 0x80 # testing only (used for debug)
311
+ if (measurement_type=='single-ended calibration'):
312
+ #SWB_A0,A1_0,A1_1: 0 0 0
313
+ self.remote_settings &= 0x7f # config SWB_A0 (bit 7)
314
+ self.remote_settings &= 0xbf # config SWB_A1_0 (bit 6)
315
+ self.remote_settings &= 0xef # config SWB_A1_1 (bit 4)
316
+ if (measurement_type=='differential calibration'):
317
+ #SWB_A0,A1_0,A1_1: 0 0 1
318
+ self.remote_settings &= 0x7f # config SWB_A0 (bit 7)
319
+ self.remote_settings &= 0xbf # config SWB_A1_0 (bit 6)
320
+ self.remote_settings |= 0x10 # config SWB_A1_1 (bit 4)
321
+ if (measurement_type=='single-ended measurement'):
322
+ #SWB_A0,A1_0,A1_1: 0 1 0
323
+ self.remote_settings &= 0x7f # config SWB_A0 (bit 7)
324
+ self.remote_settings |= 0x40 # config SWB_A1_0 (bit 6)
325
+ self.remote_settings &= 0xef # config SWB_A1_1 (bit 4)
326
+ if (measurement_type=='grounding'):
327
+ #SWB_A0,A1_0,A1_1: 1 0 0
328
+ self.remote_settings |= 0x80 # config SWB_A0 (bit 7)
329
+ self.remote_settings &= 0xbf # config SWB_A1_0 (bit 6)
330
+ self.remote_settings &= 0xef # config SWB_A1_1 (bit 4)
331
+ if (measurement_type=='back-panel single-ended measurement'):
332
+ #SWB_A0,A1_0,A1_1: 1 1 0
333
+ self.remote_settings |= 0x80 # config SWB_A0 (bit 7)
334
+ self.remote_settings |= 0x40 # config SWB_A1_0 (bit 6)
335
+ self.remote_settings &= 0xef # config SWB_A1_1 (bit 4)
336
+ if (measurement_type=='back-panel complementary single-ended measurement'):
337
+ #SWB_A0,A1_0,A1_1: 1 0 1
338
+ self.remote_settings |= 0x80 # config SWB_A0 (bit 7)
339
+ self.remote_settings &= 0xbf # config SWB_A1_0 (bit 6)
340
+ self.remote_settings |= 0x10 # config SWB_A1_1 (bit 4)
341
+ if (measurement_type=='back-panel differential measurement'):
342
+ #SWB_A0,A1_0,A1_1: 1 1 1
343
+ self.remote_settings |= 0x8f # config SWB_A0 (bit 7)
344
+ self.remote_settings |= 0x4f # config SWB_A1_0 (bit 6)
345
+ self.remote_settings |= 0x1f # config SWB_A1_1 (bit 4)
346
+
347
+ # finaly, write the data
348
+ self.spi_rack.write_data(self.module, 2, HCT595_MODE, HCT595_SPEED, bytearray([self.remote_settings]))
349
+
350
+
351
+ def select_ADC_inputs(self, adc, pos_input_name, neg_input_name):
352
+ """Set the ADCs to read from desired line
353
+
354
+ This updates the config resgisters on the ADC chip itself.
355
+
356
+ Args:
357
+ adc (int:0-1): ADC which receives the signal to sample
358
+ pos_input_name: the D4a internal signal used as the non-inverting signal
359
+ neg_input_name: the D4a internal signal used as the inverting signal
360
+ (see numbering of connectors on front-panel)
361
+ """
362
+ # input checks
363
+ if (pos_input_name == neg_input_name):
364
+ raise ValueError('Cannot set both phases to the same value. Requested set for pos_input_line and neg_input_line was {}'.format(pos_input_name))
365
+ accepted_names = ['REF-', 'REF+', 'POS', 'NEG', 'gnd']
366
+ if pos_input_name not in accepted_names:
367
+ raise ValueError('pos_input_line {} does not exist.'.format(pos_input_name))
368
+ if neg_input_name not in accepted_names:
369
+ raise ValueError('neg_input_line {} does not exist.'.format(neg_input_name))
370
+
371
+ # choosing the non-inverting ("positive") signal
372
+ if (pos_input_name=='REF-'):
373
+ # Set the ADC positive to read REF-
374
+ self.read_modify_write_CH0_AINPOS0(adc, 22)
375
+ elif (pos_input_name=='REF+'):
376
+ # Set the ADC positive to read REF+
377
+ self.read_modify_write_CH0_AINPOS0(adc, 21)
378
+ elif (pos_input_name=='NEG'):
379
+ # Set the ADC positive to read from AIN2
380
+ self.read_modify_write_CH0_AINPOS0(adc, 2)
381
+ elif (pos_input_name=='POS'):
382
+ # Set the ADC positive to read from AIN3
383
+ self.read_modify_write_CH0_AINPOS0(adc, 3)
384
+ elif (pos_input_name=='gnd'):
385
+ # Set the ADC positive to read from AIN4
386
+ self.read_modify_write_CH0_AINPOS0(adc, 4)
387
+
388
+ # choosing the inverting ("negative") signal
389
+ if (neg_input_name=='REF-'):
390
+ # Set the ADC negative to read REF-
391
+ self.read_modify_write_CH0_AINNEG0(adc, 22)
392
+ elif (neg_input_name=='REF+'):
393
+ # Set the ADC negative to read REF+
394
+ self.read_modify_write_CH0_AINNEG0(adc, 21)
395
+ elif (neg_input_name=='NEG'):
396
+ # Set the ADC negative to read from AIN2
397
+ self.read_modify_write_CH0_AINNEG0(adc, 2)
398
+ elif (neg_input_name=='POS'):
399
+ # Set the ADC negative to read from AIN3
400
+ self.read_modify_write_CH0_AINNEG0(adc, 3)
401
+ elif (neg_input_name=='gnd'):
402
+ # Set the ADC negative to read from AIN4
403
+ self.read_modify_write_CH0_AINNEG0(adc, 4)
404
+
405
+ return
406
+
407
+ def read_modify_write_CH0_AINPOS0(self, adc, adc_ain_pin):
408
+ """
409
+ """
410
+ CH0_REG_data = self._read_data(adc, self.reg.CH0_REG, 2)
411
+ CH0_REG_data = CH0_REG_data[1:]
412
+
413
+ # AINPOS0 - update
414
+ byte0 = CH0_REG_data[0]&0xfc # clear 2 lsbs
415
+ byte0_new_2msbs = ((adc_ain_pin&0x18)>>3) # calculate new 2 lsbs
416
+ byte0 |= byte0_new_2msbs # place new lsbs into the 2 lsb positions
417
+ byte1 = CH0_REG_data[1]&0x1f # clear 3 msbs
418
+ byte1_new_3lsbs = (adc_ain_pin&0x07)<<5 # calculate new 3 msbs
419
+ byte1 |= byte1_new_3lsbs # place new msbs into the 3 msb positions
420
+
421
+ wr_data = byte0<<8 | byte1
422
+ self._write_data_16(adc, self.reg.CH0_REG, wr_data)
423
+
424
+ def read_modify_write_CH0_AINNEG0(self, adc, adc_ain_pin):
425
+ """
426
+ """
427
+ CH0_REG_data = self._read_data(adc, self.reg.CH0_REG, 2)
428
+ CH0_REG_data = CH0_REG_data[1:]
429
+
430
+ # AINNEG0 - update
431
+ byte0 = CH0_REG_data[0]
432
+ byte1 = CH0_REG_data[1]&0xe0 # clear 5 lsbs
433
+ byte1_new_5lsbs = (adc_ain_pin&0x1f) # calculate new 5 lsbs
434
+ byte1 |= byte1_new_5lsbs # place new lsbs into the 5 lsb positions
435
+
436
+ wr_data = byte0<<8 | byte1
437
+ self._write_data_16(adc, self.reg.CH0_REG, wr_data)
438
+
439
+ def set_single_cycle(self, adc, sing_cyc):
440
+ """
441
+ """
442
+ # input checks
443
+ if adc not in range(2):
444
+ raise ValueError('ADC number {} does not exist. Possible values are 0 and 1.'.format(adc))
445
+ if sing_cyc not in [0,1]:
446
+ raise ValueError('The bit value {} does not exist. Possible values are 0 or 1'.format(sing_cyc))
447
+
448
+ ADCMODE_data = self._read_data(adc, self.reg.adcMODE_REG, 2)
449
+ ADCMODE_data = ADCMODE_data[1:]
450
+
451
+ byte0 = ADCMODE_data[0] & 0xdf # clear existing ref buffer setting
452
+ buf_bit = (sing_cyc & 0xff) << 5 # calculate new bit
453
+ byte0 |= buf_bit # place new bits into position
454
+ byte1 = ADCMODE_data[1]
455
+
456
+ wr_data = byte0<<8 | byte1
457
+ self._write_data_16(adc, self.reg.adcMODE_REG, wr_data)
458
+
459
+ def set_ref_input_buffers(self, adc, buf_setting):
460
+ """
461
+ """
462
+ # input checks
463
+ if adc not in range(2):
464
+ raise ValueError('ADC number {} does not exist. Possible values are 0 and 1.'.format(adc))
465
+ if buf_setting not in ['enabled','disabled']:
466
+ raise ValueError("ADC number {} does not exist. Possible values are 'enabled','disabled'".format(buf_setting[0],buf_setting[1]))
467
+
468
+ SETUPCON0_data = self._read_data(adc, self.reg.SETUPCON0_REG, 2)
469
+ SETUPCON0_data = SETUPCON0_data[1:]
470
+
471
+ if (buf_setting=='enabled'):
472
+ wr_bit = 1
473
+ elif (buf_setting=='disabled'):
474
+ wr_bit = 0
475
+ else:
476
+ print("Error")
477
+
478
+ byte0 = SETUPCON0_data[0] & 0xf3 # clear existing ref buffer setting
479
+ buf_bits = ((wr_bit*3) & 0xff) << 2 # calculate 2 new bits
480
+ byte0 |= buf_bits # place new bits into position
481
+ byte1 = SETUPCON0_data[1]
482
+
483
+ wr_data = byte0<<8 | byte1
484
+ self._write_data_16(adc, self.reg.SETUPCON0_REG, wr_data)
485
+
486
+ def set_anlg_input_buffers(self, adc, buf_setting):
487
+ """
488
+ """
489
+ # input checks
490
+ if adc not in range(2):
491
+ raise ValueError('ADC number {} does not exist. Possible values are 0 and 1.'.format(adc))
492
+ if buf_setting not in ['enabled','disabled']:
493
+ raise ValueError('ADC number {} does not exist. Possible values are {} and {}.'.format(buf_setting[0],buf_setting[1]))
494
+
495
+ SETUPCON0_data = self._read_data(adc, self.reg.SETUPCON0_REG, 2)
496
+ SETUPCON0_data = SETUPCON0_data[1:]
497
+
498
+ if (buf_setting=='enabled'):
499
+ wr_bit = 1
500
+ elif (buf_setting=='disabled'):
501
+ wr_bit = 0
502
+ else:
503
+ print("Error")
504
+
505
+ byte0 = SETUPCON0_data[0] & 0xfc # clear existing ref buffer setting
506
+ buf_bits = ((wr_bit*3) & 0xff) # calculate 2 new bits
507
+ byte0 |= buf_bits # place new bits into position
508
+ byte1 = SETUPCON0_data[1]
509
+
510
+ wr_data = byte0<<8 | byte1
511
+ self._write_data_16(adc, self.reg.SETUPCON0_REG, wr_data)
512
+
513
+ def save_remote_settings(self):
514
+ """
515
+ """
516
+ initial_settings = self.remote_settings
517
+ filter_setting = self.filter_setting
518
+ filter_type = self.filter_type
519
+ return([initial_settings, filter_setting, filter_type])
520
+
521
+ def restore_remote_settings(self, adc, initial_conditions):
522
+ """
523
+ """
524
+
525
+ # Restore remote settings
526
+ initial_settings = initial_conditions[0]
527
+ self.remote_settings = initial_settings
528
+ self.spi_rack.write_data(self.module, 2, HCT595_MODE, HCT595_SPEED, bytearray([self.remote_settings]))
529
+
530
+ # Restore filter settings
531
+ filter_setting = initial_conditions[1]
532
+ filter_type = initial_conditions[2]
533
+ self.set_filter(adc, filter_type, filter_setting)
534
+
535
+ def offset_calibration_with_module_reference(self, adc):
536
+ """Offset voltage calibration routine
537
+
538
+ Calibrates the offset of the given ADC input.
539
+ This uses the internal GND, so no need to short on front-panel.
540
+
541
+ Args:
542
+ adc (int:0-1): ADC to calibrate
543
+ """
544
+
545
+ # Save initial remote settings
546
+ initial_settings = self.remote_settings
547
+ # Save filter settings
548
+ filter_setting = self.filter_setting
549
+ filter_type = self.filter_type
550
+
551
+ # Set calibration conditions
552
+ # Setting input to GND
553
+ self.select_measurement_type(0, 'grounding')
554
+ # Set to best performance for offset calibration
555
+ self.set_filter(adc, 'sinc3', 20)
556
+
557
+ # Calibrate
558
+ # 6 is 'System offset calibration' - valid for the present channel and configuration
559
+ self._write_data_16(adc, self.reg.adcMODE_REG,
560
+ (6<<self.reg.MODE) |
561
+ (1<<self.reg.SING_CYC))
562
+ self.wait_for_data(adc)
563
+ # 0 is 'Continuous conversion mode'
564
+ self._write_data_16(adc, self.reg.adcMODE_REG,
565
+ (0<<self.reg.MODE) |
566
+ (1<<self.reg.SING_CYC))
567
+
568
+ # Restore filter settings
569
+ self.set_filter(adc, filter_type, filter_setting)
570
+ # Restore remote settings
571
+ self.remote_settings = initial_settings
572
+ self.spi_rack.write_data(self.module, 2, HCT595_MODE, HCT595_SPEED, bytearray([self.remote_settings]))
573
+
574
+ def offset_calibration_with_external_reference(self, adc):
575
+ """Offset voltage calibration routine
576
+
577
+ Calibrates the offset of the given ADC input. To run this routine, put
578
+ a short or 50 Ohm short on the input of the given ADC.
579
+
580
+ Args:
581
+ adc (int:0-1): ADC to calibrate
582
+ """
583
+ print('Make sure that ADC{} inputs are terminated with a short or 50 Ohm to GND'
584
+ 'while running this calibration!'.format(adc+1))
585
+
586
+ # Save initial conditions
587
+ initial_conditions = self.save_remote_settings()
588
+
589
+ # Set calibration conditions
590
+ # Setting input to 'single-ended measurement'
591
+ self.select_measurement_type(adc, 'single-ended measurement')
592
+ # set to best performance for offset calibration
593
+ self.set_filter(adc, 'sinc3', 20)
594
+
595
+ # Calibrate
596
+ # 6 is 'System offset calibration' - valid for the present channel and configuration
597
+ self._write_data_16(adc, self.reg.adcMODE_REG,
598
+ (6<<self.reg.MODE) |
599
+ (1<<self.reg.SING_CYC))
600
+ self.wait_for_data(adc)
601
+ # 0 is 'Continuous conversion mode'
602
+ self._write_data_16(adc, self.reg.adcMODE_REG,
603
+ (0<<self.reg.MODE) |
604
+ (1<<self.reg.SING_CYC))
605
+
606
+ # Restore initial conditions
607
+ self.restore_remote_settings(adc, initial_conditions)
608
+
609
+ def gain_calibration_with_module_reference(self, adc):
610
+ """Gain calibration routine
611
+
612
+ Calibrates the gain of the given ADC input.
613
+ This uses the in-module CAL_REF, so no need for connection on front-panel.
614
+ Sets the input-path mux to the 'CAL_REF' position,
615
+ and then restores its initial connection.
616
+
617
+ Args:
618
+ adc (int:0-1): ADC to calibrate
619
+ """
620
+ # Save initial remote settings
621
+ initial_settings = self.remote_settings
622
+ # Save filter settings
623
+ filter_setting = self.filter_setting
624
+ filter_type = self.filter_type
625
+
626
+ # Set calibration conditions
627
+ # Setting input to CAL_REF
628
+ self.select_measurement_type(0, 'single-ended calibration')
629
+
630
+ # set to best performance for offset calibration
631
+ self.set_filter(adc, 'sinc3', 20)
632
+
633
+ self._write_data_16(adc, self.reg.adcMODE_REG,
634
+ (7<<self.reg.MODE) |
635
+ (1<<self.reg.SING_CYC))
636
+ self.wait_for_data(adc)
637
+
638
+ self._write_data_16(adc, self.reg.adcMODE_REG,
639
+ (0<<self.reg.MODE) |
640
+ (1<<self.reg.SING_CYC))
641
+ #self.add_to_GAIN0(adc, -3700) # was -10900 in D4 TEMP COMMENTED
642
+
643
+ # Restore filter settings
644
+ self.set_filter(adc, filter_type, filter_setting)
645
+ # Restore remote settings
646
+ self.remote_settings = initial_settings
647
+ self.spi_rack.write_data(self.module, 2, HCT595_MODE, HCT595_SPEED, bytearray([self.remote_settings]))
648
+
649
+ def gain_calibration_with_external_reference(self, adc):
650
+ """Gain calibration routine
651
+
652
+ Calibrates the gain of the given ADC input. To run this routine, apply
653
+ 4V on the input of the given ADC using a D5a.
654
+
655
+ Args:
656
+ adc (int:0-1): ADC to calibrate
657
+ """
658
+ print('Make sure that ADC {} input is set to the experiment full-scale (using a precise voltage source)!\n',
659
+ 'For the general case use the D4a maximum scale of 3.5V.'.format(adc)) # prev. we printed 'adc' without adc+1
660
+
661
+ # Save initial conditions
662
+ initial_conditions = self.save_remote_settings()
663
+
664
+ # Set calibration conditions
665
+ # Setting input to 'single-ended measurement'
666
+ self.select_measurement_type(adc, 'single-ended measurement')
667
+
668
+ # set to best performance for offset calibration
669
+ self.set_filter(adc, 'sinc3', 20)
670
+
671
+ self._write_data_16(adc, self.reg.adcMODE_REG,
672
+ (7<<self.reg.MODE) |
673
+ (1<<self.reg.SING_CYC))
674
+ self.wait_for_data(adc)
675
+
676
+ self._write_data_16(adc, self.reg.adcMODE_REG,
677
+ (0<<self.reg.MODE) |
678
+ (1<<self.reg.SING_CYC))
679
+ #self.add_to_GAIN0(adc, -3700) # was -10900 in D4 TEMP COMMENTED
680
+
681
+ # Restore initial conditions
682
+ self.restore_remote_settings(adc, initial_conditions)
683
+
684
+ def set_GAIN0(self, adc, gain_setting):
685
+ """Set the GAIN resgiter for set-up 0
686
+ """
687
+ self._write_data_24(adc, self.reg.GAIN0_REG, gain_setting)
688
+ return
689
+
690
+ def add_to_GAIN0(self, adc, gain_incr):
691
+ """Add to the GAIN resgiter of set-up 0
692
+ """
693
+ value = self.read_GAIN0(adc)
694
+ self._write_data_24(adc, self.reg.GAIN0_REG, value+gain_incr)
695
+ return
696
+
697
+ def read_GAIN0(self, adc):
698
+ """Read the GAIN resgiter for set-up 0
699
+ """
700
+ if adc not in range(2):
701
+ raise ValueError('ADC number {} does not exist. Possible values are 0 and 1.'.format(adc))
702
+ rdata = self._read_data(adc, self.reg.GAIN0_REG, 3) # DEBUG
703
+ print(" rdata is",rdata) # DEBUG
704
+ rdata = self._read_data(adc, self.reg.GAIN0_REG, 3)[1:]
705
+ print(" The final rdata is",rdata[0], rdata[1], rdata[2], rdata) # DEBUG
706
+ value = rdata[0]<<16 | rdata[1]<<8 | rdata[2]
707
+ return value
708
+
709
+ def set_OFFSET0(self, adc, gain_setting):
710
+ """Set the OFFSET resgiter for set-up 0
711
+ """
712
+ self._write_data_24(adc, self.reg.OFFSET0_REG, gain_setting)
713
+ return
714
+
715
+ def read_OFFSET0(self, adc):
716
+ """Read the OFFSET resgiter for set-up 0
717
+ """
718
+ if adc not in range(2):
719
+ raise ValueError('ADC number {} does not exist. Possible values are 0 and 1.'.format(adc))
720
+ rdata = self._read_data(adc, self.reg.OFFSET0_REG, 3)[1:]
721
+ value = rdata[0]<<16 | rdata[1]<<8 | rdata[2]
722
+ return value
723
+
724
+ def _default_setup(self):
725
+ # Basic configuration
726
+ for adc in range(0, 2):
727
+
728
+ # adcMODE_REG:
729
+ # Mode - set continuous conversion mode
730
+ # Single cycle - only output data at filter settling rate
731
+ # Also implcitly disabling internal ref and setting the clock source to internal
732
+ self._write_data_16(adc, self.reg.adcMODE_REG,
733
+ (0<<self.reg.MODE) |
734
+ (1<<self.reg.SING_CYC))
735
+
736
+ # IFMODE_REG:
737
+ self._write_data_16(adc, self.reg.IFMODE_REG, (1<<self.reg.DOUT_RESET))
738
+
739
+ # GPIOCON_REG:
740
+ # Disable ext_synch
741
+ self._write_data_16(adc, self.reg.GPIOCON_REG,
742
+ (0<<self.reg.SYNC_EN) |
743
+ (0<<self.reg.IP_EN1) |
744
+ (0<<self.reg.IP_EN0) |
745
+ (0<<self.reg.OP_EN1) |
746
+ (0<<self.reg.OP_EN0))
747
+
748
+ # CH0_REG:
749
+ self._write_data_16(adc, self.reg.CH0_REG,
750
+ (1<<self.reg.CH_EN) |
751
+ (0<<self.reg.SETUP_SEL) |
752
+ (self.reg.AIN3<<self.reg.AINPOS) |
753
+ (self.reg.AIN2<<self.reg.AINNEG))
754
+
755
+ # CH1,2,3_REG:
756
+ self._write_data_16(adc, self.reg.CH1_REG,
757
+ (0<<self.reg.CH_EN) |
758
+ (0<<self.reg.SETUP_SEL) |
759
+ (self.reg.AIN1<<self.reg.AINPOS) |
760
+ (self.reg.AIN4<<self.reg.AINNEG))
761
+
762
+ self._write_data_16(adc, self.reg.CH2_REG,
763
+ (0<<self.reg.CH_EN) |
764
+ (0<<self.reg.SETUP_SEL) |
765
+ (self.reg.AIN2<<self.reg.AINPOS) |
766
+ (self.reg.AIN4<<self.reg.AINNEG))
767
+
768
+ self._write_data_16(adc, self.reg.CH3_REG,
769
+ (0<<self.reg.CH_EN) |
770
+ (0<<self.reg.SETUP_SEL) |
771
+ (self.reg.AIN3<<self.reg.AINPOS) |
772
+ (self.reg.AIN4<<self.reg.AINNEG))
773
+
774
+ # SETUPCON0_REG:
775
+ self._write_data_16(adc, self.reg.SETUPCON0_REG,
776
+ (1<<self.reg.BI_UNIPOLAR) |
777
+ (1<<self.reg.REFBUF0P) |
778
+ (1<<self.reg.REFBUF0M) |
779
+ (0<<self.reg.AINBUF0P) |
780
+ (0<<self.reg.AINBUF0M))
781
+
782
+ # OFFSET 0,1,2,3_REG:
783
+ self._write_data_24(adc, self.reg.OFFSET0_REG, 8388150)
784
+ self._write_data_24(adc, self.reg.OFFSET1_REG, 8388150)
785
+ self._write_data_24(adc, self.reg.OFFSET2_REG, 8388150)
786
+ self._write_data_24(adc, self.reg.OFFSET3_REG, 8388150)
787
+
788
+ # GAIN 0,1,2,3_REG:
789
+ # Set the gain such that +-3.5V is full scale. Can be overwritten by user's calibration
790
+ self._write_data_24(adc, self.reg.GAIN0_REG, 5699250)
791
+ self._write_data_24(adc, self.reg.GAIN1_REG, 5699250)
792
+ self._write_data_24(adc, self.reg.GAIN2_REG, 5699250)
793
+ self._write_data_24(adc, self.reg.GAIN3_REG, 5699250)
794
+
795
+ def set_clock_mode(self, adc, clockmode):
796
+ """Selects the Clock Mode for the ADC
797
+
798
+ """
799
+ d_clock_modes = {'IntOsc':0b00, 'IntOscToOut':0b01, 'ExtClk':0b10, 'ExtOsc':0b11}
800
+ if clockmode not in d_clock_modes:
801
+ raise ValueError('Value {} does not exist. Possible values are: {}'.format(clockmode, d_clock_modes.keys()))
802
+ self._write_data_16(self, adc, self.reg.adcMODE_REG,
803
+ (d_clock_modes[clockmode]<<self.reg.CLOCKSEL))
804
+
805
+ def set_filter(self, adc, filter_type, filter_setting):
806
+ """Sets the ADC filter
807
+
808
+ The two filter parameters determine the filter response (cutoff frequency),
809
+ the 50 Hz rejection and the resolution. See the filter table on the website
810
+ to determine which setting is correct for your application.
811
+
812
+ Args:
813
+ adc (int:0-1): ADC inside the module which needs to be set
814
+ filter_type (string): set to sinc3 or sinc5
815
+ filter_setting (int:0-20): the desired filter setting
816
+ """
817
+ filter_values = {'sinc3': 3, 'sinc5': 0}
818
+ if filter_type not in filter_values:
819
+ raise ValueError('Value {} does not exist. Possible values are: {}'.format(filter_type, filter_values))
820
+ if filter_setting not in range(21):
821
+ raise ValueError('Value {} not allowed. Possible values are from 0 to 20.'.format(filter_setting))
822
+
823
+ self._write_data_16(adc, self.reg.FILTCON0_REG,
824
+ (filter_values[filter_type]<<self.reg.ORDER0) |
825
+ (filter_setting<<self.reg.ODR))
826
+
827
+ self.filter_setting = filter_setting
828
+ self.filter_type = filter_type
829
+
830
+ def get_ADC_ID(self, adc):
831
+
832
+ # From register ID REGISTER:
833
+ # extract ID
834
+ ADC_ID_raw = self._read_data(adc, self.reg.ID_REG, 2)
835
+ ADC_ID_chopped = ADC_ID_raw[1:]
836
+ ADC_ID = (ADC_ID_chopped[0]<<8)|(ADC_ID_chopped[1])
837
+ return ADC_ID
838
+
839
+ def get_ADC_status(self, adc):
840
+ AdcState = {}
841
+
842
+ # From register ID_REG:
843
+ # extract ID
844
+ ID_REG_data = self.get_ADC_ID(adc)
845
+ print("Reading ID_REG:")
846
+ print(" ID is ", ID_REG_data)
847
+ AdcState['ID_REG']= ID_REG_data
848
+
849
+ # From register CH0_REG:
850
+ # extract CH_EN0
851
+ CH0_REG_data = self._read_data(adc, self.reg.CH0_REG, 2)
852
+ CH0_REG_data = CH0_REG_data[1:]
853
+ CH_EN0 = (CH0_REG_data[0]>>7)&0x01
854
+ AINPOS0 = ((CH0_REG_data[1]&0xe0)>>5)|((CH0_REG_data[0]&0x03)<<3)
855
+ AINNEG0 = (CH0_REG_data[1]&0x1f)
856
+ # prints for debug
857
+ print("Reading ADC{} CH0_REG:".format(adc))
858
+ print(" CH0_REG data is ", CH0_REG_data, " (or integer value of ", int.from_bytes(CH0_REG_data, byteorder='big', signed=False),")")
859
+ print(" CH0_REG's CH_EN0 is:", CH_EN0, ", AINPOS0 is:", AINPOS0, ", AINNEG0 is:", AINNEG0)
860
+ AdcState['CH_EN0']=CH_EN0
861
+ AdcState['AINPOS0']=AINPOS0
862
+ AdcState['AINNEG0']=AINNEG0
863
+
864
+ # From register adcMODE (p. 53):
865
+ # extract REF_EN, SING_CYC, MODE, CLOCKSEL
866
+ adcMODE_REG_data = self._read_data(adc, self.reg.adcMODE_REG, 2)
867
+ adcMODE_REG_data = adcMODE_REG_data[1:]
868
+ REF_EN = (adcMODE_REG_data[0]>>7)&0x01
869
+ SING_CYC = (adcMODE_REG_data[0]>>5)&0x01
870
+ MODE = (adcMODE_REG_data[1]>>4)&0x07
871
+ CLOCKSEL = adcMODE_REG_data[1]&0x0c
872
+ # prints for debug
873
+ print("Reading ADC{} MODE_REG:".format(adc))
874
+ print(" MODE_REG data is ", adcMODE_REG_data, " (or integer value of ", int.from_bytes(adcMODE_REG_data, byteorder='big', signed=False),")")
875
+ print(" adcMODE_REG's Internal_REF is:",REF_EN," SING_CYC is:", SING_CYC, ", MODE is:",MODE, ", CLOCKSEL is:",CLOCKSEL)
876
+ AdcState['Internal_REF EN']=REF_EN
877
+ AdcState['SING_CYC']=SING_CYC
878
+ AdcState['MODE']=MODE
879
+ AdcState['CLOCKSEL']=CLOCKSEL
880
+
881
+ # From register FILTCON0:
882
+ # extract ODR, Sync_Filter
883
+ FILTCON0_REG_data = self._read_data(adc, self.reg.FILTCON0_REG, 2)
884
+ FILTCON0_REG_data = FILTCON0_REG_data[1:]
885
+ Sync_Filter = FILTCON0_REG_data[1]>>5&0x03 # Order (type) of digital filter used
886
+ ODR = FILTCON0_REG_data[1]&0x1f # 'ODR' is Output Data Rate
887
+ # prints for debug
888
+ print("Reading ADC{} FILTCON0_REG:".format(adc))
889
+ print(" FILTCON0_REG data is ", FILTCON0_REG_data, " (or integer value of ", int.from_bytes(FILTCON0_REG_data, byteorder='big', signed=False),")")
890
+ print(" FILTCON0_REG's Sync_Filter is:", Sync_Filter, ", ODR code is:",ODR)
891
+ AdcState['Output Data Rate']=ODR
892
+ AdcState['Sync_Filter']=Sync_Filter
893
+
894
+ # From register GPIOCON:
895
+ # extract EXT_ENABLE, OP1_EN, GP_DATA1
896
+ GPIO_data = self._read_data(adc, self.reg.GPIOCON_REG, 2)
897
+ GPIO_data = GPIO_data[1:]
898
+ EXT_ENABLE = (GPIO_data[0]>>3)&0x01
899
+ OP_EN1 = (GPIO_data[1]>>3)&0x01
900
+ GP_DATA1 = (GPIO_data[1]>>1)&0x01
901
+ # prints for debug
902
+ print("Reading ADC{} GPIOCON:".format(adc))
903
+ print(" GPIOCON is ", GPIO_data, " (or integer value of ", int.from_bytes(GPIO_data, byteorder='big', signed=False),")")
904
+ print(" GPIOCON_REG's EXT_ENABLE is:", EXT_ENABLE, ", OP_EN1 is:", OP_EN1, ", GP_DATA1 is:",GP_DATA1)
905
+ AdcState['EXT_ENABLE']=EXT_ENABLE
906
+ AdcState['OP_EN1']=OP_EN1
907
+ AdcState['GP_DATA1']=GP_DATA1
908
+
909
+ # From register SETUPCON0 (p. 59):
910
+ # extract REFBUF0+, REFBUF0-, REF_SEL0
911
+ GPIO_data = self._read_data(adc, self.reg.SETUPCON0_REG, 2)
912
+ GPIO_data = GPIO_data[1:]
913
+ REFBUF0plus = (GPIO_data[0]>>3)&0x01
914
+ REFBUF0minus = (GPIO_data[0]>>2)&0x01
915
+ ANLGBUF0plus = (GPIO_data[0]>>1)&0x01
916
+ ANLGBUF0minus = GPIO_data[0]&0x01
917
+ REF_SEL0 = (GPIO_data[1]>>4)&0x03
918
+ # prints for debug
919
+ print("Reading ADC{} SETUPCON0:".format(adc))
920
+ print(" SETUPCON0 is ", GPIO_data, " (or integer value of ", int.from_bytes(GPIO_data, byteorder='big', signed=False),")")
921
+ print(" SETUPCON0_REG's REFBUF0+ is:", REFBUF0plus, ", REFBUF0- is:", REFBUF0minus, ", REF_SEL0 is:" ,REF_SEL0 , "ANLGBUF0+ is:", ANLGBUF0plus, ", ANLGBUF0- is:", ANLGBUF0minus)
922
+ AdcState['REFBUF0+']=REFBUF0plus
923
+ AdcState['REFBUF0-']=REFBUF0minus
924
+ AdcState['ANLGBUF0+']=ANLGBUF0plus
925
+ AdcState['ANLGBUF0-']=ANLGBUF0minus
926
+ AdcState['REF_SEL0']=REF_SEL0
927
+
928
+ # From register OFFSET0:
929
+ # prints for debug
930
+ print("Reading ADC{} OFFSET0:".format(adc))
931
+ OFFSET0 = self.read_OFFSET0(adc)
932
+ print(" OFFSET0 is:", OFFSET0)
933
+ AdcState['OFFSET0']=OFFSET0
934
+
935
+ # From register GAIN0:
936
+ # prints for debug
937
+ print("Reading ADC{} GAIN0:".format(adc))
938
+ GAIN0 = self.read_GAIN0(adc)
939
+ print(" GAIN0 is:", GAIN0)
940
+ AdcState['GAIN0']=GAIN0
941
+
942
+ return AdcState
943
+
944
+
945
+ def set_output_enable(self, SR_OEb):
946
+ """
947
+ Sets the output_enable\ signal into the SR.
948
+ Args:
949
+
950
+ """
951
+ if SR_OEb not in range(0, 2):
952
+ raise ValueError('The output_enable given {} is not a legal value. Possible values are in {}'.format(SR_OEb, range(0, 2)))
953
+
954
+ # The output byte holds two bits:
955
+ # The 'SR_OEb' - given hereby explicitly by the user
956
+ # The trig/sync - the existing bic_sync_value kept in memory
957
+ output_byte = SR_OEb<<7|self.bic_sync_value
958
+ print("The output_byte from BIC to module is",output_byte)
959
+
960
+ self.spi_rack.write_data(self.module, 5, 0, BICPINS_SPEED, bytearray([output_byte]))
961
+ self.SR_OEb = SR_OEb # need to keep this value for sync_signal setting
962
+
963
+
964
+ def set_sync_signal(self, user_sync_value):
965
+ """
966
+ Sets the sync signal from the BIC to the ADCs
967
+ to 0 or 1, as configured.
968
+ Note 1: one sync signal serves both ADC0, ADC1.
969
+ Note 2: sync\ low freezes operation. Operation resumes at sync\ rising edge,
970
+ and continues while high value maintained.
971
+ Note 3: the BIC_TRIG is OR'ed with the front-panel wired TRIG. Therefore
972
+ a 'high' setting from a front-panel TRIG is enough to keep the sync at 'high'
973
+ even with the BIC_TRIG low.
974
+
975
+ Args:
976
+
977
+ """
978
+ if user_sync_value not in range(0, 2):
979
+ raise ValueError('The sync_value given {} is not a legal value. Possible values are in {}'.format(user_sync_value, range(0, 2)))
980
+
981
+ print("set_sync_signal:\n sync_signal from user is ",bytearray([user_sync_value]))
982
+
983
+ # The output byte holds two bits:
984
+ # The 'SR_OEb' - the existing SR_OEb kept in memory
985
+ # The trig/sync - the new user_sync_value given here explicitly by the user
986
+ output_byte = self.SR_OEb<<7|user_sync_value
987
+ print(" The output_byte from BIC to module is",output_byte)
988
+
989
+ # Write to SPI addr 5 - the GPIO output direction
990
+ self.spi_rack.write_data(self.module, 5, 0, BICPINS_SPEED, bytearray([output_byte]))
991
+
992
+ self.bic_sync_value = user_sync_value # need to keep this value for SR_OEb setting
993
+
994
+ def read_unified_sync_signal(self):
995
+ """
996
+ Note: there is only one sync signal in the module, not per ADC
997
+
998
+ Args:
999
+
1000
+ """
1001
+ s_data = bytearray([0])
1002
+ r_data = self.spi_rack.read_data(self.module, 4, 0, BICPINS_SPEED, s_data)
1003
+ lsb_value = int.from_bytes(r_data, byteorder='little', signed=False)&0x1
1004
+ return lsb_value
1005
+
1006
+ def configure_sync_mode(self, adc, ext_enable):
1007
+ """Wait for external trigger to perform a conversion
1008
+
1009
+ Configures the given ADC to depend on external 'enable' (a.k.a. synch or mask) to perform a new convertion.
1010
+ A call to get the result needs to follow to access the data.
1011
+
1012
+ Args:
1013
+ adc (int:0-1): ADC to perform the conversion
1014
+ ext_enable (int:0-1): 1 - external trigger mode; 0 - regular operation (SW)
1015
+ """
1016
+ # input checks
1017
+ if adc not in range(0, 2):
1018
+ raise ValueError('ADC {} does not exist. Possible values are: {}'.format(adc, range(0, 2)))
1019
+ if ext_enable not in range(0, 2):
1020
+ raise ValueError('ext_enable {} is not a legal value. Possible values are in {}'.format(ext_enable, range(0, 2)))
1021
+
1022
+ gpio_desired = (ext_enable<<self.reg.SYNC_EN)|(ext_enable<<self.reg.OP_EN1)|(ext_enable<<self.reg.GP_DATA1)
1023
+ self._write_data_16(adc, self.reg.GPIOCON_REG, gpio_desired)
1024
+ gpio_actual = self._read_data(adc, self.reg.GPIOCON_REG, 2)
1025
+ gpio_actual = gpio_actual[1]<<8|gpio_actual[2]
1026
+ if (gpio_actual != gpio_desired):
1027
+ raise ValueError('D4a set_ext_trigger error: failed to configure desired trigger mode {} to ADC{}'.format(ext_enable, adc))
1028
+
1029
+ def _read_data(self, adc, reg, num_bytes):
1030
+ """
1031
+ Read a given number of bytes (num_bytes) from given adc register
1032
+ """
1033
+ s_data = bytearray([reg | (1<<6)] + num_bytes*[0])
1034
+ r_i_data = self.spi_rack.read_data(self.module, adc, AD7175_MODE, AD7175_SPEED, s_data)
1035
+
1036
+ return r_i_data
1037
+
1038
+ def _write_data_8(self, adc, reg, data):
1039
+ s_data = bytearray([reg, data])
1040
+ self.spi_rack.write_data(self.module, adc, AD7175_MODE, AD7175_SPEED, s_data)
1041
+
1042
+ def _write_data_16(self, adc, reg, data):
1043
+ s_data = bytearray([reg, data>>8, data&0xFF])
1044
+ self.spi_rack.write_data(self.module, adc, AD7175_MODE, AD7175_SPEED, s_data)
1045
+
1046
+ def _write_data_24(self, adc, reg, data):
1047
+ s_data = bytearray([reg, data>>16, (data>>8)&0xFF, data&0xFF])
1048
+ self.spi_rack.write_data(self.module, adc, AD7175_MODE, AD7175_SPEED, s_data)
1049
+
1050
+ def _reset_ADC(self, adc):
1051
+ s_data = bytearray([self.reg.GAIN0_REG, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff])
1052
+ self.spi_rack.write_data(self.module, adc, AD7175_MODE, AD7175_SPEED, s_data)
1053
+
1054
+
1055
+ class AD7175_registers:
1056
+ """AD7175 register class
1057
+
1058
+ A list of all the register names with values and all bits with corresponding
1059
+ locations in the registers.
1060
+ """
1061
+ # adc register locations
1062
+ STATUS_REG = 0x00
1063
+ adcMODE_REG = 0x01
1064
+ IFMODE_REG = 0x02
1065
+ REGCHECK_REG = 0x03
1066
+ DATA_REG = 0x04
1067
+ GPIOCON_REG = 0x06
1068
+ ID_REG = 0x07
1069
+ CH0_REG = 0x10
1070
+ CH1_REG = 0x11
1071
+ CH2_REG = 0x12
1072
+ CH3_REG = 0x13
1073
+ SETUPCON0_REG = 0x20
1074
+ SETUPCON1_REG = 0x21
1075
+ SETUPCON2_REG = 0x22
1076
+ SETUPCON3_REG = 0x23
1077
+ FILTCON0_REG = 0x28
1078
+ FILTCON1_REG = 0x29
1079
+ FILTCON2_REG = 0x2A
1080
+ FILTCON3_REG = 0x2B
1081
+ OFFSET0_REG = 0x30
1082
+ OFFSET1_REG = 0x31
1083
+ OFFSET2_REG = 0x32
1084
+ OFFSET3_REG = 0x33
1085
+ GAIN0_REG = 0x38
1086
+ GAIN1_REG = 0x39
1087
+ GAIN2_REG = 0x3A
1088
+ GAIN3_REG = 0x3B
1089
+
1090
+ # Status Register bits
1091
+ nRDY = 7
1092
+ adc_ERROR = 6
1093
+ CRC_ERROR = 5
1094
+ REG_ERROR = 4
1095
+ CHANNEL = 0
1096
+
1097
+ # adc Mode Register bits
1098
+ REF_EN = 15
1099
+ HIDE_DELAY = 14
1100
+ SING_CYC = 13
1101
+ DELAY = 8
1102
+ MODE = 4
1103
+ CLOCKSEL = 2
1104
+
1105
+ # IFMODE Register bits
1106
+ ALT_SYNC = 12
1107
+ IOSTRENGTH = 11
1108
+ DOUT_RESET = 8
1109
+ CONTREAD = 7
1110
+ DATA_STAT = 6
1111
+ REG_CHECK = 5
1112
+ CRC_EN = 2
1113
+ WL16 = 0
1114
+
1115
+ # GPIOCON Register bits
1116
+ MUX_IO = 12
1117
+ SYNC_EN = 11
1118
+ ERR_EN = 9
1119
+ ERR_DAT = 8
1120
+ IP_EN1 = 5
1121
+ IP_EN0 = 4
1122
+ OP_EN1 = 3
1123
+ OP_EN0 = 2
1124
+ GP_DATA1 = 1
1125
+ GP_DATA0 = 0
1126
+
1127
+ # Channel Registers bits
1128
+ CH_EN = 15
1129
+ SETUP_SEL = 12
1130
+ AINPOS = 5
1131
+ AINNEG = 0
1132
+
1133
+ # Setup Configuration Register bits
1134
+ BI_UNIPOLAR = 12
1135
+ REFBUF0P = 11
1136
+ REFBUF0M = 10
1137
+ AINBUF0P = 9
1138
+ AINBUF0M = 8
1139
+ REF_SEL = 4
1140
+
1141
+ # Filter Configuration Register bits
1142
+ SINC3_MAP0 = 15
1143
+ ENHFILTEN = 11
1144
+ ENHFILT = 8
1145
+ ORDER0 = 5
1146
+ ODR = 0
1147
+
1148
+ # adc register values
1149
+ AIN0 = 0
1150
+ AIN1 = 1
1151
+ AIN2 = 2
1152
+ AIN3 = 3
1153
+ AIN4 = 4
1154
+ REFP = 21
1155
+ REFN = 22
@@ -0,0 +1 @@
1
+ __version__ = '0.2.12'
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: spirack
3
- Version: 0.2.9
3
+ Version: 0.2.12
4
4
  Summary: Drivers for the QuTech SPI-rack
5
5
  Home-page: https://github.com/mtiggelman/SPI-rack
6
6
  Author: Marijn Tiggelman
@@ -5,6 +5,7 @@ setup.py
5
5
  spirack/B1b_module.py
6
6
  spirack/B2b_module.py
7
7
  spirack/D4_module.py
8
+ spirack/D4a_module.py
8
9
  spirack/D4b_module.py
9
10
  spirack/D5a_module.py
10
11
  spirack/D5b_module.py
@@ -1 +0,0 @@
1
- __version__ = '0.2.9'
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes