Counter/Timer

cancel
Showing results for 
Search instead for 
Did you mean: 

Trouble setting up an encoder input and PWM output tasks on CompactDAQ

Solved!
Go to solution

I am using a cDAQ-9174 chassis with a 9474 and 9411 modules. I don't believe it matters but they are the old NI cRIO-XXXX modules that came with a test setup that was distributed to early adopters. I am using DAQmx tasks in an application (C libraries) to read a quadrature encoder (angular position) and to drive a motor directly with PWM current (pulse output). To satisfy various other requirements, my setup of the tasks is as follows:

 

[DAQmx] MajorVersion = 9

MinorVersion = 2

[DAQmxChannel GenV 9411 Rotary Encoder Input/AngularPosition]

CI.AngEncoder.PulsesPerRev = 500

CI.AngEncoder.InitialAngle = 0

CI.Encoder.ZIndexVal = 0

CI.Encoder.ZIndexPhase = A High B Low

CI.Encoder.ZIndexEnable = 0

ChanType = Counter Input

CI.MeasType = Position:Angular Encoder

CI.AngEncoder.Units = Ticks

PhysicalChanName = cDAQ1Mod2/ctr2

CI.Encoder.DecodingType = X4

 

[DAQmxChannel GenV 9474 PWM Output/PulseOutput]

CO.Pulse.IdleState = Low

ChanType = Counter Output

CO.OutputType = Pulse:Time

CO.Pulse.HighTime = 5.0000000000000004E-006

CO.Pulse.LowTime = 5.0000000000000002E-005

CO.Pulse.Time.InitialDelay = 0

CO.Pulse.Time.Units = Seconds

PhysicalChanName = cDAQ1Mod1/ctr3

 

[DAQmxTask GenV 9411 Rotary Encoder Input]

Channels = GenV 9411 Rotary Encoder Input/AngularPosition

SampQuant.SampMode = Continuous Samples

SampClk.ActiveEdge = Rising

SampQuant.SampPerChan = 100000

SampClk.Rate = 100000

SampTimingType = Sample Clock

SampClk.src=/cDAQ1/100kHzTimebase

 

[DAQmxTask GenV 9474 PWM Output]

Channels = GenV 9474 PWM Output/PulseOutput

SampQuant.SampMode = Continuous Samples

SampQuant.SampPerChan = 100000

SampTimingType = Implicit

RegenMode = Allow Regeneration

 

[DAQmxCDAQChassis cDAQ1

] ProductType = cDAQ-9174

DevSerialNum = 0x18B3EC0

 

[DAQmxCDAQModule cDAQ1Mod1]

ProductType = NI 9474

DevSerialNum = 0xDEDF40

CompactDAQ.ChassisDevName = cDAQ1

CompactDAQ.SlotNum = 1

 

[DAQmxCDAQModule cDAQ1Mod2]

ProductType = NI 9411

DevSerialNum = 0xDEDB24

CompactDAQ.ChassisDevName = cDAQ1

CompactDAQ.SlotNum = 2

 

Each task works fine on its own (i.e., without the other). The problem is that if I start the encoder task first and then the PWM task, the latter causes an error:

 

Error -89137 occurred at DAQ Assistant
Possible Reason(s):
Specified route cannot be satisfied, because it requires resources that are currently in use by another route.

Source Device: cDAQ1
Source Terminal:
80MHzTimebase
Destination Device: cDAQ1
Destination
Terminal:
Ctr3Source

Required Resources in Use bySource
Device:
cDAQ1
Source Terminal: 100kHzTimebase
Destination
Device:
cDAQ1
Destination Terminal: Ctr2SampleClock

Task Name: _unnamedTask<61>

 

I don't know why that is but if I start the PWM task first and then the encoder task, it also works. I should also mention that initally I was using counter 0 for the encoder, which caused a redirection of 100kHzTimebase to Ctr0SampleClock, which, according to the 9411 device routes, is not supported; yet it worked (by itself). I wonder if what is actually happening under the hood is not quite what is being shown.

 

What exactly is the conflict and what can I do to avoid it? The reasons for needing to use the specific modes and parameters chosen (e.g., the "continuous samples" with the 100kHzTimebase clock) are rooted in various performance and optimization requirements that have been established in a previous version of our software, so I'd prefer not taking a completely different route, if some small changes would lead us to correcting the problem.

 

I appreciate your assistance.

Kamen

0 Kudos
Message 1 of 12
(7,806 Views)

I should also mention that there are no other tasks running on the chassis, so there is nothing else that might be interfering.

 

Why isn't there a way to edit a message? it is very inconvenient to have to post replies when you simply want to add or correct one simple thing.

 

Kamen

0 Kudos
Message 2 of 12
(7,796 Views)

I guess, I was desperate and tried a few things, like moving the tasks to different counters. One source who was getting the same error, suggested they could only get it to work if both tasks used the same counter. That did not work (I got another error, suggesting the resource was taken). I tried a few other combinations until I finally moved the PWM output to counter 0, while the encoder input stayed on counter 2 and... lo and behold, it worked! And now it doesn't matter in what order the tasks are started, it works both ways, so this seems to be a solution.

I have no idea what the problem was before and why it is working now, so if someone provides a plausible explanation, I'd be happy to award them the solution. But I am satisfied with the way it is working, so - no worries.

Kamen

0 Kudos
Message 3 of 12
(7,793 Views)
Solution
Accepted by topic author Kamen

Hi Kamen,

 

The 100 kHz timebase doesn't have a direct route to the counter sample clocks, the device actually uses one of the other counters to complete the route (the routing table is a little misleading here as it shows Counter 2 as the one always making the route--in reality it will be any available counter):

 

counter_cDAQ_Routing.png

 

 

So in your case, when you start the encoder task, it uses one of the other available counters to complete the configured route (100 kHz timebase to ctr2 sample clock).  Evidently it chose counter 3.

 

 

Some possible workarounds (it sounds like you've already found one yourself):

 

1.  Start the PWM task before the encoder task--if the PWM task starts first the counter is already reserved and the encoder task would choose another available counter to complete its route.

 

2.  Explicitly reserve the PWM task before starting the encoder task (if you do need to start the encoder task first).

 

3.  Use  cDAQ1/_freqout to generate the 100 kHz sample clock signal and use this instead of routing the 100 kHz timebase to the counter sample clock.

 

 

Changing the counters around should also work, but I'm not 100% sure how the device picks which counter to use for the routing (I wouldn't expect it to change in the future, but if it's not explicitly spec'ed somewhere then I wouldn't take my chances)--if it were me I would pick one of the other above options.

 

 

Best Regards,

John Passiak
0 Kudos
Message 4 of 12
(7,771 Views)

Thank you, John, your explanation makes sense. At this time, the setup I'm putting together is for testing, so I'm not worried about future-proofing it (e.g., upgrades to DAQmx drivers). But for production purposes, it would require some deeper digging. As far as the workarounds you suggested, controlling the order of task execution or reserving tasks (not sure if I'm understanding this one correctly) are not very appealing. The software that uses those tasks is a product that should be agnostic of the idiosyncrasies of the hardware and, thus, would have no way of knowing which task to start first or to reserve. Your third workaround seems very promising, though, since it would be implemented at the configuration stage, which can take into account any special requirements imposed by the hardware. I'm just not sure how to do that - I tried all combinations in MAX and was getting errors, timing out or not working. I'd hate to take much more of your time but if you could explain how I could use the FrequencyOutput to generate the sample clock, I'd appreciate that.

Kamen

0 Kudos
Message 5 of 12
(7,767 Views)

You can program the Frequency Output similar to a counter output task (Continuous Implicit Timing is the default/only timing option though).  For example:

 

DAQmxCreateTask("",&taskHandle);
DAQmxCreateCOPulseChanFreq(taskHandle,"cDAQ1/_freqout","",DAQmx_Val_Hz,DAQmx_Val_Low,0.0,100000.0,0.50);
DAQmxStartTask(taskHandle);

 

The sample clock source for the encoder task would become "/cDAQ1/FrequencyOutput" (instead of "/cDAQ1/100kHzTimebase").

 

I like this solution since you're freeing up an extra full-featured counter at the expense of the frequency generator (which is essentially a limited counter output that most people don't use or even know about).

 

 

Best Regards,

John Passiak
Message 6 of 12
(7,763 Views)

Thanks, but what I meant was how to setup the frequency output so that it can be used in the encoder and PWM tasks. I can't have this setup in the C code because those are only device interfaces, each knows nothing about the others. What I was imagining was all of this setup in MAX, with both tasks (encoder and PWM) setup and running so that the software can pick up its encoder input and PWM output, respectively (it is plug-and-play).

Kamen

0 Kudos
Message 7 of 12
(7,754 Views)

The frequency output is only going to be used by the encoder task, why not put the code for it contained within the encoder task implementation?  

 

The way you have it currently, the encoder implementation uses 2 counters (the one you specify and then some other one to facilitate the routing of the 100 kHz timebase).  This is undesirable because the second counter is picked by the driver and might correspond to one that you need for some other purpose later on.  You could in effect choose the 2nd counter by explicitly configuring it as a counter output at 100 kHz, but why not just use the Freq Out instead which is capable of what you need and can't be used for as many other useful purposes.

 

 

Best Regards,

John Passiak
0 Kudos
Message 8 of 12
(7,750 Views)

I think I understand. I'll have to talk to my coworker, who had implemented the encoder instrument driver for our previous software; he had some considerations for using the 100kHz timebase. I'll ask him whether we can do what you suggest, instead.

Thanks for everything!

Kamen

0 Kudos
Message 9 of 12
(7,748 Views)

I'm sorry to resurrect this old thread, but I recently upgraded to DAQmx 14.5.1 and my old kludgy arrangement is not working anymore. I still don't fully understand what I'm doing but I tried to follow John's suggestion (with the help of my coworker) - in my code I add the creation of an addtional task (whenever the measurement is of the encoder type and the supporting hardware - a cDAQ chassis), which task starts a CO pulse task with a channel for generating the 100kHz time-base I need, and in MAX I configure my encoder task to use the FrequencyOutput clock source. Again, I don't fully understand how this all works, but it does work with the exact setup that I have. I also read the actual chassis device name, so at least the code is not vulnerable to someone renaming the device. Here's the code:

 

if(pTasks[TskIdx].Devices[0].pcDAQmxChassisName != NULL)  // If this counter is supported by a cDAQ chassis (counters are on the chassis, not on the modules); <* this assumes a single hardware device, [0] *>
{
  char* pcCounterName;
  StrSize = strnlen(pTasks[TskIdx].Devices[0].pcDAQmxChassisName, 512) + strnlen("/_freqout", 512) + 1;  // Enough for the name and the terminating null character but no more than 1K characters
  pcCounterName = new char[StrSize]; // Allocate enough space
  strcpy_s(pcCounterName, StrSize, pTasks[TskIdx].Devices[0].pcDAQmxChassisName);  // Start with the device name (the chassis)
  strcat_s(pcCounterName, StrSize, "/");  // Add the separator
  strcat_s(pcCounterName, StrSize, "_freqout");  // Add the special channel physical name (<-* should be determined programmatically *->)
  pTasks[TskIdx].AuxCurrError = DAQmxCreateTask("Auxiliary Encoder clock-source routing Task", &pTasks[TskIdx].hAuxTaskHandle);  // Create the auxiliary task for signal routing (connecting the sample clock source of the encoder task to the freqeuncy generator of the device)
  pTasks[TskIdx].AuxCurrError = DAQmxCreateCOPulseChanFreq(pTasks[TskIdx].hAuxTaskHandle, pcCounterName, ""DAQmx_Val_HzDAQmx_Val_Low, 0.0, pTasks[TskIdx].SampleClockRate, 0.5);
  pTasks[TskIdx].AuxCurrError = DAQmxStartTask(pTasks[TskIdx].hAuxTaskHandle);
  delete[] pcCounterName;
}

 

Considering that our software is a product and we want it to be as robust as possible, there are many probelms with this approach. One of them is the inability to obtain the exact name of that channel, or whatever "cDAQ1/_freqout" happens to be ("a circuit within the device", says NI). For now, I'd be very happy to get started with the answer to that question: how to programmatically obtain the specific name of that "thing"? Or is each DAQmx device that supports encoders so quirky that it'd be a lost cause trying to automate this, anyway?

 

Kamen

0 Kudos
Message 10 of 12
(5,820 Views)