Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -558,6 +558,7 @@
#### [nidigital] Unreleased
- Added
- (Common) Added `nitlsconfig[grpc]>=1.0.0a2` to the optional gRPC dependencies.
- Added the `nidigital_unload_and_reload_specifications_file.py` example.
- Changed
- Removed

Expand Down
9 changes: 9 additions & 0 deletions docs/nidigital/examples.rst
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,12 @@ nidigital_ppmu_source_and_measure.py
:encoding: utf8
:caption: `(nidigital_ppmu_source_and_measure.py) <https://github.com/ni/nimi-python/blob/master/src/nidigital/examples/ppmu_source_and_measure/nidigital_ppmu_source_and_measure.py>`_

nidigital_unload_and_reload_specifications_file.py
--------------------------------------------------

.. literalinclude:: ../../src/nidigital/examples/unload_and_reload_specifications_file/nidigital_unload_and_reload_specifications_file.py
:language: python
:linenos:
:encoding: utf8
:caption: `(nidigital_unload_and_reload_specifications_file.py) <https://github.com/ni/nimi-python/blob/master/src/nidigital/examples/unload_and_reload_specifications_file/nidigital_unload_and_reload_specifications_file.py>`_

Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<PinLevelsFile xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" schemaVersion="1.0" xmlns="http://www.ni.com/Semiconductor/PinLevels">
<PinLevelsSheet>
<DigitalPinLevelSets>
<DigitalPinLevelSet pin="SDATA">
<Vil>0</Vil>
<Vih>DC.Vdd</Vih>
<Vol>DC.Vol</Vol>
<Voh>DC.Voh</Voh>
<TerminationMode>HighZ</TerminationMode>
</DigitalPinLevelSet>
</DigitalPinLevelSets>
</PinLevelsSheet>
</PinLevelsFile>
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<PinMap schemaVersion="1.5" xmlns="http://www.ni.com/TestStand/SemiconductorModule/PinMap.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<Instruments>
<NIDigitalPatternInstrument name="PXI1Slot2" numberOfChannels="32" group="Digital" />
<NIDigitalPatternInstrument name="PXI1Slot3" numberOfChannels="32" group="Digital" />
</Instruments>
<Pins>
<DUTPin name="SDATA" />
</Pins>
<PinGroups>
<PinGroup name="Digital_Pins">
<PinReference pin="SDATA" />
</PinGroup>
<PinGroup name="All_Pins">
<PinReference pin="SDATA" />
</PinGroup>
</PinGroups>
<Sites>
<Site siteNumber="0" />
<Site siteNumber="1" />
<Site siteNumber="2" />
<Site siteNumber="3" />
</Sites>
<Connections>
<Connection pin="SDATA" siteNumber="0" instrument="PXI1Slot2" channel="25" />
<Connection pin="SDATA" siteNumber="1" instrument="PXI1Slot2" channel="17" />
<Connection pin="SDATA" siteNumber="2" instrument="PXI1Slot3" channel="9" />
<Connection pin="SDATA" siteNumber="3" instrument="PXI1Slot3" channel="1" />
</Connections>
</PinMap>
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<SourceFile Checksum="DD1093EC813C28D903B23CEB42720E5F" Timestamp="1D52532198AA775" xmlns="http://www.ni.com/PlatformFramework">
<SourceModelFeatureSet>
<ParsableNamespace AssemblyFileVersion="5.3.1.50153" FeatureSetName="Digital Pattern Editor" Name="http://www.ni.com/PatternBasedDigital" OldestCompatibleVersion="4.5.0.0" Version="4.6.0.49152" />
<ParsableNamespace AssemblyFileVersion="5.3.1.50153" FeatureSetName="Editor" Name="http://www.ni.com/PlatformFramework" OldestCompatibleVersion="5.2.0.49153" Version="5.2.0.49153" />
<ApplicationVersionInfo Build="5.3.1.50153" Name="Digital Pattern Editor" Version="19.0.0" />
</SourceModelFeatureSet>
<ShmooSetupDefinition xmlns="http://www.ni.com/PatternBasedDigital">
<Shmoo Id="1" PatternName="demo_pattern_no_hw" ShmooPlotMode="EdgeTraversal">
<ShmooAxisSetup Id="2" Name="X-Axis" NumberOfSteps="50" PinItems="SDATA" ShmooType="Spec" SpecVariable="AC.Strobe" Start="0" Stop="10 n" TimeSets="SPI_IO_SHMOO" />
<ShmooAxisSetup Id="3" Name="Y-Axis" PinItems="SDATA" ShmooType="Spec" SpecVariable="DC.Voh" Start="0" Stop="5" />
</Shmoo>
</ShmooSetupDefinition>
</SourceFile>
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
<Specifications xmlns:f="http://www.ni.com/schemas/Semiconductor/Formula.xsd" schemaVersion="1.0" xmlns="http://www.ni.com/schemas/Semiconductor/Specifications.xsd">
<Section name="DC">
<f:Formula symbol="Vdd">
<f:Definition>5.250000E+0</f:Definition>
</f:Formula>
<f:Formula symbol="Voh">
<f:Definition>DC.Vdd - 1</f:Definition>
</f:Formula>
<f:Formula symbol="Vol">
<f:Definition>0.4</f:Definition>
</f:Formula>
</Section>
<Section name="AC">
<f:Formula symbol="Frequency">
<f:Definition>100 M</f:Definition>
</f:Formula>
<f:Formula symbol="Period">
<f:Definition>1 / AC.Frequency</f:Definition>
</f:Formula>
<f:Formula symbol="Strobe">
<f:Definition>0.4*AC.Period</f:Definition>
</f:Formula>
</Section>
</Specifications>
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="utf-8"?>
<TimingFile xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" schemaVersion="1.0" xmlns="http://www.ni.com/Semiconductor/Timing">
<TimingSheet>
<TimeSets>
<TimeSet name="DriveNext">
<Period>AC.Period</Period>
<PinEdges>
<PinEdge pin="SDATA">
<ReturnToLow>
<On>AC.Period</On>
<Data>1.25*AC.Period</Data>
<Return>1.75*AC.Period</Return>
<Off>2*AC.Period</Off>
</ReturnToLow>
<CompareStrobe>
<Strobe>AC.Strobe</Strobe>
</CompareStrobe>
<DataSource>Pattern</DataSource>
<Comment>we are sourcing and capturing on the same pin, so we move the drive edges into the subsequent vector period</Comment>
</PinEdge>
</PinEdges>
</TimeSet>
<TimeSet name="wait">
<Period>3 µs</Period>
<PinEdges>
<PinEdge pin="All_Pins">
<DriveNonReturn>
<On>0</On>
<Data>0</Data>
<Off>AC.Period</Off>
</DriveNonReturn>
<CompareStrobe>
<Strobe>AC.Strobe</Strobe>
</CompareStrobe>
<DataSource>Pattern</DataSource>
</PinEdge>
</PinEdges>
</TimeSet>
</TimeSets>
</TimingSheet>
</TimingFile>
Binary file not shown.
Binary file not shown.
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
#!/usr/bin/python

import argparse
import nidigital
import os
import random
import shutil
import sys
import tempfile
from xml.etree import ElementTree

SPECS_NAMESPACE = 'http://www.ni.com/schemas/Semiconductor/Specifications.xsd'
FORMULA_NAMESPACE = 'http://www.ni.com/schemas/Semiconductor/Formula.xsd'
NAMESPACES = {'s': SPECS_NAMESPACE, 'f': FORMULA_NAMESPACE}
ElementTree.register_namespace('', SPECS_NAMESPACE)
ElementTree.register_namespace('f', FORMULA_NAMESPACE)

SOURCE_WAVEFORM_NAME = 'demo_src_wfm'
CAPTURE_WAVEFORM_NAME = 'demo_waveform'
SOURCE_PIN = 'SDATA'
SAMPLE_WIDTH = 32
NUMBER_OF_SAMPLES = 32


def _sweep_values(start, stop, steps):
if steps == 1:
return [start]
return [start + i * (stop - start) / (steps - 1) for i in range(steps)]


def _update_specification_values(specs_file_path, new_values):
# new_values maps '<Section>.<Symbol>' to the new definition for that specification
specs_tree = ElementTree.parse(specs_file_path)
for spec_name, value in new_values.items():
section_name, formula_symbol = spec_name.split('.')
definition_element = specs_tree.find("s:Section[@name='{}']/f:Formula[@symbol='{}']/f:Definition".format(section_name, formula_symbol), NAMESPACES)
definition_element.text = repr(value)
specs_tree.write(specs_file_path, encoding='utf-8', xml_declaration=True)


def _count_mismatched_bits(expected_words, actual_words):
return sum(bin(expected_word ^ actual_word).count('1') for expected_word, actual_word in zip(expected_words, actual_words))


def example(resource_name, options, x_spec_name, x_start, x_stop, x_steps, y_spec_name, y_start, y_stop, y_steps):
example_dir = os.path.join(os.path.dirname(__file__))

pin_map_filename = os.path.join(example_dir, 'PinMap.pinmap')
pattern_filename = os.path.join(example_dir, 'demo_pattern_no_hw.digipat')
capture_waveform_filename = os.path.join(example_dir, 'demo_waveform.digicapture')
original_spec_filename = os.path.join(example_dir, 'Specifications.specs')
levels_filename = os.path.join(example_dir, 'PinLevels.digilevels')
timing_filename = os.path.join(example_dir, 'Timing.digitiming')

# Work on a temporary copy so the specifications file shipped with the example is never modified
with tempfile.TemporaryDirectory() as temp_dir, \
nidigital.Session(resource_name=resource_name, options=options) as session:
temp_spec_filename = os.path.join(temp_dir, 'Specifications.specs')
shutil.copy(original_spec_filename, temp_spec_filename)

session.load_pin_map(pin_map_filename)
session.load_pattern(pattern_filename)

# Source random data; reg0 sets the number of source and capture loops used by the pattern
source_waveform_data = [random.getrandbits(SAMPLE_WIDTH) for _ in range(NUMBER_OF_SAMPLES)]
session.write_sequencer_register(nidigital.SequencerRegister.REGISTER0, len(source_waveform_data) * SAMPLE_WIDTH)
session.pins[SOURCE_PIN].create_source_waveform_serial(SOURCE_WAVEFORM_NAME, nidigital.SourceDataMapping.BROADCAST, SAMPLE_WIDTH, nidigital.BitOrder.MSB)
session.write_source_waveform_broadcast(SOURCE_WAVEFORM_NAME, source_waveform_data)

session.create_capture_waveform_from_file_digicapture(CAPTURE_WAVEFORM_NAME, capture_waveform_filename)

session.load_specifications_levels_and_timing(temp_spec_filename, levels_filename, timing_filename)
session.apply_levels_and_timing(levels_filename, timing_filename)

total_bits = len(source_waveform_data) * SAMPLE_WIDTH
print('Start sweeping specifications')
print('Fraction of mismatched capture bits for each ({}, {}) pair:'.format(x_spec_name, y_spec_name))
for y_value in _sweep_values(y_start, y_stop, y_steps):
for x_value in _sweep_values(x_start, x_stop, x_steps):
# Only the specifications are unloaded, so reload only them; the levels and timing sheets are still loaded
session.unload_specifications(temp_spec_filename)
_update_specification_values(temp_spec_filename, {x_spec_name: x_value, y_spec_name: y_value})
session.load_specifications_levels_and_timing(specifications_file_paths=temp_spec_filename)
session.apply_levels_and_timing(levels_filename, timing_filename)

session.burst_pattern(start_label='startdemo')
site_number, captured_waveform = next(iter(session.fetch_capture_waveform(CAPTURE_WAVEFORM_NAME, len(source_waveform_data)).items()))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The pin map defines four sites, but this reads only the first site’s waveform, if I'm not wrong.
Could we iterate over the returned dictionary to report results for every site?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Something like,

                captured_waveforms = session.fetch_capture_waveform(CAPTURE_WAVEFORM_NAME, len(source_waveform_data))
                for site_number, captured_waveform in captured_waveforms.items():
                    mismatch_fraction = _count_mismatched_bits(source_waveform_data, captured_waveform) / total_bits
                    print('Site {}: {}={:g}, {}={:g}: {:.4f}'.format(site_number, x_spec_name, x_value, y_spec_name, y_value, mismatch_fraction))

mismatch_fraction = _count_mismatched_bits(source_waveform_data, captured_waveform) / total_bits
print('Site {}: {}={:g}, {}={:g}: {:.4f}'.format(site_number, x_spec_name, x_value, y_spec_name, y_value, mismatch_fraction))

print('Done sweeping specifications')

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's print this at the end after disconnecting.


session.selected_function = nidigital.SelectedFunction.DISCONNECT


def _main(argsv):
parser = argparse.ArgumentParser(description='Demonstrates how to unload and reload a specifications file while sweeping two specification values and measuring the capture waveform bit errors at each point.', formatter_class=argparse.ArgumentDefaultsHelpFormatter)
parser.add_argument('-n', '--resource-name', default='PXI1Slot2,PXI1Slot3', help='Resource name of a NI digital pattern instrument. Ensure the resource name matches the instrument name in the pinmap file.')
parser.add_argument('-s', '--simulate', default='True', choices=['True', 'False'], help='Whether to run on simulated hardware or real hardware')
parser.add_argument('-xn', '--x-spec-name', default='AC.Strobe', help='Specification to sweep along the X axis, as <Section>.<Symbol>.')
parser.add_argument('-xs', '--x-start', default=0.0, type=float, help='First value of the X axis sweep.')
parser.add_argument('-xe', '--x-stop', default=1e-8, type=float, help='Last value of the X axis sweep.')
parser.add_argument('-xc', '--x-steps', default=5, type=int, help='Number of values in the X axis sweep.')
parser.add_argument('-yn', '--y-spec-name', default='DC.Voh', help='Specification to sweep along the Y axis, as <Section>.<Symbol>.')
parser.add_argument('-ys', '--y-start', default=0.0, type=float, help='First value of the Y axis sweep.')
parser.add_argument('-ye', '--y-stop', default=5.0, type=float, help='Last value of the Y axis sweep.')
parser.add_argument('-yc', '--y-steps', default=5, type=int, help='Number of values in the Y axis sweep.')
args = parser.parse_args(argsv)

example(args.resource_name,
'Simulate=1, DriverSetup=Model:6571' if args.simulate == 'True' else '',
args.x_spec_name, args.x_start, args.x_stop, args.x_steps,
args.y_spec_name, args.y_start, args.y_stop, args.y_steps)


def main():
_main(sys.argv[1:])


def test_example():
options = {'simulate': True, 'driver_setup': {'Model': '6571'}, }
example('PXI1Slot2,PXI1Slot3', options, 'AC.Strobe', 0.0, 1e-8, 2, 'DC.Voh', 0.0, 5.0, 2)


def test_main():
_main(['--x-steps', '2', '--y-steps', '2'])


if __name__ == '__main__':
main()
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="utf-8"?>
<SourceFile Checksum="6580C473F15E9216FD11D1EC7B291705" xmlns="http://www.ni.com/PlatformFramework">
<SourceModelFeatureSet>
<ParsableNamespace AssemblyFileVersion="5.3.1.50153" FeatureSetName="Digital Pattern Editor" Name="http://www.ni.com/PatternBasedDigital" OldestCompatibleVersion="4.5.0.0" Version="4.6.0.49152" />
<ParsableNamespace AssemblyFileVersion="5.3.1.50153" FeatureSetName="Editor" Name="http://www.ni.com/PlatformFramework" OldestCompatibleVersion="5.2.0.49153" Version="5.2.0.49153" />
<ApplicationVersionInfo Build="5.3.1.50153" Name="Digital Pattern Editor" Version="19.0.0" />
</SourceModelFeatureSet>
<Project xmlns="http://www.ni.com/PlatformFramework">
<ProjectSettings Id="1" ModelDefinitionType="ProjectSettings" Name="ZProjectSettings" />
<EmbeddedDefinitionReference Id="2" ModelDefinitionType="NationalInstruments.ProjectExplorer.Modeling.ProjectDataManager" Name="ProjectExplorer">
<ProjectExplorer />
</EmbeddedDefinitionReference>
<NameScopingEnvoy Id="3" ModelDefinitionType="DefaultTarget" Name="DefaultTarget">
<DefaultTarget />
<FileReference Id="14" ModelDefinitionType="PinLevelsDefinition" Name="PinLevels\.digilevels" StoragePath="PinLevels.digilevels" p4:IsActive="True" xmlns:p4="http://www.ni.com/PatternBasedDigital" />
<FileReference Id="15" ModelDefinitionType="SpecificationsDefinition" Name="Specifications\.specs" StoragePath="Specifications.specs" />
<FileReference Id="17" ModelDefinitionType="TimingDefinition" Name="Timing\.digitiming" StoragePath="Timing.digitiming" p4:IsActive="True" xmlns:p4="http://www.ni.com/PatternBasedDigital" />
<FileReference Id="18" ModelDefinitionType="PinMap" Name="PinMap\.pinmap" StoragePath="PinMap.pinmap" p4:IsActive="True" xmlns:p4="http://www.ni.com/PatternBasedDigital" />
<SourceFileReference Id="790" ModelDefinitionType="ShmooSetupDefinition" Name="Shmoo\.digishmoo" StoragePath="Shmoo.digishmoo" />
<EmbeddedDefinitionReference Id="799" ModelDefinitionType="{http://www.ni.com/PatternBasedDigital}CaptureResultsDefinition" Name="CaptureResults">
<CaptureResultsDefinition xmlns="http://www.ni.com/PatternBasedDigital" />
</EmbeddedDefinitionReference>
<EmbeddedDefinitionReference Id="801" ModelDefinitionType="{http://www.ni.com/PatternBasedDigital}BurstResultsDefinition" Name="BurstResults">
<BurstResultsDefinition xmlns="http://www.ni.com/PatternBasedDigital" />
</EmbeddedDefinitionReference>
<EmbeddedDefinitionReference Id="803" ModelDefinitionType="{http://www.ni.com/PatternBasedDigital}SystemInfoDefinition" Name="SystemInfo">
<SystemInfoDefinition xmlns="http://www.ni.com/PatternBasedDigital" />
</EmbeddedDefinitionReference>
<EmbeddedDefinitionReference Id="804" ModelDefinitionType="{http://www.ni.com/PatternBasedDigital}DigitalScopeDefinition" Name="DigitalScope">
<DigitalScopeDefinition xmlns="http://www.ni.com/PatternBasedDigital" />
</EmbeddedDefinitionReference>
<FileReference Id="807" ModelDefinitionType="DigitalPatternEditor.PatternDefinition" Name="demo_pattern_no_hw\.digipat" StoragePath="demo_pattern_no_hw.digipat" />
<FileReference Id="840" ModelDefinitionType="CaptureWaveformDefinition" Name="demo_waveform\.digicapture" StoragePath="demo_waveform.digicapture" />
<FileReference Id="844" ModelDefinitionType="SourceWaveformDefinition" Name="demo_src_wfm\.tdms" StoragePath="demo_src_wfm.tdms" />
</NameScopingEnvoy>
<EmbeddedDefinitionReference Id="7" ModelDefinitionType="DigitalPatternEditor.ProjectPropertiesDefinition" Name="ProjectProperties">
<ProjectPropertiesDefinition xmlns="http://www.ni.com/PatternBasedDigital" />
</EmbeddedDefinitionReference>
</Project>
<ProjectInformation xmlns="http://www.ni.com/PlatformFramework" />
</SourceFile>
Loading