Multifunction DAQ

cancel
Showing results for 
Search instead for 
Did you mean: 

Synchronize Analog outputs to Counter

Solved!
Go to solution

I'm trying to synchronize a set of signals including two analog outputs to a counter signal. This is using X-series PXIe-6356 DAQ cards. This counter signal is in turn gated by another counter signal. This would be an example of what the TTL (or LV-TTL) output looks like:

gated_ttl_pulse_train.png

The red line is the gate signal (ctr2), the blue line is the timing signal (ctr0) and reflects time-to-digital conversion (TDC) pulses measured on the rising edge. The gate signal is required to be low every 10 s by a third-party device to do ... something. In this plot, the period of the gate is 3x the TDC period, plus 25 ns so the last rising edge shows up, although in practice the TDC will probably be ~1 MHz and the gate about 0.1 Hz. What I want to do, is also send out a two analog outputs (ai0:1) that change with each blue TDC rising edge. Importantly, the analog outputs are not repeated every gate pulse, I need to provide the entire analog output sequence, one for each TDC. In the below script I am just using random numbers to illustrate the requirements. This 6356 card has two simultaneous AOs.

 

Here's my simplified script (Python using the`nidaqmx` package):

 

from time import perf_counter as pc, sleep
import numpy as np
import nidaqmx as ni
from nidaqmx.constants import AcquisitionType, TaskMode, TimeUnits, Level, Edge

SLEEP_TIME = 0.001
SAFETY_FACTOR = 1.5

duty_cycle = 0.5
pulse_period = 1e-3 #
frequency = 1.0 / pulse_period

n_trigger = 8
n_gate = 8
tot_samples = (n_trigger + 1) * n_gate
scan_volts = 8.0
scan_max = 1.125 * scan_volts

coords = np.random.uniform(low=-scan_volts, high=scan_volts, size=(tot_samples, 2))

readout_period = 0.005
debounce_period = 25e-9
gate_high = pulse_period * n_trigger + debounce_period
gate_low = np.maximum(pulse_period, readout_period)
t_acquire = n_gate * (gate_high + gate_low)

parent_timing = ni.Task()
parent_gate = ni.Task()
parent_scan = ni.Task()

try:
    parent_gate.co_channels.add_co_pulse_chan_time(
            'dev1/ctr2',
            units          = TimeUnits.SECONDS,
            idle_state     = Level.LOW,
            initial_delay  = 0.0,
            low_time       = gate_low,
            high_time      = gate_high)
    parent_gate.timing.ref_clk_src = 'PXIe_Clk100'
    parent_gate.timing.ref_clk_rate = 100000000
    parent_gate.timing.cfg_implicit_timing(
            sample_mode    = AcquisitionType.FINITE,
            samps_per_chan = n_gate)
    parent_gate.triggers.sync_type.MASTER = True

    parent_timing.co_channels.add_co_pulse_chan_time(
        'dev1/ctr0',
        units=TimeUnits.SECONDS,
        idle_state=Level.LOW,
        initial_delay = 0.0,
        low_time      = (1.0 - duty_cycle) * pulse_period,
        high_time     = duty_cycle * pulse_period)
    parent_timing.timing.ref_clk_src = 'PXIe_Clk100'
    parent_timing.timing.ref_clk_rate = 100000000
    parent_timing.timing.cfg_implicit_timing(
        samps_per_chan=n_trigger + 1,
        sample_mode=AcquisitionType.FINITE)
    parent_timing.triggers.start_trigger.cfg_dig_edge_start_trig(
                    'Ctr2Source',
                    trigger_edge=Edge.RISING)
    parent_timing.triggers.start_trigger.retriggerable = True

    parent_scan.ao_channels.add_ao_voltage_chan(
        'dev1/ao0:1',
        max_val=scan_max,
        min_val=-scan_max)
    parent_scan.triggers.start_trigger.cfg_dig_edge_start_trig(
        'dev1/ctr0source')
    parent_scan.timing.cfg_samp_clk_timing(frequency,
            source='dev1/ctr0source',
            active_edge=Edge.RISING,
            sample_mode=AcquisitionType.FINITE,
            samps_per_chan=tot_samples)
    '''
    So what is valid here for source?

        nidaqmx.errors.DaqError: Source terminal to be routed could not be found on the device.
        Make sure the terminal name is valid for the specified device. Refer to Measurement & Automation Explorer for valid terminal names.
        Property: DAQmx_SampClk_Src
        Property: DAQmx_SampClk_ActiveEdge
        Source Device: dev1
        Source Terminal: dev1/ctr0internaloutput

    Some of the ANSI C examples use PFI sources, but 'dev1/PFI12' generates the same error.

        nidaqmx.errors.DaqError: Source terminal to be routed could not be found on the device.
        Make sure the terminal name is valid for the specified device. Refer to Measurement & Automation Explorer for valid terminal names.

        Property: DAQmx_SampClk_Src
        Property: DAQmx_SampClk_ActiveEdge
        Source Device: dev1
        Source Terminal: dev1/PFI12
    '''
   
    transposed_coords = coords.T.copy()
    parent_scan.write(transposed_coords, timeout=SAFETY_FACTOR * t_acquire, auto_start=False)
   
    parent_scan.start()
    parent_timing.start()

    # Everything should start with this Task
    parent_gate.start()

    sleep(t_acquire)
    while not parent_gate.is_task_done():
        sleep(SLEEP_TIME)

# Close tasks
# -----------
finally:
    parent_timing.close()
    parent_gate.close()
    parent_scan.close()

 

 

Here's the routing table:

ni_daqmx_routes.png

 

My main question is, what are valid ids for the `source` argument in `cfg_samp_clk_timing` (or `CfgSampClkTiming` in C parlance)? I've not been able to establish any acceptable strings for this input argument. I've taken a look at the ANSI C examples, which seem to be the most exhaustive, and there's no use cases of it for the analog outputs where the `sample` argument isn't the default sample clock. For the analog inputs, sometimes they specify by PFI, but if I try `dev1/PFI12` which corresponds to `ctr0` I get the same error as if I specify `dev1/Ctr0Source`:

 

        nidaqmx.errors.DaqError: Source terminal to be routed could not be found on the device.
        Make sure the terminal name is valid for the specified device. Refer to Measurement & Automation Explorer for valid terminal names.
        Property: DAQmx_SampClk_Src
        Property: DAQmx_SampClk_ActiveEdge
        Source Device: dev1
        Source Terminal: dev1/ctr0source

 

Any thoughts? Using the latest DAQmx 2022 Q4 release.

 

0 Kudos
Message 1 of 3
(878 Views)
Solution
Accepted by topic author robertmc

This is a subtle one.  The correct string to designate a terminal needs to start with a forward slash '/' character.

So "/dev1/PFI12" would be the correct designation.

 

I don't know enough Python to comment on any other details, but can confirm that what you describe *wanting* to do is in fact do-able with your device.

 

 

-Kevin P

 

CAUTION! New LabVIEW adopters -- it's too late for me, but you *can* save yourself. The new subscription policy for LabVIEW puts NI's hand in your wallet for the rest of your working life. Are you sure you're *that* dedicated to LabVIEW? (Summary of my reasons in this post, part of a voluminous thread of mostly complaints starting here).
Message 2 of 3
(829 Views)

Hi Kevin, thanks for your help, it's running without errors at least now. Now I have to connect the Picoscope and see if it's doing what I think it's doing...

0 Kudos
Message 3 of 3
(812 Views)