Introduction

In the past year, I’ve bought a bunch of measurement devices from a retired hobbyist who has been downscaling his (extensive) RF lab. During my last visit, he offered to add some extras for free, including a Racal-Dana 1992 Universal Counter.

Racal-Dana 1992 Universal Counter

A 1992 can be used as a frequency counter, to measure the delay between two signals, to calculate the clock frequency ratio between 2 signals, and various other special functions, for frequencies all the way up to 1.3GHz. And with up to 10 digits of precision, you get to measure the frequency of your 10MHz crystal oscillator down to the milliHz (but only if your reference clock is accurate enough…) When you start digging into the wonderful world of Time Nuts, the 1992 seems to be well respected. There’s a known issue with the flaky front panel switches, but there are plenty of Youtube video describing how to fix it.

I didn’t know it at the time, but its Buy-It-Now price on eBay is often higher than $500! Thanks, John!

My device came with option 55, a GPIB interface, and option 04E, a high stability oven controlled crystal oscillator (OCXO). John calibrated the instrument with his GPS disciplined oscillator (GPSDO) as reference.

I’ve been looking at making a GPSDO myself, and thought it’d be interesting to use the 1992 to record the phase difference between the raw, high jitter, GPS pulse-per-second (pps) signal that comes out of my cheap M8N GPS receiver module, and the equivalent signal that’s generated by the GPSDO. The first step to make that happen is establish communication between my PC and the 1992 using GPIB. It should be relatively easy to do, but some well-placed booby-traps turned it into something that took a whole day before everything was working as expected.

This short blog post describes the road blocks and how to get past them.

GPIB: MATE/CIIL vs default protocol

The issue that took most of my time was getting the 1992 to talk the right protocol. Section 5 of the User Manual is straightforward enough: you send a string with one or more 2 or 3 characters and optional numerical parameters, and the device will sometimes reply with a string that’s always 21 bytes long.

The problem was that this didn’t work at all. When I sent the internal self-test CK command, I could see some LEDs temporarily flickering on the front panel and see the REM (remote) LED switch permanently on, but every further GPIB transaction resulted in an error, and the device didn’t actually switch to CK mode either…

I eventually stumbled into this conversation on the EEVblog forum, which mentions the existence of an SK4 jumper on the military version of the GPIB board that must be set in the right position. It also links to an amended version of the manual, with the following diagram at page 200/7-22:

SK4 diagram

Opening up the 1992 can be done by removing just 2 screws, after which you can slide out the bottom cover first, followed by the top:

SK4 jumper in the chassis

Here’s a closer look:

SK4 jumper zoomed in

This is how the jumper should be positioned if you want the GPIB interface to work as described in the manual. In my case, the jumper was placed over the 2 pins right above it.

In that other position, the GPIB interface will conform to MATE/CIIL specification. Check out my updated blog post about test and measurement protocols to learn more about it.

There are multiple versions of the GPIB interface board. From what I’ve been able to figure out, only version 401820 has the SK4 jumper. It’s part of option 02M which adds support for MATE/CIIL.

Missing GPIB EOI at End of Message

With jumper SK4 in the right position, the 1992 immediately behaved as expected when sending configuration commands: CK puts it into self-check mode, PA switches to period measurement on channel A, and so forth.

Reading data back was still an issue.

I’m using pyvisa for my GPIB adventures.

Here’s the code that you’d expect to work:

import pyvisa

pyvisa.log_to_screen()
rm=pyvisa.ResourceManager()
inst = rm.open_resource("GPIB::14")
inst.write("RGS")
inst.read()

The RGS command is supposed to return the firmware version of the device, but the code times out:

Traceback (most recent call last):
2022-12-14 14:48:52,877 - pyvisa - DEBUG - GPIB0::14::INSTR - reading 20480 bytes (last status <StatusCode.success_max_count_read: 1073676294>)
2022-12-14 14:48:56,053 - pyvisa - DEBUG - GPIB0::14::INSTR - exception while reading: VI_ERROR_TMO (-1073807339): Timeout expired before operation completed.
Buffer content: bytearray(b'')
  File "<stdin>", line 1, in <module>
  File "/home/tom/.local/lib/python3.8/site-packages/pyvisa/resources/messagebased.py", line 486, in read
    message = self._read_raw().decode(enco)
  File "/home/tom/.local/lib/python3.8/site-packages/pyvisa/resources/messagebased.py", line 442, in _read_raw
    chunk, status = self.visalib.read(self.session, size)
  File "/home/tom/.local/lib/python3.8/site-packages/pyvisa_py/highlevel.py", line 519, in read
    return data, self.handle_return_value(session, status_code)
  File "/home/tom/.local/lib/python3.8/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.

The solution came, once again, after finding this EEVblog forum post:

I remember back when I was trying to get my 1992 working on GPIB, there was an issue with the EOI line. Apparently, the 1992 doesn’t use it. Make sure that your program isn’t expecting it.

This comment on a National Instruments forum gives more details about EOI:

The best default termination character is none. GPIB (IEEE 488.1) defines a special hardware line, EOI, which is asserted with the last byte to signify the end of a transfer. You should rely on this method to terminate a GPIB transfer, as opposed to a termination byte that is stuffed into the bytestream. Some older devices (primarily those that were initially RS-232) use only an EOS character, and that can be CR, LF, or CR-LF, which is why the option exists to terminate a read transfer on EOS with NI-488.2.

Most devices (such as those following the IEEE 488.2 protocol) use both (they send an LF at the end with EOI asserted). Even in that case, however, you should only really be concerned with the EOI since that is the native termination of the GPIB.

So here’s what’s happening:

  • All messages from the Racal 1992 to the controller, your PC, are exactly 21 bytes.
  • The messages end with 2 termination characters.
  • The GPIB EOI line is never asserted to indicate the end of a message!

The pyvisa read() and read_raw() commands keep on reading until they see EOI, even if you specify a size of 21 with read_raw()! The only way to correctly read the data is by using read_bytes().

Like this:

import pyvisa

rm=pyvisa.ResourceManager()
inst = rm.open_resource("GPIB::14")
inst.write("RGS")
inst.read_bytes(21)      <<<<<<<<<<

When to Read Measurement Data

A final, minor, issue was knowing when the 1992 returns data.

Most instruments have a request-reply protocol, where the instrument only has data ready to be read after the controller asks for it.

Not so for the 1992: it will indeed prepare data to be read after it has been sent a command that starts with an Rxx, but it also places data in a read-data FIFO whenever it completes a new measurement. Note also that there is no Rxx command to read back measurement data, you just have to assume that there’s going to be data available when you issue a GPIB read. If not, then pyvisa will time out.

When you send an R command, the read-data FIFO gets cleared, you can be sure that the first data after an R will be the data that you requested.

If you can’t predict whether or not there’ll be data available in the read-data FIFO, e.g. because you’re measuring events that don’t happen at predictable points of time, then you can program the 1992 with the Q2, Q3, Q6 or Q7 command to assert the GPIB SRQ (Service ReQuest) line when there’s data available, and use the pyvisa wait_for_srq() function.

Racal 1992 SRQ Config Commands

Unfortunately, SRQ handling is not supported on a Linux machine with pyvisa and the low-level pyvisa-py driver, so I wasn’t able to test that.

A decent alternative is to manually poll the GPIB status byte which has the following status bits:

Racal 1992 GPIB Status Bits

Note that the numbers starts with 1 instead of 0!

In pyvisa, you can check this status byte with the stb property.

Bit 4 (starting from 0) will be set when there’s data waiting to be read.

Here’s an example of an stb based polling loop:

import pyvisa
rm = pyvisa.ResourceManager()
inst = rm.open_resource("GPIB::14")

while True:
    while (inst.stb & 0x10) == 0:
        print(".", end='', flush=True)
        pass
    print(inst.read_bytes(21))

And here’s the result:

.............b'CK+0010.0000000E+06\r\n'
.............b'CK+0010.0000000E+06\r\n'
.............b'CK+0010.0000000E+06\r\n'
.............b'CK+0010.0000000E+06\r\n'
.............b'CK+0010.0000000E+06\r\n'
.............b'CK+0010.0000000E+06\r\n'
.............b'CK+0010.0000000E+06\r\n'

The other alternative is to program is very large timeout:

inst.timeout=10000

Weird Modal Syntax Error Behavior with 3-character Commands

On my system, all the example code above worked fine… until it didn’t. I don’t know what happened, but from one moment to next, all commands with 3 characters resulted in a syntax error, as indicated by the stb property:

import pyvisa
rm = pyvisa.ResourceManager()
inst = rm.open_resource("GPIB::14")
inst.write("RGS")
print("STB: 0x%02x" % inst.stb)
STB: 0x25

The 3 LSBs of STB contain the error code, and a value of 5 means “Syntax error in GPIB command”.

My 1992 was not able to recover from it. (It still hasn’t!) Sending the instrument preset IP command, power cycling the unit, rebooting the PC, unplugging the GPIB dongle, none of that has worked.

I found 3 ways to work around it:

  • Add a space in front of each command

    Instead of this:

    inst.write("RGS")
    

    Do this:

    inst.write(" RGS")
    
  • Change the GPIB write terminator from \r\n to \n\r

    I have no idea why this makes a difference, but it does.

    This is magical pyvisa incantation:

    inst.write_termination='\n\r'
    

    This has the benefit over adding a space that you only need to do this once, but it has the potential disadvantage that it may not work on an instrument that doesn’t have my issue.

    You can select the correct terminator by checking for syntax errors. Like this:

    inst.write_termination='\r\n'
    inst.write("RUT")
    if (inst.stb & 0x7) == 5:
      inst.write_termination='\n\r'
      inst.write("RUT")
    if (inst.stb & 0x7) == 5:
      raise Exception("Can't find working write termination!")
    else:
      # Read data from dummy RUT command
      unit_type = inst.read_bytes(21)
    
  • Don’t assert EOI for write operations

    When using ibtest, which is part of the Linux GPIB tools, I’m also able to make it work by instructing it to not send an EOI at the end of a transmission (o followed by 0).

    However, pyvisa doesn’t give you the option to not send EOI.

I’ve been working a Racal-Dana 1992 driver for pymeasure. Since I’m the one who’s writing it, I can use the first option without the need to fiddle with termination options.

It’s unsettling when something that used work perfectly fine suddenly doesn’t, with no known way to restore things. If anyone has an idea, I’d love to hear about it! You can file an issue on GitHub or send a direct message to my Twitter or Mastodon account.