Multifunction DAQ

cancel
Showing results for 
Search instead for 
Did you mean: 

Synchronization of M-Series cards via RTSI and ANSI C?

Hi!

This is my first post and I'm happy to be here. I tried to search as thoroughly as possible, but if this has been answered elsewhere, I'd be grateful for a hint/link nevertheless.

System:
Win 2000 Pro with NI-DAQmx (part of NI-DAQ 7)
2x PCI-6220M, 1x PCI-6221M
RTSI Cable
all components are registered in MAX

Problem:
I want to synchronize the cards over the RTSI bus. I am using the ANSI C library. There's an example SharedClk10-FiniteAcq_main.c, but it is designed for PXI and uses the undocumented (at least in the C reference?) DAQmxSetTimingAttribute function. I tried to pass '/Dev1/RTSI7' as the clock source, but it did not work.
Then, after reading the C reference a bit more, it seemed as if I needed to use DAQmxExportSignal. But it gives me an error DAQmxErrorInvalidRoutingSourceTerminalName_Routing = -89120 when I try to route DAQmx_Val_20MHzTimebaseClock to '/Dev1/RTSI7'

I'd like to know what C functions I have to call in which order to enable synchronized sampling with the three M-Series cards.
So far I do:
DAQmxCreateTask (primary & driven)
DAQmxCreateAIVoltageChan (p & d)
DAQmxExportSignal (p)
DAQmxCfgDigEdgeStartTrig (d - trying to import the failed export of /Dev1/RTSI7)
DAQmxStartTask (d & p)
DAQmxReadAnalogF64 (p & d)
DAQmxStopTask(p & d)

This is my first time using M-Cards or the ANSI C functions, so I might have missed something essential.

Can anyone give a hint as to what I need to do?
Jens
0 Kudos
Message 1 of 12
(5,251 Views)
First, if you haven't, you should explicitly create a RTSI cable in MAX. This can be done by right-clicking on Devices and Interfaces -> NI-DAQmx Devices and choosing Create New NI-DAQmx Device -> RTSI Cable. Then, for each device that is connected to the RTSI cable, use MAX to edit its properties and in the "RTSI Configuration" tab, specify the RTSI cable. This will allow NI-DAQmx to automatically route signals of the RTSI cable.

Now that a RTSI cable is configured, you don't need to explicitly export signals from the task. You can use the DAQmxGetMasterTimebaseSrc function to retrieve the master timebase terminal name from the primary task and the DAQmxSetMasterTimebaseSrc function to set the master timebase terminal name for the driven task. The DAQmxGetMasterTimebaseRate and DAQmxSetMasterTimebaseRate functions can be used in a similar manner. Configuring these properties will result in NI-DAQmx automatically routing the master timebase signal from the primary task to the driven task using the RTSI cable. To ensure the driven device starts at the same time, invoke the DAQmsxCfgDigEdgeStartTrip function passing a triggerSource parameter of "/ai/StartTrigger" which will result in NI-DAQmx automatically exporting the start trigger signal for the primary task over the RTSI bus and using it as a digital start trigger for the driven task.

I assume that you will also want to invoke the DAQmxCfgSampClkTiming function for each task to specify the acquisition rate and number of samples to acquire. Note that since the master timebase signal and the start trigger signal are already routed using the RTSI cable, the sample clock itself does not need to be shared between the two tasks.

geoff
--
Geoff Schmit
Huskie Robotics, FIRST Team 3061 Lead Mentor
http://team3061.org/
@team3061
Message 2 of 12
(5,250 Views)
Hi Geoffrey!

Thanks so very much!
It works! I am sampling rectangular/triangular waveforms and a pure sine of 1...10kHz with 100kHz on my three cards and it works smoothly!
RTSI is truely a magnificent invention!
I already had configured RTSI and cards correctly in MAX, BTW.

Please let me add to your very helpful post by mentioning that it's (of course) necessary to pass
/*MasterDeviceName*/ai/StartTrigger for the DAQmxCfgDigEdgeStartTrig function.

CU
Jens
0 Kudos
Message 3 of 12
(5,225 Views)
As Jens pointed out in his reply, the DAQmsxCfgDigEdgeStartTrip function should be passed a triggerSource parameter of "<primary device name>/ai/StartTrigger" where "<primary device name>" is replaced by the name of the primary device as specified in MAX.

As I just realized, any text in angle brackets (i.e., <text> ), which I commonly use to represent variables, will be stripped when a message is posted. I suppose it is treated as an HTML tag. This can be avoided by encoding the angle brackets by hand (i.e., &lt; text &gt; ) However, be careful since if you preview the post, the encoding will be lost.
--
Geoff Schmit
Huskie Robotics, FIRST Team 3061 Lead Mentor
http://team3061.org/
@team3061
0 Kudos
Message 4 of 12
(5,221 Views)
Hi Geoffrey!

Sorry to re-appear, but I now found that I get an error
-200452 = Specified property is not supported by the device or is not applicable to the task.
(I know I should have checked immediately - and I thought I had!)

When I try to either
DAQmxGetMasterTimebaseSrc
DAQmxSetMasterTimebaseSrc
DAQmxResetMasterTimebaseSrc
on my tasks, I get the -200452 error for all three function calls.
It also happens when I manually transmit /Dev1/20MHzTimebase OR even rubbish names.

Despite this error, I can start the tasks and they _seem_ to run synchronized with
DAQmxCfgDigEdgeStartTrig and a trigger source of '/Dev1/ai/StartTrigger'
However, as the real synchronization obviously failed, this may be due to 20MHz clock(s) being very exact.
As I am measuring only a few seconds, it might be possible that I am just not noticing the deviation?!

I am using
DAQmxCreateTask
DAQmxCreateAIVoltageChan
to create my master and driven tasks.
These calls work without an error.

The RTSI cable is still correctly registered in MAX.

Is there anything I am missing?
Kind regards
Jens
0 Kudos
Message 5 of 12
(5,200 Views)
Sorry about that. For M-Series devices the Reference Clock Rate and Reference Clock Source properties should be used (rather than the Master Timebase Rate and Master Timebase Source properties for E-Series devices). These properties can be accessed with the DAQmxGetRefClkRate, DAQmxSetRefClkRate, DAQmxGetRefClkSrc, and DAQmxSetRefClkSrc functions. I don't have an M-Series device handy to verify this, but these should be the appropriate properties.

If the reference clock is not routed from the primary device to the secondary device, the tasks will not be synchronized. While the two tasks will start acquiring samples at close to the same time, the two acquisitions will drift over time if the reference clocks are not shared. This may not be noticeable if samples are only acquired for a few seconds.

geoff
--
Geoff Schmit
Huskie Robotics, FIRST Team 3061 Lead Mentor
http://team3061.org/
@team3061
0 Kudos
Message 6 of 12
(5,180 Views)
Hi Geoffrey!
10:30pm here, finished for today 😕
I get no error messages anymore, but my tasks won't finish.
Here's the matlab code. Maybe someone can find my mistake?
I stripped the matlab declarations, I hope it is readable.

[a,b,taskh1] = calllib('myni','DAQmxCreateTask',taskname1,taskh1)
[a,b,taskh2] = calllib('myni','DAQmxCreateTask',taskname2,taskh2)
[a,b,c,d] = calllib('myni','DAQmxCreateAIVoltageChan',uint32(taskh1),taskchans1,'',-1,-10,10,DAQmx_Val_Volts,'')
[a,b,c,d] = calllib('myni','DAQmxCreateAIVoltageChan',uint32(taskh2),taskchans2,'',-1,-10,10,DAQmx_Val_Volts,'')
[a]=calllib('myni','DAQmxSetRefClkSrc',taskh1,'/Dev1/20MHzTimebase')
[a]=calllib('myni','DAQmxSetRefClkRate',taskh1,20000000)
[a]=calllib('myni','DAQmxSetRefClkRate',taskh2,clockrate)
[a,b]=calllib('myni','DAQmxSetRefClkSrc',taskh2,termname)
[a,b]=calllib('myni','DAQmxCfgSampClkTiming',taskh1,'',fsample,DAQmx_Val_Rising,DAQmx_Val_FiniteSamps,nsample)
[a,b]=calllib('myni','DAQmxCfgSampClkTiming',taskh2,'',fsample,DAQmx_Val_Rising,DAQmx_Val_FiniteSamps,nsample)
[a,b]=calllib('myni','DAQmxCfgDigEdgeStartTrig',taskh1,'/Dev1/PFI0',DAQmx_Val_Rising )
[a,b]=calllib('myni','DAQmxCfgDigEdgeStartTrig',taskh2,'/Dev1/ai/StartTrigger',DAQmx_Val_Rising )
[a]=calllib('myni','DAQmxStartTask',taskh2)
[a]=calllib('myni','DAQmxStartTask',taskh1)

taskh1 is master, taskh2 is driven. /Dev1/PFI sees a change from 0 to 5 to 0 Volts.
The data acquisition part of the code worked when I had the non-working "synchronisation" on place,
so I think it should be correct.

CU
Jens
0 Kudos
Message 7 of 12
(5,166 Views)
I think the problem lies within the following lines:

[a]=calllib('myni','DAQmxSetRefClkSrc',taskh1,'/Dev1/20MHzTimebase')
[a]=calllib('myni','DAQmxSetRefClkRate',taskh1,20000000)
[a]=calllib('myni','DAQmxSetRefClkRate',taskh2,clockrate)
[a,b]=calllib('myni','DAQmxSetRefClkSrc',taskh2,termname)

I'm not sure where the clockrate and termname variables are set. Regardless, I wouldn't explicitly set the Reference Clock Source or Rate on taskh1. Instead, query the Reference Clock Source and Rate of taskh1 and use these values to set the Reference Clock Source and Rate for taskh2. It would look something like this in C (I didn't try to compile this or anything):

terminalName = DAQmxGetRefClkSrc( taskh1 );
clockRate = DAQmxGetRefClkRate( taskh1 );
DAQmxSetRefClkSrc( taskh2, terminalName );
DAQmxSetRefClkRate( taskh2, clockRate );
--
Geoff Schmit
Huskie Robotics, FIRST Team 3061 Lead Mentor
http://team3061.org/
@team3061
0 Kudos
Message 8 of 12
(5,155 Views)
Hi Geoffrey!

The reason I do as posted is:
When I proceed as you recommend (and I started this way because it made sense), I get a RefClkSrc of "/Dev1/none" and a RefClkRate of 10000000. Doesn't make much sense and when I proceed nevertheless, I get a DAQmxErrorRouteNotSupportedByHW_Routing = -89136 error and Matlab crashes afterwards.
If I try to manually SET the RefClkSRC first, I get an error telling me to SET the RefClkRate. If I do that, then everything works as stated in my previous post - so it does not give errors, but it hangs.

Well, I think I'll try to export the Dev1/20MHzTimebase to /Dev1/RTSI7 for the master and then set the MasterTimebase of the slaves to /Dev?/RTSI7. Maybe it'll work...

Jens
0 Kudos
Message 9 of 12
(5,147 Views)
I spent some time learning about the timing architecture on the M-Series devices. I don't have a device with which to verify the following suggestion, but, hopefully, this will finally work.

Apparently, as you've observed, a task doesn't use a reference clock by default. Therefore, you need to specify the reference clock for both the primary and secondary tasks. This common reference clock, in addition to the start trigger, will ensure that the acquisitions are synchronized.

I believe you need to set the reference clock source, for both tasks, to /Dev1/10MHzRefClock. And set the reference clock rate, for both tasks, to 10MHz. The secondary task will automatically route the /Dev1/10MHzRefClock signal over RTSI to the secondary device based on this specification.

I will update this thread if I learn any new information.
--
Geoff Schmit
Huskie Robotics, FIRST Team 3061 Lead Mentor
http://team3061.org/
@team3061
Message 10 of 12
(5,088 Views)