10-02-2008 01:55 PM
Hi,
I’m trying
to build an MFC application with MSVC++6, where I would continuously acquire
samples on 8 analog channels of a USB-6008. I’m using the DAQmx C functions. The sampling rate is rather low (100 Hz), but
it is important that all the sample values are written to disk. Also, I want to
read the digital lines every second (that part is easy by using the Timer class
in MFC).
So I tried
this C example code: ContAcq-IntClk.c.
It explains how to acquire data continuously, using a callback
function. I took a modified version of
this program where it saves the data on disk. I tried different values, but I
can’t get all the data written, there are always gaps (dropped values).
What I
would like to achieve is that: when more than half of the internal buffer is
filled, the first half is written to disk. After that, when the buffer is
completely filled and start to be filled from its beginning, the second half is
written to disk and so on. But now I'm lost, I have no idea of how to achieve that.
It would be
greatly appreciated if you could tell me how to code it in C++.
Thank you
in advance
Marc Melillo
marc.melillo@umontreal.ca
10-03-2008 04:24 PM
Hi Marc,
Can you please explain what your mean by dropped values? Are you receiving any buffer errors? To achieve your goal, you can set the buffer size and then read half the values. NI-DAQmx help has information on how to use the set buffer size function. To access help, go to Start » Programs » National Instruments » NI-DAQmx C Reference Help. You can search for buffer or set buffer size once you have the help open.
Thank you,
10-07-2008 03:54 PM
Hi Simran,
Thank you for replying. I ran a test using a sampling rate of 200 Hz, with a buffer of 10K samples. The callback function is called each 5K samples acquired. I put the values in Excel and made that graph:
[IMG]http://i472.photobucket.com/albums/rr88/melimelo/graphdata.jpg[/IMG]
The analog signal is a perfect sine wave. The x axis is not exactly the time, because it's a simple curve graph in Excel, using one column of data. The gaps in the values can be seen on the graph. There are also strange values in the data on disk: it seems that some values are "truncated", i.e. normally they values are between -5 and 2 (floating point), but some show up like -2.354529-2.354529 or 6568. It's like some characters used to represent the values are missing.
Here is the source code:
#include <stdio.h>
#include <NIDAQmx.h>
#define DAQmxErrChk(functionCall) if( DAQmxFailed(error=(functionCall)) ) goto Error; else
int32 CVICALLBACK EveryNCallback(TaskHandle taskHandle, int32 everyNsamplesEventType, uInt32 nSamples, void *callbackData);
int32 CVICALLBACK DoneCallback(TaskHandle taskHandle, int32 status, void *callbackData);
int main(void)
{
int32 error=0;
TaskHandle taskHandle=0;
char errBuff[2048]={'\0'};
/*********************************************/
// DAQmx Configure Code
/*********************************************/
DAQmxErrChk (DAQmxCreateTask("",&taskHandle));
DAQmxErrChk (DAQmxCreateAIVoltageChan(taskHandle,"Dev1/ai0","",DAQmx_Val_Cfg_Default,-10.0,10.0,DAQmx_Val_Volts,NULL));
DAQmxErrChk (DAQmxCfgSampClkTiming(taskHandle,"",200.0,DAQmx_Val_Rising,DAQmx_Val_ContSamps,10000));
DAQmxErrChk (DAQmxRegisterEveryNSamplesEvent(taskHandle,DAQmx_Val_Acquired_Into_Buffer,5000,0,EveryNCallback,NULL));
DAQmxErrChk (DAQmxRegisterDoneEvent(taskHandle,0,DoneCallback,NULL));
/*********************************************/
// DAQmx Start Code
/*********************************************/
DAQmxErrChk (DAQmxStartTask(taskHandle));
printf("Acquiring samples continuously. Press Enter to interrupt\n");
getchar();
Error:
if( DAQmxFailed(error) )
DAQmxGetExtendedErrorInfo(errBuff,2048);
if( taskHandle!=0 ) {
/*********************************************/
// DAQmx Stop Code
/*********************************************/
DAQmxStopTask(taskHandle);
DAQmxClearTask(taskHandle);
}
if( DAQmxFailed(error) )
printf("DAQmx Error: %s\n",errBuff);
printf("End of program, press Enter key to quit\n");
getchar();
return 0;
}
int32 CVICALLBACK EveryNCallback(TaskHandle taskHandle, int32 everyNsamplesEventType, uInt32 nSamples, void *callbackData)
{
int32 error=0;
char errBuff[2048]={'\0'};
static int totalRead=0;
int32 read=0;
float64 data[5000];
int i;
FILE *datafile;
datafile = fopen("testdata","a");
/*********************************************/
// DAQmx Read Code
/*********************************************/
DAQmxErrChk (DAQmxReadAnalogF64(taskHandle,5000,10.0,DAQmx_Val_GroupByScanNumber,data,5000,&read,NULL));
if( read>0 ) {
printf("Acquired %d samples. Total %d\r",read,totalRead+=read);
for (i=0;i<=5000;i++){
fprintf(datafile,"%f\n",data[i]);
}
fflush(stdout);
}
Error:
if( DAQmxFailed(error) ) {
DAQmxGetExtendedErrorInfo(errBuff,2048);
/*********************************************/
// DAQmx Stop Code
/*********************************************/
DAQmxStopTask(taskHandle);
DAQmxClearTask(taskHandle);
printf("DAQmx Error: %s\n",errBuff);
}
return 0;
}
int32 CVICALLBACK DoneCallback(TaskHandle taskHandle, int32 status, void *callbackData)
{
int32 error=0;
char errBuff[2048]={'\0'};
// Check to see if an error stopped the task.
DAQmxErrChk (status);
Error:
if( DAQmxFailed(error) ) {
DAQmxGetExtendedErrorInfo(errBuff,2048);
DAQmxClearTask(taskHandle);
printf("DAQmx Error: %s\n",errBuff);
}
return 0;
}
Obviously, I do something wrong, but I can't spot it. Can you help please?
Thank you in advance,
Marc Melillo
10-08-2008 07:34 AM
Hi, I have done nearly the same, so it should be possible. Here are some suggestions:
You can set some flags for the buffering like DAQmxErrChk( DAQmxSetReadOverWrite(m_taskHandle,DAQmx_Val_DoNotOverwriteUnreadSamps) ); but then you must be
sure to keep up with the system.
In DAQmxReadAnalog you can use -1 to read all available samples?
And maybe you can keep the output file open, until finished?
-cpede
10-08-2008 03:34 PM
Hi cpede,
Thank you for answering. I tried the DAQmxSetReadOverWrite() function as you said, I tried also to put -1 instead of 500, I even tried to put the DAQmx read function as the very first function inside the callback function, but with no luck. I did another test, this time using a ramp function instead of a sine wave. The ramp is not very smooth because I generated it manually by slowly turning a potentiometer.
You can clearly see on this graph that some portions are misplaced, so that leads me to a problem in the reading position in the internal buffer. BTW, that test had 3 calls of the callback function, 25 seconds each (200Hz*5000 samples). Does this rings you a bell?
Again, thank you in advance
Marc Melillo
marc.melillo@umontreal.ca
10-09-2008 05:33 PM
Hi Marc,
Can you please run the original example without modifications and see if you receive all the data without any gaps? If you do, there could be a problem with the File I/O portion of the code. How are you writing the data to the disk?
Thank you,
10-10-2008 12:53 PM
Hi Sirman,
As the original ContAcq-IntClk.c file doesn't save data to disk, I took the modified version by Saha at National Instruments (can by found here). Her version works fine, but it saves just the first 100 data of the buffer, not the whole buffer as I want. And really, I can't see something wrong with my disk I/O part:
for (i=0;i<=5000;i++){
fprintf(datafile,"%f\n",data[i]);
}
Anyway, I added these line right after the DAQmxCfgSampClkTiming() function:
DAQmxErrChk (DAQmxCfgInputBuffer (taskHandle, 10000));
DAQmxErrChk( DAQmxSetReadOverWrite(taskHandle,DAQmx_Val_DoNotOverwriteUnreadSamps) );
And at the beginning of the callback function, I added these three function calls, around the DAQmxReadAnalogF64() function.
DAQmxErrChk (DAQmxGetReadCurrReadPos(taskHandle, &readpos));
DAQmxErrChk (DAQmxGetReadAvailSampPerChan(taskHandle, &availdata));
DAQmxErrChk (DAQmxReadAnalogF64(taskHandle,5000 ,10.0,DAQmx_Val_GroupByScanNumber,data,5000,&read,NULL));
DAQmxErrChk (DAQmxGetBufInputBufSize(taskHandle, &bufsize));
In the printf statement, I added the readpos, availdata and bufsize variables. I got these values:
read total Readpos Bufsize Availdata
5000 5000 0 0 10000
5000 10000 5000 0 10000
5000 15000 10000 0 10000
5000 20000 15000 0 10000
I'm confused with those results. Why Bufsize (returned by the DAQmxGetBufInputBufSize() function) is 0, and not 10000 (the actual size of the internal buffer, I think)? And why Readpos (returned by the DAQmxGetReadCurrReadPos() function) keeps growing by a value of 5000? The input buffer being circular, I would think that the current read position would flip between 0 and 5000 (i.e. 0, 5000, 0, 5000, 0, 5000, ...). And why Availdata (returned by the DAQmxGetReadAvailSampPerChan() function) is 10000? Isn't supposed to be 5000, given that the callback function is called every 5000 samples acquired?
At the risk of repeating myself, What I would like to achieve is that: when more than half of the internal buffer is filled, the first half is written to disk. After that, when the buffer is completely filled and start to be filled from its beginning, the second half is written to disk and so on.
Your help is greatly appreciated.
Thank you in advance
Marc Melillo
marc.melillo@umontreal.ca
10-13-2008 07:30 PM
Hi Marc,
What happened when you tired the solution I mentioned in my first post? Were you able to set the buffer size and read half the buffer at a time?
Thank you,
10-14-2008 10:50 AM
Hi Sirman,
This is what I'm trying to do. If you look at the code in my second post, you can see that it is supposed to read in alternance both halves of the entire buffer. And it gives me the scrambled results you can see in the graphs. Maybe I should forget about the DAQmxRegisterEveryNSamplesEvent() function, and do my own thread creation. But then I would have to know at what place in the entire buffer the writing of the data is taking place, and I would have to set the exact place to start the transfer of the data from the internal buffer to my own array. BUT, for doing that, I suppose that I would need the DAQmxGetReadCurrReadPos() and maybe the DAQmxSetReadOffset() functions. But really, I don't know how, and the strange results I get in my last post make me have serious doubts that it could be done that way.
Do you have any clues about this?
Thank you in advance
Marc Melillo
marc.melillo@umontreal.ca
10-15-2008 04:02 PM
Hi Marc,
I looked through your code, Saha's code and the original example that comes with the driver. We need to narrow down the problem and for that we need to test the code separately. I see that your configuration settings are different from the original sample and Saha's code. I want you to run the original example code (without any modifications) and tell me if everything works properly. Once we know everything works properly with the default settings, we will try to run the code using your configuration settings. If everything works there, then we will add the saving to disk part. File I/O can slow your program and we really need to narrow down the problem to a particular area. Right now we are not even sure if acquisition is causing the problem or storing the data.
If you have NI-DAQmx installed, the original example is located on your computer at a path similar to C:\Documents and Settings\All Users\Documents\National Instruments\NI-DAQ\Examples\DAQmx ANSI C\Analog In\Measure Voltage\Cont Acq-Int Clk.
Please let me know if you have any questions.
Thank you,