Counter/Timer

cancel
Showing results for 
Search instead for 
Did you mean: 

Counting with Arm Start Trigger with Python - NI-DAQmx

We are trying to arm start trigger with the DAQ board to acquire data from a single photon counter. We developed the code like this: 

 

# Create a counter task:
readTask = nidaqmx.Task()
channel = readTask.ci_channels.add_ci_count_edges_chan("Dev1/ctr0","", initial_count=0, edge=Edge.RISING, count_direction=CountDirection.COUNT_UP)
channel.ci_count_edges_term = "PFI0"

#Configure start trigger
readArmTrig = readTask.triggers.arm_start_trigger
readArmTrig.trig_type = TriggerType.DIGITAL_EDGE
readArmTrig.dig_edge_src="PFI4"

 

However I don't think the program reads the ci_channel with the trigger we defined. Do anyone know how to enable the arm trigger for a digital counter? Thanks. 

 

Jon

0 Kudos
Message 1 of 21
(6,025 Views)

I don't know the syntax for the API from Python, but it *looks* to me as though you are creating some kind of "trigger object" to define your arm start trigger.  You are setting the necessary properties (trigger type and signal source.  You can also specify either rising or falling edge polarity if that's important to your app).  But you're never calling a DAQmx trigger config function to make any *association* between this "trigger object" and your task.   I think that might be all that's missing.

 

Or it's possible that the API for configuring triggers needs to deal with those settings a different way rather than packaged up in that "trigger object."   But the main thing is that it looks like you've created some kind of trigger object variable that the task knows nothing about.

 

 

-Kevin P

ALERT! LabVIEW's subscription-only policy came to an end (finally!). Unfortunately, pricing favors the captured and committed over new adopters -- so tread carefully.
0 Kudos
Message 2 of 21
(5,971 Views)

Thanks, Kevin. It's likely that we are missing some sort of mechanism to pass the parameters to the task, as you said.

 

Here is a little more background on this. If it's a regular trigger, we will use this code.

 

 

 

readStartTrig = readTask.triggers.start_trigger
readStartTrig.cfg_dig_edge_start_trig("PFI4",Edge.RISING)

 

 

 

The cfg_dig_edge_start_trig function is defined here: https://nidaqmx-python.readthedocs.io/en/latest/start_trigger.html

However, there is not an equivalent function for arm trigger: https://nidaqmx-python.readthedocs.io/en/latest/arm_start_trigger.html

 

I will try to add one more properties to define the rising edge and see what happens. Any more thoughts?

0 Kudos
Message 3 of 21
(5,964 Views)

Not being a Python guy, the help you linked isn't able to help *me* very much.  I just don't understand how to navigate and interpret what I see.

 

I would generally expect that the right coding approach for setting up an Arm Start trigger should look & feel a lot like setting up a regular Start trigger.  Just with the name "arm_start" in place of "start" and suchlike.

 

If you have source modules for the DAQmx Python API, I'd try text searching them for the expected function that wasn't shown on that help website.  Maybe it actually exists and the help site isn't complete?   Arm Start triggers are kind of a special little corner case area of DAQmx and might have gotten missed.

 

 

-Kevin P

ALERT! LabVIEW's subscription-only policy came to an end (finally!). Unfortunately, pricing favors the captured and committed over new adopters -- so tread carefully.
0 Kudos
Message 4 of 21
(5,952 Views)

The python functions are wrappers of the corresponding C functions, such as DAQmxSetDigEdgeArmStartTrigSrc, etc. There are indeed nothing like CfgArmStartTrig in the c library. I found an old post that might be related to this topic, in which the configuration seems not necessary ... here is the link, https://forums.ni.com/t5/Measurement-Studio-for-VC/DAQmx-synchronizing-two-pulse-output-tasks/td-p/1...

0 Kudos
Message 5 of 21
(5,946 Views)

After reading the aforementioned last post from Roger, I run a test to print out the terminal name after setting the arm start trigger. It seems that there is a bug somewhere which results a terminal name: "/Dev1/Ctr0StartArmTrigger", which clearly should be "/Dev1/Ctr0/StartArmTrigger" or something similar. 

0 Kudos
Message 6 of 21
(5,941 Views)

Can we back up a couple steps?   What exactly do you need to accomplish with this "Arm Start" triggering?   I just want to make sure that it's actually necessary for the task at hand, considering the difficulty in getting in configured and working.

 

 

-Kevin P

ALERT! LabVIEW's subscription-only policy came to an end (finally!). Unfortunately, pricing favors the captured and committed over new adopters -- so tread carefully.
0 Kudos
Message 7 of 21
(5,925 Views)

The task seems fairly elementary. The trigger is used to find out the difference between two sequential counter readouts. Here is a simple diagram.

JonDOEreal_0-1596817317463.png

0 Kudos
Message 8 of 21
(5,908 Views)

But what is it that you're actually *counting*?   What's the meaning/importance of the time when the triggering signal pulses?   Where is the sample clock coming from?

 

My understanding:

- you've got some kind of pulsing signal that you want to count

- you've got some other pulsing signal that'll act as a sample clock

- you only want to start counting and sampling after a triggering pulse happens

- all you actually care about is the count difference between the those first two samples following the triggering event

 

Is this correct?  If so, then configuring for an arm start trigger is at least sensible and from what I understand so far, probably necessary.

 

Moving on, I looked over that other thread you linked where (eventually) it seemed that the C interface to DAQmx does indeed support Arm Start Triggers.  So what's different?   Well, here's what I can come up with, but the caveat is that I don't have a good understanding of python syntax and grammar.

 

In the C function calls, the functions themselves include DAQmx in the names, indicating to me that they're part of the NI-supplied API.   When configuring the Arm Start Trigger, the function call arguments include a task handle.  So it's pretty clear that DAQmx has a way to associate the config argument with the task argument.

 

As I try to interpret your python configuration code, here's what I'm thinking, line by line.

 

readArmTrig = readTask.triggers.arm_start_trigger

A new variable is being created on-the-fly whose name is "readArmTrig".  Its type and value is determined by whatever the expression "readTask.triggers.arm_start_trigger" resolves to. 

   To me this looks like a mere query and assignment.  We're asking the readTask about its trigger info and particularly about its arm_start_trigger.  Which is presently NULL at the moment we query as we haven't configured it yet.

 

 

readArmTrig.trig_type = TriggerType.DIGITAL_EDGE
readArmTrig.dig_edge_src="PFI4"

 

We're now setting some properties of this new variable.  Apparently, "readArmTrig" is an object that contains properties related to triggering.  And now we've set the "trig_type" property to be a digital edge and the "dig_edge_src" property to be "PFI4".

   But so what?  These are just values held in an object that doesn't reference back to the task.  (And also, given the lessons of the linked thread, the source string should look more like "/Dev1/PFI4", with the very important leading forward slash.)

 

Might it be the case that we should now do something like this?

readTask.triggers.arm_start_trigger = readArmTrig

Would this take the trigger config info we just assigned in the standalone variable and copy it over to the actual task?   I sure don't know, but it's something I wonder as I try to think this through.

 

 

-Kevin P

ALERT! LabVIEW's subscription-only policy came to an end (finally!). Unfortunately, pricing favors the captured and committed over new adopters -- so tread carefully.
Message 9 of 21
(5,900 Views)

I am new to Python as well, Kevin, but hopefully I can answer your question correctly.

In Python, you actually are calling a setter function when you assign a value, for example, to dig_edge_src, in which the following function is called.

 

 

    @dig_edge_src.setter
    def dig_edge_src(self, val):
        cfunc = lib_importer.windll.DAQmxSetDigEdgeArmStartTrigSrc
        if cfunc.argtypes is None:
            with cfunc.arglock:
                if cfunc.argtypes is None:
                    cfunc.argtypes = [
                        lib_importer.task_handle, ctypes_byte_str]

        error_code = cfunc(
            self._handle, val)
        check_for_error(error_code)

 

 

The first line in my code is to obtain a handle. When you assigned the value it should be equivalent to the line quoted in the last post, I think.

 

 

DAQmxErrChk(DAQmxSetDigEdgeArmStartTrigSrc(LasHandle,TrgTerm));

 

 

 

Make sense?

 

0 Kudos
Message 10 of 21
(5,893 Views)