From Friday, April 19th (11:00 PM CDT) through Saturday, April 20th (2:00 PM CDT), 2024, ni.com will undergo system upgrades that may result in temporary service interruption.

We appreciate your patience as we improve our online experience.

Multifunction DAQ

cancel
Showing results for 
Search instead for 
Did you mean: 

AI-AO feedback loop for 6259 using ANSI C

I own a NI-6259 board.  I have used it with a WindowsXP and it worked fine.
Now, I have changed to a RedHat 4.6  Linux system. My needs are simple:  I don't want to use LabView, all I want
to do is to simple ANSI C functions. I downloaded   nidaqmxbase-3.1.0.iso  and installed it. It works.

What I want to do is to run a feedback loop where I read four AI channels in,
make some calculations on the data and then write three AO channels out to my drivers.
The loop should run at 5 to 10 kHz. 
I have been able to read the AI channels and write the AO channels separately but when I try to run them
simultaneously, it bombs.
The main part of the program looks like this:
1    DAQmxErrChk (DAQmxBaseCreateTask("",&AOtaskHandle));
2    DAQmxErrChk (DAQmxBaseCreateAOVoltageChan(AOtaskHandle,AOchan,"",AOmin,AOmax,DAQmx_Val_Volts,NULL));
3   DAQmxErrChk    (DAQmxBaseCfgSampClkTiming(AOtaskHandle,"",sampleRate,DAQmx_Val_Rising,DAQmx_Val_ContSamps,samplesPerChan));
4    DAQmxErrChk (DAQmxBaseCreateTask("",&AItaskHandle));
5    DAQmxErrChk (DAQmxBaseCreateAIVoltageChan(AItaskHandle,AIchan,"",DAQmx_Val_Cfg_Default,AImin,AImax,DAQmx_Val_Volts,NULL));
6    DAQmxErrChk (DAQmxBaseCfgSampClkTiming(AItaskHandle,"",sampleRate,DAQmx_Val_Rising,DAQmx_Val_FiniteSamps,samplesPerChan));
7    DAQmxErrChk (DAQmxBaseStartTask(AItaskHandle));
8   DAQmxErrChk (DAQmxBaseStartTask(AOtaskHandle));
9    for(k=0;k<6;k++) {
10    DAQmxErrChk (DAQmxBaseReadAnalogF64 (AItaskHandle,samplesPerChan, timeout, 2, datain, bufferSize, &pointsRead, NULL));
11    DAQmxErrChk (DAQmxBaseWriteAnalogF64(AOtaskHandle,samplesPerChan,0,timeout,2,dataout,&pointsWritten,NULL));

I get the following error message just after the first WriteAnalogF64 statement:
  
"DAQmxBase Error: The generation has stopped to prevent the regeneration of old samples.
   Your application was unable to write samples to the background buffer fast enough to
   prevent old samples from being regenerated.
   LavView caught fatal signal
    8.2.1 - Received SIGSEGV
   Reason: address not mapped to object
   Attempt to reference address: 0xb4496500
   Segmentation fault "

It looks like I got some serious timing problems.  I need some advice
I'll attach the whole program for your information.
 
Lee Holloway
0 Kudos
Message 1 of 8
(3,247 Views)

Hello Lee,

 

As this error message indicates the analog output buffer is not being updated with new samples quickly enough to prevent regenerating samples.  In general this means that you either need to run your loop faster or write more samples to the buffer at a time.  In order to run your loop faster you would need to make your analysis more efficient or implement threading to make some of your code run in parallel (this may cause significant gains if you have a dual core computer).  Inevitably you will reach a speed that is the maximum your computer can handle.  On most non-real-time operating systems for basic PID control loops this rate is somewhere on the order of 1 kHz (this varies significantly based on your particular computer).

 

Are you looking to run your loop at a rate of 5-10 kHz meaning that you need to have a control loop response time at this speed or are you just wanting to update and read values at this rate?  The point I'm trying to make is that you can make your code more efficient by reading/writing multiple points.  If you read in 10 points at a time at a rate of 10,000 rather than 1 point at a time your loop will run 10 times slower and put much less strain on your CPU.  The downside here is that your control loop time also slows down (by control loop time I mean the delay between reading in a value, performing calculations, and outputting values) since you update the output only once per loop iteration.

 

The bottom line is that you're computer may not be able to handle running the analysis you require at the rate you want.  However, if you can still meet your needs by running the loop slower and dealing with larger data chunks then there is a good chance you can get this to work.

 

 

If your application requires that your output response time be 0.1-0.2 msec then you may need to consider moving to a real-time operating system.  However, if a response on the order of 5 msec is acceptable then you can probably get this to work by making your code more efficient and reducing the loop rate by working with more data each loop iteration.

 

I hope this helps, and have a good night!

Brooks
0 Kudos
Message 2 of 8
(3,228 Views)
Hello Brooks, 
Thanks for the reply.  
It must be something more than that, perhaps synchronization or... something.
Two reasons: 
 
0 Kudos
Message 3 of 8
(3,220 Views)
Hello Brooks, 
Thanks for the reply.  
There must be something more than that, perhaps synchronization or... whatever.
Two reasons: 
  1. The loop won't run at even  a 1 Hz rate.
  2. When I had the same type of program running on a WindowsXP system (the very same computer)
       it  ran cheerfully at 10 kHz  (I even tried it successfully at 20 kHz).

I Tried to sort of copy the old Windows version onto the Linux system but  the old Windows used
an older version of NIDAQ and some of the functions have changed names, or whatever.

I'll try to find my old version and send it to you in a later post.

Lee
0 Kudos
Message 4 of 8
(3,219 Views)
Hi Brooks.
Below are the relevant function calls for the new, non working, and the old Windows version that worked well.
There are differences that involve synchronization,  see line 23 which doesn't exist in DACmxBase. 
I hope you can find my error.
Lee


    This is the new Linux version.  It bombs out at line 12 (even the first time through)
1    DAQmxBaseCreateTask("",&AOtaskHandle);\par
2    DAQmxBaseCreateAOVoltageChan(AOtaskHandle,AOchan,"",AOmin,AOmax,DAQmx_Val_Volts,NULL);\par
3    DAQmxBaseCfgSampClkTiming(AOtaskHandle,"",sampleRate,DAQmx_Val_Rising,DAQmx_Val_ContSamps,samplesPerChan);\par
4    DAQmxBaseCreateTask("",&AItaskHandle);\par
5    DAQmxBaseCreateAIVoltageChan(AItaskHandle,AIchan,"",DAQmx_Val_Cfg_Default,AImin,AImax,DAQmx_Val_Volts,NULL);\par
6    DAQmxBaseCfgSampClkTiming(AItaskHandle,"",sampleRate,DAQmx_Val_Rising,DAQmx_Val_FiniteSamps,samplesPerChan);\par
7    DAQmxBaseStartTask(AItaskHandle);\par
8    DAQmxBaseStartTask(AOtaskHandle);\par
9    for(k=0;k<nloop;k++)
10          {
11     DAQmxBaseReadAnalogF64 (AItaskHandle,samplesPerChan, timeout, 2, datain, bufferSize, &pointsRead, NULL);\par
12     DAQmxBaseWriteAnalogF64(AOtaskHandle,samplesPerChan,0,timeout,2,dataout,&pointsWritten,NULL);\par
13         // Make calculations ...
14          }

        This is the old Windows version using NI-DAC
        The function at line 23 usint DAQmx_Val_HWTimedSinglePoint doesn't exist in DAQmxBase
21  DAQmxCreateTask("",&AItaskHandle);\par
22  DAQmxErrChk(DAQmxCreateAIVoltageChan(*AItaskHandle,AIchan,"",DAQmx_Val_Cfg_Default,AImin,AImax,\par
23  DAQmxCfgSampClkTiming(*AItaskHandle,"",rate,DAQmx_Val_Rising,DAQmx_Val_HWTimedSinglePoint ,2);\par
24  DAQmxCreateTask("", AOtaskHandle);\par
25  DAQmxCreateAOVoltageChan(*AOtaskHandle,AOchan,"",AOmin,AOmax,DAQmx_Val_Volts,NULL);\par
26  DAQmxCfgSampClkTiming(*AOtaskHandle,"",rate,DAQmx_Val_Rising,DAQmx_Val_ContSamps,2);\par
27  DAQmxCreateTask("",&AOtaskHandle);\par
28  DAQmxCfgDigEdgeStartTrig (*AOtaskHandle,"ai/StartTrigger",DAQmx_Val_Rising);\par
29  if( numAIchannels ) DAQmxGetTaskAttribute(*AItaskHandle,DAQmx_Task_NumChans,numAIchannels);\par
30  if( numAOchannels ) DAQmxErrChk2DAQmxGetTaskAttribute*AOtaskHandle,DAQmx_Task_NumChans,numAOchannels); \par
31  DAQmxStartTask(AOtaskHandle);\par
32  DAQmxStartTask(AItaskHandle);\par
33  for(k=0;k<nloop;k++) \par
34        {
35   DAQmxWriteAnalogF64(AOtaskHandle,samplesPerChan,0,timeout,2,dataout,&pointsWritten,NULL);\par
36   DAQmxReadAnalogF64(AItaskHandle,sampsPerChan,timeout,2,datain,bufferSize,&pointRead,NULL);\par
37        \\ Make calculations ...
38         }
     
     

0 Kudos
Message 5 of 8
(3,203 Views)
Hello Lee,
 
Are you able to run the DAQmx Base code on your Windows machine?  If so, does this machine have a better processor?  If you don't already have DAQmx Base installed on your Windows machine you can download it here.
 
This would be the easiest test of the CPU theory.  At a first glance your code looks like it should work okay as long as the program can loop fast enough so by running the DAQmx Base code on the same computer we can either eliminate or confirm this issue.
 
Cheers,
Brooks
0 Kudos
Message 6 of 8
(3,178 Views)
Hello Brooks,

It's the same physical computer.   I wiped out the Windows OS and installed Linux.  
There must be something wrong with the
CfgDigEdgeStartTrig  or
CfgSampClkTiming    or
CfgDigEdgeStartTrig  or
or something else.

All I know is that the old Windows program worked and the Linnux one doesn't.
I can't copy the old program line by line because some of the function calls
don't exist in the
DAQmxBase library.  There are probably equivalent ones but
I don't know what they are named.

Lee
0 Kudos
Message 7 of 8
(3,166 Views)

Hello Lee,

Here are a few things to try.

There are DAQmxBase examples that are installed to this directory by default:  /usr/local/natinst/nidaqmx/examples

I would suggest looking at the analog output (ao) example folder and running the continuous generation example.  This example will call the same DAQmxBaseWriteAnalogF64 function you're using so we can test to make sure your driver install is working correctly.

Secondly, it is possible that this error is being thrown because you aren't writing points to the analog output buffer before you start the task.  If you start the task without putting samples in the buffer then I would expect an error to be thrown indicating that the task didn't have anything to write.  To fix this you can call a DAQmxBaseWriteAnalogF64 function to put samples in the buffer before the task is started.

The last thing I would do in your program is to add in the DAQmxBaseCfgDigEdgeStartTrig function call to synchronize your two tasks like you've done in you DAQmx code.

Let me know what you find.

Cheers,

Brooks
0 Kudos
Message 8 of 8
(3,126 Views)