Skip to content

Commit 6151991

Browse files
committed
Updates
1 parent 482ba75 commit 6151991

File tree

7 files changed

+161
-30
lines changed

7 files changed

+161
-30
lines changed

README.md

+6
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,8 @@
11
# NI-RRAM-Python
22
NI RRAM programming in Python
3+
4+
## Conda environment
5+
Install: jupyter and pylint
6+
7+
## Pip environment
8+
Install: hightime, numpy, nitclk, nifgen, nidcpower, nidaqmx

dll/niHSDIO_64.dll

957 KB
Binary file not shown.

ni_rram.py

+121-22
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,13 @@
66
import nidcpower
77
import nifgen
88
import numpy as np
9-
from ni_hsdio import NIHSDIO
9+
from nihsdio import NIHSDIO, NIHSDIOException
1010

11+
12+
# Warnings become errors
1113
warnings.filterwarnings("error")
1214

15+
1316
def accurate_delay(delay):
1417
"""Function to provide accurate time delay"""
1518
_ = time.perf_counter() + delay
@@ -38,8 +41,8 @@ def __init__(self, chip, settings="settings.json"):
3841
# TODO: initialize logger
3942

4043
# Store/initialize parameters
41-
self.chip = chip
4244
self.settings = settings
45+
self.settings["chip"] = chip
4346
self.addr = 0
4447
self.prof = {"READs": 0, "SETs": 0, "RESETs": 0}
4548

@@ -49,21 +52,22 @@ def __init__(self, chip, settings="settings.json"):
4952
# Initialize NI-DAQmx driver for READ voltage
5053
self.read_chan = nidaqmx.Task()
5154
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)
5357

5458
# Initialize NI-DAQmx driver for WL voltages
5559
self.wl_ext_chans = []
5660
for chan in settings["DAQmx"]["chanMap"]["wl_ext"]:
5761
task = nidaqmx.Task()
5862
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)
6164
self.wl_ext_chans.append(task)
6265

6366
# Initialize NI-DCPower driver for BL voltages
6467
self.bl_ext_chans = []
6568
for chan in settings["DCPower"]["chans"]:
6669
sess = nidcpower.Session(settings["DCPower"]["deviceID"], chan)
70+
# sess.current_limit = 1 # requires aux power input
6771
sess.voltage_level = 0
6872
sess.commit()
6973
sess.initiate()
@@ -76,7 +80,8 @@ def __init__(self, chip, settings="settings.json"):
7680
self.sl_ext_chan.initiate()
7781

7882
# Set address to 0
79-
self.set_address(0)
83+
self.set_addr(0)
84+
8085

8186
def read(self):
8287
"""Perform a READ operation. Returns tuple with (res, cond, meas_i, meas_v)"""
@@ -95,7 +100,10 @@ def read(self):
95100
accurate_delay(self.settings["READ"]["settling_time"])
96101

97102
# Measure
103+
self.read_chan.start()
98104
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()
99107
meas_i = meas_v/self.settings["READ"]["shunt_res_value"]
100108
res = np.abs(self.settings["READ"]["VBL"]/meas_i - self.settings["READ"]["shunt_res_value"])
101109
cond = 1/res
@@ -112,8 +120,80 @@ def read(self):
112120
# Return measurement tuple
113121
return res, cond, meas_i, meas_v
114122

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+
117197

118198
def set_vsl(self, voltage):
119199
"""Set VSL using NI-FGen driver"""
@@ -128,10 +208,12 @@ def set_vbl(self, voltage):
128208
inactive_bl = self.bl_ext_chans[1-active_bl_chan]
129209

130210
# Set voltages and commit
131-
active_bl.voltage_level = voltage
132-
active_bl.commit()
133211
inactive_bl.voltage_level = 0
134212
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)
135217

136218
def set_vwl(self, voltage):
137219
"""Set (active) VWL using NI-DAQmx driver (inactive disabled)"""
@@ -141,21 +223,35 @@ def set_vwl(self, voltage):
141223
active_wl = self.wl_ext_chans[active_wl_dev]
142224
inactive_wl = self.wl_ext_chans[1-active_wl_dev]
143225

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+
147235

148-
def pulse_vwl(self, voltage, pw):
236+
def pulse_vwl(self, voltage, pulse_width):
149237
"""Pulse (active) VWL using NI-DAQmx driver (inactive disabled)"""
150238
# Select 8th and 9th bit to get the channel and the driver card, respectively
151239
active_wl_chan = (self.addr >> 8) & 0b1
152240
active_wl_dev = (self.addr >> 9) & 0b1
153241
active_wl = self.wl_ext_chans[active_wl_dev]
154242
inactive_wl = self.wl_ext_chans[1-active_wl_dev]
155243

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()
159255

160256
def decoder_enable(self):
161257
"""Enable decoding circuitry using digital signals"""
@@ -169,7 +265,7 @@ def decoder_disable(self):
169265
self.hsdio.write_data_across_chans("sl_dec_en", 0b0)
170266
self.hsdio.write_data_across_chans("wl_clk", 0b0)
171267

172-
def set_address(self, addr):
268+
def set_addr(self, addr):
173269
"""Set the address and hold briefly"""
174270
# Update address
175271
self.addr = addr
@@ -211,10 +307,13 @@ def close(self):
211307
# Give some time to shutdown
212308
time.sleep(1)
213309

310+
def __del__(self):
311+
# Try to close session on deletion
312+
try:
313+
self.close()
314+
except NIHSDIOException:
315+
pass
316+
214317
if __name__=="__main__":
215318
# Basic test
216319
nirram = NIRRAM("Chip9")
217-
for address in range(2000):
218-
nirram.set_address(address)
219-
if address % 100 == 0:
220-
print((address, nirram.read()),)

ni_hsdio.py renamed to nihsdio.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ def __init__(self, deviceID, chanMap=None, channelList="", logicFamily=NIHSDIO_V
2626
self.chan_map = chanMap if chanMap is not None else {}
2727

2828
# Create driver and VI session
29-
self.driver = CDLL("lib/niHSDIO_64.dll")
29+
self.driver = CDLL("dll/niHSDIO_64.dll")
3030
self.sess = c_uint(0)
3131

3232
# Initialize generation session

requirements.txt

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
nidaqmx
2+
nifgen
3+
nidcpower
4+
numpy

settings.json

+22-7
Original file line numberDiff line numberDiff line change
@@ -28,21 +28,36 @@
2828
},
2929

3030
"READ": {
31-
"read_clk_rate": 500000,
32-
"n_samples": 100,
31+
"read_rate": 1000000,
32+
"n_samples": 1000,
3333
"shunt_res_value": 560,
3434
"VWL": 2.5,
3535
"VBL": 0.2,
36-
"settling_time": 1.5e-3
36+
"settling_time": 2e-3
3737
},
3838

3939
"SET": {
40-
"VWL": 2.5,
41-
"VBL": 2.5,
42-
"settling_time": 1.5e-3
40+
"VWL": 1.8,
41+
"VBL": 3,
42+
"PW": 10e-6,
43+
"settling_time": 1e-3
44+
},
45+
46+
"FORM": {
47+
"VWL": 1.4,
48+
"VBL": 3,
49+
"PW": 10e-6,
50+
"settling_time": 1e-3
51+
},
52+
53+
"RESET": {
54+
"VWL": 3,
55+
"VSL": 3,
56+
"PW": 40e-6,
57+
"settling_time": 1e-3
4358
},
4459

45-
"addr_hold_time": 5e-4,
60+
"addr_hold_time": 1e-3,
4661
"samp_clk_rate": 1000000,
4762

4863
"log_file": "TODO"

test.py

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
from ni_rram import NIRRAM
2+
from time import sleep
3+
nisys = NIRRAM("Chip_9")
4+
nisys.set_addr(348)
5+
print(nisys.read())
6+
nisys.set_pulse()
7+
print(nisys.read())

0 commit comments

Comments
 (0)