VB6 and ETS on an ADC212/100

Post general discussions on using our drivers to write your own software here
mike_ims

VB6 and ETS on an ADC212/100

Post by mike_ims »

In my attempt to integrate an ADC212/100 into an existing VB6 program, I have come to a snag. I am having trouble getting ETS to work properly.

This seems to encompass 2 issues:

1 - I have followed the example ETS code provided earlier in this forum (in C). In my VB6 implementation, the device never becomes "ready" after I call adc200_run() (and hence, gets stuck in the endless adc200_ready() loop). Note that the device works flawlessly while not in ETS mode and that the ETS example provided in C executes fine.

2 - I received a .bas file containing "declare" statements to access the driver DLL. There was a declare statement missing for the adc200_get_times_and_values() and adc200_set_time_units() functions. So I attempted to add my own declare statements because the ETS example code in C used those functions just fine (ie they must be in the driver). I based my statements off of the C versions and the other declare statements within that file. They are as follows...

Code: Select all

Declare Function adc200_set_time_units Lib "ADC20032.dll" (units As Integer) As Integer
Declare Function adc200_get_times_and_values Lib "ADC20032.dll" (times As Long, buffer_a As Integer, buffer_b As Integer, ByVal no_of_values As Long) As Long
The code compiled fine after adding these. adc200_set_time_units() executed but returned a large negative number (-2994, I believe). adc200_get_times_and_values() did not execute and caused an overflow. This was done in non-ETS mode.

Can you give my any insight as to why either of these are happening?

Thanks,
-Mike

User avatar
markspencer
Site Admin
Site Admin
Posts: 598
Joined: Wed May 07, 2003 9:45 am

Post by markspencer »

Hi,

I am sorry to hear that you are expereincing this problem, forn looking at your delcareations I noticed that the first one is incorrect. You are passing the value by reference where infact it should be passed by value such as:

Code: Select all

Declare Function adc200_set_time_units Lib "ADC20032.DLL" (ByVal units As Integer) As Integer
I would make the changes and then see if this makes any difference, as the get_times_and_values routine is dependent on the set_time_units.

Best regards,
Regards,

Mark Spencer

mike_ims

Post by mike_ims »

Thank you for your response. It fixed part of my 2nd problem. The overflow only occurs when I set the time unit below microseconds (nano and below). Microseconds and above don't give me the overflow, but are insufficient for my application.

Does anything from the following seem wrong?

Code: Select all

    ReDim times(RecordLengthValue - 1) As Long
    ReDim ChanBuf(RecordLengthValue - 1) As Integer
    ReDim ChanBufB(RecordLengthValue - 1) As Integer
    
    Dim ok As Integer

    ok = adc200_set_time_units(2)
    
    ok = adc200_get_times_and_values(times(0), ChanBuf(0), ChanBufB(0), RecordLengthValue)
RecordLengthValue = the number of values to be collected (adc200_run(RecordLengthValue) )

If this seems correct, what else could be causing the overflow?

Note also that after attempting to execute the "get times and values" line and returning the overflow, it does fill times and ChanBuf, but does NOT fill ChanBufB.

Thanks again,
-Mike

Edit: When I pass 0, 1, 2, or 5 to adc200_set_time_units(), the overflow occurs on the "get times and values" call. When I pass 3 or 4, the overflow does not occur.

I also noticed that in passing a 0 or a 5 to the "set time units" function does not create an error or return a value that indicates an error, but when I look at the values in the "times" array after attempting to collect the data (and getting the overflow), I see what seems to be nanosecond times rather than the correct timebase. To me, it sounds like the time units are defaulting back to nanoseconds in this case. Is this correct? Does it have anything to do with the overflow?

User avatar
markspencer
Site Admin
Site Admin
Posts: 598
Joined: Wed May 07, 2003 9:45 am

Post by markspencer »

Hi,

When you talk about the overflow are you talking about the get_overflow or an error during running.

I have noticed that you are declaring an array with one less value availalbe than you are trying to collect, the array should be:

ReDim times(RecordLengthValue) As Long

for all the buffers.

If you have access to a C programming environment I would suggest trying the adc200con.c example, and see if you experience the same problems. You might also want to check your variable types, some of them are unsigned, I do not know the equivlent for VB.

Best regards,
Regards,

Mark Spencer

mike_ims

Post by mike_ims »

I fixed the overflow issue I was having (which had nothing to do with adc200_get_overflow()). adc200_get_times_and_values() returns an unsigned long rather than an integer - just an oops on my part.

In declaring arrays in VB6, the upper (and optionally lower) bound is passed rather than the size of the array. Since the default "base" for arrays is 0 (not 1), passing the array size would give you an array with one extra element.

I still have one last issue in communicating with the ADC212 and after sifting through old posts here, I found that I wasn't the only one with this issue. After enabling ETS mode and calling adc200_run(), adc200_ready() never returns true (1).

A post made in January 03 was talking about the same problem. Some sample code was provided, but the issue was never resolved publicly.

After further analysis, it appears that the data does indeed get collected, but adc200_ready() never acknowledges it. If I replace typical adc200_ready() loop with a sufficiently long enough wait, I can access the data. Obviously this is not desirable solution for me, but it may provide you guys with insight as to why this is happening.

So again, I would appreciate any help in solving this problem (from anyone).

Thanks,
-Mike

Note: http://www.picotech.com/support/viewtopic.php?t=116 is the post in question

User avatar
markspencer
Site Admin
Site Admin
Posts: 598
Joined: Wed May 07, 2003 9:45 am

Post by markspencer »

Hi,

I am sorry to hear that you are experiencing problems with VB and ETS, I have tested the below code in VBA (excel macro) which is very close to VB in the way the functions are declared and how they are called. This example exits the ready routine.

Code: Select all

Declare Function adc200_open_unit Lib "ADC20032.dll" (ByVal port As Integer) As Integer
Declare Function adc200_set_unit Lib "ADC20032.dll" (ByVal port As Integer) As Integer
Declare Sub adc200_close_unit Lib "ADC20032.dll" (ByVal port As Integer)

Declare Function adc200_get_driver_version Lib "ADC20032.dll" () As Integer
Declare Function adc200_get_product Lib "ADC20032.dll" () As Integer
Declare Function adc200_get_hw_version Lib "ADC20032.dll" () As Integer
Declare Function adc200_has_relays Lib "ADC20032.dll" () As Integer
Declare Function adc200_get_unit_info Lib "ADC20032.dll" (ByVal str As String, ByVal lth As Integer, ByVal line_no As Integer, ByVal port As Integer) As Integer

Declare Function adc200_set_frequency Lib "ADC20032.dll" (ByVal Frequency As Long) As Long
Declare Function adc200_set_range Lib "ADC20032.dll" (ByVal channel As Integer, ByVal gain As Integer) As Integer
Declare Sub adc200_set_dc Lib "ADC20032.dll" (ByVal channel As Integer, ByVal enable_dc As Integer)

Declare Function adc200_set_channels Lib "ADC20032.dll" (ByVal mode As Integer) As Integer
Declare Function adc200_set_oversample Lib "ADC20032.dll" (ByVal factor As Integer) As Integer
Declare Function adc200_set_trigger Lib "ADC20032.dll" (ByVal enabled As Integer, ByVal source As Integer, ByVal direction As Integer, ByVal delay_percent As Integer, ByVal threshold As Integer) As Integer
Declare Function adc200_set_timebase Lib "ADC20032.dll" (ns As Long, is_slow As Integer, ByVal timebase As Integer) As Integer
Declare Function adc200_set_time_units Lib "ADC20032.dll" (ByVal units As Integer) As Integer

Declare Function adc200_max_samples Lib "ADC20032.dll" () As Long

Declare Function adc200_run Lib "ADC20032.dll" (ByVal no_of_values As Long) As Integer
Declare Function adc200_ready Lib "ADC20032.dll" () As Integer
Declare Function adc200_get_values Lib "ADC20032.dll" (buffer_a As Integer, buffer_b As Integer, ByVal no_of_values As Long) As Integer
Declare Function adc200_get_overflow Lib "ADC20032.dll" (channel As Integer) As Integer
Declare Sub adc200_stop Lib "ADC20032.dll" ()

Declare Sub adc200_get_single Lib "ADC20032.dll" (buffer As Integer)

Declare Function adc200_get_ets_time Lib "ADC20032.dll" () As Long
Declare Function adc200_get_max_ets Lib "ADC20032.dll" () As Integer
Declare Sub adc200_set_ets Lib "ADC20032.dll" (ByVal interleave As Integer, ByVal max_cycles As Integer, ByVal mode As Integer)



Dim buffer_a(100) As Integer
Dim buffer_b(100) As Integer
Dim ns As Long
Dim is_slow As Integer
Dim S As String * 255

Sub GetData()

  port = 1
  ok = adc200_open_unit(port)
  
  For i = 0 To 4
    j = adc200_get_unit_info(S, 255, i, port)
    Cells(18 + i, "E").Value = S
  Next i
  
  If ok Then
    Cells(17, "E").Value = "ADC-200 opened"
    ok = adc200_set_trigger(1, 0, 0, 0, 100)
    ok = adc200_set_channels(0)
    mv = adc200_set_range(0, 8)      ' Range 8 = 5V
    Call adc200_set_dc(0, True)      ' If software controlled AC/DC switch, set to DC
    
    ok = adc200_set_time_units(0)
    ok = adc200_set_oversample(1)
    ok = adc200_set_timebase(ns, is_slow, 5)
    Call adc200_set_ets(10, 50, 2)
    ok = adc200_run(100)
    While adc200_ready() = 0
    Wend
  
    Call adc200_stop
  
    Call adc200_get_values(buffer_a(0), buffer_b(0), 100)
 
    For i = 0 To 99
      Cells(i + 4, "A").Value = ns * i
      Cells(i + 4, "B").Value = buffer_a(i)
      Cells(i + 4, "C").Value = (mv * buffer_a(i)) / 2048
    Next i
  Else
    Cells(17, "E").Value = "Unable to open ADC-200"
  End If
End Sub
Best regards,
Regards,

Mark Spencer

mike_ims

Post by mike_ims »

I copied your VBA code into an excel macro and it worked fine. Next, I copied the code into a VB6 project. I had to do a bit of editing to get it to compile, but with great dismay, the same problem occurs.

I copied all the declares into a module and did not modify them. The rest of the code is in a form:

Code: Select all

Option Explicit

Private Sub Command1_Click()

  Dim buffer_a(100) As Integer
  Dim buffer_b(100) As Integer
  Dim ns As Long
  Dim is_slow As Integer
  Dim S As String * 255
  Dim port As Integer, i As Integer, j As Integer, ok As Integer, mv As Integer

  port = 1
  ok = adc200_open_unit(port)
  
  If ok Then
    Debug.Print ("ADC-200 opened")
    ok = adc200_set_trigger(1, 0, 0, 0, 100)
    ok = adc200_set_channels(0)
    mv = adc200_set_range(0, 8)      ' Range 8 = 5V
    Call adc200_set_dc(0, True)      ' If software controlled AC/DC switch, set to DC
    
    ok = adc200_set_time_units(0)
    ok = adc200_set_oversample(1)
    ok = adc200_set_timebase(ns, is_slow, 5)
    Call adc200_set_ets(10, 50, 2)
    ok = adc200_run(100)
    While adc200_ready() = 0
    Wend
  
    Call adc200_stop
  
    Call adc200_get_values(buffer_a(0), buffer_b(0), 100)

    'For i = 0 To 99
    '  Cells(i + 4, "A").Value = ns * i
    '  Cells(i + 4, "B").Value = buffer_a(i)
    '  Cells(i + 4, "C").Value = (mv * buffer_a(i)) / 2048
    'Next i
    
    Call adc200_close_unit(1)
  Else
    'Cells(17, "E").Value = "Unable to open ADC-200"
    Debug.Print ("Open failed")
  End If
    
End Sub
Again, the code never leaves the While loop.

I am working on a 98SE machine with 64MB memory. The results of the adc200_get_driver_info() call are as follows:

ADC200 Driver V3.02
ADC212-100 V13 on LPT1
Batch EJL31
Cal date 01Dec03
pico.vxd V1.5

These drivers came with Picoscope v5.09.4, which is not the latest version I realize. I will install the latest Picoscope/drivers, but have my reservations about them changing anything.

-Mike

User avatar
markspencer
Site Admin
Site Admin
Posts: 598
Joined: Wed May 07, 2003 9:45 am

Post by markspencer »

Hi,

I am sorry to hear that this did not work in VB6, I will have to spend sometime trying it in a VB environment, I will get back to you as soon as possible.

Best regards,
Regards,

Mark Spencer

Guest

Post by Guest »

Hi,

I have encountered the same problem using ETS. adc200_ready have never return true. I have also tried to replace the adc200_ready loop with a time limit using the timer in VB. However, the data was never get collected (unlike in Mike's case). Here is my code.

Code: Select all

Private Sub tmrFast_Timer()

Dim running As Integer
Dim ready As Integer
ReDim times(99) As Long
ReDim values_a(99) As Integer
ReDim values_b(99) As Integer
Dim time As Long
Dim volts_a As Integer
Dim volts_b As Integer
Dim no_of_values As Integer
Dim i As Integer

If opened And fast_collect Then
    ok = adc200_set_channels(cboChannel_select.ListIndex)
    mv_a = adc200_set_range(0, 2 + cboVoltage_select_a.ListIndex)
    mv_b = adc200_set_range(1, 2 + cboVoltage_select_b.ListIndex)
    ok = adc200_set_trigger(True, 0, 0, 0, 100)
    Call adc200_set_ets(10, 50, 2)
    running = adc200_run(100)
    lstTime.Clear
    lstChannalA.Clear
    lstChannalB.Clear
    If running Then
        Do
            If tmrETS.Interval Then
                Exit Do
            End If
        Loop
        Call adc200_stop
        no_of_values = adc200_get_times_and_values(times(0), values_a(0), values_b(0), 100)
        For i = 0 To 99
            time = times(i)
            lstTime.AddItem (time & Chr(9) & "ns")
            If cboChannel_select.ListIndex = 0 Or cboChannel_select.ListIndex = 2 Then
                volts_a = values_a(i) / 2047 * mv_a
                lstChannalA.AddItem (volts_a & Chr(9) & "mV")
            End If
            If cboChannel_select.ListIndex = 1 Or cboChannel_select.ListIndex = 2 Then
                volts_b = values_b(i) / 2047 * mv_b
                lstChannalB.AddItem (volts_b & Chr(9) & "mV")
            End If
        Next i
    Else
        lstMessages.AddItem ("Error running ADC!")
    End If
End If

End Sub
Is there an error in my code? And also a question for Mike, would you mind telling me the procedure that you use to replace the adc200_ready loop and get access to the data?

Thank you

User avatar
markspencer
Site Admin
Site Admin
Posts: 598
Joined: Wed May 07, 2003 9:45 am

Post by markspencer »

Hi,

I have tested this cade in visual basic and found that the ready does come true. I an setting the voltage range to ±5 volts and triggering when the voltage reaches 100 ADC counts (244mV)

Code: Select all


port = 1
ok = adc200_open_unit(port)
  If ok Then
    ok = adc200_set_trigger(1, 0, 0, 0, 100)
    ok = adc200_set_channels(0)
    mv = adc200_set_range(0, 8)      ' Range 8 = 5V
    Call adc200_set_dc(0, 1)      ' If software controlled AC/DC switch, set to DC
    
    ok = adc200_set_time_units(0)
    ok = adc200_set_oversample(1)
    ok = adc200_set_timebase(ns, is_slow, 5)
    Call adc200_set_ets(10, 50, 2)
    ok = adc200_run(100)
    ok = adc200_ready()
    While ok = 0
      ok = adc200_ready()
    Wend
  
    Call adc200_stop
  
    Call adc200_get_values(buffer_a(0), buffer_b(0), 100)
End If
The Guest post has triggering set with the same voltage. If the voltage level being put into the channel A is not being reached then there will be no samples to collect, also it could be taking longer to get the samples and download them to the driver than it is to flow through your code. This is why the ready routine is required.

Please let me know if the above works for you.

Best regards,



Best regards,
Regards,

Mark Spencer

Guest

Post by Guest »

Hi,

I've fixed a problem. Apparently, there was an error in the when I declare adc200_set_ets function. However, I encounter another problem. When using ETS, I am unable to get the data using The fucntion adc200_get_times_and_values. It works fine when ETS is turned off. When using ETS, The function returned 0 indicating that there was no data transfered. But when I checked adc200_ready, it returned true. What could be a problem here?

Code: Select all

Private Sub tmrFast_Timer()

Dim running As Integer
Dim ready As Integer
ReDim times(99) As Long
ReDim values_a(99) As Integer
ReDim values_b(99) As Integer
Dim time As Long
Dim volts_a As Integer
Dim volts_b As Integer
Dim no_of_values As Integer
Dim i As Integer

If opened And fast_collect Then
    lstTime.Clear
    lstChannalA.Clear
    lstChannalB.Clear
    ok = adc200_set_channels(cboChannel_select.ListIndex)
    mv_a = adc200_set_range(0, 2 + cboVoltage_select_a.ListIndex)
    mv_b = adc200_set_range(1, 2 + cboVoltage_select_b.ListIndex)
    ok = adc200_set_trigger(True, 0, 0, 0, 0)
    Call adc200_set_ets(100, 200, 2)
    running = adc200_run(100)

    If running Then
        Do
            ready = adc200_ready()
            If ready Then
                Exit Do
            End If
        Loop
        Call adc200_stop
        no_of_values = adc200_get_times_and_values(times(0), values_a(0), values_b(0), 100)
        For i = 0 To 99
            time = times(i)
            lstTime.AddItem (time & Chr(9) & "ps")
            If cboChannel_select.ListIndex = 0 Or cboChannel_select.ListIndex = 2 Then
                volts_a = values_a(i) / 2047 * mv_a
                lstChannalA.AddItem (volts_a & Chr(9) & "mV")
            End If
            If cboChannel_select.ListIndex = 1 Or cboChannel_select.ListIndex = 2 Then
                volts_b = values_b(i) / 2047 * mv_b
                lstChannalB.AddItem (volts_b & Chr(9) & "mV")
            End If
        Next i
    Else
        lstMessages.AddItem ("Error running ADC!")
    End If
End If

End Sub

mike_ims

Post by mike_ims »

My method of replacing the the adc200_ready() while loop was using the debugger. I would put a break point in between the adc200_run() and the adc200_get_times_and_values() commands (and comment out the while loop). When the execution reached the break point, I let it set there momentarily before resuming execution.

It should be possible to do this in a more automated fashion though. Add the following declaration to your code...

Code: Select all

Private Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)
and you should have a sleep command just like in Visual C++.

Code: Select all

    Sleep (1000)    ' sleep for a second
I never tried using the Sleep routine in this situation so some experimenting will have to be done to find the right amount of time to sleep.

Hope this helps.

-Mike

User avatar
markspencer
Site Admin
Site Admin
Posts: 598
Joined: Wed May 07, 2003 9:45 am

Post by markspencer »

Hi All,

I have done some more research into this problems and found out the adc200_stop should not be called. If you take this routine out of your code and repeat your tests, has the problem been solved.

Best regards,
Regards,

Mark Spencer

yrlin

Post by yrlin »

Hi All,

the adc200_stop could be called but not immediately after the loop of adc200_ready(). I just store and analysis the data from adc200 first and then call adc200_stop(). It work well!

mike_ims

Post by mike_ims »

Sorry for dropping off the face of the world for a while. I had to move on with the project involving the adc212 and did not have any time to continue debugging this issue.

That project is complete, but there is still a desire to get ETS working within the confines of VB6.

Looking back a few posts, Mark posted some code that used ETS in VB6. I was unable to get that code working on my side. I first verified that I was looking at a signal larger than 244mV (the trigger level of 100), successfully ran this code modified to run without ETS, and then attempted to run the code as listed below. I attempted running the program with versions 3.02, 3.03, 4.00 of adc20032.dll resulting with the same issue.

I had to add/assume a few things since it was only a code snippet posted. Below is the entirety of the program I used to produce my adc200_ready() issue.

adc20032.bas

Code: Select all

Declare Function adc200_open_unit Lib "ADC20032.dll" (ByVal port As Integer) As Integer
Declare Function adc200_set_unit Lib "ADC20032.dll" (ByVal port As Integer) As Integer
Declare Sub adc200_close_unit Lib "ADC20032.dll" (ByVal port As Integer)

Declare Function adc200_get_driver_version Lib "ADC20032.dll" () As Integer
Declare Function adc200_get_product Lib "ADC20032.dll" () As Integer
Declare Function adc200_get_hw_version Lib "ADC20032.dll" () As Integer
Declare Function adc200_has_relays Lib "ADC20032.dll" () As Integer
Declare Function adc200_get_unit_info Lib "ADC20032.dll" (ByVal str As String, ByVal lth As Integer, ByVal line_no As Integer, ByVal port As Integer) As Integer

Declare Function adc200_set_frequency Lib "ADC20032.dll" (ByVal Frequency As Long) As Long
Declare Function adc200_set_range Lib "ADC20032.dll" (ByVal channel As Integer, ByVal gain As Integer) As Integer
Declare Sub adc200_set_dc Lib "ADC20032.dll" (ByVal channel As Integer, ByVal enable_dc As Integer)

Declare Function adc200_set_channels Lib "ADC20032.dll" (ByVal mode As Integer) As Integer
Declare Function adc200_set_oversample Lib "ADC20032.dll" (ByVal factor As Integer) As Integer
Declare Function adc200_set_trigger Lib "ADC20032.dll" (ByVal enabled As Integer, ByVal source As Integer, ByVal direction As Integer, ByVal delay_percent As Integer, ByVal threshold As Integer) As Integer
Declare Function adc200_set_timebase Lib "ADC20032.dll" (ns As Long, is_slow As Integer, ByVal timebase As Integer) As Integer
Declare Function adc200_set_time_units Lib "ADC20032.dll" (ByVal units As Integer) As Integer

Declare Function adc200_max_samples Lib "ADC20032.dll" () As Long

Declare Function adc200_run Lib "ADC20032.dll" (ByVal no_of_values As Long) As Integer
Declare Function adc200_ready Lib "ADC20032.dll" () As Integer
Declare Function adc200_get_values Lib "ADC20032.dll" (buffer_a As Integer, buffer_b As Integer, ByVal no_of_values As Long) As Integer
Declare Function adc200_get_overflow Lib "ADC20032.dll" (channel As Integer) As Integer
Declare Sub adc200_stop Lib "ADC20032.dll" ()

Declare Sub adc200_get_single Lib "ADC20032.dll" (buffer As Integer)

Declare Function adc200_get_ets_time Lib "ADC20032.dll" () As Long
Declare Function adc200_get_max_ets Lib "ADC20032.dll" () As Integer
Declare Sub adc200_set_ets Lib "ADC20032.dll" (ByVal interleave As Integer, ByVal max_cycles As Integer, ByVal mode As Integer)
Form1.frm

Code: Select all

Private Sub Command1_Click()

    Dim buffer_a(99) As Integer
    Dim buffer_b(99) As Integer
    
    port = 1
    ok = adc200_open_unit(port)
    If ok Then
    
        Dim unit_info As String * 255
        Dim i As Integer
        
        unit_info = String$(120, " ")
        
        For i = 0 To 3
            ok = adc200_get_unit_info(unit_info, 255, i, port)
            MsgBox (unit_info)
        Next i
        
        ok = adc200_set_trigger(1, 0, 0, 0, 100)
        ok = adc200_set_channels(0)
        mv = adc200_set_range(0, 8)      ' Range 8 = 5V
        Call adc200_set_dc(0, 1)      ' If software controlled AC/DC switch, set to DC
        
        ok = adc200_set_time_units(0)
        ok = adc200_set_oversample(1)
        ok = adc200_set_timebase(ns, is_slow, 5)
        Call adc200_set_ets(10, 50, 2)
        ok = adc200_run(100)
        ok = adc200_ready()
        While ok = 0
            ok = adc200_ready()
        Wend
      
        'Call adc200_stop
      
        Call adc200_get_values(buffer_a(0), buffer_b(0), 100)
    End If
    
    adc200_close_unit (1)
End Sub
Again, this code never exits the while loop controlled by the call to adc200_ready().

Thoughts? Suggestions?

-Mike

Post Reply