LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

Buffered event counting. Why can't I explicitly sequence generating the Sample Clock Pulse and reading the counters?

cebailey:  Still here and yes, your timing diagram is what I pictured.
 
I'm attaching yet another mod of the code.  The purpose is to try to gather some troubleshooting info while avoiding the counter read timeout.  This code doesn't actually read any of the counter data but instead it merely queries the counter tasks to find out how many samples they have buffered.  When you first start the program and no samples have been buffered, the query calls should return immediately and correctly report that TotalNumSamples = 0.  Each time you activate the "Strobe Now" user interface button, both counts should increase by 1.   The behavior I described is exactly what I see on a PCI-6259.
 
Looking toward the future where you need to support counting 4 separate instruments and both rising and falling edges, you may be getting yourself into new data acq hardware.
 
From NI, the 6602 counter/timer board has 8 counter channels, one per instrument/edge combo.  The main catch would be that you'd need to explicitly program at least 5 of the tasks to use interrupt-based data acq because only 3 DMA channels are available.
 
In principle, you might be able to handle such a job using the "change detection" feature of your existing M-series board too.  Given the troubles you're seeing so far, this is something you'd want to verify before counting on it.  The basic idea would be to use change detection to buffer your instruments' signal states each time any of them had a transition.  Then whenever you get a "read opportunity", you'd read whatever # of samples are presently available, which is the total # of transitions from all the instruments.  Finally, you'd scan through those samples to figure out how many transitions occurred on each signal individually.  To get exactly the right counts, you'll need to remember the latest sample read on the prior opportunity to know which signal has a transition in the first sample of this read opportunity.
 
-Kevin P.
ALERT! LabVIEW's subscription-only policy came to an end (finally!). Unfortunately, pricing favors the captured and committed over new adopters -- so tread carefully.
0 Kudos
Message 21 of 48
(1,757 Views)

Kevin,

Glad you're still along for the ride, and we're comprehending each other so far.

Thanks for *numsamps.vi. I tried it. It runs without timing out (guess timeouts are obviously impossible), but clicking or holding Strobe Now does not change TotalSamp 0 or TotalSamp 1, they remain at zero. I am interested to see how to ask the counter how many samples it has. Have I missed something that would be telling the counters they are SUPPOSED to buffer samples? I did try explicitly setting the number of samples in the buffer, with the "number of samples to take" input (which is mislabeled in this case), but no different.

On a hunch that it would be humorous, I modified this to create *numsampsParallel.vi by putting the samples taken queries in their own while loop, running in parallel with the existing loop. This also runs but, contrary to my hunch, it also keeps reporting zero samples. I figured this change would make it start reporting samples, probably one on each counter per Strobe Now. I don't know what to make of this. I did, however, run NestedSequences.vi again to verify that counts do appear, and they do indeed, so it's not a hardware change from days ago.

I know I need more counters. The NI salesman looked for a counter that sees rising and falling edges both, but said he found none. So I think this requires multiple counters. Also, of course, I need about 17 or 18 bits, so I wind up needing 4 counters per instrument, as far as I know. Which is no problem, as long as I can make buffering work.

>The basic idea would be to use change detection to buffer your instruments' signal states each time any of them had a transition.  Then whenever you get a "read opportunity", you'd read whatever # of samples are presently available --- Wow. Does this imply that there's a stack in play, and I'm actually using the stack depth as my measured variable? Wow. If not a stack, what's the mechanism for holding multiple unread samples, and checking the count of those samples? Can it hold 10^4 or 10^5 or so of them? Do I follow correctly?

>...you'd need to explicitly program at least 5 of the tasks to use interrupt-based data acq... --- What does "explicitly program" mean? Writing it with nodes rather than VI's? Writing a .dll outside of LV and calling it? Would this be hardware interrupts or software interrupts? Seems like a product that doesn't try to set aside a whole DMA channel for what is actually a non-time-critical movement of two bytes would be a cleaner choice, no? I mean, even an RS232 port would probably have the bandwidth.

I'm going to go see if I can try some things on the larger hardware system. Thanks!

0 Kudos
Message 22 of 48
(1,748 Views)
Crystal,
 
Wiring for this DAQ device, a USB-6259, is as follows:
 
Signal generator is grounded on Pin 94 (D GND).
 
Signal generator output is tied to:
Pin 68 (P0.3, a digital input for VI's that monitor this to verify there's a signal)
Pin 76 (PFI 3, by default CTR 1 SRC)
Pin 81 (PFI 8, by default CTR 0 SRC)
 
The following are jumpered together:
Pin 66 (P0.1, the digital output that drives this group)
Pin 67 (P0.2, a digital input for VI's that monitor this to verify there's a signal)
Pin 77 (PFI 4, by default CTR 1 GATE)
Pin 73 (PFI 0, the source for Timing (Sample Clock) vi for counter 0 and maybe counter 1.
Pin 74 (PFI 1, the source for Timing (Sample Clock) vi for counter 1 if it's not set to Pin 73.
Pin 83 (PFI 9, by default CTR 0 GATE)
 
In this second, jumpered group, sometimes I use the GATEs, sometimes I use the Timing vi source, sometimes I use both. The last couple of forum postings were using both. Different references say to use one or the other. I haven't found a difference, but it's pretty hard to cover all the hardware and software permutations so I'm not sure there isn't one.
0 Kudos
Message 23 of 48
(1,738 Views)
Ok, seems like the problem is narrowed down, though still puzzling.  I'll be very interested in the results you get on the PXI system.
 
1. I've posted 2 examples that work perfectly on my PCI-6259 but not on your USB 6259.  In both cases, it appears that the attempt to toggle a DIO output bit high and then low does *not* register as a "sample clock" by the counter task.  The counter task doesn't seem to receive the active edge, thus attempts to Read produce a timeout and attempts to query for # available samples always returns 0.  Since you've reported that there's no output error from these attempts to toggle DIO, I can only wonder if the output signal isn't behaving properly -- if you try to drive too low an impedance, you won't achieve the 5V output you expect.
 
Try running in debug mode so you can single-step through the function calls.  Measure the output voltage of the digital bit after setting it to True.  Measure again after setting it to False.  Verify that you're really going from 0-->5 volts and back.
 
2. Another step of simplification: in your list of wiring, it appears that your p0.1 "strobe" bit is being parallel connected to lots of places.  Could you humor me a minute?   Don't run whatever other code you've got to monitor p0.2 and p0.3.  Also, physically disconnect all wires from your terminal block.  Then try running one of my examples again.  Note: when I run the code on my 6259, there are no physical wire connections at all.  I have the terminal block completely disconnected from the board but all the "strobing" works just fine.
 
3.  I'm away from LV but looked at your "NestedSequences.vi" screenshot.  If that works under the same conditions (physical wiring, presence of other parallel code that monitors digital bits, external devices and signals in same state) that my examples don't work, then I'm at a loss.   It is not typical behavior for NI's boards.  I've never seen or heard of similar symptoms. 
 
I'm down to the "last resort" kinds of things to try like uninstall / reinstall the board,  uninstall / reinstall DAQmx,  try a different USB port connection (maybe you need 2.0 and the connector is only giving you 1.x) or different USB cable.  Long shots all, but I'm all out of reasonable suggestions.
 
--------------------------------------------------------------------------------------
 
Now, switching over to the longer-term future stuff.  First consider using the digital change detection feature on your USB 6259.
 
4.  It's not exactly a stack, but DAQmx does create a storage buffer.  It's much more like a queue with first-in-first-out behavior.  However, in a continuous acquisition the buffer is circular.  When it fills up it can start overwriting the oldest data.   The mechanism is built into the DAQmx driver.  When you call DAQmx Timing to define a sample clock for a task, the driver automatically creates a buffer in RAM to store your acquisition data.  The driver will also move data from the board to that RAM buffer without any work on your part.  When you call DAQmx Read, you'll be retrieving data from that RAM buffer and you can ask for any # samples you want, even 10^4 or 10^5 of them at a time. 
 
The call in my latest 'query' example shows how to use the DAQmx Read Property Node to query the data acq buffer.  I queried for the total # acquired.  One could instead query for # available.  The former won't change when you read data with DAQmx Read but the latter property will decrement by the # you've just copied from the acquisition buffer to your application.
 
5. If you use a 6602, then 'explicitly program' means you'll need to explicitly call one of the DAQmx property nodes (don't recall which one) to specify that the task will use interrupts.  For your app, you could probably have all 8 counters use interrupts to keep the code more identical.
 
-Kevin P.
ALERT! LabVIEW's subscription-only policy came to an end (finally!). Unfortunately, pricing favors the captured and committed over new adopters -- so tread carefully.
0 Kudos
Message 24 of 48
(1,725 Views)
Kevin,
 
>I'm away from LV but looked at your "NestedSequences.vi" screenshot.  If that works under the same conditions (physical wiring, presence of other parallel code that monitors digital bits, external devices and signals in same state) that my examples don't work, then I'm at a loss.  ---  Well, this is certainly true, up till the part about you being at a loss. I think another very telling test has been the VI's you sent me that timed out but would run if I cut their sequencing error wires. I could try the disconnected physical wires. I could also try swapping components, etc. What looks most productive to me is to focus on the PXI system, and the other manufacturer's boards if they arrive today. I did start on the PXI with most recent VIs but had some wiring work to do too. Maybe I can get much further with it today.
 
>If you use a 6602, then 'explicitly program' means you'll need to explicitly call one of the DAQmx property nodes (don't recall which one) to specify that the task will use interrupts.  --- I see. I much prefer to have more things explicit than the typical examples do. It always seems much easier to take charge and think through what's happening, rather than to try through experimentation and guesswork to figure out what the system is doing when I haven't specified things intentionally.
 
Thanks!
0 Kudos
Message 25 of 48
(1,706 Views)

Kevin,

Exciting new results on the PXI system after a fresh start. Now things work fine, and I can't mess them up to save my life. I'm gonna go dump some tomato juice into the vents, as historically that has been a strong challenge, but in the meantime...

Attached here are two new VIs. ReadCountersOnce fires a timed pulse and then gets the latest values out of both counters. It sequences all these operations, which is what won't work on the development hardware. This is an important vi because I want to be able to employ it throughout the project. It takes the task references as inputs, so I can call it many times but only create the task once.

DistributionOfReadCountersOnce.vi calls ReadCountersOnce as a subvi, and does so in a loop that also displays the deltas and the difference between the deltas. Furthermore, it tallies how many times the difference is 0, or 1 or 2 or >2, or -1 or -2 or <-2, and displays what this distribution is. The purpose of this vi is just to test ReadCountersOnce with many repetitions. And when I left the lab, it was still doing so, at maybe 100 Hz, without any timeouts yet in the current configuration.

Actually, I did have the PXI system time out once, early on in this step when I didn't think I had changed anything but might have anyway, but I haven't reproduced that timeout, so am a little cautious.

Conclusions: 1) I have had various little things wrong here and there, 2) There is something significant but mysterious wrong with the development system hardware or install, 3) The first combination of little things being right and being tried on the PXI system has only just, and tentatively, occurred today, and, 4) Focusing on the development system shouldn't have been a bad choice but I got very unlucky.

 

Kevin, thanks for all this work! If you don't mind my asking, how'd I get lucky to have your help here? I see you've posted over a thousand replies but only started 4 threads. Are you just a kind of Lone Ranger, doing good deeds? I'm appreciative and also curious. Do I, uh, owe you anything? Should I take you out to lunch? What continent do you live on? How can I thank you for all this (assuming I'm not going to post an "Oh, no..." followup in an hour)?

Download All
0 Kudos
Message 26 of 48
(1,696 Views)

Oh, no...

On the PXI system it ran almost 1e6 iterations without stopping and I stopped it. Then I discovered that about 15% of the time, it dies on the first iteration when starting, with a timeout, at random as far as I noticed.

I thought to add a pulse on the digital line before the loop starts in the calling, test program Distribution....vi. I sequenced the task configuration and start vi's for the counters to finish before the task configuration of the digital line starts, so the counters are ready and waiting when this initial extra pulse occurs. Now I find in 50 starts there were no timeouts. So I'm letting it run overnight.

But there's a problem. I added the pulse because I worried there might be some off-by-one error in how many samples are buffered, but the more I think about it, the less reasonable the idea seems. Besides, doing what I did should make the result I am getting obsolete by one iteration. So, an idea that was really pretty stupid turned out to eliminate the symptom, creating one more mystery and one more doubt.

Tomorrow I may create another test program that keeps calling the existing test program, to see how confident I can be that it will start. But at this point I'm checking Receiving several times a day to see if the other counters are here. I know, I know, UPS only comes once a day.

0 Kudos
Message 27 of 48
(1,684 Views)
Created the outer loop that in effect restarts Distribution. It's not a separate program, it's Distribution... with a loop added around everything else. I also made the initial setup steps explicit in time with a sequence and some timing vi's.
 
I have to drive the digital line high and low in the beginning of this loop before starting the counting loop itself. I imagine I am loading an extra value into the counter buffer. Without doing this the inner loop has about a 15% chance of timing out on its first iteration. However, with this, I fear the depth of the buffer is indeterminate by a value of 1, and on any given read I can't be sure whether I am getting current or one-old data. Or, worse, I badly misunderstand what is happening. It's unnerving that this extra stuff would be necessary. This is on the PXI system.
 
However, this new program ran 20,000 iterations of the outer loop, and therefore 20,000 restarts of the inner loop on a 100 iteration run meaning 2e6 inner loop iterations per se. There were no timeouts. All this is consistent with the incomplete picture I've been describing.
Download All
0 Kudos
Message 28 of 48
(1,654 Views)

Hi, Chris

I'm still trying to wrap my head around what is happening and why you need the extra steps.  However, I do have a couple comments on the LV code you attached. 

1.  Are the 1 ms waits between DAQmx nodes really necessary?  I've never had to put waits between DAQ functions before. 

2.  What I do when a wait is necessary is to encapsulate it in a little subVI with error I/O terminals as shown in the attached VIs.  This maintains the data flow and preserves error information.

3.  The sequence structure in the inner loop is completely unnecessary.  There is data dependency through the wires coming out of the subVI and the comparison functions, so you don't need the sequence to define which operations occur first.  In general, you shouldn't have to use sequences (there are very rare occasions).  They tend to make the diagram busier than necessary and overly complicate the code.

4.  It always makes me nervous to see any sort of I/O where the error terminals aren't wired.  You might not have a good plan for handling those errors at the beginning, but it is good practice to always wire the error in and error out terminals.  This defines the data flow through the program and prevents downstream VIs from attempting to run if an error occurred previously.  If you have operations that need to operate in parallel, then you can run the errors parallel and downstream use the Merge Errors to consolidate them.

5.  There is a Boolean to 0:1 function that eliminates the need for the Select function and the 0 and 1 constants.  This is a very minor thing, but it does replace 3 nodes with 1.

I'm sorry I've not been more helpful on the HW end, but it seems like Kevin was completely on top of things and he actually has counter/timer HW to try things out with...I didn't have any readily available.  Thanks for the timing diagrams and wiring info.  I'm sorting through all of it now.

Download All
0 Kudos
Message 29 of 48
(1,649 Views)

Crystal, thanks, nice to hear from you!

>Are the 1 ms waits between DAQmx nodes really necessary?  --- I don't know under what conditions different waits are necessary. Since there are sometimes funny dependencies between steps that I expected not to have them, and since at some level we should have to wait after asserting a line in one device until its desired effect has happened in another device to which it's physically wired, I think the conservative approach is to try things with the waits and then if the things work try reducing or eliminating the waits. In some of the vi's I've posted, though (I think TwoLoops was one such), the typical number of iterations I could get before a timeout would depend on the wait duration, so maybe with 5 ms it would run a few thousand times between timeouts whereas with 2 ms it would only run a hundred or so. In fact, I wonder if *longer* waits would accomplish anything new?

>In general, you shouldn't have to use sequences....  ---  This gets at a programming style issue that I think NI actually teaches incorrectly. Let me rant about why: The terminals that are clearly called "Error" often get used to determine sequences, in NI's examples and in the first two courses (which I took), even though the Flat Sequence and Stacked Sequence are fundamental constructs provided just for this purpose. Certainly, this is a programming trick which confuses and obscures the distinction between the otherwise unrelated and clear goals of controlling execution order and catching exceptions. To quote _The Elements of Programming Style_ (Kernighan & Plaugher), "Write clearly - don't be too clever.", "Say what you mean, simply and directly.", and "Use the fundamental control flow constructs." Worse still, the timing vi's, which perhaps more than any others tend to get used in order-sensitive situations, lack Error terminals, so they actually require using sequences, or else other tricky means like nesting into a subVI, or wiring the numeric inputs and outputs (with numerical operations that essentially neutralize the significance of the wirings) as I used earlier. So I hear you, and know your advice is in the mainstream of LabVIEW programming, but still think using the Sequence constructs wise and consistent with good programming principles.

>The sequence structure in the inner loop is completely unnecessary.  There is data dependency through the wires coming out of the subVI and the comparison functions, so you don't need the sequence to define which operations occur first. ----  Yes, I do need it! Though I agree with you I shouldn't need it! On 8/8/07 I posted InSeparateSequence.vi, which introduced this sequencing, with this explanation: "Here's an odd, unexpected observation: I have to sequence the reads of the counters to occur before I use the results I read, or else many of the cycles of this combine a new count from one counter with the one-back count from the other counter, and Diff takes on values like the number of counts in a loop. I though the dataflow principle would dictate that current values would get used, but apparently not so. Sequencing the calculations to happen after the reads fixes this. Any idea why?" Since posting this I have not thought of or read anything new on the question. It seems like an important clue, but I haven't figured out how.

>It always makes me nervous to see any sort of I/O where the error terminals aren't wired.  ---  And rightly so. I'm being lazy with many of these. Some do have errors wired through, and some even use Merge, but many don't. Sorry! I've been lazy partly because I've had to create so many vi's as part of this problem and partly because when I did use error terminals the messages were never interesting (the only error I've seen has been the timeout, which creates its own warning box on the desktop whether I use error terminals or not). But you are right, I am taking a chance when doing so and could have missed The Answer because of it! Kernighan would be ashamed of me, especially since I quoted him. I resolve to use them on future vi's I post.

>There is a Boolean to 0:1 function...   ---   Well, so there is. Thanks! Point out any others I've missed if you notice them.

>...Kevin was completely on top of things...  ---  Yes, I've been amazed with how he has helped. With what he brought to this discussion, I'd think I could be doing buffered event counting using nothing but a couple of diodes and LPT1. If it weren't for his postings, I'd think I was just learning disabled.

0 Kudos
Message 30 of 48
(1,637 Views)