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?

At irregular occasions I need to grab counts from several counters, and buffering the counts must be done simultaneously for all counters. I'm modeling my approach after zone.ni.com/devzone/cda/tut/p/id/5404 which someone kindly pointed out in an earlier thread. However, that example only uses one counter, and you can't test the synchronization with only one counter, so I am using two counters configured the same way, and they're wired to a single benchtop signal generator (for example at 300 kHz).
 
What I want to do, I can test in a loop with a somewhat random wait in it. I want to drive a hardware digital output line high for a few ms and then low again. The hardware line is physically connected to terminals for my timing vi's Sample Clock Source and so will cause them to buffer their counts for later reading. After I pulse this line, when I know new good buffered counts await me, I want to read both my counters. If their bufferings are simultaneous, then each counter will have counted the same number of additional counts since the last loop iteration, which I can check by subtracting the last value sitting in a shift register and then subtracting the two "additional counts" values and displaying this difference as "Diff". It should always be 0, or occasionally +1 followed immediately by -1, or else the reverse, because buffering and a count could happen practically at the same moment.
 
When I do this using a flat sequence to control the relative timing of these steps, so the read happens after the pulse, the counters often time out and everything dies. The lengths of time before, during, and after the pulse, and the timeout value for the read vi, and the size of the buffer and various other things, don't seem to change this, even if I make things so long I could do the counting myself holding a clipboard as my buffer. I've attached AfterPulse.vi to illustrate this. If I get 3 or 10 or so iterations before it dies, I observe Diff = 0; at least that much is good.
 
When I use two flat sequences running in parallel inside my test loop, one to control the pulse timing, and the other to read the counters and do things with their results, it seems to work. In fact, Diff is always 0 or very occasionally the +/- 1 sequence. But in this case there is nothing controlling the relative timing such that the counters only get read after the pulse fires, though the results seem to show that this is true. I think the reads should be indeterminate with respect to the pulses, which would be unreliable. I don't know why it's working and can't expect it to work in other environments, can I? Moreover, if I set some of the pulse timing numbers to 1 or 2 or 5 ms, timeouts start happening again, too. So I think I have a workaround that I don't understand, shouldn't work, and shouldn't be trusted. See SeparateSequence.vi for this one.
 
I also tried other versions of the well-defined, single sequence vi, moving the counter reads to different sequence frames so that they occur with the Sample Clock Source's rising edge, or while it is high, or with the falling edge, and they also often time out. I'll post these if anyone likes but can't post now due to the attachment limit.
 
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?
 
So, why am I not succeeding in taking proper control of the sequence of these events?
 
Thanks!!!
Download All
0 Kudos
Message 1 of 48
(4,213 Views)

Maybe this finishes it?

Restructured AfterPulse.vi by nesting the pulse sequence inside the counter sequence, in the same pane as the counter read. This vi behaves like I want it to. The high transition digital output vi has to happen before the low transition, because of the inner sequence. Therefore, there are 3 possible sequences involving the transition vi's and the read vi. The read can happen before them, or between them, or after them. Yet, when I add error wiring to force any of these orders, the timeout happens on the first cycle. This explanation does not address the role of the time delays, but the read timeout is many times larger than the time delays, so I don't think that can be it either.

Therefore, it looks like the pulse has to happen *during* the execution of the read vi. That is, the read vi starts, then the pulse has to start and finish, and finally the read vi finishes. Does this make sense???

0 Kudos
Message 2 of 48
(4,198 Views)
Reply and modified code in similar thread here.
 
-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 3 of 48
(4,181 Views)
Thanks, Kevin. It was great of you to take the time to do this!
 
But the vi doesn't work. When I run it, I get counter timeout when I click Strobe Now.
 
I think you've done the same thing my AfterPulse vi does, namely, force the execution order to drive the line high, drive it low, and read counter. And like I say in all my experiments this causes timeouts. If I let the counter read happen concurrently with the pulse, it usually works (though in a test I left running last night with 50 ms delays before, during, and after the pulse, it still only ran 5000 times before it died with a timeout).
 
I do know about stringing error lines to force execution order. The problem was, ANY method of forcing the execution order causes timeouts. I have tried flat sequences, and stringing error lines, and stringing numerical results from one vi to the next with appropriate treatment of the numerical values so that the dependancies are actually practically nill.
 
With a solid 40 hours of effort now into strobing and reading counters, I'm starting to wonder if it really works - but it certainly isn't easy! I now have 33 different vi's that try to do this and fail, not counting yours.
 
And it can be done with other products. Below is code in FORTH that strobes and reads 3 different counters in a CyberResearch CTCTM05 board. This is the whole program, reading and writing directly to the Am9513 chip registers, without using any device driver, and it has to do it all explicitly a byte at time. It took about 4 hours to write and debug and test, and has been running 6 years without any errors. Not so hard! But the company wants everything redone using current tools, which is proving harder than I thought! Should I consider writing my own .dll to call from LabView?
 
: cyc.data.read 308h port.in ; \ Read data port
: cyc.data.write 308h port.out ; \ Write data port
: cyc.control.read 309h port.in ; \ Read control port
: cyc.control.write 309h port.out ; \ Write control port
: cyc.in 30ah port.in ; \ Read status of 8 digital input lines
: cyc.out 30bh port.out ; \ Write status of 8 digital output lines
: cyc.initialize  \ Prepare for use
ffh cyc.control.write \ Master reset               p1-26
e7h cyc.control.write \ Clear MM13 enter 8 bit bus mode p1-26
e8h cyc.control.write \ Set MM14 disable data pointer sequencing p1-26
dfh cyc.control.write \ Disarm all counters before mode set per p1-22
01h cyc.control.write \ Aim data pointer at counter 1 mode p1-5
08h cyc.data.write \ Write LSB to counter 1 mode regester p1-23
01h cyc.data.write \ Write MSB to counter 1 mode regester p1-23
09h cyc.control.write \ Aim data pointer at counter 1 load p1-5
00h cyc.data.write \ Write LSB of zero to counter 1 load
00h cyc.data.write \ Write MSB of zero to counter 1 load
02h cyc.control.write \ Likewise counter 2
08h cyc.data.write
02h cyc.data.write
0ah cyc.control.write
00h cyc.data.write
00h cyc.data.write
03h cyc.control.write \ Likewise counter 3
08h cyc.data.write
0ch cyc.data.write \ (counter 3 counts F2 = 62,500 Hz = F1 / 16)
0bh cyc.control.write
00h cyc.data.write
00h cyc.data.write
27h cyc.control.write ;     \ Arm counters 1 & 2 p1-26
: cyc.strobe \ Disarm, latch, rezero, arm counters 1-3
87h cyc.control.write      \ Disarm and hold     p1-26
67h cyc.control.write ;    \ Load and arm        p1-26
: cyc.read.1 \ Report latched counter 1 value
11h cyc.control.write \ Aim data pointer at counter 1 hold p1-5
cyc.data.read \ Read LSB
cyc.data.read \ Read MSB
256 * + ;    \ Reassemble
: cyc.read.2 \ Report latched counter 2 value
12h cyc.control.write \ Aim data pointer at counter 2 hold p1-5
cyc.data.read \ Read LSB
cyc.data.read \ Read MSB
256 * + ;    \ Reassemble
: cyc.read.3 \ Report latched counter 3 value
13h cyc.control.write \ Aim data pointer at counter 3 hold p1-5
cyc.data.read \ Read LSB
cyc.data.read \ Read MSB
256 * + ;    \ Reassemble
0 Kudos
Message 4 of 48
(4,166 Views)

First, I've done dozens of buffered ("strobed") counter tasks and they work well and sensibly.  Not sure yet what the specific problem is in your case, but this kind of thing is generally pretty straightforward.  You shouldn't need to revert to older hardware, etc.

Meanwhile sorry for the non-working code.   I'm away from my LV box now and can't re-examine it but from what I remember, there isn't much to it.  There really aren't many candidate places for trouble.  A pulse is generated with DIO, then a single sample is read from each counter.  A timeout means either that the pulse isn't generated or that the counter tasks don't receive it.

Have you run with the little execution highlighting lightbulb on?  Have you verified that the digital pulse happens using a scope?  Are there any errors asserted?  Are you sure that the digital pulse can be seen by the counter task? 

Wait!  I think that's it!  If I recall correctly, you're generating the digital pulse on port0/line0 while you've specified that the counters should look for that signal at PFI0.  Is that right?  I didn't catch this earlier because that combination would be exactly right for a 6602 counter timer board.  However, it is NOT right for an M-series board.  On a 6259, the lines of port 0 are only for correlated DIO and do not map to PFI.  Ports 1 and 2  *do* map to PFI's.  So one example of a working combo is port1/line0 and PFI0.

-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 5 of 48
(4,160 Views)
Kevin, thanks for all the work.
 
>Have you run with the little execution highlighting lightbulb on? -Yes. In versions of this where there is no enforced timing between the counter and the digital line, and there's a delay inserted before the digital line, it works. There are nearly simultaneous starts on two tracks. Execution proceeds directly along the task wire to the counter. Meanwhile, the execution along the task wire to the digital high gets delayed. Then, when the digital high fires, the counter completes its task, and execution proceeds downstream from the counter. Note, I do have to set the timeout on the counter longer, because the vi runs so slowly when it's painting its progress along the wires. If there is any timing relationship enforced between the counter and the digital transition, it doesn't work. It appears to me that to read a counter, you have to ask it for a result, then drive the line high, and then receive the result, and execution inside the counter has to be ongoing during the rising line edge.
 
>from what I remember, there isn't much to it.  There really aren't many candidate places for trouble.  A pulse is generated with DIO, then a single sample is read from each counter.  -Yup, you got it. This should be trivial.
 
>A timeout means either that the pulse isn't generated or that the counter tasks don't receive it. - Or it could mean that the counter task must be in the middle of executing when the rising edge of the pulse arrives. Certainly the highlighted execution indicates that. Making a broken vi run by cutting the error wires that sequence the counter read relative to the pulse also seems to support that.
 
>Have you verified that the digital pulse happens using a scope? -Verified in some versions by running another loop watching a digital input, and lighting an indicator, or recording how many times the line goes high, etc. Also, in your vi, with highlighting, if I delete the error wire from the last digital output to the first counter to allow parallel execution, I see the counter execution start before the rising edge, and complete when the line high vi executes. Also, if I use separate loops to drive the line high and to read the counter, it works (see TwoLoops.vi or see the screenshot of the block diagram attached below so you don't need a LV box). I could go sign out a scope, but think it's obvious the line is pulsing given that all these things work.
 
>Wait!  I think that's it!  If I recall correctly, you're generating the digital pulse on port0/line0...  On a 6259, the lines of port 0 are only for correlated DIO and do not map to PFI. -But I'm not using internal connections, I actually physically wired P0L1 (pin 66) to PFI0 (pin 73). It was port0/line1, by the way. And when running some of these vi's, I also physically jumper this connection to port0/line2 as an analog input to watch it. And, again, the pulse does cause the counter to operate, so it clearly connects - it just doesn't operate the way I think it is described operating.
 
For what it's worth, there's another mystery. Some of the docs seem to say that the pulse has to be applied to the counter gate terminal, rather than to the line associated with the sample clock source on the timing vi. I have tried combinations of counter gate and or sample clock source and concluded it seems like the sample clock source is the terminal that matters, and it's what I'm using lately, but for example the document I cited, "Buffered Event Counting", from last September, says "It uses both the source and gate of a counter for its operation. The active edges on the gate of a counter is used to latch the current count register value in a hardware register which is then transferred via Direct Memory Access...". I may go a round of trying those combinations with the latest vi's we've discussed.
0 Kudos
Message 6 of 48
(4,154 Views)
Nope. Tried several vi's including the most important, AfterPulse.vi, after I reconnected the physical wires to use counter gates rather than sample clock source terminals, but it still doesn't work, and highlighted execution is still consistent with the idea that the counter has to be executing at the moment the rising edge hits in order for it to work.
0 Kudos
Message 7 of 48
(4,152 Views)

And here's a screenshot of AfterPulse.vi so you don't need a LV box to see it.

 

BTW, is there a way to export a graphic of the block diagram directly, so the image size isn't limited by what you can fit on the screen at one time?

0 Kudos
Message 8 of 48
(4,149 Views)

For troubleshooting, I made a couple very small mods and had no trouble at all on an M-series board.  I changed the DO strobe to go to port1/line0 because it already maps to the same pin as PFI0.  (My terminal blocks aren't easily accessible and this helped me avoid screwdriver work.)   Then I told explicitly directed both counter tasks to count edges from the internal 100 kHz timebase.  (I also temporarily changed the device name from 'Laplace' to my device's name, but I *think* I got it changed back in all the necessary places.  Better double check that though.)

No extra delays or sequence structures or anything complicated.  I can strobe as fast as I can click my mouse or I can wait a long time.  The counters always read reasonable counts immediately and I don't get any timeout errors.  After the first strobe, the difference between the 2 counter differences was always 0, as it should be.   (I also tried it with the 80 MHz timebase and would occasionally get +/- 1 for the difference of the differences.  Not unexpected -- this is typically related to signal propagation times within the board.)

Try this one and see what you get.

-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 9 of 48
(4,126 Views)

Kevin, thanks!

I tried your vi and it dies with a counter timeout on the first Strobe Now.

Then I cut the error lines that order the two counters after the digital line pulse, and it runs, and behaves as you describe: zero difference except on the very first try, and reasonable counts, whether using long or short waits. I conclude you did change from your device name to Laplace correctly. I did not make any other changes than deleting one segment of each of the two error wires and hitting Ctrl-b to tidy up.

I attached the version with the cut error lines, even though it's a very minor change, just so you could see for certain. Does this version work for you?

I am going to change this cut error wire version so that it keeps strobing itself, so I can see how many times it works before a timeout. My NestedSequences vi died at 5000, and in real life it is going to cost us maybe $1000 every time a block of 1,000,000 cycles includes a timeout, so cut-wire versions that work in casual testing are still not close to useable even if the casual testing says the numbers are correct and I elect to ignore my doubts.

0 Kudos
Message 10 of 48
(4,121 Views)