Multifunction DAQ

cancel
Showing results for 
Search instead for 
Did you mean: 

DAQmx AO square-wave generation revisit

Hello,

This is my second experience of using DAQmx C programming functions for AO square wave generation, some of the forum members are very helpful and I was able to overcome some of my problem, thank you all !
Now I need help again, this time I want a 2KHz square wave to be continuously increasing from 0V to 10V with 50mV increment at each step. The increment process can be slow at 0.5 second each time, since I need to do some image capturing during the incremental process.

According to following example, I can do modulation of the square wave with only two amplitude and I need to build my own data arrray prior to task creation and write process. Do I need to do the same thing again?

#include <NIDAQmx.h>
#include <windows.h>
#include <stdio.h>
#include <conio.h>

int main()
{
TaskHandle taskHandle;
int32 written;
float64 square_low_amp_data[6600];
float64 square_high_amp_data[6600];
int i,j;

//ADD code here to fill your arrays
for (j=0; j<6600; j+=100)
{
    for (i=j; i<j+50; i++)
        square_low_amp_data[i]=-1.65;
    for (i=j+50; i<j+100; i++)
        square_low_amp_data[i]=1.65;
}

for (j=0; j<6600; j+=100)
{
    for (i=j; i<j+50; i++)
        square_high_amp_data[i]=-2.32;
    for (i=j+50; i<j+100; i++)
        square_high_amp_data[i]=2.32;
}


DAQmxCreateTask("",&taskHandle);
DAQmxCreateAOVoltageChan(taskHandle,"Dev1/ao0","",-10.0,10.0,DAQmx_Val_Volts,NULL);
DAQmxCfgSampClkTiming(taskHandle,"",200000.0,DAQmx_Val_Rising,DAQmx_Val_ContSamps,1000);
DAQmxSetWriteRegenMode(taskHandle,DAQmx_Val_DoNotAllowRegen);
DAQmxWriteAnalogF64(taskHandle,6600,0,10.0,DAQmx_Val_GroupByChannel,square_low_amp_data,&written,NULL);
DAQmxStartTask(taskHandle);

while(!_kbhit())
    {
       DAQmxWriteAnalogF64(taskHandle,6600,0,10.0,DAQmx_Val_GroupByChannel,square_high_amp_data,&written,NULL);

       DAQmxWriteAnalogF64(taskHandle,6600,0,10.0,DAQmx_Val_GroupByChannel,square_low_amp_data,&written,NULL);
    }

DAQmxStopTask(taskHandle);
DAQmxClearTask(taskHandle);
return 0;
}

The picture "mod" show the output of the above code, and the other one "incmnt" show the desired output, can anyone help me again this time? Thank you very much!
Download All
0 Kudos
Message 1 of 10
(5,210 Views)
Hi Rolly,

Your approach is correct based on this example; you will have to build an array of data points to be written to the analog channel.  However, take into consideration that the example writes 50 samples for a particular voltage level.  You may run into a problem of having too large of an array since there are 200 transitions from 0V to 10V when incrementing by 50mV.  Most of our data acquisition boards will hold the last value generated, meaning that you would only need 2 samples per period of the square wave for a given voltage level instead of 100.  The only modification needed to make them functionally equivalent would be to lower the sample rate.

Regards,
Andrew W
National Instruments
0 Kudos
Message 2 of 10
(5,178 Views)
Hi Andrew,

Thank you very much, I have modified my code as follows, plz have a look:

#include <NIDAQmx.h>
#include <windows.h>
#include <stdio.h>
#include <conio.h>

#define DAQmxErrChk(functionCall) if( DAQmxFailed(error=(functionCall)) ) goto Error; else

int32 CVICALLBACK DoneCallback(TaskHandle taskHandle, int32 status, void *callbackData);

int main()
{
    int32    error=0;
    TaskHandle    taskHandle=0;
    TaskHandle    off;
    int32    written;
    char    errBuff[2048]={'\0'};
    float64    data[10];
    float64    OFF[1]={0.00};
    int i,j,k,kmax;       
    double inc, ninc;

    /* kmax=200, inc=0.05, ninc=-0.05 */
    //kmax = 200;
    //inc = 0.05;
    //ninc = inc*(-1);

    /* kmax=1000, inc=0.05, ninc=-0.05 */
    kmax = 1000;
    inc = 0.01;
    ninc = inc*(-1);

    /*********************************************/
    // DAQmx Config for OFF 0V
    /*********************************************/
    DAQmxErrChk (DAQmxCreateTask("",&off));   
    DAQmxErrChk (DAQmxCreateAOVoltageChan(off,"Dev1/ao0","",-10.0,10.0,DAQmx_Val_Volts,NULL));
    DAQmxErrChk (DAQmxStartTask(off));
    DAQmxErrChk (DAQmxWriteAnalogF64(off,1,1,10.0,DAQmx_Val_GroupByChannel,OFF,NULL,NULL));
    DAQmxErrChk (DAQmxStopTask(off));
    DAQmxErrChk (DAQmxClearTask(off));

    /*********************************************/
    // DAQmx Config for SQUARE-WAV generation
    /*********************************************/
    //DAQmx config initial array
    for (j=0; j<10; j+=2)
    {
        for (i=j; i<j+1; i++)
            data[i]=ninc;
        for (i=j+1; i<j+2; i++)
            data[i]=inc;
    }

    DAQmxErrChk (DAQmxCreateTask("",&taskHandle));
    DAQmxErrChk    (DAQmxCreateAOVoltageChan(taskHandle,"Dev1/ao0","",-10.0,10.0,DAQmx_Val_Volts,NULL));
    DAQmxErrChk    (DAQmxCfgSampClkTiming(taskHandle,"",4000.0,DAQmx_Val_Rising,DAQmx_Val_ContSamps,1000));
    DAQmxErrChk (DAQmxCfgOutputBuffer (taskHandle,1000));
    DAQmxErrChk (DAQmxSetWriteRegenMode(taskHandle,DAQmx_Val_DoNotAllowRegen));
    DAQmxErrChk (DAQmxSetAODataXferMech(taskHandle,"Dev1/ao0",DAQmx_Val_DMA));
    DAQmxErrChk    (DAQmxWriteAnalogF64(taskHandle,10,0,10.0,DAQmx_Val_GroupByChannel,data,&written,NULL));
    DAQmxErrChk    (DAQmxStartTask(taskHandle));

    printf("\nGenerating square-wave with increasing amplitude continuously...\n");
   
    for(k=0; k<kmax; k++)
        {
            //config arrays
            for (j=0; j<10; j+=2)
            {
                for (i=j; i<j+1; i++)
                data[i]=k*ninc;
                for (i=j+1; i<j+2; i++)
                data[i]=k*inc;
            }   
            DAQmxErrChk    (DAQmxWriteAnalogF64(taskHandle,10,0,10.0,DAQmx_Val_GroupByChannel,data,&written,NULL));
            Sleep(500);

        }

    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);

    /*********************************************/
    // DAQmx Config for OFF 0V
    /*********************************************/
    DAQmxErrChk (DAQmxCreateTask("",&off));
    DAQmxErrChk (DAQmxCreateAOVoltageChan(off,"Dev1/ao0","",-10.0,10.0,DAQmx_Val_Volts,NULL));
    DAQmxErrChk (DAQmxStartTask(off));
    DAQmxErrChk (DAQmxWriteAnalogF64(off,1,1,10.0,DAQmx_Val_GroupByChannel,OFF,NULL,NULL));
    DAQmxErrChk (DAQmxStopTask(off));
    DAQmxErrChk (DAQmxClearTask(off));

    printf("\nEnd of program, press Enter key to quit\n");
    _getch();

    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;
}

I am not sure if this is ok since I have not tested it on a hardware DAQ but just using a DAQmx simulated device.
Besides, here are some conceptual questions I want to clarify:
(1) DAQmxCfgSampClkTiming - setting 4000 as output rate and 2 samples per period, I will have sq-wave of 2KHz?
(2) DAQmxWriteAnalogF64 - setting numSamsPerChan must agree with the array to be written? i.e. If float64 data[10] then numSampsPerChan must set to 10? otherwise, DAQmx prompts error??
(3) What effects will be increasing data[10] to data[1000] or decreasing data[10] to data[2] in my case?
(4) Is Sleep(500) too long for this case? I have notice, DAQmx will prompt error if insufficient data is written to the buffer? What will be the max Sleep() workable?

Thank you very much & Merry Xmas!
Rolly
0 Kudos
Message 3 of 10
(5,163 Views)
Hi Rolly,

To answer your questions:

1.)  With a sample rate of 4kHz and 2 samples per period for your waveform, the effective rate of your signal will be 2kHz.
2.)  For the DAQmxWriteAnalogF64 function, the numSamsPerChan parameter must be less than or equal to the length of the array to be written.
3.)  In your application, increasing from data[10] to data[1000] will simply prolong the length of time that your square wave is being generated for a particular voltage level assuming that the number of samples per channel you generate is equal in length to the array.  Lowering from data[10] to data[2] will do the opposite.
4.)  I believe you may be running into a problem with your code by making a call to DAQmxWriteAnalogF64 before you call DAQmxStartTask to generate your waveform.  Removing this function call should remove any errors associated with having the Sleep in your loop.

Happy Holidays!

Andrew W
0 Kudos
Message 4 of 10
(5,148 Views)
Hi Andrew,
 
Thanks for the explanation, I tried (4) but DAQmx prompted error:
 
DAQmx Error: Generation cannot be started, because the output buffer is empty.
 
Before starting a buffered generation, write data. Unreserving a task empties the buffer. Changing the size of the buffer or setting the Regenration Mode property will result in the buffer being unreserved and empty.
 
Status Code: -200462
 
Is the DAQmxWriteAnalogF64 before calling DAQmxStartTask necessary in my case?
 
Thanks very much!
 
Cheers,
Rolly
0 Kudos
Message 5 of 10
(5,139 Views)
Hi Rolly,

I apologize for the misunderstanding - with your setup you do in fact have to call DAQmxWriteAnalogF64 before calling DAQmxStartTask to load the samples into the buffer for generation.  The Sleep duration would depend upon how fast your system is able to transfer the samples from memory to your device FIFO.  Because you are disabling regeneration, new data will have to be written fast enough across the PCI bus for the device to generate, or a buffer underflow will occur (which is the error I believe you are seeing).  You may consider calling the function DAQmxSetAODataXferReqCond that allows you to configure the property for when new data is sent to the onboard FIFO.  Information about this function and the properties associated with it can be found in the NI-DAQmx C Reference Help.

Regards,
Andrew W
National Instruments
Message 6 of 10
(5,116 Views)
Hi Andrew,

I have test the following codes and I found it has limitation on the number of elements in the data[ ] with my NI hardware:

    for (j=0; j<1000; j+=2)
    {
        for (i=j; i<j+1; i++)
            data[i]=ninc;
        for (i=j+1; i<j+2; i++)
            data[i]=inc;
    }

    //DAQmx write to AC-LCVR
    DAQmxErrChk    (DAQmxCreateTask("",&taskHandle));
    DAQmxErrChk    (DAQmxCreateAOVoltageChan(taskHandle,"Dev1/ao0","",-10.0,10.0,DAQmx_Val_Volts,NULL));
    DAQmxErrChk    (DAQmxCfgSampClkTiming(taskHandle,"",4000.0,DAQmx_Val_Rising,DAQmx_Val_ContSamps,1000));
    DAQmxErrChk    (DAQmxCfgOutputBuffer (taskHandle,100000000));
    DAQmxErrChk    (DAQmxSetWriteRegenMode(taskHandle,DAQmx_Val_DoNotAllowRegen));
    //DAQmxErrChk    (DAQmxSetAODataXferMech(taskHandle,"Dev1/ao0",DAQmx_Val_DMA));
    DAQmxErrChk (DAQmxSetAODataXferReqCond(taskHandle,"Dev1/ao0", DAQmx_Val_OnBrdMemEmpty));
    DAQmxErrChk    (DAQmxWriteAnalogF64(taskHandle,1000,0,10.0,DAQmx_Val_GroupByChannel,data,&written,NULL));
    DAQmxErrChk    (DAQmxStartTask(taskHandle));

    printf("\nGenerating square-wave with increasing amplitude continuously...\n");
   
    for(k=0; k<kmax; k++)
        {
            //config arrays
            for (j=0; j<1000; j+=2)
            {
                for (i=j; i<j+1; i++)
                data[i]=k*ninc;
                for (i=j+1; i<j+2; i++)
                data[i]=k*inc;
            }   
            DAQmxErrChk    (DAQmxWriteAnalogF64(taskHandle,1000,0,10.0,DAQmx_Val_GroupByChannel,data,&written,NULL));
            Sleep(500);

        }

With simulated NI hardware, I can set j<10 and the code runs fine but with NI PCMCIA 6062E and NI PCI 6221, it complains:
DAQmx Error: The generation has stopped to prevent the regeneration of old samples. Yoour application was unable to write samples to the background buffer fast enough to prevent old samples from regenerated.

To avoid this error, you can do...
(1) Increase the size of the back ground buffer (100000000 is the maximum I can get)
(2) Increase the number of samples you write each time you invoke a write operation (i found j<2000 is ok, and j<1024 is the minimum without DAQmxSetAODataXferReqCond?)
(3) Write samples more often ( Sleep(500) is too long?)
(4) Reduce the sample rate ( 4000 is fix and no adjustable in my case)
(5) Change to DMA ( this is not applicable for PCMCIA device)
(6) Reduce the number of application your computer is running concurrently ( not a problem since this is a P4 2.8GHz with 2GB RAM)

Any suggestion to these? Am I correct to say j<10 or data[10] is too small for DAQmxWriteAnalogF64?

Thank you!
Rolly


0 Kudos
Message 7 of 10
(5,066 Views)
Hi Rolly,

I ran a quick test of your code, and found that by simply changing the Sleep duration (I set it to 20 in my attempt), I was able to remove the error produced from DAQmx not having enough samples available in the buffer like you were receiving.  I ran this with data[1000] and everything seemed fine; however, with data[10] I did receive the error again even with having a Sleep(20) configured, so it looks like an array size of 10 may be too small.  These samples are written out of the buffer very fast with a sample rate of 4000.  Excluding the Sleep also produced the same error you received, so it appears that a balance of the sleep time with array size must be found (all of this will be system dependent).  Let us know what you find from further testing.

Regards,
Andrew
0 Kudos
Message 8 of 10
(5,044 Views)

Hi,

   I want to generate a contineously increasing signal. Kindly tell me what is the name of the example you reffered to in the first post. If possible also tell me the path.

 

Regards,
Farhan Ahmad.
0 Kudos
Message 9 of 10
(4,293 Views)
Thank you for contacting NI support.  I noticed that you have another forum open with us here that I will be happy to help you with.
0 Kudos
Message 10 of 10
(4,279 Views)