11-10-2008 02:10 PM
I need to take data from 8 PWM channels at the same time, for a long time (3 hours).
I have this piece of code working, but I am only asking for 1 minute of data - and there are some strange erroneous values that I am seeing in a fraction of the data.
What I am seeing is when I read just 1 PWM channel (validbits=1 or 2^n [n=0..7]) there are no bad values, but when I add more channels (any number more, 2 causes bad data too)
I get an occasional glitch, like .001 for the low time and .320 for the high time (my PWM freq is 500hz, the total low and high should never be much different than .002)
I am using the semiperiod and calculating the pwm value from that, which is historically what we have done here. It seems like I would have to know the frequency to get the PWM value otherwise, and
using the createCIsemiperiodchannel I get both the pwm and frequency if I do a little math.
Brynn
''''''''''''''''''''''''''''''''''''''''''''''''''''''
Public Function AquireAllPWMs(validbits As Integer, samples As Long, ByRef data() As Double) As Boolean
Dim TaskHandle(8) As Long
Dim TaskIsRunning(8) As Boolean
Dim ReadCount As Long
Dim strCounterString As String
Dim Index, dmacnt As Long
Dim lngChannelCount As Long
Static ErrorCount As Long
Static ErrorBoxDisplayed As Boolean
On Error GoTo ErrorHandler
dmacnt = 0
For Index = 0 To 7
If (validbits And 2 ^ Index) = 2 ^ Index Then
DAQmxErrChk DAQmxCreateTask("", TaskHandle(Index))
TaskIsRunning(Index) = True
Select Case Index
Case 0 To 5
strCounterString = "Dev1/ctr" & (Index + 2) ' Like "Dev1/ctr2" The EOL tester uses counters 2-7
Case 6, 7
strCounterString = "Dev1/ctr" & (Index - 6) ' Like "Dev1/ctr2" The EOL tester uses counters 2-7
End Select
DAQmxErrChk DAQmxCreateCISemiPeriodChan(TaskHandle(Index), strCounterString, "", 0.0000001, 0.006, DAQmx_Val_TimeUnits_Seconds, "" )
DAQmxErrChk DAQmxCfgImplicitTiming(TaskHandle(Index), DAQmx_Val_AcquisitionType_FiniteSamps, samples)
DAQmxErrChk DAQmxSetCISemiPeriodStartingEdge(TaskHandle(Index), strCounterString, DAQmx_Val_Rising)
' Set up a simultaneous Trigger arm by a digital edge (PFI3)
DAQmxErrChk DAQmxSetArmStartTrigType(TaskHandle(Index), DAQmx_Val_TriggerType4_DigEdge)
DAQmxErrChk DAQmxSetDigEdgeArmStartTrigSrc(TaskHandle(Index), "/Dev1/PFI3" )
' Since there are only 3 DMA channels, we have to set the rest to use Interrupts as the transfer mechanism
dmacnt = dmacnt + 1
If dmacnt > 3 Then
DAQmxErrChk DAQmxSetCIDataXferMech(TaskHandle(Index), strCounterString, DAQmx_Val_DataTransferMechanism_Interrupts)
End If
End If
Next Index
For Index = 0 To 7
If (validbits And 2 ^ Index) = 2 ^ Index Then
DAQmxErrChk DAQmxStartTask(TaskHandle(Index)) ' Start the task, get ready for the hardware trigger
End If
Next Index
Call WriteDIO("Dev1/Line3", True) ' GO! this is the hardware trigger for simultanous readings
For Index = 0 To 7
If (validbits And 2 ^ Index) = 2 ^ Index Then ' validbits is a bitmap of which of the 8 PWM channels to read, think of it as 255 to read all 8 channels
' DAQmx Read Code
DAQmxErrChk DAQmxReadCounterF64(TaskHandle(Index), samples, 0.005 * samples, data(0, Index), samples, ReadCount, ByVal 0& )
' All done! StopTask
DAQmxErrChk DAQmxStopTask(TaskHandle(Index))
DAQmxErrChk DAQmxClearTask(TaskHandle(Index))
TaskIsRunning(Index) = False
' dblPWMValue(Index) = 100# * (data(1) / (data(1) + data(2))) ' this would be how to calculate the pwm value, it gets done when I write it out to an .csv excel file later
End If
Next Index
Call WriteDIO("Dev1/Line3", False) ' Reset the trigger line
AquireAllPWMs = True
Exit Function
ErrorHandler:
' MsgBox "Error: " & Err.Number & " " & Err.Description, , "Error"
mlngPWM_ErrorCount(Index) = mlngPWM_ErrorCount(Index) + 1
If Index = 0 Then
ErrorCount = ErrorCount
End If
ErrorCount = ErrorCount + 1
'MainForm.PWMErrorCount = "Errors(" & lngIndex & "): " & mlngPWM_ErrorCount(Index)
Resume Next
End Function
11-12-2008 10:12 AM
Hello Brynn,
I have looked into your code and I don't see anything glaringly wrong, but I have a few questions. You say that you are getting goo reading on one channel, does it matter which channel it is? What I mean is have you tried reading all of your channels by themselves?
Also, how long do you run your experiment with only 1 channel? If you haven't run several sequences in a row, it may be useful to try. This may be pretty time consuming, but testing each channel in this manner could bring to light connection/noise problems.
Lastly, it isn't a big deal, but the proper naming convention for your Write to Digital Line should be Dev1/port0/line3, not Dev1/line3. I'm not sure if this is taken care of in the driver or in your code, but the port is usually specified, even on devices with a single port.
Regards,
Dan King
11-12-2008 01:25 PM
Hi Dan_K,
I believe I tried reading all the channels by themselves, individually. If I didn't I did do most of them - and I definatly did ones that I had seen flakey values on.
I have run for 10 minutes on one channel with no errors that I can see. I am getting a bit suspicious of the connectors (which are actually very high quality robust connectors) because of some spikes I have seen.
I was wondering if the problem is that I am trying to get more data than can be transferred over the PCI bus.
My PWM's are all 500 hz
If I use the semiperiod I should get 250 low times and 250 high times, 500 per second. a Double is 8 bytes. 8 channels is 8. so I am trying to get 500*8*8 = 32000 bytes per second.
That doesn't seem like too much, but it is 8 seperate tasks, only the first 3 of which can be DMA. You can see the code that changes the tasks to IO for the rest of the channels.
So each channel is trying to get 4000 bytes per second, which, again, doesn't sound like very much.
I also tried setting up the tasks as pulsewidth, on the theory that I would only get 250 low times per second, halving the data. This does seem to work better, but still has some issues with reading times that I disbelieve. Yes, I should get a storage scope on there to look and see if these spikes are real, but we have been making this product for years and our big customer would be screaming blody murder if they ever saw such a spike - when I have time I will set up the scope to prove that I am seeing bad counts from the nidaq card, but right now I don't see them when only capturing one channel, and I do see them when capturing more, and that is enough evidence for me right now.
For my test (Tomorrow) I'll be happy if I can just discard bad data and keep capturing good data. Is there a way that I can just continue on with my continuous capture task even if I get an error?
Brynn
11-14-2008 08:32 AM - edited 11-14-2008 08:36 AM
A couple thoughts/observations, possibly of dubious worth.
1. I'm rusty in text language syntax, but wondered what is meant by the "data(0, Index)" argument in the DAQmxRead function call. Is that a 2D array indexing syntax? Later you appear to want to reference your data as "data(1)" which looks more like 1D. Also the function prototype calls out "data()" in a way that reminds me more of 1D, though I'm not knowledgeable about VB syntax.
It appears you are likely trying to pass a pointer that points to the beginning of a particular row or column of a 2D array. Does VB even allow that? And if so, are you sure the actual memory layout for 2D arrays is compatible with your indexing scheme? It appears you expect the memory layout to put consecutive bytes into consecutive rows of a particular column. Are you sure the DAQmx call doesn't fill in consecutive columns of a particular row?
2. Once you work that part out for *certain*, there's another catch (I think). You should ignore the first measured value from each counter task. I'm pretty sure that the first value will be a random-ish time from when you triggered the counter task until the first active edge.
3. You can reduce your data rate by a factor of 2 if you read the count value as an 32-bit unsigned integer. (Offhand, it doesn't sound like data rate is the likely problem, because data rate problems would cause data acq error messages, not bad data.)
-Kevin P.
11-14-2008 10:27 AM
Hi Kevin, thanks for the response...
1) I am a C programmer so getting this right in VB was some work, but what I posted is working code. the data(0,index) is sending a row to the DAQmxread call, like it appears. I did have to swap the (index,0) around to get this to work. VB does allow it, and it does work, but as you noticed it sure looks stupid (stupid VB).
What I am seeing right now is that for the 3 DMA channels I get all the data, but the remaining 5 interrupt channels puke out about 3 minutes into the aquisition with 'data was overwritten' errors from the read.
2) yes, we have been ignoring the first data point because it is garbage.
3) What I did do to halve the data (which did help a lot) was to switch from the semiperiod which gives both a low time and a high time, to using the pulsewidth instead, where I now get 500 samples per second per channel instead of the 1000 I got with the semiperiod.
in the VB CAPI there is no 'DAQmxreadU32', but there is a DAQmxreadraw which seems like it does the same thing.
So I tried the read raw and I still got the same amount of samples before it puked.
Once I switched to the pulsewidth I do indeed get data acq errors and not bad data. (it appears)
What I surmise is that the DAQmx drivers are not able to get the data from the hardware fast enough, and the error message I see (data is overwritten before being read) is actually telling me the data in the PCI-6602 card got overwritten before the drivers were able to pull it out.
So my current plan of attack is to try to just drop any data that I couldn't read fast enough - using the line
DAQmxErrChk DAQmxSetReadOverWrite(taskhandle(index), DAQmx_Val_OverwriteMode1_OverwriteUnreadSamps)
which
should tell it not to care if the data gets overwritten, but I see
that I also have to play with the relativeto and offset pointers as the
documentation says:
When an acquisition encounters unread data in the buffer, the acquisition continues and overwrites the unread samples with new ones. You can read the new samples by setting RelativeTo to DAQmx_Val_MostRecentSamp and setting Offset to the appropriate number of samples.
Brynn