EEVblog® Electronics Community Forum

Electronics => Projects, Designs, and Technical Stuff => Topic started by: dazz1 on December 20, 2023, 09:52:54 pm

Title: Problems Writing code for GPIB Py VISA
Post by: dazz1 on December 20, 2023, 09:52:54 pm
Hi
I have assembled Xyphro's excellent USB:GPIB adapter at this link https://www.eevblog.com/forum/testgear/open-source-gpib-adapter/ (https://www.eevblog.com/forum/testgear/open-source-gpib-adapter/)
I now have the problem of writing code to make use of the adapters.  I have decided to use Python and PyVISA.  I am new to Python and GPIB. 

My target test equipment includes:

All of these are notably ancient so for at least two of them, there is no point in asking questions like: "How do I program for my WaveTek 2520" when there is probably me and no-one else on the planet that want to run such an antique instrument over GPIB. 

I plan to use this thread as the place I ask generalised questions about specific problems I am, or likely, to have.  I anticipate others like me will have questions of their own.  I searched the internet for an active PYVISA forum, but none found.

Title: WaveTek 2520 SigGen : Aligning commands with the buffer
Post by: dazz1 on December 20, 2023, 10:16:56 pm
I have started to program a test program in Python for my WaveTek 2520 RF Sig Gen.
The first problem I have hit is buffering.  The WaveTek includes a FIFO message buffer. 

The problem I have is aligning the GPIB commands with the buffer content.  If I issue a command to read the ID string, the ID is loaded into the buffer.  If anything is already in the buffer, that comes out ahead of the ID string.
The code looks like this:
Code: [Select]
print("ID ")
print(SigGen.write('ID ?'))
print(SigGen.read())

Note I have chosen not to use the query command.

The first time I run this code after power up I get:
Code: [Select]
ID                                                                                                                                                               
5                                                                                                                                                               
D:\darren\My Documents\Electronics\GPIB USB Adapter\dazz\gpib_test_2_WvTk2520.py:24: UserWarning: read string doesn't end with termination characters             
print(SigGen.read())                                                                                                                                           
101-COMMAND HEADER 

In this case, the "101-COMMAND HEADER is printed out.  The contents of the buffer is not aligned with the read ID string command.
The next time I ran the same code I got:

Code: [Select]
ID                                                                                                                                                               
5                                                                                                                                                               
WVTK/2520A,V81.1,F5.1                                                                                                                                           

Now the ID string is printed out because there is nothing ahead of it in the buffer.  The read ID command is aligned with the ID string in the buffer.

The WaveTek does not have a command to clear the buffer.    The issue is further complicated by the STR function that allows a user to press a key on the front panel that generates a service request.  Potentially messages can be randomly inserted into the buffer.

Is there a recommended method of aligning buffered strings with the command that called for them?







Title: Re: Problems Writing code for GPIB Py VISA
Post by: alm on December 20, 2023, 10:19:34 pm
My solution for this was to develop python-ivi (https://github.com/python-ivi/python-ivi) drivers, for example this driver for the HP 3456A (https://github.com/alson/python-ivi/blob/ef7ae0beaa7e3b2f446d2dd99ba9d1d4bcfffeb9/ivi/agilent/agilent3456A.py) which might be kind of similar to the HP 3478A. But if you're new to Python, I would not recommend it. It makes the code a lot more complicated and requires some familiarity with the IVI specification which is not worth it for a beginner.

I would start by sending simple commands to the meter or signal gen (probably the simplest to program), and write functions like this:

Code: [Select]
def set_3478a_to_3v_dc(instr):
  instr.write("F1R0")

def read_from_3478a(instr):
  response = instr.read()
  return float(response)

rm = ...
instr = rm....
set_3478a(instr)
while True:
  print(read_from_3478a(instr))

In this case, the "101-COMMAND HEADER is printed out.
I'm not familiar with this signal gen, but this reads like an error message to me. Should there be a space between 'ID' and '?'?
Title: Re: Problems Writing code for GPIB Py VISA
Post by: dazz1 on December 20, 2023, 10:51:14 pm
Hi
I have been doing exactly as you suggested, writing small test programs to try things out.  The code sample provided above is a snippet from the test program.
I wouldn't expect you, or anyone else, to be familiar with a dinosaur like the 2520.  It dates back to late 1980s, so doesn't conform with the later standards on command format.  In this case "ID ?" is correct.  I know that from the manual, but the manual doesn't cover query and buffer alignment.

The starting assumption was that issuing a read command would always return the desired string message.  The 101-COMMAND HEADER message was something left in the message buffer from previous testing.  It is not related to the ID command, and that is the problem.  I issued a read ID command and got back a random message.  I am thinking this is likely to be a problem on any instrument with a message buffer.

Note that in response to any read command, I receive a digit and then the message.  I have not figured out the purpose/significance of this yet.  This appears to be the length of the string sent to the 2520, including the termination symbol ('\n')

Title: Re: Problems Writing code for GPIB Py VISA
Post by: alm on December 20, 2023, 11:56:30 pm
I'd start with the HP 3478A. DMMs are simpler than scopes and in my experience HP equipment has been the most well behaved with GPIB, with Datron pretty close, but Keithley as more finicky. Sounds like Wavetek might be similar to Keithley.
Title: Re: WaveTek 2520 SigGen : Aligning commands with the buffer
Post by: caiser01 on December 21, 2023, 02:38:30 am
The first time I run this code after power up I get:
Code: [Select]
ID                                                                                                                                                               
5                                                                                                                                                               
D:\darren\My Documents\Electronics\GPIB USB Adapter\dazz\gpib_test_2_WvTk2520.py:24: UserWarning: read string doesn't end with termination characters             
print(SigGen.read())                                                                                                                                           
101-COMMAND HEADER 

This is almost certainly an artifact of the xyphro firmware's Auto ID feature. If you have an older instrument, such as this WaveTek, that does not respond to the *IDN? query, and this WaveTek doesn't, an error will be generated on the instrument when the adapter automatically sends *IDN? at power up in an attempt to make a "pretty" VISA resource string. According to my reading of the Wavetek's manual, 101-COMMAND HEADER means "I don't recognize the command that was sent", which is as expected since it doesn't support *IDN?.

You have three choices to get around this:
1. Disable the Auto ID feature of the adapter using the method xyphro describes near the end of his GitHub README
2. Throw in an extra read at the start of the program to read out the error message and just ignore it
3. My personal preference: Use the VISA clear function to reset the instrument at the beginning of the program. This is preferred because it should reset the instrument to its power-on state, clear all buffers, etc.

Also, since this an old, possibly quirky instrument, it may be necessary to change the default read termination behavior of the xyphro firmware. I have to do this for my HP 5385A frequency counter or else I can't read properly from it.

Below is my attempt at a script to read the ID of the WaveTek 2520 that incorporates my recommendations from above. Please note: the sleep delays ARE necessary, especially after a VISA clear. I speak from experience...

Code: [Select]
import pyvisa
from sys import platform
from time import sleep

if platform == "linux" or platform == "linux2":
   # Linux
   rm = pyvisa.ResourceManager("/usr/lib/librsvisa.so@ivi")
elif platform == "darwin":
   # macOS
   rm = pyvisa.ResourceManager("/Library/Frameworks/RsVisa.framework/RsVisa@ivi")
elif platform == "win32":
   # Windows
   rm = pyvisa.ResourceManager()

SigGen = rm.open_resource('YOUR_RESOURCE_STRING_HERE')

# xyphro UsbGpib configuration
# Configure read termination as Option 1 (EOI and \n)
SigGen.control_in(0xa1, 0x40, 0, 0, 1)
SigGen.write('!0101')
# Wait to make sure configuration took effect
sleep(1)
# end xyphro UsbGpib configuration

SigGen.timeout = 5000
SigGen.write_termination = '\r'
SigGen.read_termination = '\n'

# Reset the instrument, wait for reset to complete
SigGen.clear()
sleep(1)

print('Instrument ID:', SigGen.query('ID?'))

# xyphro UsbGpib configuration
# Configure read termination as Option 0 (EOI only)
SigGen.control_in(0xa1, 0x40, 0, 0, 1)
SigGen.write('!0100')
# Wait to make sure configuration took effect
sleep(1)
# end xyphro UsbGpib configuration

# Reset the instrument, wait for reset to complete
SigGen.clear()
sleep(1)

# Return front panel to local control
SigGen.control_ren(pyvisa.constants.VI_GPIB_REN_ADDRESS_GTL)
SigGen.close()
rm.close()
Title: Re: WaveTek 2520 SigGen : Aligning commands with the buffer
Post by: dazz1 on December 21, 2023, 06:44:48 am
The first time I run this code after power up I get:
Code: [Select]
ID                                                                                                                                                               
5                                                                                                                                                               
D:\darren\My Documents\Electronics\GPIB USB Adapter\dazz\gpib_test_2_WvTk2520.py:24: UserWarning: read string doesn't end with termination characters             
print(SigGen.read())                                                                                                                                           
101-COMMAND HEADER 

This is almost certainly an artifact of the xyphro firmware's Auto ID feature. If you have an older instrument, such as this WaveTek, that does not respond to the *IDN? query, and this WaveTek doesn't, an error will be generated on the instrument when the adapter automatically sends *IDN? at power up in an attempt to make a "pretty" VISA resource string. According to my reading of the Wavetek's manual, 101-COMMAND HEADER means "I don't recognize the command that was sent", which is as expected since it doesn't support *IDN?.

That makes perfect sense but my assertion that any dregs in the buffer get pulled out ahead of the expected string remain extant, until I find another cause.
On closer reading the 2520 command should be "ID?", but "ID ?" also works.   I am still skimming along the surface of GPIB and Python so simple things are not yet simple for me.

Quote from: caiser01
You have three choices to get around this:
1. Disable the Auto ID feature of the adapter using the method xyphro describes near the end of his GitHub README
2. Throw in an extra read at the start of the program to read out the error message and just ignore it
3. My personal preference: Use the VISA clear function to reset the instrument at the beginning of the program. This is preferred because it should reset the instrument to its power-on state, clear all buffers, etc.
I haven't found a clear/reset type command for the 2520 yet but I will keep looking.  It does allow me to set/recall settings, so I can put the 2520 into a defined state.  A sample output is:
Code: [Select]
FREQUENCY 222.222 MHz                                                                                                                                           
FREQ STEP 50.0 kHz                                                                                                                                               
AMPLITUDE -10.0 dBm                                                                                                                                             
INTERNAL AM 100.0 %                                                                                                                                             
INTERNAL FM 80.0 kHz                                                                                                                                           
 EXTERNAL AM 100.0 %                                                                                                                                             
EXTERNAL FM 235.0 kHz                                                                                                                                           
RF OUTPUT OFF                                                                                                                                                   
MOD RATE 1000 Hz                                                                                                                                                 
MODULATION OFF                                                                                                                                                   
AMP STEP 0.10 dB                                                                                                                                                 
EXT PHASE 5.9 rads                                                                                                                                               
350-STORED SETTINGS ERROR 

The recalled settings have an error, but I don't know which setting is faulty.

Quote from: caiser01
Also, since this an old, possibly quirky instrument, it may be necessary to change the default read termination behavior of the xyphro firmware. I have to do this for my HP 5385A frequency counter or else I can't read properly from it.
The termination is programmable.  I can and have changed the termination to /n.  That seems to work OK.  I don't see corrupted output.

Quote from: caiser01
Below is my attempt at a script to read the ID of the WaveTek 2520 that incorporates my recommendations from above. Please note: the sleep delays ARE necessary, especially after a VISA clear. I speak from experience...
[/code]
I started adding sleeps, but I have been removing them without ill effect.
Quote from: caiser01
Code: [Select]
import pyvisa
from sys import platform
from time import sleep

if platform == "linux" or platform == "linux2":
   # Linux
   rm = pyvisa.ResourceManager("/usr/lib/librsvisa.so@ivi")
elif platform == "darwin":
   # macOS
   rm = pyvisa.ResourceManager("/Library/Frameworks/RsVisa.framework/RsVisa@ivi")
elif platform == "win32":
   # Windows
   rm = pyvisa.ResourceManager()

SigGen = rm.open_resource('YOUR_RESOURCE_STRING_HERE')

# xyphro UsbGpib configuration
# Configure read termination as Option 1 (EOI and \n)
SigGen.control_in(0xa1, 0x40, 0, 0, 1)
SigGen.write('!0101')
# Wait to make sure configuration took effect
sleep(1)
# end xyphro UsbGpib configuration

SigGen.timeout = 5000
SigGen.write_termination = '\r'
SigGen.read_termination = '\n'

# Reset the instrument, wait for reset to complete
SigGen.clear()
sleep(1)

print('Instrument ID:', SigGen.query('ID?'))

# xyphro UsbGpib configuration
# Configure read termination as Option 0 (EOI only)
SigGen.control_in(0xa1, 0x40, 0, 0, 1)
SigGen.write('!0100')
# Wait to make sure configuration took effect
sleep(1)
# end xyphro UsbGpib configuration

# Reset the instrument, wait for reset to complete
SigGen.clear()
sleep(1)

# Return front panel to local control
SigGen.control_ren(pyvisa.constants.VI_GPIB_REN_ADDRESS_GTL)
SigGen.close()
rm.close()
There are definitely some code snippets I can plagiarize from your code sample.
Looking at the circuit design and the manuals, I think there is a high risk of finding querks.  I have found the 2520 manual difficult to use as a look-up reference.  I am writing a summary version.
I am also writing a sample / test script that exercises all commands (there aren't too many of them) to seek out the querks and learn a bit about Python. 
Title: Re: Problems Writing code for GPIB Py VISA
Post by: ch_scr on December 21, 2023, 12:24:52 pm
To get a grip on the behaviour of an instrument, I find it a lot easier to use the interactive "pyVISA Shell" first, then write the script (knowing what the instrument expects).
Here's a script that is about the absolute minimum to log data from a DMM, with ample comments. Even though it's written for a different instrument, you might find parts of it helpfull.
Title: Re: WaveTek 2520 SigGen : Aligning commands with the buffer
Post by: caiser01 on December 21, 2023, 02:05:14 pm
I haven't found a clear/reset type command for the 2520 yet

There's not a clear command for the WaveTek 2520 and most very old instruments don't have one.

I was suggesting using the VISA clear() function. That will execute a GPIB Device Clear (DC1) which is explicitly supported by the 2520 as stated on page 6-1 of the manual. That should clear the "dregs in the buffer" when executed at the beginning of the script before attempting any reads from or writes to the instrument.

Code: [Select]
# Reset the instrument, wait for reset to complete
SigGen.clear()
sleep(1)

This is exactly what I do for my HP 5385A, which throws an error when powered on with the xyphro adapter connected because of the Auto ID feature. I run clear() which makes it reset and boot cleanly.
Title: Re: Problems Writing code for GPIB Py VISA
Post by: dazz1 on December 22, 2023, 06:52:24 am
To get a grip on the behaviour of an instrument, I find it a lot easier to use the interactive "pyVISA Shell" first, then write the script (knowing what the instrument expects).
Here's a script that is about the absolute minimum to log data from a DMM, with ample comments. Even though it's written for a different instrument, you might find parts of it helpfull.

Thanks for the script.  My test script is similar but less sophisticated. 
Title: Re: WaveTek 2520 SigGen : Aligning commands with the buffer
Post by: dazz1 on December 22, 2023, 07:34:47 am
I haven't found a clear/reset type command for the 2520 yet

There's not a clear command for the WaveTek 2520 and most very old instruments don't have one.

I was suggesting using the VISA clear() function. That will execute a GPIB Device Clear (DC1) which is explicitly supported by the 2520 as stated on page 6-1 of the manual. That should clear the "dregs in the buffer" when executed at the beginning of the script before attempting any reads from or writes to the instrument.
Yes that is listed in the chapter intro, but not further on.  If it does work, there is a good chance it will change the termination. 
The 2520 provides 3x ways of changing the termination and the termination can include 1,2 or 3 chars.  The DIP switches are set to CR/LF/EOI, but I have set the termination to CR (/n) in software, so a DCI instruction, if it works, might change the termination to the DIP switch settings.   The current setting survives power cycling but may revert to the DIP SW settings to a DCI instruction.    I need to test for it.

Is there a preferred termination in the GPIB world?

Quote from: caiser01
[code
# Reset the instrument, wait for reset to complete
SigGen.clear()
sleep(1)[/code]

This is exactly what I do for my HP 5385A, which throws an error when powered on with the xyphro adapter connected because of the Auto ID feature. I run clear() which makes it reset and boot cleanly.
Wondering if it might be practical to use the eeprom on the adapter to store adjustable settings to manage the Auto ID feature. Something Xyphro could consider doing.
Title: Re: Problems Writing code for GPIB Py VISA
Post by: ch_scr on December 22, 2023, 10:08:16 am
Wondering if it might be practical to use the eeprom on the adapter to store adjustable settings to manage the Auto ID feature. Something Xyphro could consider doing.
AFAIK, it does just that? You can turn off the Auto-ID and it remembers that setting?

Here's what he writes about it:
Quote from: xyphro github repo
[...]
All parameters are applied immediately after setting them and are stored in a non voltatile way in the EEProm of the microcontroller.
[...]
Automatic instrument identification readout

To turn off the automatic instrument ID readout after power up, execute: VM.control_in(0xa1, 0x40, 0, 0) VM.write('!0001')

To turn on the automatic instrument ID readout (this is the default behaviour of GPIBUSB), execute: VM.control_in(0xa1, 0x40, 0, 0) VM.write('!0000')

After a power cycle the USB device VISA ressource name and USB serial number string will change, based on this setting
Seems like it would be good to have a ready-made script to switch that, instead of every user having to fend for themself?
Title: Re: WaveTek 2520 SigGen : Aligning commands with the buffer
Post by: caiser01 on December 22, 2023, 07:44:56 pm
If it does work, there is a good chance it will change the termination.

It is indeed possible but I would not automatically assume that because...

The current setting survives power cycling

Device Clear (at least on old instruments) is generally about putting the instrument back to its power-on state and clearing all GPIB buffers, status, and flags. But since this WaveTek is a bit of an oddball, who knows?

I need to test for it.

Yes, definitely, and if you find the 2520 termination setting is volatile, you could still make 'TRM' the first command you send following the call to VISA clear() to put it back the way you want it. It is generally good practice when writing code to communicate with instruments to never assume any settings or configurations carry over from one use to the next. That should all be in the initialization code for each instrument.

Is there a preferred termination in the GPIB world?

 :-DD

...but seriously, the inconsistency of expected termination sequences, especially with older instruments can be one of the most frustrating things about working with GPIB. An otherwise perfectly written program will cause the instrument to sit there angrily beeping and blinking annunciators at you for the sake of an incorrect termination sequence.

My experience has been that since the 90s at least, instrument makers seem to have settled on newline (LF) as the most common terminator. With older instruments, it's down to reading the manual and experimenting. Some instruments want CR, some want LF, some want both. It's a mess and it's telling that WaveTek included *multiple* ways to change the termination sequence for the 2520.

This is more of an issue when you have a single, traditional GPIB controller with multiple instruments hooked up. In that case, you need all the instruments to have at least compatible termination sequences. Since the xyphro adapter is one adapter per instrument, it's pretty easy to set unique termination sequences for each instrument. In object-oriented terms, each instrument can be its own object with its own properties, including termination.

Briefly, for using an instrument with the xyphro adapter, just set the termination to whatever works best for that instrument. Don't worry too much over whether it's the same as other instruments or not.

Wondering if it might be practical to use the eeprom on the adapter to store adjustable settings to manage the Auto ID feature. Something Xyphro could consider doing.

In my conversations with xyphro, he expressed a love/hate relationship with his Auto ID feature. I think he's open to ideas for changes and improvements. Why not flesh out your suggestion and submit an issue at GitHub?
Title: Re: Problems Writing code for GPIB Py VISA
Post by: dazz1 on December 22, 2023, 08:42:42 pm
I took a look at Xyphro instructions:
Quote
read termination method

The following read termination method options are available:

    Option 0: (default): EOI only (the normal way GPIB works)
    Option 1: EOI + \n (LF / line feed)
    Option 2: EOI + \r (CR / carriage return)

If your device terminates with \r\n, select Option #2.

To set these options execute (Pyvisa example): VM.control_in(0xa1, 0x40, 0, 0) VM.write('!01XX')

for XX enter either:

    00 for Option 0 (EOI only) => VM.write('!0100')
    01 for Option 1 (EOI and \n) => VM.write('!0101')
    02 for Option 2 (EOI and \r) => VM.write('!0102')

Automatic instrument identification readout

To turn off the automatic instrument ID readout after power up, execute: VM.control_in(0xa1, 0x40, 0, 0) VM.write('!0001')

To turn on the automatic instrument ID readout (this is the default behaviour of GPIBUSB), execute: VM.control_in(0xa1, 0x40, 0, 0) VM.write('!0000')

After a power cycle the USB device VISA resource name and USB serial number string will change, based on this setting



I am on the bottom of the learning curve of,  starting to learn, three things:

So I wasn't expecting the adapter to care about terminations.  Based on advice at this link:  https://forums.ni.com/t5/Instrument-Control-GPIB-Serial/Default-GPIB-termination-character/td-p/242545 (https://forums.ni.com/t5/Instrument-Control-GPIB-Serial/Default-GPIB-termination-character/td-p/242545)  EOI should be the default terminator.  Given that is a hardwired control line, the adapter needs to know this.

I am looking at all of this and thinking the adapters should be transparent and instrument agnostic.  The GPIB controlling software should write/select the correct terminator at start-up.  This will ensure that no matter which equipment the adapter is plugged into, it will be correctly configured by the controller for the instrument being controlled.  eePROM has limited write cycles so what is needed is a method of reading the terminator setting, and only writing if it needs changing.  This will significantly extend the life of the adapter.

I have opened up the 2520 and set the termination to LF with DIP switches but I think I need to change that to EOI.  I can still change the termination from the front panel or via GPIB but at least one command reverts to the DIP switch setting. 
Title: Re: WaveTek 2520 SigGen : Aligning commands with the buffer
Post by: dazz1 on December 22, 2023, 08:50:30 pm
Quote from: caiser01
In my conversations with xyphro, he expressed a love/hate relationship with his Auto ID feature. I think he's open to ideas for changes and improvements. Why not flesh out your suggestion and submit an issue at GitHub?

Done that :  https://github.com/xyphro/UsbGpib/issues/48 (https://github.com/xyphro/UsbGpib/issues/48)

Being able to read back the settings from the adapter will eliminate a potential source of trouble.
Title: Re: WaveTek 2520 SigGen : Aligning commands with the buffer
Post by: dazz1 on December 22, 2023, 08:58:27 pm
Quote from: caiser01

Briefly, for using an instrument with the xyphro adapter, just set the termination to whatever works best for that instrument. Don't worry too much over whether it's the same as other instruments or not.


OK I am going to go with EOI as my default termination.  If that doesn't work for a specific instrument, use LF or whatever works. 
My instruments include a scope and EMC receiver with a scope-like output.  Hopefully using EOI will avoid issues with byte data streams.
Title: Re: Problems Writing code for GPIB Py VISA
Post by: caiser01 on December 22, 2023, 09:19:57 pm
So I wasn't expecting the adapter to care about terminations.  Based on advice at this link:  https://forums.ni.com/t5/Instrument-Control-GPIB-Serial/Default-GPIB-termination-character/td-p/242545 (https://forums.ni.com/t5/Instrument-Control-GPIB-Serial/Default-GPIB-termination-character/td-p/242545)  EOI should be the default terminator.  Given that is a hardwired control line, the adapter needs to know this.

A "normal" GPIB controller (like an NI or HP USB adapter or PCI card) doesn't care about read termination. Only the read termination setting in your application would matter. The xyhpro adapter cares about read termination (if I understand correctly) because of the mechanics of the translation from GPIB to USBTMC.

Yes, EOI is the only termination that should be needed for newer (488.2 compliant) instruments. Keep in mind though that just because the updated 488.2 GPIB spec was published in 1987, there was nothing to say that instrument makers *had* to comply with it. Many legacy 488.1 instruments remained in production (in fact a few oddball 488.1 instruments may still be in limited production, I have stories from my job...). So it's possible to have a post-1987 instrument that is only 488.1 compliant (and/or not SCPI-compliant for that matter). This is all part of the fun of GPIB  :rant:

I am looking at all of this and thinking the adapters should be transparent and instrument agnostic.  The GPIB controlling software should write/select the correct terminator at start-up.  This will ensure that no matter which equipment the adapter is plugged into, it will be correctly configured by the controller for the instrument being controlled.

Yep, yep. Configuring in the application software every time is the smart way.

OK I am going to go with EOI as my default termination.  If that doesn't work for a specific instrument, use LF or whatever works. 
My instruments include a scope and EMC receiver with a scope-like output.  Hopefully using EOI will avoid issues with byte data streams.

Good plan  :-+
Title: Re: Problems Writing code for GPIB Py VISA
Post by: dazz1 on December 23, 2023, 07:45:04 am
Hi am trying to try the DCL command.
I have figured out I need to write hex value 0x14, but all I can find is confusion and error messages.  An example being this: 
https://github.com/pyvisa/pyvisa/issues/491 (https://github.com/pyvisa/pyvisa/issues/491) 
and here:
https://pyvisa.readthedocs.io/en/latest/introduction/rvalues.html (https://pyvisa.readthedocs.io/en/latest/introduction/rvalues.html)

Also I haven't figured out how to send an EOI terminator to the 2520.  I need to be able to tell pyVISA the terminator is "EOI".
I also need to send the 2520 a string that sets the terminator to EOI.  The manuals are silent.

[EDIT]  I still have the 2520 terminator DIP switch set to /n. I want to test the software command to set EOI before I change the DIP switches.
Title: Re: Problems Writing code for GPIB Py VISA
Post by: dazz1 on December 23, 2023, 08:08:33 am
I tried this:
Code: [Select]
D:\GPIB USB Adapter\dazz>python                                                                                                                     
Python 3.12.1 (tags/v3.12.1:2305ca5, Dec  7 2023, 22:03:25) [MSC v.1937 64 bit (AMD64)] on win32                                                                                   
Type "help", "copyright", "credits" or "license" for more information.                                                                                                             
>>> import pyvisa                                                                                                                                                                   
>>> rm = pyvisa.ResourceManager()                                                                                                                                                   
>>> print(rm.list_resources())                                                                                                                                                     
('USB0::0x03EB::0x2065::GPIB_02_24238323232351C01171::INSTR', 'ASRL1::INSTR')                                                                                                       
>>> SigGen = rm.open_resource('USB0::0x03EB::0x2065::GPIB_02_24238323232351C01171::INSTR')                                                                                         
>>> cmd = bytes([0x14, ])                                                                                                                                                                                                     
>>> SigGen.send_command(data=cmd)                                                                                                                                                 
 Traceback (most recent call last):                                                                                                                                                   
File "<stdin>", line 1, in <module>                                                                                                                                             
 AttributeError: 'USBInstrument' object has no attribute 'send_command'                                                                                                             
>>>         

So wondering if the adapter has a method to write command bytes to the instrument?
Title: Re: Problems Writing code for GPIB Py VISA
Post by: caiser01 on December 23, 2023, 04:12:43 pm
Hi am trying to try the DCL command.
I have figured out I need to write hex value 0x14, but all I can find is confusion and error messages.  An example being this: 
https://github.com/pyvisa/pyvisa/issues/491 (https://github.com/pyvisa/pyvisa/issues/491)

In the issue you link to, the person is clearly using a "real" GPIB adapter or card because they refer to the pyVISA GPIBInstrument class. The xyphro adapter presents itself as a USBTMC device and therefore pyVISA can only talk to the instrument using its USBInstrument class, and therefore, the only valid VISA functions are those listed here: https://pyvisa.readthedocs.io/en/latest/api/resources.html#pyvisa.resources.USBInstrument (https://pyvisa.readthedocs.io/en/latest/api/resources.html#pyvisa.resources.USBInstrument)

That's why you got this error message:
Code: [Select]
AttributeError: 'USBInstrument' object has no attribute 'send_command'Because send_command() is valid for a GPIBInstrument object but not a USBInstrument object.

With xyphro adapter, you don't need to (and in fact can't) send low-level commands to the instrument in the manner you're attempting.

If you just run:

Code: [Select]
SigGen.clear()
..and the adapter firmware will do all the low-level stuff for you.

If you want to prove to yourself what's really happening, you can follow the logic through the various specs and xyphro's firmware:

You run SigGen.clear() and pyVISA will send INITIATE_CLEAR to the xyphro adapter. Since the adapter is a USBTMC device and is USB488 compliant, it will behave as described in 4.2.1 of that specification (http://sdpha2.ucsd.edu/lab_equip_manuals/usbtmc_usb488_subclass_1_00.pdf (http://sdpha2.ucsd.edu/lab_equip_manuals/usbtmc_usb488_subclass_1_00.pdf)), which is to say it will send Selected Device Clear (SDC) (hex 0x04) to the instrument. Note: The result of sending a DCL (0x14, clear all instruments on the bus) and a SDC (0x04, clear only the addressed instrument) would be the same in our case since only one instrument can be connected to the xyhpro adapter.

Now, we can follow what's happening in xyphro's firmware. In TestAndMeasurement.c (https://github.com/xyphro/UsbGpib/blob/master/SW/TestAndMeasurement/TestAndMeasurement.c (https://github.com/xyphro/UsbGpib/blob/master/SW/TestAndMeasurement/TestAndMeasurement.c)), there is a switch-case starting at line 566

Code: [Select]
switch (USB_ControlRequest.bRequest)
Because we got INITIATE_CLEAR from pyVISA, that will kick us down to line 703

Code: [Select]
case Req_InitiateClear:
The important thing that happens here is that the handleSDC flag is set true. Next we jump down to line 1099

Code: [Select]
if (handleSDC)
{
gpib_ren(1); /* ensure that remote control is enabled */
timeout_start(50000); /* 0.5s timeout*/
gpib_sdc(gpib_addr, is_timedout);

handleSDC = false;
}

gpib_sdc is called and now we have to jump over to gpib.c (https://github.com/xyphro/UsbGpib/blob/master/SW/TestAndMeasurement/gpib.c (https://github.com/xyphro/UsbGpib/blob/master/SW/TestAndMeasurement/gpib.c)) to see that function starting at line 269. Inside gpib_sdc, one more function is called and that's gpib_cmd_SDC, which is very straightforward:

Code: [Select]
static bool gpib_cmd_SDC(gpibtimeout_t ptimeoutfunc) // selective device clear
{
return gpib_tx(0x04, true, ptimeoutfunc);
}

The command byte 0x04 is sent to the instrument to perform SDC, which as we noted above is equivalent to DCL for our single connected instrument.

So to finally summarize, executing SigGen.clear() in your python script will send SDC (0x14) to your instrument.

I need to be able to tell pyVISA the terminator is "EOI".

No, you don't. The firmware on the adapter again takes care of setting EOI for you and you can follow your way through the code to prove that to yourself as above.
Title: Re: Problems Writing code for GPIB Py VISA
Post by: dazz1 on December 24, 2023, 03:49:34 am
My first paddle into the sea of Python is a script that tests the time to execute and reliability of query commands.
It does this simply by executing the same query command (ID?) 10x in quick succession, and measuring the execution time to complete each query.  The purpose of posting this is to make it available to others.  It should probably run with any and all GPIB instruments.

With very little modification, this script could read a command line argument and execute that.  One script to run many different query commands.  I have chosen not to do that.
My plan is to copy/paste/modify this script for each query command, run the tests, and record a summary of the results in the script.

I have already found that the WaveTek 2520 is not a reliable responder.  The pyVISA exception handling is not handling the occasional errors I see.

Code: [Select]
# Wavetek 2520 RF Signal Generator simple read test
# The purpose of this script is to gauge gpib command reliability, and to measure the
# execution time. 
# This repeats the same gpib query command 10 times and measures the execution time
# for each query.

import pyvisa
import time
from timeit import default_timer as timer

# Define a function that measures the execution time of the argument.
# The argument is a gpib command.

# User Editable Variables
pause = 0.02  # Edit this.  This is the pause from the end of one query to the next. 
# It is the time taken for the instrument to be ready for the next query.
gpib_query = "ID? " # Edit this.  This is the gpib query command under test.

# ID string for adapter 0:  'USB0::0x03EB::0x2065::GPIB_23_24238323232351C01171::INSTR'
def exec_query(cmd):
try:
start = timer()
ans = SigGen.query(cmd)
end = timer()
print("Query : ", cmd,"         Returned : ", str( ans ) )
ExTm = round((end - start) * 1000,2) # milliseconds
except pyvisa.VisaIOError:
print("########### WARNING : Time Out exception has occurred")
SigGen.clear()
return "   Cmd Execution time: ", ExTm,"ms"
 

print("###### Simple GPIB test for WaveTek 2520 SigGen")
print("# Executes read ID 10x")
print()
print("# Show the list of Resources")
rm = pyvisa.ResourceManager()
print(rm.list_resources())


print("# Opening the SigGen")
# Resource = GPIB-usb adapter 0.  Different for each adapter.

SigGen = rm.open_resource('USB0::0x03EB::0x2065::GPIB_02_24238323232351C01171::INSTR')
print()
# Reset the instrument, wait for reset to complete
SigGen.clear()  # Doesn't appear to have any effect on the Signal Generator.

######  Run this once to turn off auto ID.  AutoID is not supported by the WaveTek 2520.
#SigGen.control_in(0xa1, 0x40, 0, 0)
#SigGen.write('!0001')

SigGen.write_termination = '\n'
SigGen.read_termination = '\n'
SigGen.timeout = 1000         #sets 1s timeout for the meter after the read

#print("Read the ID")
try:
for x in range (1,10):
print("# Loop Count :", x, exec_query(gpib_query)) # Edit the gpib
time.sleep(pause)
except KeyboardInterrupt:
SigGen.clear()
SigGen.close()
rm.close()

# RESULTS
# typical execution time of print(SigGen.query('ID? ')) is <12ms
# delay 20ms before next ID? read.

I usually get an output that looks like this:
Code: [Select]
GPIB_test>python WvTk2520_gpib_rd_ID.py\
###### Simple GPIB test for WaveTek 2520 SigGen
# Executes read ID 10x

# Show the list of Resources
('USB0::0x03EB::0x2065::GPIB_02_24238323232351C01171::INSTR', 'ASRL1::INSTR')
# Opening the SigGen

Query :  ID?           Returned :  WVTK/2520A,V81.1,F5.1
# Loop Count :  1 ('   Cmd Execution time: ', 11.91, 'ms')
Query :  ID?           Returned :  WVTK/2520A,V81.1,F5.1
# Loop Count :  2 ('   Cmd Execution time: ', 11.75, 'ms')
Query :  ID?           Returned :  WVTK/2520A,V81.1,F5.1
# Loop Count :  3 ('   Cmd Execution time: ', 11.74, 'ms')
Query :  ID?           Returned :  WVTK/2520A,V81.1,F5.1
# Loop Count :  4 ('   Cmd Execution time: ', 11.78, 'ms')
Query :  ID?           Returned :  WVTK/2520A,V81.1,F5.1
# Loop Count :  5 ('   Cmd Execution time: ', 11.89, 'ms')
Query :  ID?           Returned :  WVTK/2520A,V81.1,F5.1
# Loop Count :  6 ('   Cmd Execution time: ', 11.92, 'ms')
Query :  ID?           Returned :  WVTK/2520A,V81.1,F5.1
# Loop Count :  7 ('   Cmd Execution time: ', 11.73, 'ms')
Query :  ID?           Returned :  WVTK/2520A,V81.1,F5.1
# Loop Count :  8 ('   Cmd Execution time: ', 11.95, 'ms')
Query :  ID?           Returned :  WVTK/2520A,V81.1,F5.1
# Loop Count :  9 ('   Cmd Execution time: ', 11.74, 'ms')

when it doesn't work, I get an output that looks like this:
Code: [Select]
D:\darren\My Documents\Electronics\Wavetek SigGen\GPIB_test>python WvTk2520_gpib_rd_ID.py\
###### Simple GPIB test for WaveTek 2520 SigGen
# Executes read ID 10x

# Show the list of Resources
('USB0::0x03EB::0x2065::GPIB_02_24238323232351C01171::INSTR', 'ASRL1::INSTR')
# Opening the SigGen

Traceback (most recent call last):
  File "D:\darren\My Documents\Electronics\Wavetek SigGen\GPIB_test\WvTk2520_gpib_rd_ID.py\", line 51, in <module>
    SigGen.clear()
  File "G:\Programs\Python310\Lib\site-packages\pyvisa\resources\resource.py", line 381, in clear
    self.visalib.clear(self.session)
  File "G:\Programs\Python310\Lib\site-packages\pyvisa\ctwrapper\functions.py", line 616, in clear
    return library.viClear(session)
           ^^^^^^^^^^^^^^^^^^^^^^^^
  File "G:\Programs\Python310\Lib\site-packages\pyvisa\ctwrapper\highlevel.py", line 226, in _return_handler
    return self.handle_return_value(session, ret_value)  # type: ignore
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "G:\Programs\Python310\Lib\site-packages\pyvisa\highlevel.py", line 251, in handle_return_value
    raise errors.VisaIOError(rv)
pyvisa.errors.VisaIOError: VI_ERROR_SYSTEM_ERROR (-1073807360): Unknown system error (miscellaneous error).
Title: Re: Problems Writing code for GPIB Py VISA
Post by: dazz1 on December 24, 2023, 04:03:13 am
Quote from: caiser01

If you just run:

Code: [Select]
SigGen.clear()
..and the adapter firmware will do all the low-level stuff for you.

OK now I know.   :-+
The gem has avoided a very deep dive into a rabbit hole.

FYI:  The
Code: [Select]
clear() command has no observable effect on the 2520.   I could write a function that simply sets the 13 user variable settings to known defaults.
Title: Re: Problems Writing code for GPIB Py VISA
Post by: dazz1 on December 24, 2023, 08:16:35 am

So below is the result of a test where the only query command executed is the current RF output LVL.
The previous tests were  for Frequency and for ID.

The output shows the query was "LVL" but the response is Frequency, ID and lastly Level.
The "350-Stored Settings Error" appears to signal that the 2520 knows something is wrong.

I think it is safe to say the 2520 is probably full of bugs.

Code: [Select]
###### Simple GPIB test for WaveTek 2520 SigGen                                                                                       
# Executes read ID 10x                                                                                                                                                                                                                                                       
# Show the list of Resources                                                                                                           
('USB0::0x03EB::0x2065::GPIB_02_24238323232351C01171::INSTR', 'ASRL1::INSTR')                                                         
# Opening the SigGen                                                                                                                                                                                                                                                         
Clear the instrument                                                                                                                   
Query :  LVL?           Returned :  FREQUENCY 222.222 MHz                                                                             
# Loop Count : 1 ('   Cmd Execution time: ', 12.29, 'ms')                                                                             
Query :  LVL?           Returned :  FREQUENCY 222.222 MHz                                                                             
# Loop Count : 2 ('   Cmd Execution time: ', 12.16, 'ms')                                                                             
Query :  LVL?           Returned :  FREQUENCY 222.222 MHz                                                                             
# Loop Count : 3 ('   Cmd Execution time: ', 12.39, 'ms')                                                                             
Query :  LVL?           Returned :  350-STORED SETTINGS ERROR                                                                         
# Loop Count : 4 ('   Cmd Execution time: ', 12.3, 'ms')                                                                               
Query :  LVL?           Returned :  350-STORED SETTINGS ERROR                                                                         
# Loop Count : 5 ('   Cmd Execution time: ', 12.35, 'ms')                                                                             
Query :  LVL?           Returned :  350-STORED SETTINGS ERROR                                                                         
 # Loop Count : 6 ('   Cmd Execution time: ', 12.38, 'ms')                                                                             
Query :  LVL?           Returned :  WVTK/2520A,V81.1,F5.1                                                                             
# Loop Count : 7 ('   Cmd Execution time: ', 12.27, 'ms')                                                                             
Query :  LVL?           Returned :  WVTK/2520A,V81.1,F5.1                                                                             
# Loop Count : 8 ('   Cmd Execution time: ', 12.28, 'ms')                                                                             
Query :  LVL?           Returned :  WVTK/2520A,V81.1,F5.1                                                                             
# Loop Count : 9 ('   Cmd Execution time: ', 12.35, 'ms')                                                                             
Query :  LVL?           Returned :  WVTK/2520A,V81.1,F5.1                                                                             
# Loop Count : 10 ('   Cmd Execution time: ', 12.38, 'ms')                                                                           
 Query :  LVL?           Returned :  WVTK/2520A,V81.1,F5.1                                                                             
# Loop Count : 11 ('   Cmd Execution time: ', 12.3, 'ms')                                                                             
Query :  LVL?           Returned :  WVTK/2520A,V81.1,F5.1                                                                             
# Loop Count : 12 ('   Cmd Execution time: ', 12.23, 'ms')                                                                             
Query :  LVL?           Returned :  WVTK/2520A,V81.1,F5.1                                                                             
# Loop Count : 13 ('   Cmd Execution time: ', 12.2, 'ms')                                                                             
Query :  LVL?           Returned :  WVTK/2520A,V81.1,F5.1                                                                             
# Loop Count : 14 ('   Cmd Execution time: ', 12.38, 'ms')                                                                             
Query :  LVL?           Returned :  WVTK/2520A,V81.1,F5.1                                                                             
# Loop Count : 15 ('   Cmd Execution time: ', 12.33, 'ms')                                                                           
 Query :  LVL?           Returned :  350-STORED SETTINGS ERROR                                                                         
# Loop Count : 16 ('   Cmd Execution time: ', 12.35, 'ms')                                                                             
Query :  LVL?           Returned :  AMPLITUDE -10.0 dBm                                                                               
# Loop Count : 17 ('   Cmd Execution time: ', 12.24, 'ms')                                                                             
Query :  LVL?           Returned :  AMPLITUDE -10.0 dBm                                                                               
# Loop Count : 18 ('   Cmd Execution time: ', 12.37, 'ms')                                                                           
 Query :  LVL?           Returned :  AMPLITUDE -10.0 dBm                                                                               
# Loop Count : 19 ('   Cmd Execution time: ', 12.25, 'ms')       

I tested the hypothesis that the commands were issued too quickly with not enough time for the 2520 to finish.  I extended times, especially after .clear for up to 60 seconds.
The test script had dynamic fatal errors. 

So when I program gpib, I will need to keep sending commands until I get a valid response. 
Title: Re: Problems Writing code for GPIB Py VISA
Post by: dazz1 on December 24, 2023, 09:24:46 am
I am getting error messages when a gpib command generates and exception. 

Code: [Select]
  File "D:\My Documents\Electronics\Wavetek SigGen\GPIB_test\WvTk2520_gpib_rd_LVL.py\", line 32, in exec_query
    return "   Cmd Execution time: ", ExTm,"ms"
                                      ^^^^
UnboundLocalError: cannot access local variable 'ExTm' where it is not associated with a value

I think the problem is that when the gpib command fails within a defined function the variable ExTm is not assigned a value.

Code: [Select]
...
ans = SigGen.query(cmd)                                                             # query fails generating an exception.
end = timer()
print("Query : ", cmd,"         Returned : ", str( ans ) )
ExTm = round((end - start) * 1000,2) # milliseconds           # Extm never gets assigned a value
except pyvisa.VisaIOError:
print("########### WARNING : Time Out exception has occurred") 
return "   Cmd Execution time: ", ExTm,"ms"                                                   # on return, ExTm is unassigned
...

Not sure how to fix this yet. Looking into it.


Edit:  Fixed this by moving the execution time calculation to the return(...) statement.
Code: [Select]
print("Query : ", cmd,"         Returned : ", str( ans ) )
#ExTm = round((end - start) * 1000,2) # milliseconds
except pyvisa.VisaIOError:
print("########### WARNING : Time Out exception has occurred")
return "   Cmd Execution time: ", round((end - start) * 1000,2),"ms"
Title: Re: Problems Writing code for GPIB Py VISA
Post by: dazz1 on December 25, 2023, 11:38:31 pm
Having said I wouldn't do something, I have done it. 
I have written a python script that takes a gpib query command (eg.  "ID?") as a argument.
That command is then executed in a loop.

The output includes the response to the command and measures the time taken for the instrument to execute and response to the command.  This measured time is end-to-end and includes the duration of communications to send the command and receive the response.

This script is designed for commands where something is written to the instrument, and then a response is read back.  This script does not attempt to cover all types if instructions. 


This script should run with any instrument.      It allows a user to test the response of any instrument to gpib query commands.

Code: [Select]
# Wavetek 2520 RF Signal Generator simple read test
# The purpose of this script is to gauge gpib command reliability, and to measure the
# execution time. 
# This repeats the same gpib query command 10 times and measures the execution time
# for each query.

import pyvisa
import time
import sys
from timeit import default_timer as timer
# CMD commands to run
# D:
# D:\My Documents\Electronics\Wavetek SigGen\GPIB_test\

# Define a function that measures the execution time of the argument.
# The argument is a gpib command.

# User Editable Variables
read_cnt = 20      # The number of queries looped through

pause = 1  # Edit this.  This is the pause from the end of one query to the next. 
# It is the added delay to allow the instrument to be ready for the next query.

# The function to execute a GPIB query command.  The command is executed and the results
# are printed. 
def exec_query(cmd):
try:
start = timer()
end = start
ans = SigGen.query(cmd)
end = timer()
print("Query : ", cmd,"         Returned : ", str( ans ) )
except pyvisa.VisaIOError:
print("########### WARNING : Time Out exception has occurred")
return "   Cmd Execution time: ", round((end - start) * 1000,2),"ms"

 
# ID string for adapter 0:  'USB0::0x03EB::0x2065::GPIB_23_24238323232351C01171::INSTR'

if len(sys.argv) > 0 :
gpib_cmd = str(sys.argv[1])
else:
gpib_cmd = "ID?"  # in the absence of a command, default to ID?

print("The entered query command is : ", gpib_cmd)



print("###### Simple GPIB test for WaveTek 2520 SigGen")
print("# Executes read ID 10x")
print()
print("# Show the list of Resources")
rm = pyvisa.ResourceManager()
print(rm.list_resources())

print("# Opening the SigGen")
# Resource = GPIB-usb adapter 0.  Different for each adapter.

SigGen = rm.open_resource('USB0::0x03EB::0x2065::GPIB_02_24238323232351C01171::INSTR')
print()
# Reset the instrument, wait for reset to complete
#time.sleep(pause)
print("Clear the instrument")
SigGen.clear()
time.sleep(0.1)

######  Run this once to turn off auto ID.  AutoID is not supported by WvTk2520.
#SigGen.control_in(0xa1, 0x40, 0, 0)
#SigGen.write('!0001')

SigGen.write_termination = '\n'
SigGen.read_termination = '\n'
SigGen.timeout = 500        #sets timeout (ms) for the instrument to respond.

#print("Read the ID")
try:
for x in range (0,read_cnt):
print("# Loop Count :", x, exec_query(gpib_cmd)) # The gpib command under test
time.sleep(pause)
except KeyboardInterrupt:
print("################ Interrupted by keyboard !")
SigGen.clear()
SigGen.close()
rm.close()

# RESULTS
# typical execution time of print(SigGen.query('ID? ')) is <13ms
# delay 20ms before next ID? read.
# Randomly returns : Query :  FRQ?           Returned :  350-STORED SETTINGS ERROR

This is a development of the first python script I have written, so for all those that know what they are doing, be gentle on me.
This is a test program so it is unpolished and simple. 

The output shows the command, the response and the execution time (duration).
A sample output is:

Code: [Select]
# Show the list of Resources                                                                                           
('USB0::0x03EB::0x2065::GPIB_02_24238323232351C01171::INSTR', 'ASRL1::INSTR')                                           
# Opening the SigGen                                                                                                                                                                                                                           
Clear the instrument                                                                                                   
Query :  lst?          Returned :  AMPLITUDE -10.0 dBm                                                                 
# Loop Count : 0 ('   Cmd Execution time: ', 11.99, 'ms')                                                               
Query :  lst?          Returned :  AMPLITUDE -10.0 dBm                                                                 
# Loop Count : 1 ('   Cmd Execution time: ', 11.94, 'ms')                                                               
Query :  lst?          Returned :  AMPLITUDE -10.0 dBm                                                                 
# Loop Count : 2 ('   Cmd Execution time: ', 12.27, 'ms')                                                               
Query :  lst?          Returned :  AMPLITUDE -10.0 dBm                                                                 
# Loop Count : 3 ('   Cmd Execution time: ', 12.07, 'ms')                                                               
Query :  lst?          Returned :  AMPLITUDE -10.0 dBm                                                                 
# Loop Count : 4 ('   Cmd Execution time: ', 12.08, 'ms')                                                               
Query :  lst?          Returned :  AMPLITUDE -10.0 dBm                                                                 
# Loop Count : 5 ('   Cmd Execution time: ', 11.98, 'ms')                                                               
Query :  lst?          Returned :  AMPLITUDE -10.0 dBm                                                                 
# Loop Count : 6 ('   Cmd Execution time: ', 12.15, 'ms')                                                               
Query :  lst?          Returned :  AMPLITUDE -10.0 dBm                                                                 
# Loop Count : 7 ('   Cmd Execution time: ', 12.12, 'ms')                                                               
Query :  lst?          Returned :  AMPLITUDE -10.0 dBm                                                                 
# Loop Count : 8 ('   Cmd Execution time: ', 12.02, 'ms')                                                               
Query :  lst?          Returned :  AMPLITUDE -10.0 dBm                                                                 
# Loop Count : 9 ('   Cmd Execution time: ', 12.82, 'ms')                                                               
Query :  lst?          Returned :  AMPLITUDE -10.0 dBm                                                                 
# Loop Count : 10 ('   Cmd Execution time: ', 12.16, 'ms')                                                             
Query :  lst?          Returned :  AMPLITUDE -10.0 dBm                                                                 
# Loop Count : 11 ('   Cmd Execution time: ', 12.27, 'ms')                                                             
Query :  lst?          Returned :  AMPLITUDE -10.0 dBm                                                                 
# Loop Count : 12 ('   Cmd Execution time: ', 11.97, 'ms')                                                             
Query :  lst?          Returned :  AMPLITUDE -10.0 dBm                                                                 
# Loop Count : 13 ('   Cmd Execution time: ', 12.16, 'ms')                                                             
Query :  lst?          Returned :  350-STORED SETTINGS ERROR                                                           
# Loop Count : 14 ('   Cmd Execution time: ', 12.2, 'ms')                                                               
Query :  lst?          Returned :  350-STORED SETTINGS ERROR                                                           
 # Loop Count : 15 ('   Cmd Execution time: ', 11.99, 'ms')                                                             
Query :  lst?          Returned :  AMP STEP 0.10 dB                                                                     
# Loop Count : 16 ('   Cmd Execution time: ', 12.12, 'ms')                                                             
Query :  lst?          Returned :  AMP STEP 0.10 dB                                                                     
# Loop Count : 17 ('   Cmd Execution time: ', 11.96, 'ms')                                                             
Query :  lst?          Returned :  AMP STEP 0.10 dB                                                                     
# Loop Count : 18 ('   Cmd Execution time: ', 12.37, 'ms')

The sample shows that the WaveTek 2520 is unreliable.  At face value, the sample output looks like a timing issue.  Increasing the pause durations between instructions does not change the output.  It also looks like a FIFO buffer needs to be cleared before the correct response is received.

I tested the hypothesis that  .clear() would flush any buffers.  The gpib command: SigGen.clear() has no observable effect on the WaveTek2520, but it takes 125ms to complete, so it is doing something.
Title: Re: Problems Writing code for GPIB Py VISA
Post by: caiser01 on December 26, 2023, 02:23:08 am
Nice job on the script and thanks for sharing.

A few thoughts:

1. I did not know of the existence of the timeit library so that's something to file away for later use. I've always used perf_counter from the time library for timing execution.
2. 12ms response time is pretty good and typical of an instrument of this vintage.
3. I wonder if changing just the write termination to '\r' in the script (no changes to the instrument's DIP switches, etc.) would eliminate the 350 errors. For my Fluke 6060B RF signal generator, I had to change the write termination to ';' to keep it from occasionally hiccuping.
Title: Test script for Query Commands
Post by: dazz1 on December 26, 2023, 09:29:27 am
Hi
I have been looking for / testing methods to get a reliable response from gpib queries sent to my WaveTek2520 RF signal generator.
The script I have come up with does this by ignoring any initial null responses, then it keeps reading until at least two adjacent nulls are returned.

I have no idea if this is best practice, or any practice, but it appears to work.
The instruction set and other key parameters are easily adjusted, so this script could be readily adapted to other instruments with simple query commands. That is why I have posted the script here:
Code: [Select]
# Wavetek 2520 RF Signal Generator simple read test
# The purpose of this script is to test a method to obtain reliable
# responses from the instrument.  This script is designed to reliably
# read the responses to query type commands only.
#
# Reads fail because:
# the script runs too fast (pauses need to be inserted)
# the first read returns a null response and,
# responses are initially from a FIFO buffer.
#
# This script:
# discards an initial single null response.
# keeps reading until the responses are at least two nulls.
# This script will read multi-line responses. 
# This script executes all query type gpib commands in a loop.
# The commands are stored in a 2xn matrix. 
# The columns are a:
# query command
# description of the command
#
# 0:  cmd      SET?
# 1:  description List all internal settings

# The instructions are in a user defined loop count. 
# The commands are in an editable array to allow this script to
# be used with any simple query command, including multi-line responses.
# Edit "pause" to adjust the inserted delay periods. 

import pyvisa
import time
from timeit import default_timer as timer
import sys
import array as arr
import numpy as np


# CMD commands to run
# D:
# D:\My Documents\Electronics\Wavetek SigGen\GPIB_test\

# Define a function that measures the execution time of the argument.
# The argument is a gpib command.

# User Editable Variables
read_cnt = 5      # The number of times to loop through a set of queries

pause = .05  # Edit this.  This is the pause from the end of one query to the next. 
# It is the added delay to allow the instrument to be ready for the next query.

############ Query Commands Arrays
# Edit this array to define all of the query commands. 
# Array:  "command", No. of response lines to read, description

arrayCmds = np.array([
["ID?" ,"ID"],
["FRQ?","Frequency"],
["FST?","Frequency Step"],
["LVL?","Amplitude"],
["LST?","Amp Step"],
["RF? ","RF Output on/off"],
["IAM?","Internal AM "],
["IFM?","Internal FM "],
["XAM?","External AM "],
["XFM?","External FM "],
["RTE?","Internal modulation tone 400/1000Hz"],
["MOD?","Modulation Mode"],
["ERR?","Error message"],
["OPT?","Installed Options"],
["SET?","List all settings:"]])



# The function to execute a GPIB query command.  The command is executed and the results
# are printed. 
def exec_query():
try:
for row in arrayCmds:
print("#   Query : ", row[0],"  =  ",row[1])
start = timer()
end = start
# Write, Read same as query
SigGen.write(row[0])          # send command to instrument
RdNull = False           # Count the number of nulls received
while True:
time.sleep(pause)
ans = SigGen.read()
end = timer()
duration = round((end - start) * 1000,2)
if ans == "" : # if read = null
#print("Null 1", RdNull)
if RdNull == True:
#print("Null 2", RdNull)
break
RdNull = True
else:
RdNull = False
print("#   Returned : ", str( ans ),"   Duration : ", duration )

except pyvisa.VisaIOError:
print("########### WARNING : Time Out exception has occurred")
return "#   Cmd Execution time: ", duration,"ms"

 
# ID string for adapter 0:  'USB0::0x03EB::0x2065::GPIB_23_24238323232351C01171::INSTR'


print("###### Simple GPIB test for WaveTek 2520 SigGen")
print("# Executes a list of query commands")
print()
print("# Show the list of Resources")
rm = pyvisa.ResourceManager()
print(rm.list_resources())

print("# Opening the SigGen")
# Resource = GPIB-usb adapter 0.  Different for each adapter.

SigGen = rm.open_resource('USB0::0x03EB::0x2065::GPIB_02_24238323232351C01171::INSTR')
print()
# Reset the instrument, wait for reset to complete
print("# Clear the instrument")
SigGen.clear()
time.sleep(0.1)

######  Run this once to turn off auto ID.  AutoID is not supported by WvTk2520.
#SigGen.control_in(0xa1, 0x40, 0, 0)
#SigGen.write('!0001')

SigGen.write_termination = '\n'
SigGen.read_termination = '\n'
SigGen.timeout = 500        #sets timeout (ms) for the instrument to respond.

print("# Run all query commands ...")
try:
for x in range (0,read_cnt):
print("# Loop Count :", x, exec_query()) # The gpib command under test
time.sleep(pause)
except KeyboardInterrupt:
print("################ Interrupted by keyboard !")
SigGen.clear()
SigGen.close()
rm.close()

# RESULTS
# Reading the responses (multiple reads) until nulls are sensed is a reliable method of
# reading data from a WaveTek 2520 RF signal generator.  This may work with other
# instruments by modifying the command array.

A sample output is shown below:

Code: [Select]
# Loop Count : 3 ('#   Cmd Execution time: ', 884.63, 'ms')
#   Query :  ID?   =   ID
#   Returned :  WVTK/2520A,V81.1,F5.1             Duration :  59.91
#   Query :  FRQ?   =   Frequency
#   Returned :  FREQUENCY 222.222 MHz             Duration :  60.2
#   Query :  FST?   =   Frequency Step
#   Returned :  FREQ STEP 50.0 kHz                Duration :  62.51
#   Query :  LVL?   =   Amplitude
#   Returned :  AMPLITUDE -10.0 dBm               Duration :  61.86
#   Query :  LST?   =   Amp Step
#   Returned :  AMP STEP 0.10 dB                  Duration :  113.0
#   Query :  RF?    =   RF Output on/off
#   Returned :  RF OUTPUT OFF                     Duration :  60.41
#   Query :  IAM?   =   Internal AM
#   Returned :  INTERNAL AM 100.0 %               Duration :  61.69
#   Query :  IFM?   =   Internal FM
#   Returned :  INTERNAL FM 80.0 kHz              Duration :  62.06
#   Query :  XAM?   =   External AM
#   Returned :  EXTERNAL AM 60.0 %                Duration :  62.13
#   Query :  XFM?   =   External FM
#   Returned :  EXTERNAL FM 235.0 kHz             Duration :  111.9
#   Query :  RTE?   =   Internal modulation tone 400/1000Hz
#   Returned :  499-SYSTEM OPERATIONAL            Duration :  60.57
#   Query :  MOD?   =   Modulation Mode
#   Returned :  MODULATION EXT PM                 Duration :  60.55
#   Query :  ERR?   =   Error message
#   Returned :  499-SYSTEM OPERATIONAL            Duration :  60.66
#   Query :  OPT?   =   Installed Options
#   Returned :  OPT 75:Level Step                 Duration :  60.07
#   Returned :  OPT 7A:External Phase Mod         Duration :  121.1
#   Query :  SET?   =   List all settings:
#   Returned :  FREQUENCY 222.222 MHz             Duration :  112.46
#   Returned :  FREQ STEP 50.0 kHz                Duration :  172.73
#   Returned :  AMPLITUDE -10.0 dBm               Duration :  233.66
#   Returned :  INTERNAL AM 100.0 %               Duration :  293.71
#   Returned :  INTERNAL FM 80.0 kHz              Duration :  353.74
#   Returned :  EXTERNAL AM 60.0 %                Duration :  414.08
#   Returned :  EXTERNAL FM 235.0 kHz             Duration :  475.76
#   Returned :  RF OUTPUT OFF                     Duration :  536.76
#   Returned :  499-SYSTEM OPERATIONAL            Duration :  596.77
#   Returned :  MODULATION EXT PM                 Duration :  657.02
#   Returned :  AMP STEP 0.10 dB                  Duration :  717.81
#   Returned :  EXT PHASE 0.30 rads               Duration :  778.42
# Loop Count : 4 ('#   Cmd Execution time: ', 882.73, 'ms')
Title: PyMeasure
Post by: dazz1 on December 26, 2023, 10:15:49 am
Hi
I found PyMeasure here:  https://pymeasure.readthedocs.io/en/latest/index.html (https://pymeasure.readthedocs.io/en/latest/index.html)

I am looking at this a fast track way to write pymeasure.instruments for my own instruments.
I can use existing similar instruments and their code, as a template for mine. 

Anyone have experience with this? 
Title: Re: Problems Writing code for GPIB Py VISA
Post by: dazz1 on December 26, 2023, 10:19:38 am
Nice job on the script and thanks for sharing.

A few thoughts:

...
3. I wonder if changing just the write termination to '\r' in the script (no changes to the instrument's DIP switches, etc.) would eliminate the 350 errors. For my Fluke 6060B RF signal generator, I had to change the write termination to ';' to keep it from occasionally hiccuping.

I can set the termination from the front panel for testing.  Haven't really done that yet.
The manual says read/write terminations need to be the same.
Title: Re: Problems Writing code for GPIB Py VISA
Post by: bson on December 27, 2023, 09:24:47 pm
The output shows the query was "LVL" but the response is Frequency, ID and lastly Level.
The "350-Stored Settings Error" appears to signal that the 2520 knows something is wrong.

I think it is safe to say the 2520 is probably full of bugs.
NI VISA is also full of bugs.  It might be worth trying usbtmc directly to the instrument without the bloated VISA stuff.
https://github.com/python-ivi/python-usbtmc
Title: Re: Problems Writing code for GPIB Py VISA
Post by: dazz1 on December 29, 2023, 12:23:26 am
Quote from: bson

NI VISA is also full of bugs.  It might be worth trying usbtmc directly to the instrument without the bloated VISA stuff.
https://github.com/python-ivi/python-usbtmc

I am using the R&S GPIB driver which I understand is a lot lighter than NI-VISA.
Title: WaveTek 2520 GPIB locking up
Post by: dazz1 on December 29, 2023, 12:39:41 am
Hi
I have a problem where the 2520 GPIB interface becomes unresponsive after being left alone for a few minutes.    The fix is to unplug/plug-in the USB-GPIB adapter.  This suggest the possibility that it might be possible for the adapter firmware to be modified to recover the 2520

There is no evidence of indication of a bug in the usb-gpib adapter firmware.  This looks like a problem with the 2520 firmware.

The timeout appears to be entirely within the 2520.
The code looks like this:
Code: [Select]
# Wavetek 2520 RF Signal Generator simple read test
# CMD commands to run
# D:
# cd \darren\My Documents\Electronics\Wavetek SigGen\GPIB_test\
#  python WvTk2520_gpib_RTE.py
import pyvisa
import time

print("Show the list of Resources")
rm = pyvisa.ResourceManager()
print(rm.list_resources())

print("# Opening the SigGen")
# Resource = GPIB-usb adapter 0.  Different for each adapter.
SigGen = rm.open_resource('USB0::0x03EB::0x2065::GPIB_02_24238323232351C01171::INSTR')
SigGen.timeout = 2000         #sets 2s timeout for the meter after the read

print("# Clear")
SigGen.clear()
...

and this generate a time out error message as follows:

Code: [Select]
Simple GPIB test for WaveTek 2520 SigGen
Show the list of Resources
('USB0::0x03EB::0x2065::GPIB_02_24238323232351C01171::INSTR', 'ASRL1::INSTR')
# Opening the SigGen
# Clear
Traceback (most recent call last):
  File "D:\darren\My Documents\Electronics\Wavetek SigGen\GPIB_test\WvTk2520_gpib_RTE.py", line 32, in <module>
    SigGen.clear()
  File "G:\Programs\Python310\Lib\site-packages\pyvisa\resources\resource.py", line 381, in clear
    self.visalib.clear(self.session)
  File "G:\Programs\Python310\Lib\site-packages\pyvisa\ctwrapper\functions.py", line 616, in clear
    return library.viClear(session)
           ^^^^^^^^^^^^^^^^^^^^^^^^
  File "G:\Programs\Python310\Lib\site-packages\pyvisa\ctwrapper\highlevel.py", line 226, in _return_handler
    return self.handle_return_value(session, ret_value)  # type: ignore
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "G:\Programs\Python310\Lib\site-packages\pyvisa\highlevel.py", line 251, in handle_return_value
    raise errors.VisaIOError(rv)
pyvisa.errors.VisaIOError: VI_ERROR_TMO (-1073807339): Timeout expired before operation completed.

It is important to note that this code will run OK if it is run frequently.  The lock out happens if things are left alone for a few minutes.

It seems that cycling the power to the USB adapter does something that "clear" does not.  Just wondering if others have exprienced and solved this problem?

Title: Re: Problems Writing code for GPIB Py VISA
Post by: dazz1 on December 29, 2023, 09:39:18 am
Done some searching around the Internet.  I ran this command to get info on my system setup.

Code: [Select]
>pyvisa-info
Machine Details:
   Platform ID:    Windows-10-10.0.19045-SP0
   Processor:      Intel64 Family 6 Model 94 Stepping 3, GenuineIntel

Python:
   Implementation: CPython
   Executable:     G:\Programs\Python310\python.exe
   Version:        3.12.1
   Compiler:       MSC v.1937 64 bit (AMD64)
   Architecture:   AMD64
   Build:          Dec  7 2023 22:03:25 (#tags/v3.12.1:2305ca5)
   Unicode:        UCS4

PyVISA Version: 1.14.1

Backends:
   ivi:
      Version: 1.14.1 (bundled with PyVISA)
      #1: C:\WINDOWS\system32\visa32.dll:
         found by: auto
         architecture:
            ('x86', 64)
         Vendor: Rohde & Schwarz GmbH
         Impl. Version: 7340546
         Spec. Version: 7340544
      #2: C:\WINDOWS\system32\visa64.dll:
         found by: auto
         architecture:
            ('x86', 64)
         Vendor: Rohde & Schwarz GmbH
         Impl. Version: 7340546
         Spec. Version: 7340544

None of this has helped my diagnose the problem, but it does show that what I have appears to be working.
Title: Re: Problems Writing code for GPIB Py VISA
Post by: caiser01 on December 29, 2023, 03:43:13 pm
It seems that cycling the power to the USB adapter does something that "clear" does not.

Try adding this at the very end of the script.

Code: [Select]
SigGen.clear()
sleep(1)
SigGen.control_ren(pyvisa.constants.VI_GPIB_REN_ADDRESS_GTL)
SigGen.close()
rm.close()

The control_ren() function does just what it says, controls the REN (remote enable) signal on the GPIB according to a constant you pass it. Passing VI_GPIB_REN_ADDRESS_GTL puts the instrument back into local mode (equivalent to pressing the Local key on the front panel). The REN signal naturally goes away when you unplug the USB adapter. Having this function at the end of the script does the same thing programmatically.
Title: Re: Problems Writing code for GPIB Py VISA
Post by: coromonadalix on December 29, 2023, 04:13:08 pm
but it the other case, is there a "keep alive" communication, or maybe do some status polling ?? who would help prevent the disconnection from the 2520 ??

Title: Re: Problems Writing code for GPIB Py VISA
Post by: caiser01 on December 29, 2023, 10:09:21 pm
but it the other case, is there a "keep alive" communication, or maybe do some status polling ?? who would help prevent the disconnection from the 2520 ??

Never heard of a GPIB instrument that needed a communication heartbeat. That's not to say one couldn't exist.

I'm more inclined to say the Wavetek 2520 may just have a poor GPIB implementation. I have seen that multiple times.

If your program completes running cleanly and you want to run it again after some arbitrary length of time, the instrument should communicate again without issue. It sounds as though this instrument may get into a weird state if held in remote without interaction, which should not happen.

Apart from the script additions I suggested earlier, another thing to try is:
1. Run the script to completion
2. Press the Local key on the front panel
3. Leave it for a few minutes
4. Try running the script again

That will tell you if the issue indeed lies with the instrument being too long in remote mode without communication.
Title: Re: Problems Writing code for GPIB Py VISA
Post by: rcjoy on December 30, 2023, 07:42:27 am
You could try increasing the timeout time.  Try 10 or 30 seconds.  Just a guess.

Title: Re: Problems Writing code for GPIB Py VISA : writing bytes
Post by: dazz1 on January 06, 2025, 07:54:03 am
Hi
I am trying to write code for an Electro-Metrics EMC30 EMC test receiver.https://www.eevblog.com/forum/testgear/electro-metrics-em-30-emc-receiver/ (https://www.eevblog.com/forum/testgear/electro-metrics-em-30-emc-receiver/)

I am writing pyvisa code to write a command that sets the receiver frequency.  The command is 3 bytes of binary data.  I will write the numbers here in decimal for clarity, but the data sent is binary bytes.  The frequency control values are in the range 0-255. 
I am a python noob but I have been programming for 45 years.

The command format is:    255 xx yy
where:
xx = frequency course control byte
yy = frequency fine control byte.

So an actual command sent might look like:    255  102 47
The second two bytes are stored as decimal variables:  FreqCse and FreqFine.

My question is how do I write these 3 bytes to the gpib interface devices with pyVISA ??

I have tried a few different commands and variants.

The one that almost works is:

emc30.write(bin(255))
emc30.write(bin(FreqCse))
emc30.write(bin(FreqFine))

It doesn't matter what values I put in the two variable, the frequency always goes to zero  zero.

I have tried: emc30.write_binary_values(255), but that doesn't work.  I get an error message that says:  TypeError: ... missing 1 required positional argument: "values"
That looks like operator error. 

What is the correct way of writing 3x bytes to my device with PyVISA?





Title: Re: Problems Writing code for GPIB Py VISA
Post by: Kean on January 06, 2025, 09:49:25 am
What is the correct way of writing 3x bytes to my device with PyVISA?

I don't use PyVISA, but I believe you would want to encode the data in a bytearray (or bytes object).

Try this:
emc30.write(bytearray([255, 102, 47]))
or
emc30.write(bytes([255, FreqCse, FreqFine]))
Title: Re: Problems Writing code for GPIB Py VISA
Post by: dazz1 on January 06, 2025, 10:21:01 am
What is the correct way of writing 3x bytes to my device with PyVISA?

I don't use PyVISA, but I believe you would want to encode the data in a bytearray (or bytes object).

Try this:
emc30.write(bytearray([255, 102, 47]))
or
emc30.write(bytes([255, FreqCse, FreqFine]))

In a moment of desperation, resorted to reading the instructions found here:  https://pyvisa.readthedocs.io/en/latest/introduction/rvalues.html (https://pyvisa.readthedocs.io/en/latest/introduction/rvalues.html)
I tried using a list of decimal values (as you have done), typed as 'd', but that didn't work.  I think both a list of bytearray should work, but don't.

I have raised this as an issue here:  https://github.com/pyvisa/pyvisa/issues/883 (https://github.com/pyvisa/pyvisa/issues/883)    It shouldn't be this difficult to figure out.
Title: Re: Problems Writing code for GPIB Py VISA
Post by: Kean on January 06, 2025, 10:35:51 am
It looks like the write function only accepts a string.

Similar to the suggestion on your issue, you can try write_raw but with a byte array
Code: [Select]
emc30.write_raw(bytes([255, FreqCse, FreqFine]))
But based on the description of that function, you could hit an issue with certain byte values, like the XON/XOFF or even NUL ASCII codes.
https://pyvisa.readthedocs.io/en/latest/api/resources.html#pyvisa.resources.SerialInstrument.write_raw

Edit: I'm guessing you are using the PyVisa SerialInstrument for a USB serial to an Arduino for the GPIB interface.  In that case it appears that flow_control defaults to none...
https://pyvisa.readthedocs.io/en/latest/api/resources.html#pyvisa.resources.SerialInstrument