02-18-2010 10:46 AM
I want to get precise times of edges on 32 digital lines using a PCIe 6537 card. The card should have a 50MHz sampling clock (200MHz/N and minimum N is 4). So if I can get a count of the sample clock when any of the lines goes from low to high, I know the time to a resolution of 20ns. Each line should have one low to high transition per second. They should all be synchronised, so it is possible that more than one line will have an edge in the same sample clock pulse.
I am programming in Visual C++ with the DAQmx ANSI C API.
From what I have tried so far, I think I need to set up two DAQmx tasks: one to count the sample clock, and one to detect transitions on the 32 I/O lines. The next problem after that is to use the transition task to trigger a capture of a count on the first task.
But I cannot even set up a counter task. I think I need to call DAQmxCreateCICountEdgesChan() to create a channel for the sample clock. The example code that I found (Mult_Counters_Count_Dig_Start_Trig_TIO.c) defines the counter channel name with a constant:
#define COUNTER_SOURCE1 "Dev2/ctr0"
My device is "Dev1". If I try to use "Dev1/ctr0", I get:
Measurements: Physical channel specified does not exist on this device.
Refer to the documentation for channels available on this device.
Device: Dev1
Physical Channel Name: ctr0
Task Name: Dev1CtrTask
Status Code: -200170
I tried calling DAQmxGetDevCIPhysicalChans() to get the channel name, and I got an empty string back. So I tried "Dev1/" and got a similar error, except of course
Physical Channel Name: empty string
Is it possible to count the sample clock with the 6537? Or is there a better way to get accurate time values for transitions on the I/O lines?
Frank
Solved! Go to Solution.
02-19-2010
08:43 AM
- last edited on
04-25-2025
06:50 PM
by
Content Cleaner
Hi Frank,
The reason you're getting this error message is because you're specifying a counter channel for a card that does not have counters. The PCIe-6537 is a high-speed digital i/o card. You should take a look at cards that have Counter/timer inputs. For example some of the X Series Data Acquisition cards have counter/timer inputs.
Regards,
03-02-2010 06:17 AM
Thanks for your reply, Rico.
Unfortunately those cards are not an option because we've bought the 6537 already 🙂
However, it seems that I can sort of count the sample clock cycles if I get a block of samples -- each sample is taken on a rising edge of the sample clock so the number of elements in the array of samples is the number of sample clocks. Clunky, but it might work...
Unfortunately I seem only to be getting a quarter the number of samples that I expect. I think my problem now is with DAQmxReadRaw()
The documentation for this function says:
int32 DAQmxReadRaw (TaskHandle taskHandle, int32 numSampsPerChan, float64 timeout, void *readArray, uInt32 arraySizeInBytes, int32 *sampsRead, int32 *numBytesPerSamp, bool32 *reserved);
...
sampsRead int32 * The actual number of bytes read into the array per scan.
So is sampsRead the number of samples read, or the number of bytes read? The documentation clearly says bytes, but I'm getting fewer bytes than I expect.
Here's what I do... I set continuous sampling with
DAQmxCfgSampClkTiming(m_TaskHandle,
NULL, // Sample clock source = internal clock
MaxSampleClock(), // 150 at the moment, while debugging
DAQmx_Val_Rising,
DAQmx_Val_ContSamps,
10000
);
and set a callback to happen every N samples
DAQmxRegisterEveryNSamplesEvent(m_TaskHandle,
DAQmx_Val_Acquired_Into_Buffer,
m_NSamplesPerCallback, // 100 at the moment
0, // options, ORed together -- use default
NI6537_EveryNSamplesCallback,
this
);
At the moment, I have m_NSamplesPerCallback = 100 and MaxSampleClock() returns 150, when I get this working I want to have MaxSampleClock() return 50000000 and increase m_NSamplesPerCallback so the callback has enough time to work.
The callback uses DAQmxReadRaw() to get the samples.
DAQmxReadRaw(taskHandle, DAQmx_Val_Auto, 0,
SampleArray,
SampleSize*m_MaxNSamples,
&nRead, &numBytesPerSamp, NULL
)
SampleSize is 4 because there are 4 8-bit ports on the card. m_MaxNSamples is 1000 so there is plenty of room in the card. SampleArray is an array of uInt8 with 4000 elements.
The array is populated with samples, in sets of 4 bytes, 32 bits, with each bit representing a different digital IO line. Perfect!
BUT! The callback should be called after every 100 samples of 4 bytes per sample. So, according to the documentation, &nRead (which is the pointer sampsRead in the documentation for DAQmxReadRaw()) should be 400 when this function returns:
sampsRead | int32 * | The actual number of bytes read into the array per scan. |
It is coming out as 100. The documentation clearly says "bytes read"! It's out by a factor of 4, there are 4 bytes per sample. Coincidence? Does this mean 100 samples, or is this factor of 4 a different 4 from somewhere else?
Is the documentation wrong about this?
Frank
03-03-2010 01:55 PM
Hey Frank,
The documentation for DAQmxReadRaw appears to be wrong in this case. It should say that this parameter returns the number of samples - not bytes. I have filed a Corrective Action Request (CAR) on this issue so that we can resolve this in the future.
On a separate note, for digital data, there's not really much advantage in reading raw versus "digital" since they effectively come down to copying bytes (and not applying scaling). You might consider using DAQmxReadDigitalU32 (which literally does a memcpy of the 32 lines in the port for all channels) or DAQmxReadDigitalLines (though it has slightly more overhead since it considers the "invert line" setting in DAQmx as well as some other very minor hits).
03-03-2010 10:51 PM
03-03-2010 11:44 PM
03-03-2010 11:51 PM
03-04-2010 08:24 AM
The documentation for DAQmxReadRaw appears to be wrong in this case. It should say that this parameter returns the number of samples - not bytes. I have filed a Corrective Action Request (CAR) on this issue so that we can resolve this in the future.
Thanks. It looked like that, but I dislike coding contrary to the documentation without confirmation 🙂
On a separate note, for digital data, there's not really much advantage in reading raw versus "digital" since they effectively come down to copying bytes (and not applying scaling). You might consider using DAQmxReadDigitalU32 (which literally does a memcpy of the 32 lines in the port for all channels) or DAQmxReadDigitalLines (though it has slightly more overhead since it considers the "invert line" setting in DAQmx as well as some other very minor hits).
Well, the program is working now, albeit at 40MS/s rather than the 50MS/s that the datasheet implied would be possible. So I'll leave it as it is for now.
If I'm revisiting it, I'll consider changing to DAQmxReadDigitalU32(). I used the Raw one instead because I wasn't too confident about the interleaved/noninterleaved references in the documentation. It made me thing that DAQmxReadDigitalU32() wasn't a simple memcpy of the buffer, so it would have a higher overhead than the Raw.
Frank
03-04-2010 09:44 AM
Yes; it does just do a memcpy for each "channel". You would want to use DAQmx_Val_ChanForAllLines in DAQmxCreateDigitalChannel.
As to the performance, I can personally attest that I have streamed 12 PXIe-6537's at max rate (50 MHz) with 32 lines to disk. It seems there must a configuration issue in this case
03-04-2010 11:35 AM
As to the performance, I can personally attest that I have streamed 12 PXIe-6537's at max rate (50 MHz) with 32 lines to disk. It seems there must a configuration issue in this case
Ok, well, I didn't get that sorted. It's still running at only 40MHz. But we decided 25ns resolution was close enough for now (ran out of time for development 🙂 ). It's a different problem from setting up the task, so I asked a separate question at PCIe 6537 maximum sample clock ANSI C
Since, with the help of the forum I got my program running, I want to summarise the thread, and the solution to my problem, in case anyone else is looking it up later.
Thanks to all who helped with my enlightenment 🙂
Frank