10-15-2007 02:55 PM
10-15-2007 08:13 PM
DAQmxErrChk (DAQmxCreateTask("",&taskHandle));
DAQmxErrChk (DAQmxCreateDOChan(taskHandle,"Dev1/port0","",DAQmx_Val_ChanForAllLines));
DAQmxErrChk (DAQmxStartTask(taskHandle));
DAQmxErrChk (DAQmxWriteDigitalU32(taskHandle,1,1,10.0,DAQmx_Val_GroupByChannel,&data,&written,NULL));
Error:
if( DAQmxFailed(error) ) DAQmxGetExtendedErrorInfo(errBuff,2048);
if( taskHandle!=0 ) {
DAQmxStopTask(taskHandle);
DAQmxClearTask(taskHandle);
}
...
It seems natural to use the start() first and then the write() so many times as you need, isn't it?
Yes, that's how it works for reading analog data and I suppose digital data as well. We have done all these programming techniques, continuous reading using callback functions to get the data in real time etc. And they all work.
But to WRITE digital data, it does not work. It raises the error: "Generation cannot be started because the output buffer is empty" !
You need to use write() first, where you set the buffer and the number of bytes to write, and THEN use the starttask() to make it work.
But THEN... you also need to stop() it if you want to start() again... and you are trapped on the bad loop of start/stop.
Or... you can use the write() with the autostart parameter true, what makes the same as if you use the start() / stop() approach. It is weird? Yes it is. But you need to write() first to set the output buffer and then you can use the start(). The result? Horrible timing.
10-16-2007 12:18 AM
LMP,
Unfortunately I am at home and do not have any hardware with me to test the example now (nor do I have Traditional DAQ installed, so I am without reference for that at the moment). I will say that I use the LabVIEW version of this example quite frequently and have not had any problems with it. There is only one line which looks suspicious to me which is the following:
DAQmxErrChk (DAQmxWriteDigitalU32(taskHandle,1,1,10.0,DAQmx_Val_GroupByChannel,&data,&written,NULL));
I am not sure why they 'autoStart' argument is set to '1' since the task was already started. I would think this should be set to '0' (though according to the documentation this should have no effect for a task which was already started). At this point you should be able to write repeatedly. However this does not seem to be in line with the behavior you are seeing. Let me ask a few questions so that I can clarify what you are trying to accomplish in my mind.
>> It raises the error: "Generation cannot be started because the output buffer is empty" !
You need to use write() first, where you set the buffer and the number of bytes to write, and THEN use the starttask() to make it work.
When you originally wrote that you were writing an application to replace an E-Series device, I assumed that you were performing software timed writes (essentially every call to the write function updates the value output on your digital port. However, this error would seem to indicate that you have explicitly set up a buffer (and possibly hardware timing?) as part of your task. If you have configured timing, then essentially then data will need to be written before that task is started such that there is data available to the hardware before the clock responsible for updating the port occurs. However, I don't believe that E-Series devices had this functionality, so I was assuming that this was not what you were attempting. I would imagine you would get such an error if you called DAQmxCfgInputBuffer or DAQmxCfgSampClkTiming.
>> As we see, there are two different issues here:
1) the simple low level I/O write of the Traditional that we do not have in the Mx. THIS should be the right solution.
2) how to make the task approach less cumbersome and time consuming just to write a byte!
To address point 1, DAQmx is task based. Therefore, the key is to configure the task to behave the way you would like it to. There really aren't any low level functions that should be necessary to make this happen. Ideally, you would create your channels, do any configuration necessary (for example setting up any timing parameters or triggers), start the task, then read or write the task as required. Once the task is started, you should be able to call DAQmxWriteDigitalXX just as you would have DIG_Out_Prt, and DAQmx should update your hardware with the new value you have written.
>> We need to use the WriteDigitalU8() that needs 8 parameters (!) and uses a BUFFER to write N bytes, not to mention the task control
To address this and point number 2 above, the idea behind the highly parameterized DAQmxWriteDigitalXX functions I believe was to present a consistent interface to write data regardless of 'application' or task configuration. The parameters of write and the configuration of the task tell the driver how to behave (This in effect presents a consistent interface across functionality, and eliminates the need for 'low' level functions). In a software timed case, the driver will write the data in 'writeArray' to the hardware as quickly as possible. In a hardware timed, buffered case the driver will write the data in 'writeArray' to the buffer from which the hardware reads as quickly as possible.
Hopefully this information is at least informative, and at most helpful. At this point, I would suspect from the errors that you are seeing that something in your task's configuration is not quite correct for what you are trying to do. I'll see about giving the example a try when I get to work tomorrow and have some hardware available to me. In the mean time, please let me know if you have questions about any of that, or if I am still not understanding what you need to accomplish.
Dan
10-16-2007 08:59 AM
10-16-2007 01:37 PM
DAQmxErrChk (DAQmxCreateTask("",&taskHandle));
DAQmxErrChk (DAQmxCreateDOChan(taskHandle,"Dev1/port0","",DAQmx_Val_ChanForAllLines));
DAQmxErrChk (DAQmxCfgSampClkTiming(taskHandle,"/Dev1/PFI0",1000.0,DAQmx_Val_Rising,DAQmx_Val_FiniteSamps,1000));
Please note that the digital lines on M-Series devices do not have any timing mechanism dedicated to them. Therefore you will need to provide an external clock to it. For my testing purposes, I used Counter 0 to output a pulse train to use as the sample clock for my digital task. I simply wired this to PFI0, which I used as a sample clock source. Here, write will complete as soon as DAQmx has been able to transfer your requested samples into a buffer on your PC. Because of this, I use the DAQmxWaitUntilTaskDone call to wait for all of my sample to be output before I continue.
Hopefully these modified examples will guide you in the right direction. Please let me know if you have any other questions.
Hope this helps,
Dan
10-16-2007 02:39 PM
>> Please note that the digital lines on M-Series devices do not have any timing mechanism dedicated to them.
Ok, but it accepts the clkTiming() with an internal clock source for generation of the output waveform with no errors or warnings. It accepts the parameter but it seems it does not use it or obey it.
On the other stuff, we are in synch.
Thanks for your help,
🙂
10-16-2007 03:33 PM
10-16-2007 05:40 PM
10-16-2007 06:04 PM
10-16-2007 06:08 PM
Hi LMP,
Here is an instance where DAQmxCfgSampClkTiming may not behave exactly how you are expecting. The error you receive that states that there is no clock source in the device when you attempt to use on-board clock is correct. That is because M-Series devices do not have timing controllers dedicated to them like AI or AO would. With AI and AO have some dedicated timers which can be used to create clock signals for those subsystems. If you use the onboardClock option with these subsystems and set a sample rate, hardware will get programmed which causes these counters to create a clock signal with the specified rate, and will then route this signal to your DAC or ADC. Things are a bit different for Digital input or Digital Output.
These subsystems lack the ability to create their own clock. Therefore they must use a source which is external to the subsystem. There are several multiple signals which are possible to use as a sample clock for DI or DO. Dev1/100KhzTimebase is routable to the do/sampleClock. If you configure this route, DO will update at the rate of this clock, in this instance 100 kHz. The rate input to DAQmxCfgSampClkTiming will only be used by the driver as a sanity check for what you are attempting, not to control the the frequency of the sample clock. This is why I had tested my earlier example by using a counter to provide a clock for my digital output.
Hope this helps,
Dan