Rigol DS1052E USB

I recently purchased a Rigol DS1052E. It is a nice scope for a reasonable price. One feature I really appreciate is that it has support for the USB Test and Measurement Class (USBTMC). This feature allows GPIB commands to be sent through USB to control the scope and capture data from it.

I spent a couple of hours the other day trying out the USB interface and I thought I would write up my initial experience working with USBTMC in Linux since there are quite a few different options and potential gotchas.

First, there are a few different options I looked at for communicating to USBTMC in Linux. The options included:

NI-VISA

I have used NI-VISA in the past at work and wasn’t a big fan of the setup – it was clunky for my needs and I like to have access to the code from top-to-bottom. From prior experience I felt I could get the functionality I needed out of the open offerings with a simpler implementation so I didn’t pursue the NI-NISA drivers for this test. That said: others have reported sucess with the Rigol scope and NI-VISA.

Agilent USBTMC

Initially I didn’t realize that the Kernel comes with a standard USBTMC driver and Ubuntu has the driver/module precompiled for use so my first attempt was with the Agilent USBTMC Kernel driver. The driver they created is a bit outdated and will not compile as-is with a current day kernel.

To get it to compile as a quick-and-dirty test I ended up commenting out the ioctl interface. After doing that I loaded the module and was able to see the *IDN? information from the scope but my machine soon crashed after.

Linux Kernel USBTMC Driver

Once I knew what device name to look for I realized that Ubuntu was already identifying the device and creating a device interface for it. I should have been less hasty and read the system logs when I plugged it in.

Knowing that a driver was already loaded and device file available to talk to I set out trying some standard GPIB commands in C.

My first application was as follows:

#include <stdio.h>
#include <string.h>

void main(int argc, char **argv)
{
    char c;
    int count=0;

    FILE * scope;

    if(argc < 2)
        return;


    scope = fopen("/dev/usbtmc0", "rw+");

    fputs(argv[1], scope);

    if(strchr(argv[1], '?') != NULL )
    {
        do
        {
            c = fgetc(scope);
            putc(c, stdout);
        } while(c != EOF && count++ != 0x261);
        putc('\n', stdout);
    }

    fclose(scope);
}

I started by reading the "*IDN?" value and received that back, but it took a while and I was getting log messages like this:

[82398.253756] usbtmc 5-1.3:1.0: Unable to read data, error -110

It was interesting that when I tried to issue the following set of commands the scope crashed:

kkurbjun@supamonk:~$ ./test ":STOP"
kkurbjun@supamonk:~$ ./test ":WAV:POIN:MODE NOR"
kkurbjun@supamonk:~$ ./test ":WAV:DATA? CHAN1" > dump

It appears that a lot of people have had problems with the USBTMC driver in Linux.

OpenMoko libUSB

After the scope crash I started looking into the OpenMoko libUSB implementation because some people had suggested it was more reliable and it is more portable. I tend to wipe my computer periodically to keep it clean though so I wanted to find a reliable way to use the scope with the standard kernel module so that it would work on a fresh Ubuntu install with minimal application complexity. Because of this I didn't go far into the OpenMoko driver.

Cleaning it up

After looking at the driver it appeared that it should output the amount of data sent back from the scope, but something was being lost using the ANSI C file accessors. Since the Kernel module is (or is nearly) a direct wrapper for the POSIX read operation, I thought I would try a different approach:

#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>

void main(int argc, char **argv)
{
    char c;
    int count;

    char buffer[2048];

    int scope_id;

    if(argc < 2)
        return;

    scope_id = open("/dev/usbtmc0", O_RDWR);

    write(scope_id, argv[1], strlen(argv[1]));

    if(strchr(argv[1], '?') != NULL )
    {
        count = read(scope_id, buffer, sizeof(buffer));
        buffer[count+1] = 0;
        printf("%s\n", buffer);
    }

    close(scope_id);
}

After using the POSIX file operators everything ran smooth. I suspect that the file IO accessors in the kernel module are incomplete, but I have not taken the time to dig into them. For now using POSIX file IO seems to be doing the trick.

In the end using the standard Kernel module works for me, but it does appear that there are some caveats based on other people's experiences. If you want to create something more portable it might be better to look into the OpenMoko implementation from the beginning.

Comments Off on Rigol DS1052E USB

Filed under Hacking

Comments are closed.