Multifunction DAQ

cancel
Showing results for 
Search instead for 
Did you mean: 

Odd error when piggybacking counter read on analog read

Solved!
Go to solution

Background:

I have an application that needs to read an analog value and an encoder value when a user presses a button. As a quadrature counter channel will only maintain its position while a task is active, I cannot simply start and stop the counter task without losing my encoder position. My standard plan for reading mixed analog/encoder signals is to use the AISampleClock as the Counter's sample clock, meaning they both sample at the same time (since Counter read tasks don't have a SampleClock, and I don't want to use up one of my Counters to create one).

 

I am prototyping on a USB-6341, which supports retriggerable tasks (the ideal way to do this), but the target device is an M series card, which does not support retriggerable tasks. On an M series card, you have to use a counter, which I don't want to do. I am trying to implement a similar-ish concept by using the AI SampleClock as the source for the CI's sample clock, then clearing and restarting an AI task as needed.

 

The issue:

The concept works... most of the time. Unfortunately, not all sample rate/samples per read value work together, and I can't figure out why. For example, if I read 5 samples per channel, a sample rate of 1502 works, but a rate of 1501 gives me error -200284 (a Timeout error).

I ran some experiments and determined the following:

  • 5 samples/channel: 1502 works, 1501 doesn't
  • 6 samples/channel: 1877 works, 1876 doesn't
  • 7 samples/channel: 2253 works, 2252 doesn't
  • 10 samples/channel: 3379 works, 3378 doesn't
  • 40 samples/channel: 14640 (14641.3)works, 14639 (14639.1) doesn't
  • 100 samples/channel: 37161 (37174.7) works, 37160 (37160.9) doesn't

(*Most of these coerced to basically the correct values, but these two weren't as close as the others between their specified and coerced values)

 

Here is the code:

Test counter start-stop.png

 

Any ideas here would be greatly appreciated. I can't figure out any correlation between the samples/channel and the sample rate that would predict this issue. I assume something is getting coerced somewhere, but I can't figure out what it might be. It does appear that the relationship between the samples per channel and correct frequency is linear but I can't explain why. It appears that if the sampling takes longer than around 3.2 ms, it times out. Any thoughts would be greatly appreciated- it's late on a Friday and I'm totally out of ideas 🙂

0 Kudos
Message 1 of 5
(2,123 Views)

(As an aside, I'd like to point out that yes I could use On Demand timing to accomplish this same task by simply not configuring the sample clock for the Counter read, but I'd like to read it at a fairly high rate for a determined period of time when the button is clicked, hence I believe I need to use a sample clock. If I am mistaken in this please let me know.)

0 Kudos
Message 2 of 5
(2,114 Views)
Solution
Accepted by topic author BertMcMahan

1. The behavior you report strikes me as very odd indeed and I have no specific working theory (unless something comes to me while I type).

 

2. I know you know your way around this stuff pretty well, so I figure you'll be able to handle some of my comments which may be nitpicky at best, and are most likely unimportant to the issue at hand.  But since I don't really understand the issue at hand, it's a matter of "deal with stuff that might be a good idea to deal with anyway, then see if magic happens."

 

3.  Your counter task is set for Continuous Sampling.  That's what I would do in this case too.  However, it's also the case that when you do continuous sampling, the 'samples per channel' input to DAQmx Timing is routinely ignored.  DAQmx picks a size for you.  (Somewhat recently I poked and prodded at this and found that the link actually shows the *minimum* buffer size DAQmx will insist on.  If you ask for a bigger one, it will honor that, but not a smaller one.)

    This is mostly an FYI, I find it hard to imagine that this would matter to your symptoms.  But if this was my app, *one* of the things I'd end up trying is to leave that input unwired for the Counter task.   The DAQmx buffer rules *might* be different for counter tasks that can't use a *known* internal timebase to generate the sample clock.  Perhaps there's more caution, quirks, and hence bugs built into the algorithm.

   I'm very skeptical of this theory, but there you go anyway.  The specific cutoff points you find for requested sample rates look nothing like the round number cutoff points in the linked article.

 

3. When you feed the sample rate input to the Counter task, you may as well feed the *right* one, which is the output of the AI property node query.

 

4. The extraneous code that puts a signal out to PFI for an oscilloscope uses DAQmx Connect Terminals.  I would personally do this a different way most of the time.  Connecting Terminals is more persistent than the methods I usually use, either DAQmx Export Signal or a "write" property node to define a destination terminal for the signal in question.  Once you connect terminals, the connection routing definitely persists until you disconnect them or reset the device.

   The methods I use are somewhat less persistent.  They're guaranteed to last only as long as the task itself.  Once the task is cleared, they're *allowed to* stop being routed or have their routing changed.  In reality, it often doesn't happen immediately -- search "lazy uncommit" for more info.

 

5.  HOLD ON!  WAITAMINUTE!  Something *DID* just occur to me while I was typing.

     You're clearing your AI task before entering the loop!  You probably shouldn't.  You're giving DAQmx implicit permission to remove the routing you set up between the AI Sample Clock terminal and the Counter Sample Clock source.  It may or may not take advantage of that permission due to "lazy uncommit", but I'm half-willing to bet that the weird behavior you see relates to a combination of clearing AI, the somewhat indeterminate behavior of "lazy uncommit", and other inexplicable factors needed to account for the odd cutoff points you saw.  That part still seems weird, assuming you did multiple reps on both sides of those cutoffs to confirm consistency.

 

6. Proposed solution:  Do NOT clear the AI task before the loop.  Also continue not to start it before the loop.  And finally, make a call to DAQmx Control Task to "commit" the task before the loop.  Inside the loop, just Start, Read, and Stop (but do not Clear, not until after the loop the way you do with your Counter task.)

   The "commit" action is part of the DAQmx Task State Model.  (I see that the help page is more helpful than it used to be.)   If you "commit" before you Start, then the subsequent Stop does not wind back the task state nearly so far.  The pre-commit guarantees that the task won't unwind and "unreserve" the signal routing, leaving it up to the whims of "lazy uncommit" whether the routing remains or goes away.

     If you need the ability to change sample rate or # finite samples in the loop, you'll have to let the task state unwind and then re-program the sample clock terminal routing inside the loop.

 

Let me know if it works.

 

 

-Kevin P

CAUTION! New LabVIEW adopters -- it's too late for me, but you *can* save yourself. The new subscription policy for LabVIEW puts NI's hand in your wallet for the rest of your working life. Are you sure you're *that* dedicated to LabVIEW? (Summary of my reasons in this post, part of a voluminous thread of mostly complaints starting here).
Message 3 of 5
(2,065 Views)

Kevin, I was hoping you'd chime in on this, and sure enough you got it figured out. I believe it was the "lazy uncommit" doing some kind of shenanigans. I'd give you more Kudos if I could 🙂

 

A few comments since you were so kind as to type all of that out:

1-3: Agreed, and I absolutely appreciate "nitpicky" comments. In my experience, bugs like this come from something nitpicky, not something "architectural"- in this case, you were able to find the needle in the haystack!

3b (there were two 3's ;)) I had actually done this already to get the coerced values from my original post, I just uploaded a slightly earlier version due to some brain fart. Good catch.

4: I almost never need to do this, so thanks for the suggestion. In this case I think it might have confused me more, as that route might have been removed along with the internal connection!

5: And this was the solution- committing the task before the loop, then starting and stopping it inside, works at a bunch of random sample rates I tested. I'm not sure I've ever started a task a second time before to be honest.

 

Working code is attached. Thanks Kevin for talking all of that out, on a Saturday no less! I'd sure love to understand what specifically was going on here so I can avoid it happening again (any NI guys/gals want to chime in?) but for now the test code is working, so I can get it going in the real thing.

 

Test counter start-stop working.png

 

0 Kudos
Message 4 of 5
(2,024 Views)

I'm curious about the original behavior too, but am too lazy / insufficiently invested to write it all up for NI.  My guess is that now that this thread is marked as "solved", it's a lot less likely to get official NI eyes on it.  It seems that official NI attention tends to come in on threads that sit unanswered and unsolved for a little while.

 

Maybe you could write it up as a separate topic that links back to this one for more details?

 

(P.S.  Touché on the doubling-up of #3's!  One good nitpick deserves another! Smiley Tongue)

 

 

-Kevin P

CAUTION! New LabVIEW adopters -- it's too late for me, but you *can* save yourself. The new subscription policy for LabVIEW puts NI's hand in your wallet for the rest of your working life. Are you sure you're *that* dedicated to LabVIEW? (Summary of my reasons in this post, part of a voluminous thread of mostly complaints starting here).
0 Kudos
Message 5 of 5
(2,015 Views)