Multifunction DAQ

cancel
Showing results for 
Search instead for 
Did you mean: 

Specifying ao/StartTrigger PFI input in text based NIDAQmx

Solved!
Go to solution

I am in the process of converting some traditional NIDAQ code to NIDAQmx, and I am having a problem with continuous waveform output with a ao/StartTrigger.  I have a PCI 6251 multifunction DAQ running on Windows 7.

 

The relevant part of my code is as follows (this is in Pascal, TriggerEdge is defined as DAQmx_Val_Edge1_Falling)

 

//create a task

status:=DAQmxCreateTask('', @ExposeBeamTaskHandle);
if status=0 then
  begin
    //Define the output channels
    AOChannels:=BoardIdentifier+'/ao0:1';
    //Configure for +/- 10 V.
    status:=DAQmxCreateAOVoltageChan(ExposeBeamTaskHandle, PChar(AOChannels),
                                             '', -10.0, 10.0, DAQmx_Val_VoltageUnits2_Volts, nil);
    //configure the trigger input to start the output, use the default analog output start trigger
    status:=DAQmxCfgDigEdgeStartTrig(ExposeBeamTaskHandle, 'ao/StartTrigger', Trigger_Edge);

 

 

//Set the trigger inputs so that PFI6 is the input to ao/StartTrigger 


TerminalString:='/'+BoardIdentifier+'/ao/StartTrigger';
TriggerString:='/'+BoardIdentifier+'/PFI6';
status:=DAQmxConnectTerms(PChar(TriggerString), PChar(TerminalString), DAQmx_Val_DoNotInvertPolarity);

 

 

//Set the sampling rate
status:=DAQmxCfgSampClkTiming(ExposeBeamTaskHandle,
                                                    nil, // use the internal timer
                                                    1000000/TimeStep, //rate, in samples per second per channel
                                                    DAQmx_Val_Rising, //rising edge of thec clock
                                                    DAQmx_Val_AcquisitionType_FiniteSamps, //finite number of samples to acquire
                                                    Buf_Points); // number of points to output per channel

 

status:=DAQmxWriteBinaryI16(ExposeBeamTaskHandle,
                                              Buf_Points, //1 point per channel
                                              FALSE, //no autoupdate
                                              0, //no timeout...return immediately after writing
                                              DAQmx_Val_GroupByScanNumber, //interleaved data
                                             @Buffer[0], //Pointer to the array
                                             @SampsWritten, //number of samples actually written
                                              nil); // reserved for future use

 

status:=DAQmxStartTask(ExposeBeamTaskHandle);
StartingTime:=Time;
while ((not done) and (Time<StartingTime + 60000)) do
   begin
      status:=DAQmxIsTaskDone(ExposeBeamTaskHandle, @done);
   Application.ProcessMessages;
end;
status:=DAQmxStopTask(ExposeBeamTaskHandle);

 

 

+++++++++++++++++++++++++++++++++++++++++++++++++++++

 

The trigger is set independently by wiring to the PFI6 pin.

 

If I comment out the DAQmxCfgDigEdgeStartTrig command, I get the desired output.  However, the triggering does not work...(it did work in traditional NI-DAQ).  I get various errors on DAQmxWriteBinaryI16 (-89131, -89134 or -89137), which translate as either the particular route is already in use, or if I use /Dev1/PFI6 in DAQmxCfgDigEdgeStartTrig, that the source and the destination cannot be the same.

 

I cannot find any examples in textbased NIDAQmx on how to configure a specific PFI as input for the ao/StartTrigger.

 

Any help would be appreciated.

 

 

 

0 Kudos
Message 1 of 6
(4,217 Views)
Solution
Accepted by topic author shiva

Hi shiva,

 

The issue you are seeing is likely arising because of the following line of code:

 

status:=DAQmxCfgDigEdgeStartTrig(ExposeBeamTaskHandle, 'ao/StartTrigger', Trigger_Edge);

 

The function, DAQmxCfgDigEdgeStartTrig, routes a specified terminal to the AO Start Trigger; you cannot route the AO Start Trigger to itself.  Rather, you should specify PFI6 in this line:

 

status:=DAQmxCfgDigEdgeStartTrig(ExposeBeamTaskHandle, 'PFI6', Trigger_Edge);

 

DAQmx installs several ANSI C examples on your machine.  The following example on your machine should outline what you are trying to do:

 

<Documents>\National Instruments\NI-DAQ\Examples\DAQmx ANSI C\Analog Out\Generate Voltage\Mult Volt Updates-Int Clk-Dig Start

 

With this setup, you do not need the DAQmxConnectTerms function in your code.  This should get you squared away.

 

Regards,

Regards,
Chris Elliott
x36772
0 Kudos
Message 2 of 6
(4,198 Views)

Chris,

 

Thanks...I'll give a try and let you know what happens.

 

 

0 Kudos
Message 3 of 6
(4,194 Views)

Dear Chris,

 

Specifying 'PFI6' as the trigger indeed worked.  However, I have a few more questions regarding triggering and routing specific signals:

 

1.  In another part of my application, in addition to the triggered, timed analog output on two channels, I would like to perform ai on a single channel, with both ao and ai being triggered by the same event.  Can I specify the same trigger input 'PFI6' for both the ao and ai tasks, i.e.,  the full definition of the simultaneous ai task would be

 

status:=DAQmxCreateAIVoltageChan(ExposeAlignTaskHandle, PChar(AIChannel), '',
                      DAQmx_Val_InputTermCfg_Diff, -Image_input_voltage, Image_input_voltage,
                       DAQmx_Val_VoltageUnits2_Volts, nil);
status:=DAQmxCfgDigEdgeStartTrig(ExposeAlignTaskHandle, 'PFI6', Trigger_Edge);

 

 

2.  Timing is critical for my application...immediately after the requisite number of points are sent out by the ao task, it is important for me to send a specific digital line high (DO1).  If I wait for the output task to be done and then send the line high, the usual windows latency means that there is a few ms delay, which is not acceptable.  The way I have been getting around this is to use the two counters on the board to count the number of transitions of the ao update signal, and when the count reaches the expected output count, to send the digital line high.  In traditional NIDAQ, I wired the ao UPDATE signal to CTR0 input, and the CTR0 output, which is set up to send a pulse on reaching TC, to the input of CTR1.  In my working traditional NIDAQ code, I routed the signals using SELECT_SIGNAL.  My translation of this code into NIDAQmx is given below, but based on your suggestion earlier, I think the routing part is incorrect, i.e., I need to know how to wire the UPDATE output to the CTR0 input, and the CTR0 output to the CTR1 input.  I would also like to know if it is possible to reset the count of each counter to 0 without stopping and restarting the task.

 

Thanks in advance for your help!

 

(The traditional nidaq code are the statements that are commented out that begin with status=)

 

procedure Set_timers;
 var
     CTR0Channel,
     CTR1Channel : PChar;
     TriggerString,
     TerminalString :PChar;

  begin
     //General purpose counter 0
     //This counter is used to count the number of update clicks from the dacs
     //First create a task handle
     status:=DAQmxCreateTask('', @CTR0TaskHandle);

    //Next create a CTR channel to count edges, setting the initial count to 0
    StrPCopy(CTR0Channel, BoardIdentifier+'/ctr0');
    status:=DAQmxCreateCICountEdgesChan(CTR0TaskHandle,
                                                                  CTR0Channel, //Counter number
                                                                  '', //default virtual name to assign
                                                                  DAQmx_Val_Falling, //count on falling edge
                                                                  0, //initial count
                                                                  DAQmx_Val_CountDirection1_CountUp); // count direction

 

   //Reset the counter
   //Not sure if the next line is already taken care of above
   // status:=GPCTR_Control(deviceNumber, ND_COUNTER_0, ND_RESET);

   //Application is simple event counting ************ ALREADY DONE ABOVE !!
   // status:=GPCTR_Set_Application(deviceNumber, ND_COUNTER_0, ND_SIMPLE_EVENT_CNT);

   //Set the initial count to 0 ************ ALREADY DONE ABOVE !!
   // status:=GPCTR_Change_Parameter(deviceNumber, ND_COUNTER_0, ND_INITIAL_COUNT, 0);


   //Use the UPDATE* signal from the dacs on the PFI_5 pin
   StrPCopy(TriggerString,'/'+BoardIdentifier+'/ao/SampleClock'); //may want to change this to PFI5 
   StrPCopy(TerminalString, '/'+BoardIdentifier+'Ctr0Source');
   status:=DAQmxConnectTerms(TriggerString, TerminalString, DAQmx_Val_DoNotInvertPolarity);

 

   //the lines abopve replaced the lines below
   //status:=GPCTR_Change_Parameter(deviceNumber, ND_COUNTER_0, ND_SOURCE,ND_PFI_5);

   //ALREADY TAKEN CARE OF ABOVE
   // status:=GPCTR_Change_Parameter(deviceNumber, ND_COUNTER_0, ND_SOURCE_POLARITY, ND_HIGH_TO_LOW);

 

  //Output pulses on reaching TC
  status:=DAQmxSetExportedCtrOutEventOutputBehavior(CTR0TaskHandle,DAQmx_Val_ExportActions2_Pulse);

 

   //line above replaced the line below
  // status:=GPCTR_Change_Parameter(deviceNumber, ND_COUNTER_0, ND_OUTPUT_MODE, ND_PULSE);

  //Arm the counter, ready to start when the waveform output starts
  //Will do this at the end for both counters
  // status:=GPCTR_Control(deviceNumber, ND_COUNTER_0, ND_PROGRAM);


  {counter number 1. This counter is hooked up to counter 0, and it counts
  how many times the other counter has turned over}

  //First create a task handle
  status:=DAQmxCreateTask('', @CTR1TaskHandle);

  StrPCopy(CTR1Channel, BoardIdentifier+'/ctr1');
  status:=DAQmxCreateCICountEdgesChan(CTR1TaskHandle,
                                                                CTR1Channel, //Counter number
                                                                 '', //default virtual name to assign
                                                                DAQmx_Val_Rising, //count on falling edge
                                                                0, //initial count
                                                                DAQmx_Val_CountDirection1_CountUp); // count direction

  //Reset the counter
  // status:=GPCTR_Control(deviceNumber, ND_COUNTER_1, ND_RESET);

  //Application is simple event counting
  // status:=GPCTR_Set_Application(deviceNumber, ND_COUNTER_1, ND_SIMPLE_EVENT_CNT);

  //Set the initial count to 0
  // status:=GPCTR_Change_Parameter(deviceNumber, ND_COUNTER_1, ND_INITIAL_COUNT, 0);


  //Use TC output of the first counter
  StrPCopy(TriggerString,'/'+BoardIdentifier+'Ctr0Out'); //may want to change this to PFI5
  StrPCopy(TerminalString, '/'+BoardIdentifier+'Ctr1Source');
  status:=DAQmxConnectTerms(TriggerString, TerminalString, DAQmx_Val_DoNotInvertPolarity);
  //The above lines replaced the line below
  // status:=GPCTR_Change_Parameter(deviceNumber, ND_COUNTER_1, ND_SOURCE, ND_OTHER_GPCTR_TC);

  //Line below is taken care of above by DAQmx_Val_Rising
  // status:=GPCTR_Change_Parameter(deviceNumber, ND_COUNTER_1, ND_SOURCE_POLARITY, ND_LOW_TO_HIGH);

  //Arm the counter, ready to start when the waveform output starts
  // status:=GPCTR_Control(deviceNumber, ND_COUNTER_1, ND_PROGRAM);

  //Start both counter tasks
  status:=DAQmxStartTask(CTR0TaskHandle);
  status:=DAQmxStartTask(CTR1TaskHandle);
  end;

 

0 Kudos
Message 4 of 6
(4,188 Views)

Hi shiva,

 

I'm glad to hear you were able to get the start trigger working.  With regards to your other questions, it would be a good idea to post a new thread for each so that other users can more easily find relevant information in forum posts.  I'll give you some quick responses here, but you should start new threads to get in-depth discussions:

 

  1. No, but you can use the start trigger of one task (master) to start the other (slave).  The slave task should be running first, waiting for a start trigger, then when the master is started, its start trigger will start the slave task.
  2. There is no hardware event at the end of a finite analog acquisition, so counter/timers are indeed one solution.  There may be some other ways to go about doing this in DAQmx, but this question would be best addressed in a separate thread since it is unrelated and somewhat complex.

 

Regards,

Regards,
Chris Elliott
x36772
0 Kudos
Message 5 of 6
(4,178 Views)

Chris,

 

Thanks.  I will post the other two questions separately.

 

 

0 Kudos
Message 6 of 6
(4,175 Views)