Measurement Studio for .NET Languages

cancel
Showing results for 
Search instead for 
Did you mean: 

Hardware Timed Interrupt

Solved!
Go to solution

I am revisiting this issue after some time now.  Is this the best method to implement a hardware timer that calls a function in Visual Basic?

 

    Public Sub CreateTimerTasks()
        Try
            ' Input Task
            With DCChannels(ptrLoopTimer.Value)
                counterReadTask = New Task()

                counterReadTask.CIChannels.CreateCountEdgesChannel(.Device & "/" & .Channel, "Input", _
                        edgeType, 0, countDirection)

                counterReadTask.Timing.ConfigureSampleClock("/" & .Device & "/PFI8", _
                        20000, SampleClockActiveEdge.Rising, _
                        SampleQuantityMode.ContinuousSamples, 20000)

                runningCTRTask = counterReadTask
                myCounterReader = New CounterReader(counterReadTask.Stream)

                myCallBack = New AsyncCallback(AddressOf CounterReadCallback)

                myCounterReader.SynchronizeCallbacks = True

                myCounterReader.BeginReadMultiSampleDouble(Convert.ToInt32(2000), myCallBack, counterReadTask)
            End With
            With DCChannels(ptrLoopClock.Value)

                counterWriteTask = New Task

                counterWriteTask.COChannels.CreatePulseChannelFrequency(.Device & "/" & .Channel, _
                    "Output", COPulseFrequencyUnits.Hertz, COPulseIdleState.Low, 0.0, _
                    20000, 0.5)

                counterWriteTask.Timing.ConfigureImplicit(SampleQuantityMode.ContinuousSamples, 30000)

                counterWriteTask.Start()
            End With
        Catch exception As DaqException
            MessageBox.Show("Make sure you have the loop timer configured properly or disable this feature in the Init.txt file.", "Alert!", MessageBoxButtons.OK)
            counterReadTask.Dispose()
            runningTask = Nothing
            Dim timerDelegate As TimerCallback = AddressOf ControlCode
            TenHzLoopTimer = New System.Threading.Timer(timerDelegate, inProcess, 0, 100)
        End Try
    End Sub

Public Sub CounterReadCallback(ByVal ar As IAsyncResult)
Try
If runningCTRTask Is ar.AsyncState Then
Dim data As Double()
data = myCounterReader.EndReadMultiSampleDouble(ar)

myCounterReader.BeginReadMultiSampleDouble(2000, myCallBack, counterReadTask)
ControlCode()
End If
Catch exception As DaqException
txtMessage.AppendText("Check on cell. Control loop may have stopped. " & Now.Second & ":" & _
LastControlIteration & vbNewLine & vbNewLine & exception.Message)
TextMessage("Check on cell. Control loop may have stopped. " & Now.Second & ":" & LastControlIteration)
counterReadTask.Dispose()
runningTask = Nothing
Dim timerDelegate As TimerCallback = AddressOf ControlCode
TenHzLoopTimer = New System.Threading.Timer(timerDelegate, inProcess, 0, 100)
End Try
End Sub
Programming Data Acquisition and Control in Measurement Studio and Labwindows/CVI
0 Kudos
Message 11 of 39
(2,531 Views)

Hi Michael,

 

As far as I understand, you want to read a counter output in Visual Basic and then call a function when the counter reaches 20000 rising edges. Is this correct?

What hardware are you currently using?

 

 

 

Mikhail
RF Toolkits, Product Support Engineer
National Instruments
0 Kudos
Message 12 of 39
(2,509 Views)

Almost.  I want to call some function at 10 Hz but Windows is only able to acheive 9 Hz.  I believe the pulse train is operating at 20kHz and the counter should enter a callback function every time the count hits 2000.  That should be very close to 100ms.  At that time I'd like to call a function (threaded), reset the counter, and then start again.  This is my attempt at HW timing.

Programming Data Acquisition and Control in Measurement Studio and Labwindows/CVI
0 Kudos
Message 13 of 39
(2,506 Views)

I should also mention that I have it working....somewhat, but that the buffer overflows or it times out waiting for more samples.  My question is more related to the buffer size, etc.

Programming Data Acquisition and Control in Measurement Studio and Labwindows/CVI
0 Kudos
Message 14 of 39
(2,501 Views)

Hi Michael,

 

When you set your clock to Continuous Samples, an "interactive" buffer is created as a function of the rate acquisition.

One thing you can try to eliminate the buffer overflow error is to expand the default buffer size set when you are sampling Continuous Samples mode. The following function let's you expand the size of your buffer:

 

DAQmxCfgInputBuffer

int32 DAQmxCfgInputBuffer (TaskHandle taskHandle, uInt32 numSampsPerChan);

 

Purpose

Overrides the automatic input buffer allocation that NI-DAQmx performs.

Parameters

 

Input
NameTypeDescription
taskHandle TaskHandle The task used in this function.
numSampsPerChan uInt32 The number of samples the buffer can hold for each channel in the task. Zero indicates no buffer should be allocated. Use a buffer size of 0 to perform a hardware-timed operation without using a buffer.

Return Value

 

NameTypeDescription
status int32 The error code returned by the function in the event of an error or warning. A value of 0 indicates success. A positive value indicates a warning. A negative value indicates an error.

 

Also, here are some articles you might find helpful:

 

How Is the DAQmx Buffer Size Allocated for a Finite or Continuous Acquisition?

 

How to signal edge triggered event on Digital Input line of PCI-6025E using DAQmx in VB.Net?


NI-DAQmx: Counter Measurements - Count Digital Events - Buffered Finite with External Clock in .NET

 

Mikhail
RF Toolkits, Product Support Engineer
National Instruments
0 Kudos
Message 15 of 39
(2,479 Views)

I need to revisit this issue so that I can settle it once and for all.  I am still getting the following error, though the buffer size should be fine.  I don't know how to call that function called DAQmxCfgInputBuffer, but I did add a function call to set the buffer size: [counterReadTask.Stream.Buffer.InputBufferSize = 2500].  This error happens on any glitch in the Windows environment.  Once it happened fairly routinely when I would start the engine (in the test cell).  The last instance happened when I dragged a window from one monitor to another.  I got the white background where Windows didn't refresh the screen (don't normally have this issue).  During this time the error occured.  The samples provided were not exactly what I'm doing either...

 

Should I be doing FiniteSamples instead of Continuous in this case?  I am trying to create a hardware timed loop instead of using System.Timers.Timer

 

Output clock: 20 kHz

Counts to read: 2000 (100ms)

 

Attempted to read samples that are no longer available. The requested sample was previously available, but has since been overwritten.

Increasing the buffer size, reading the data more frequently, or specifying a fixed number of samples to read instead of reading all available samples might correct the problem.

Property: NationalInstruments.DAQmx.DaqStream.ReadRelativeTo
Corresponding Value: NationalInstruments.DAQmx.ReadRelativeTo.CurrentReadPosition
Property: NationalInstruments.DAQmx.DaqStream.ReadOffset
Corresponding Value: 0

Task Name: _unnamedTask<0>

Status Code: -200279

 

Input Counter Setup

 

            With DCChannels(ptrLoopTimer.Value)
                counterReadTask = New Task()

                counterReadTask.CIChannels.CreateCountEdgesChannel(.Device & "/" & .Channel, "Input", _
                        edgeType, 0, countDirection)

                counterReadTask.Timing.ConfigureSampleClock("/" & .Device & "/PFI8", _
                        20000, SampleClockActiveEdge.Rising, _
                        SampleQuantityMode.ContinuousSamples, 2500)

                counterReadTask.Stream.Buffer.InputBufferSize = 2500



                runningCTRTask = counterReadTask
                myCounterReader = New CounterReader(counterReadTask.Stream)

                myCallBack = New AsyncCallback(AddressOf CounterReadCallback)

                myCounterReader.SynchronizeCallbacks = True

                myCounterReader.BeginReadMultiSampleDouble(Convert.ToInt32(2000), myCallBack, counterReadTask)
            End With

 

Output Counter Setup

 

            With DCChannels(ptrLoopClock.Value)

                counterWriteTask = New Task

                counterWriteTask.COChannels.CreatePulseChannelFrequency(.Device & "/" & .Channel, _
                    "Output", COPulseFrequencyUnits.Hertz, COPulseIdleState.Low, 0.0, _
                    20000, 0.5)

                counterWriteTask.Timing.ConfigureImplicit(SampleQuantityMode.ContinuousSamples, 20000)

                counterWriteTask.Start()
            End With

 

 

 

Programming Data Acquisition and Control in Measurement Studio and Labwindows/CVI
0 Kudos
Message 16 of 39
(2,383 Views)

Hi Michael,

 

You are correct in using Stream.Buffer.InputBufferSize function to increase the buffer size in C#. DAQmxCfgInputBuffer is for C.

 

In C

  DAQmxCfgInputBuffer (taskHandle, bufferSize);

In C#

  myTask.Stream.Buffer.InputBufferSize=bufferSize;

 

Now you are setting your buffer to 2500 samples and you are also aquiring 2500 samples on every iteration. If you don't read the samples fast enough

from the buffer, you will get an error -200279. Windows clock will control how fast your counter read operation gets executed. If other Windows processes are running in the background this can affect the execution speed of your C# code. Ideally you want to set your buffer size slightly larger than the number of samples to acquire. For more information on how to eliminate error -200279 refer to the following article:

Why Do I Get Error -200279 from my DAQmx Read VI or Property Node? 

 

Mikhail
RF Toolkits, Product Support Engineer
National Instruments
0 Kudos
Message 17 of 39
(2,366 Views)

Since I am doing Continuous Acquisition, the buffer size is set automatically based off of the number of samples I expect to read.  I set this number to 2500, but I really only want 2000.  When I actually begin acquisition I ask to count 2000 pulses.  Should I change my expected samples in the ConfigureSampleClock call back to 2000 and then manually set the buffer to 2500?  Should in increase the buffer size even more?

 

 

From the article:

 

I am reading 2000 samples and my buffer size should be 2500, so I have increased the buffer size.

 

How can I read the data more frequently?  I have set one counter to output a 20 kHz clock, and I've set another counter to count 2000 samples and then fire a software event.

 

I have specified that I want to count 2000 pulses.  The card should be able to do this independently of Windows and then should call an event (which would then depend on Windows).

 

How can I monitor the buffer?  Why should it buffer anyway?  It needs to count pulses until it hits 2000, then it should clear the buffer and count 2000 more pulses.

 

This is the callback for when 2000 pulses are counted.  Do I need to clear any buffers?

 

            If runningCTRTask Is ar.AsyncState Then
                Dim data As Double()
                data = myCounterReader.EndReadMultiSampleDouble(ar)

                myCounterReader.BeginReadMultiSampleDouble(2000, myCallBack, counterReadTask)
                ControlCode()
            End If

 

Thank you for your help.  This has been troubling me for a long time.

 

Programming Data Acquisition and Control in Measurement Studio and Labwindows/CVI
0 Kudos
Message 18 of 39
(2,356 Views)

I cut down the clock rate to 2 kHz and I'm counting 200 samples.  It seems to work a little better but I haven't started the engine yet.

 

I noticed that when I resized the window it overran the buffer.  After reducing the rate I could resize the window and then violently move it around with the mouse without overrunning the buffer.  I'll wait to we run the engine and report back with the results.

Programming Data Acquisition and Control in Measurement Studio and Labwindows/CVI
0 Kudos
Message 19 of 39
(2,321 Views)

Hi Michael,

 

Let me explain a bit more about what's happening with the buffer in your application. When you are doing continious (buffered) edge counting your device latches the number of edges counted onto each active edge of the sample clock and stores the number in the buffer. Refer to the following diagram:

Untitled.png

 

Active edges on the gate latch the current counter register values into PC memory.  Using either interrupts or DMA (software configurable), count register values are transferred individually to a software buffer across the PCI bus.  The software buffer can be finite or circular for continuous operations.  Once in the software buffer, the values are then read into LabVIEW with Buffer Read. To read data more frequently you need prioritize running your LabVIEW code on the CPU on your PC over over other processes that run on your computer. You can try to increase the LabVIEW priority and set CPU affinity in Windows Task Manager:

Task Manager - TechNet - Microsoft

Set Processor Affinity - TechNet - Microsoft

 

What is the current memory and CPU usage (as seen in Windows Task Manager) on your PC when you run your LabVIEW code?  What are the performance specifications of your PC (i.e. CPU, RAM size,)? Have your tried running your code on a different, more performant PC?

To monitor the current samples in the buffer you can use: DaqStream..::.AvailableSamplesPerChannel Property

 

C#
public long AvailableSamplesPerChannel { get; }

Property Value

Indicates the number of samples available to read per channel. This value is the same for all channels in the task.

 

Keep me updated on your progress and let me know if you have any further questions.

 

 

 

Mikhail
RF Toolkits, Product Support Engineer
National Instruments
0 Kudos
Message 20 of 39
(2,311 Views)