6
6
import nidcpower
7
7
import nifgen
8
8
import numpy as np
9
- from ni_hsdio import NIHSDIO
9
+ from nihsdio import NIHSDIO , NIHSDIOException
10
10
11
+
12
+ # Warnings become errors
11
13
warnings .filterwarnings ("error" )
12
14
15
+
13
16
def accurate_delay (delay ):
14
17
"""Function to provide accurate time delay"""
15
18
_ = time .perf_counter () + delay
@@ -38,8 +41,8 @@ def __init__(self, chip, settings="settings.json"):
38
41
# TODO: initialize logger
39
42
40
43
# Store/initialize parameters
41
- self .chip = chip
42
44
self .settings = settings
45
+ self .settings ["chip" ] = chip
43
46
self .addr = 0
44
47
self .prof = {"READs" : 0 , "SETs" : 0 , "RESETs" : 0 }
45
48
@@ -49,21 +52,22 @@ def __init__(self, chip, settings="settings.json"):
49
52
# Initialize NI-DAQmx driver for READ voltage
50
53
self .read_chan = nidaqmx .Task ()
51
54
self .read_chan .ai_channels .add_ai_voltage_chan (settings ["DAQmx" ]["chanMap" ]["read_ai" ])
52
- self .read_chan .timing .cfg_samp_clk_timing (settings ["READ" ]["read_clk_rate" ])
55
+ read_rate , spc = settings ["READ" ]["read_rate" ], settings ["READ" ]["n_samples" ]
56
+ self .read_chan .timing .cfg_samp_clk_timing (read_rate , samps_per_chan = spc )
53
57
54
58
# Initialize NI-DAQmx driver for WL voltages
55
59
self .wl_ext_chans = []
56
60
for chan in settings ["DAQmx" ]["chanMap" ]["wl_ext" ]:
57
61
task = nidaqmx .Task ()
58
62
task .ao_channels .add_ao_voltage_chan (chan )
59
- task .timing .cfg_samp_clk_timing (settings ["samp_clk_rate" ])
60
- task .start ()
63
+ task .timing .cfg_samp_clk_timing (settings ["samp_clk_rate" ], samps_per_chan = 2 )
61
64
self .wl_ext_chans .append (task )
62
65
63
66
# Initialize NI-DCPower driver for BL voltages
64
67
self .bl_ext_chans = []
65
68
for chan in settings ["DCPower" ]["chans" ]:
66
69
sess = nidcpower .Session (settings ["DCPower" ]["deviceID" ], chan )
70
+ # sess.current_limit = 1 # requires aux power input
67
71
sess .voltage_level = 0
68
72
sess .commit ()
69
73
sess .initiate ()
@@ -76,7 +80,8 @@ def __init__(self, chip, settings="settings.json"):
76
80
self .sl_ext_chan .initiate ()
77
81
78
82
# Set address to 0
79
- self .set_address (0 )
83
+ self .set_addr (0 )
84
+
80
85
81
86
def read (self ):
82
87
"""Perform a READ operation. Returns tuple with (res, cond, meas_i, meas_v)"""
@@ -95,7 +100,10 @@ def read(self):
95
100
accurate_delay (self .settings ["READ" ]["settling_time" ])
96
101
97
102
# Measure
103
+ self .read_chan .start ()
98
104
meas_v = np .mean (self .read_chan .read (self .settings ["READ" ]["n_samples" ]))
105
+ self .read_chan .wait_until_done ()
106
+ self .read_chan .stop ()
99
107
meas_i = meas_v / self .settings ["READ" ]["shunt_res_value" ]
100
108
res = np .abs (self .settings ["READ" ]["VBL" ]/ meas_i - self .settings ["READ" ]["shunt_res_value" ])
101
109
cond = 1 / res
@@ -112,8 +120,80 @@ def read(self):
112
120
# Return measurement tuple
113
121
return res , cond , meas_i , meas_v
114
122
115
- def set_pulse (self , vwl = None , vbl = None , pw = None ):
116
-
123
+ def form_pulse (self , vwl = None , vbl = None , pulse_width = None ):
124
+ """Perform a FORM operation."""
125
+ # Get parameters
126
+ vwl = self .settings ["FORM" ]["VWL" ] if vwl is None else vwl
127
+ vbl = self .settings ["FORM" ]["VBL" ] if vbl is None else vbl
128
+ pulse_width = self .settings ["FORM" ]["PW" ] if pulse_width is None else pulse_width
129
+
130
+ # Operation is equivalent to SET but with different parameters
131
+ self .set_pulse (vwl , vbl , pulse_width )
132
+
133
+ def set_pulse (self , vwl = None , vbl = None , pulse_width = None ):
134
+ """Perform a SET operation."""
135
+ # Get parameters
136
+ vwl = self .settings ["SET" ]["VWL" ] if vwl is None else vwl
137
+ vbl = self .settings ["SET" ]["VBL" ] if vbl is None else vbl
138
+ pulse_width = self .settings ["SET" ]["PW" ] if pulse_width is None else pulse_width
139
+
140
+ # Increment the number of SETs
141
+ self .prof ["SETs" ] += 1
142
+
143
+ # Address decoder enable
144
+ self .decoder_enable ()
145
+
146
+ # Set voltages
147
+ self .set_vsl (0 )
148
+ self .set_vbl (vbl )
149
+
150
+ # Settling time for VBL
151
+ accurate_delay (self .settings ["SET" ]["settling_time" ])
152
+
153
+ # Pulse VWL
154
+ self .pulse_vwl (vwl , pulse_width )
155
+
156
+ # Turn off VBL
157
+ self .set_vbl (0 )
158
+
159
+ # Settling time for VBL
160
+ accurate_delay (self .settings ["SET" ]["settling_time" ])
161
+
162
+ # Address decoder disable
163
+ self .decoder_disable ()
164
+
165
+ def reset_pulse (self , vwl = None , vsl = None , pulse_width = None ):
166
+ """Perform a RESET operation."""
167
+ # Get parameters
168
+ vwl = self .settings ["RESET" ]["VWL" ] if vwl is None else vwl
169
+ vsl = self .settings ["RESET" ]["VSL" ] if vsl is None else vsl
170
+ pulse_width = self .settings ["RESET" ]["PW" ] if pulse_width is None else pulse_width
171
+
172
+ # Increment the number of SETs
173
+ self .prof ["RESETs" ] += 1
174
+
175
+ # Address decoder enable
176
+ self .decoder_enable ()
177
+
178
+ # Set voltages
179
+ self .set_vbl (0 )
180
+ self .set_vsl (vsl )
181
+
182
+ # Settling time for VSL
183
+ accurate_delay (self .settings ["RESET" ]["settling_time" ])
184
+
185
+ # Pulse VWL
186
+ self .pulse_vwl (vwl , pulse_width )
187
+
188
+ # Turn off VSL
189
+ self .set_vsl (0 )
190
+
191
+ # Settling time for VSL
192
+ accurate_delay (self .settings ["RESET" ]["settling_time" ])
193
+
194
+ # Address decoder disable
195
+ self .decoder_disable ()
196
+
117
197
118
198
def set_vsl (self , voltage ):
119
199
"""Set VSL using NI-FGen driver"""
@@ -128,10 +208,12 @@ def set_vbl(self, voltage):
128
208
inactive_bl = self .bl_ext_chans [1 - active_bl_chan ]
129
209
130
210
# Set voltages and commit
131
- active_bl .voltage_level = voltage
132
- active_bl .commit ()
133
211
inactive_bl .voltage_level = 0
134
212
inactive_bl .commit ()
213
+ active_bl .voltage_level = voltage
214
+ active_bl .commit ()
215
+ inactive_bl .wait_for_event (nidcpower .Event .SOURCE_COMPLETE )
216
+ active_bl .wait_for_event (nidcpower .Event .SOURCE_COMPLETE )
135
217
136
218
def set_vwl (self , voltage ):
137
219
"""Set (active) VWL using NI-DAQmx driver (inactive disabled)"""
@@ -141,21 +223,35 @@ def set_vwl(self, voltage):
141
223
active_wl = self .wl_ext_chans [active_wl_dev ]
142
224
inactive_wl = self .wl_ext_chans [1 - active_wl_dev ]
143
225
144
- # Write
145
- active_wl .write ([(1 - active_wl_chan )* voltage , active_wl_chan * voltage ], auto_start = True )
146
- inactive_wl .write ([0 ,0 ], auto_start = True )
226
+ # Write voltage to hold
227
+ signal = [[(1 - active_wl_chan )* voltage ]* 2 , [active_wl_chan * voltage ]* 2 ]
228
+ inactive_wl .write ([[0 ,0 ],[0 ,0 ]], auto_start = True )
229
+ inactive_wl .wait_until_done ()
230
+ inactive_wl .stop ()
231
+ active_wl .write (signal , auto_start = True )
232
+ active_wl .wait_until_done ()
233
+ active_wl .stop ()
234
+
147
235
148
- def pulse_vwl (self , voltage , pw ):
236
+ def pulse_vwl (self , voltage , pulse_width ):
149
237
"""Pulse (active) VWL using NI-DAQmx driver (inactive disabled)"""
150
238
# Select 8th and 9th bit to get the channel and the driver card, respectively
151
239
active_wl_chan = (self .addr >> 8 ) & 0b1
152
240
active_wl_dev = (self .addr >> 9 ) & 0b1
153
241
active_wl = self .wl_ext_chans [active_wl_dev ]
154
242
inactive_wl = self .wl_ext_chans [1 - active_wl_dev ]
155
243
156
- # Write
157
- active_wl .write ([(1 - active_wl_chan )* voltage , active_wl_chan * voltage ], auto_start = True )
158
- inactive_wl .write ([0 ,0 ], auto_start = True )
244
+ # Configure pulse width
245
+ active_wl .timing .cfg_samp_clk_timing (1 / pulse_width , samps_per_chan = 2 )
246
+
247
+ # Write pulse
248
+ signal = [[(1 - active_wl_chan )* voltage , 0 ], [active_wl_chan * voltage , 0 ]]
249
+ inactive_wl .write ([[0 ,0 ],[0 ,0 ]], auto_start = True )
250
+ inactive_wl .wait_until_done ()
251
+ inactive_wl .stop ()
252
+ active_wl .write (signal , auto_start = True )
253
+ active_wl .wait_until_done ()
254
+ active_wl .stop ()
159
255
160
256
def decoder_enable (self ):
161
257
"""Enable decoding circuitry using digital signals"""
@@ -169,7 +265,7 @@ def decoder_disable(self):
169
265
self .hsdio .write_data_across_chans ("sl_dec_en" , 0b0 )
170
266
self .hsdio .write_data_across_chans ("wl_clk" , 0b0 )
171
267
172
- def set_address (self , addr ):
268
+ def set_addr (self , addr ):
173
269
"""Set the address and hold briefly"""
174
270
# Update address
175
271
self .addr = addr
@@ -211,10 +307,13 @@ def close(self):
211
307
# Give some time to shutdown
212
308
time .sleep (1 )
213
309
310
+ def __del__ (self ):
311
+ # Try to close session on deletion
312
+ try :
313
+ self .close ()
314
+ except NIHSDIOException :
315
+ pass
316
+
214
317
if __name__ == "__main__" :
215
318
# Basic test
216
319
nirram = NIRRAM ("Chip9" )
217
- for address in range (2000 ):
218
- nirram .set_address (address )
219
- if address % 100 == 0 :
220
- print ((address , nirram .read ()),)
0 commit comments