08-05-2020 06:18 PM
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
08-06-2020 07:55 AM
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
08-06-2020 11:15 AM - edited 08-06-2020 11:31 AM
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?
08-06-2020 01:15 PM
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
08-06-2020 02:57 PM
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....
08-06-2020 03:19 PM
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.
08-06-2020 11:02 PM
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
08-07-2020 11:23 AM
The task seems fairly elementary. The trigger is used to find out the difference between two sequential counter readouts. Here is a simple diagram.
08-07-2020 05:58 PM
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
08-07-2020 07:18 PM - edited 08-07-2020 07:23 PM
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?