Counter/Timer

cancel
Showing results for 
Search instead for 
Did you mean: 

Upgrading from Legacy code to C# - need help configuring counter input and output channels

I am in the process of upgrading some legacy Visual C++ 6 code that was programmed against the NI PCI-6034e card.  The card that was identified by NI as an equivalent replacment is the NI PCIe-6321 card.  There is upstream hardware that is not being replaced or reconfigured, so this card was identified as providing the same functionality and I/O as the older NI card.

 

I am trying to figure out how to program the onboard counter input/output using the latest NIDAQ .NET 4.5 libraries (C#) to achieve the same functionality as the legacy code.

 

Here is the legacy code for the Counter 0 configuration:

 

// Reset the counter for programming.
GPCTR_Control(m_iDevice, ND_COUNTER_0, ND_RESET), "Reset GPCTR0" );
// Set General purpose counter #0 to use pulse-train count. GPCTR_Set_Application(m_iDevice, ND_COUNTER_0, ND_PULSE_TRAIN_GNR);
// Set General purpose counter #0 to count using the PFI6 pin. GPCTR_Change_Parameter(m_iDevice, ND_COUNTER_0, ND_SOURCE, ND_PFI_6);
// Make sure the counting is on low to high transitions of the PFI6 signal pin. GPCTR_Change_Parameter(m_iDevice, ND_COUNTER_0, ND_SOURCE_POLARITY, ND_LOW_TO_HIGH);
// Generate first pulse after m_GPCTR0_Value pulses. GPCTR_Change_Parameter(m_iDevice, ND_COUNTER_0, ND_COUNT_1, m_GPCTR0_Value);
// Generate second pulse after next m_GPCTR0_Value pulses. GPCTR_Change_Parameter(m_iDevice, ND_COUNTER_0, ND_COUNT_2, m_GPCTR0_Value);

// When count reaches zero, pulse the counter output signal pin. GPCTR_Change_Parameter(m_iDevice, ND_COUNTER_0, ND_OUTPUT_MODE, ND_TOGGLE);
// General purpose counter #0 will count down when DIO6 is low. GPCTR_Change_Parameter(m_iDevice, ND_COUNTER_0, ND_UP_DOWN, ND_HARDWARE);
// Load the settings into the counter and arm it. GPCTR_Control(m_iDevice, ND_COUNTER_0, ND_PROGRAM);


 

My analysis of this code is that in current NIDAQmx programming, I have to create both a CIChannel task, and a COChannel task.

 

I have figured out that the CIChannel should be:

 - Count Edges Counter

 - CountEdgesTerminal = PFI6

 - CountEdgesActiveEdge = low to high

 

What I am struggling with is how to program the coordination between the CIChannel and the COChannel. From the documentation of the legacy NIDAQ library,  I think that the logic of the legacy code is that for every "m_GPCTR0_Value" pulses of the PFI6 signal being counted by the counter input, the counter output sends out either the high value or the low value of its output signal.  The CIChannel needs to count down from "m_GPCTR0_Value" to 0, then signal the COChannel to output the correct state, then start counting down again from "m_GPCTR0_Value" to 0. I believe this is a continuous operation that starts when the signal on Digital Input #6 goes "Low", and stops when it goes back "High".

 

I am new to having to interface with hardware down to this level, so I may be completely missing something in my interpretation of the legacy operation.

 

I would appreciate any help that can be offered. 

 

Thanks,

Elaine Visner

0 Kudos
Message 1 of 6
(6,213 Views)

Hi Elaine,

 

You should only need to use a single counter to do this.  Configuring a "counter output" task in DAQmx is what you are going for.  If I change the wording of some of the comments in your original code to make it more akin to DAQmx terminology I think things will become a little more clear:

 

// Set General purpose counter #0 to use continuous pulse-train count generation.
// Set General purpose counter #0 to count generate using the PFI6 pin as the timebase source.
// Make sure the counting is on low to high transitions of the PFI6 signal pin. Timebase is active on rising edge by default anyway, this line isn't necessary.
// Generate first pulse after m_GPCTR0_Value pulses. Set Low Time and Initial Delay to m_GPCTR0_Value.
// Generate second pulse after next m_GPCTR0_Value pulses. Set High Time to m_GPCTR0_Value.

// When count reaches zero, pulse the counter output signal pin. Output Behavior is Toggle by default for output task, this line isn't necessary.
// General purpose counter #0 will count down when DIO6 is low. Are you actually toggling DIO6 or just holding it low? If just holding it low, this line isn't necessary. If you are toggling the line and getting some sort of behavior change however I would be curious, as this property shouldn't be supported for ND_PULSE_TRAIN_GNR applications (only ND_SIMPLE_EVENT_CNT or ND_BUFFERED_EVENT_CNT according to here). In DAQmx I know it is not supported in counter output applications, so if you somehow need to use this property in your output applicaiton we'll have to figure something else out (perhaps you can achieve the same goal with a pause trigger).

 

When using a counter output task, the counter will load up a value into the count register, decrement the value in the register on each timebase edge, and when the register value reaches zero the counter will toggle its output and load a new value into the register.  So it's still counting in a sense, but the end result is that you are generating a pulse train at a specified frequency (depends on the rate of the timebase) and duty cycle (50% in your case since high and low register values are the same).

 

The one call you'll need to make in DAQmx that doesn't have an equivalent in the older driver is to configure continuous, implicit timing.  This configures the output to repeat itself indefinitely (as in the legacy application) rather than outputting only a single pulse.

 

 

Best Regards,

John Passiak
0 Kudos
Message 2 of 6
(6,209 Views)

Hi John,

 

Thanks for your quick response.  Your explanation definitely clarifies this for me.

 

Just a quick clarification:  am I right that the .NET COChannel I will be configuring is a "Pulse Ticks" channel (Task.COChannels.CreatePulseChannelTicks())?

 

Also, I looked over the rest of the legacy code and do not see that the DIO6 is ever toggled through code.  Using the NI Explorer Test Panels, I am able to see that DIO6 is only toggled by the upstream hardware when a "start trace" switch is toggled.  The software actually monitors a different DI that toggles high on this same "start trace" switch for when to begin saving data.  So, I believe this DIO6 signal is actually no longer of value.  It may have been used in an earlier version of the code when an even older NI board may have been used.

 

Again, thanks for your help.

 

Elaine Visner

0 Kudos
Message 3 of 6
(6,154 Views)

John,

 

Thanks for the quick response. Your comments and clarifications definitely helped.

 

One quick question: for the .NET code, based on your comments, I believe I need to configure a "Pulse Ticks" COChannel (task.COChannels.CreatePulseChannelTicks()).  Is this correct?

 

Also, I looked through the rest of the code for this application and cannot find any additional NIDAQ calls that toggle the DIO6 signal.  It is actually toggled by a switch on the upstream hardware, which I have verified through the NI Explorer test panels. There is also another DIO that goes high at the same time DIO6 goes low, and this other DI is the signal that is monitored as a trigger to begin data acquisition.  So, it looks like DIO6 actually has no importance anymore.  Maybe an earlier version of the program with an even older NI card used DIO6.

 

Again, thanks for your help.

 

Elane Visner

0 Kudos
Message 4 of 6
(6,178 Views)

Hi John,

 

Thanks for the quick reply.  Your comments definitely helped clarify things.

 

A quick question:  based on your comments, I believe I have to call the .NET  CreatePulseChannelTicks() method to create the correct type of COChannel that is required. Is this correct?

 

Also, in looking through the rest of the legacy data acquisition code, I do not see any other calls that toggle DIO6.  It is in fact toggled by the upstream hardware.  However, DIO6 is not used as a trigger for any subsequent data collection.  There is another DI that goes high at the same time that is actually the trigger for the required data collection.  So, I don't think DIO6 is important anymore.  Maybe this call is left over from an even earlier version of the legacy code that used a different NI board.

 

Again, thanks for you help.

 

Elaine Visner

0 Kudos
Message 5 of 6
(6,187 Views)

 A quick question:  based on your comments, I believe I have to call the .NET  CreatePulseChannelTicks() method to create the correct type of COChannel that is required. Is this correct?


Exactly.  The configuration portion might look something like this (omitted the inputs to CreatePulseChannelTicks but you can see them in the linked documentation):

 

myTask = new Task("counterTask");

myTask.COChannels.CreatePulseChannelTicks(...);

myTask.Timing.ConfigureImplicit(SampleQuantityMode.ContinuousSamples);

myTask.Start();

 

You don't need to configure a writer in this case since the output parameters are actually defined in the channel properties and are never changed.

 

 


Also, in looking through the rest of the legacy data acquisition code, I do not see any other calls that toggle DIO6.  It is in fact toggled by the upstream hardware.  However, DIO6 is not used as a trigger for any subsequent data collection.  There is another DI that goes high at the same time that is actually the trigger for the required data collection.  So, I don't think DIO6 is important anymore.  Maybe this call is left over from an even earlier version of the legacy code that used a different NI board.


I honestly just suspect that the original programmer thought that it was necessary to explicitly control the count direction using an external signal to make it count down.  Based on the documentation (I don't have the old driver installed or hardware to be able to test it myself) I don't believe that this is necessary or that setting it even does anything, but if it does and your application was depending on whatever behavior is the result then we might need to revisit...

 

 

 

So to summarize, the code you have attached essentially implements a counter output task using continuous pulse generation with an external timebase.  The output line will remain low for m_GPCTR0_Value ticks of the timebase, then switch to high for m_GPCTR0_Value ticks of the timebase, and repeat this switching indefinitely.

 

 

Best Regards,

John Passiak
0 Kudos
Message 6 of 6
(6,174 Views)