01-13-2013 05:22 PM
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.
Solved! Go to Solution.
01-14-2013 01:22 PM
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,
01-14-2013 01:34 PM
Chris,
Thanks...I'll give a try and let you know what happens.
01-14-2013 03:38 PM
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;
01-15-2013 07:51 AM
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:
Regards,
01-15-2013 09:26 AM
Chris,
Thanks. I will post the other two questions separately.