Wednesday, February 5, 2014

Arduino UNO as a USB to GPIB adapter / controller


NOTE:
This version is OBSOLETE!! Please go to this post for the 6.1 release software and documentation.
---

Version 1 of this project is aimed to provide a cheap and quick GPIB solution to those that need to gain control over a single instrument and interact with it (e.g. to calibrate instruments that can be calibrated by GPIB only -- 6632A Power Supply being a good example).

I supposed that cheap adapters were available on the market to interface GPIB instruments with a PC. I was wrong. The only feasible solution is to go with a Prologix USB to GPIB converter, still it would have cost me some tens of bucks.
Other solutions required buying or building hardware.

On the other end I had an Arduino UNO floating around on my bench waiting for a problem to solve other than blinking leds or writing "hello world" on an LCD..

So I decided to face the challenge of writing down a c++ program and have the Arduino play the adapter role I was looking for.
To make a long story short.. (I supposed that GPIB was simple at least as much RS-232 is, .. and it is not! I was wrong again!) after reading a lot of IEEE-488 documentation and giving a try to a similar program I found over the internet, I got a decent implementation of a GPIB controller out of my Arduino UNO. This post is dedicated to describe the project.

Because of the hard effort I put on the project, I kindly request you to donate a couple of bucks if you find this program useful for your hobby.




Download GPIB1_0.hex file by right click and save link as..

Below you'll find the program documentation describing the implemented functionalities, limitations, commands syntax and hardware required (close to null.., just a bunch of wires and a plug).

====

Disclaimer:
This program is provided as is. It is a hobby work.
It doesn't work correctly. It has not been tested. It can damage your Arduino and the device you connect it to.
Can have unexpected behaviors, can get stuck at any moment, can read and write data to/from the device in ways you might not expect. It can send wrong or erratic commands to the device. Can display data that differ from the actual data the device sent out. Can address GPIB devices
differently from what you might expect.
I have not conducted any speed test; the maximum speed supported is simply unknown.
Is does not follow any official standard. Only a minimum set of the functions included in IEEE-488 is barely emulated.
Hardware limitations: the lack of a GPIB line driver has two major implications: first: your Arduino is directly connected to the device GPIB port without any form of electrical protection of buffering - this can potentially damage your Arduino and/or your device; second: what can happen if you connect more than one GPIB device to the BUS is unpredictable both from an hardware and software point of view. I only experimented with a single GPIB device connected to the BUS.


This program is inspired  by a similar job done by IW3IIF who started from what he has found at
http://www.bananawani-mc.blogspot.fr.

----

Introduction

This program is an attempt to have the Arduino to implement a GPIB controller. The objective was to have a way to get control of test instruments to send and receive commands to/from such devices via GPIB.
Future implementation may include binary data transfer mainly aimed to get plot data out of test instruments like oscilloscopes or spectrum analysers.
This is version 1.0. As everybody knows nobody should trust version 1 subversion 0 of any program... but that's it. Give it a try.
Despite the disclaimer I can say that the objective has been successfully met; with this program uploaded to an Arduino UNO I can now control my hobby lab GPIB instruments and even calibrated some of them. I hope it can work with yours as well.
There are a bunch of actual limitations:
- the program operates in controller mode only; it is not (yet) able to behave like a device.
- two important GPIB pins are not correctly managed: REN and SRQ.
- Serial poll is not implemented.
- subaddressing is not implemented.
- only ASCII transfer have been tested. It shouldn't be too difficult for me to implement binary transfers in version 2...

Hardware set up instructions:

The hardware needed is simple: just a bunch of wires from the GPIB plug to Arduino pins. Here is the pin mapping:

  A0   GPIB 1
  A1   GPIB 2

  A2   GPIB 3 
  A3   GPIB 4
  A4   GPIB 13
  A5   GPIB 14
  4    GPIB 15
  5    GPIB 16
  12   GPIB 5
  11   GPIB 6
  10   GPIB 7
  9    GPIB 8
  8    GPIB 9
  7    GPIB 11


NOTE:
 GPIB pins 10, 17-24 goto GND, but:
  •  GPIB pin 17 (REN) has to be investigated further ..stay ready to reroute it differently in the future;
  •  GPIB pin 10 (SRQ) has to be investigated further ..stay ready to reroute it differently in the future;
  •  GPIB pin 12 should be connected to the cable shield (not used here - I left it n/c).
Build the the shield the way you want. Nothing is simpler provided you have a minimum electronic construction skills.
For testing I preferred the "flying" shield visible in the pictures but the actual construction is your choice.
The male GPIB connector was realized sacrificing a CENTRONICS 32pins male connector out of a PC parallel printer cable. I have just cut it leaving 12 positions out of the original 16.

Get it working

Get any terminal emulator and manage to have it working with the FTDI RS232/USB converter (nothing to do in linux/UNIX; install the driver in Windows). I have tryed it with the serial display provided by the arduino IDE and putty under Linux. Nothing let me suspect it shouldn't work with HyperTerminal under Windows or similar programs. Just give it a try.
You probably have to set the some serial communication parameters.
The default serial speed is 115200 bps.
Other serial parameters are: Data_bits=8, Stop_bits=1, Parity=None, Flow_control=None.
If everything is working you should have the Arduino output the welcome message: "I am a GPIB controller now" followed by the ">" prompt.

Principle of operations

Everything received from the USB is passed to GPIB (131 char max).
Characters are fetched in one by one and buffered; at the moment only ascii transfer is supported, so you can send command to the device. The software support for both CR, LF and CRLF line termination. Once the line termination char is encountered in the USB input stream the entire buffer gets parsed. If you need to include CR or LF in the input stream you must rely on the help of the linux serial device driver using ^V in front of ^M or ^J (see stty manual). Still the ^V mechanism is not enough. ^V prevents the linux driver from sending out your line, but still the received CR or LF are interpreted as end of line by the Arduino. To avoid this an escape mechanism has been implemented. The escape char is "\". So to send CR to the BUS you need to write "\^V^M" and similarly for LF. To send a single "\" you must escape it with "\" so you need to send "\\". In the Arduino serial monitor you can terminate the input line with "\" so that the following CR or LF will be escaped. If you insert unescaped CR or LF in the stream (e.g with "^V^M" sequence with no preceding "\") the line is split in two parts: everything preceding the CR or LF is passed on for processing; everything following the CR or LF is simply discarded.
WARNING: if you use buffered I/O on the sender side, and you often do, be aware that sending more than 64 chars per line can lead to serial buffer overflow as my program cannot keep pace with the burst of characters coming in @115200bps. Yet, the program detects this situation, issues a "Serial buffer overflow - line discarded. Try setting non buffered I/O" message and discards the line entirely. As the error message suggests, you can switch you sender (terminal emulator) to unbuffered I/O so that it sends out one char at a time. If you are typing at a keyboard the problem is solved (unless you are typing at the speed of light); if the data comes from some kind of script, care must be taken to send small chunks of data introducing delays to allow for the program to eat them.

Implemented commands:

NOTE: the command interpreter is very raw: I remember from high school that they have to be programmed in a certain way, but I don't really remember how; so I did my best. Misspelled commands will (better: should) generate a Syntax error message. As soon a Syntax error is detected the line is discarded entirely. After a valid command has been recognised, any additional characters following it (if any) is discarded.

++addr [address] 
address can be any number between 1 and 31.
Without any parameters it displays the current setting of the address stored within the Arduino and used to address any communication (read or write).
If address is present the command will set the address to the specified number.
Any character after a valid command is discarded, so "++addr 4 fakechars" will change addr to 4 and "fakechars" is discarded. "++addr 4s" will also change addr to 4 and the leading "s" is discarded.
The addr parameter can start with "0" so "++addr 03" is a valid command.

++ver
just displays a version number of the controller

++auto
just toggle between auotomode ON and automode OFF. Default is OFF.
But what is automode? Ok, you have to know that GPIB devices do not work the way we are used to with modern devices. When you send a command they process it and if any output is generated they put it to a buffer waiting to be addressed to speak. The final result is that just to get the identification string out of a device you have to send the request command (e.g "id?") and then issue the command "++read" to the controller. Automode ON just makes this for you: for every string sent to GPIB, the controller issues an implicit "++read" to the addressed device. This gives you the impression to have the device immediately react in front of the string you sent it. Beautiful! ...however a hidden trap is around: some GPIB device gets upset if asked to speak when it has nothing to say and with automode ON this can happen very often (e.g. if you just press CR, an empty string is processed and, because of automode ON, the device is immediately asked to speak, even if nothing has been sent to it). I have a device that lights the error annunciator on the front panel when this situation occurs, but yet it continues working as nothing happened.

++read
Asks the currently addressed device to speak. Everything received is sent upstream to the USB. The stream is buffered (132 chars max) and this is the limitation preventing me to implement bulk binary transfers. V2 will try to overcome this issue.
If automode is ON issuing the "++read" command causes TWO reads in rapid succession. This is not always welcome by GPIB devices...

++clr
Sends a SDC command to addressed device. Reaction to this command is device dependent, but all the devices I know about react with a power on reset at least at GPIB interface level.

++ifc
Sends a (universal) DCL to the BUS. This is a BUS command sent to the BUS and not to a single devices. Reaction to this command is device dependent, but all the devices I know about react with a power on reset.

++eos [mode]
mode can be any number between 1 and 3. Default is eos=1.
Without any parameters it displays the current setting of the eos;
mode=0 means that the controller will send CRLF as the last character in the stream sent to GPIB;
mode=1 means that the controller will send CR as the last character in the stream sent to GPIB;
mode=2 means that the controller will send LF as the last character in the stream sent to GPIB;
mode=3 means that the controller will not send any special char as the last character in the stream sent to GPIB;
In any case, when transmitting the last character, the controller asserts the EOI GPIB line, a line most devices are able to manage.
The command syntax follows the same rules of the +addr command.

How to upload  the HEX file to your Arduino

I learned how to do an HEX upload to Arduino reading a post on the Arduino official forum (http://forum.arduino.cc/index.php?topic=120286.0).

The idea is to use the same command the IDE uses to upload just compiled files.
Assuming you have the IDE correctly setup and up and runing, you need to do the following:

  • in the Arduino IDE select File-> preferences and check the "Show verbose output during -> upload" checkbox;
  • compile a simple example sketch (e.g blink.ino is ok);
  • look at the IDE output and examine the "avrdude" command (the actual upload program used by the Arduino IDE);
  • use exactly the same command to upload the GPIB1_0.hex file.

Here is the command that works for me (everything in fixed font goes on a single line):
/home/emanuele/arduino-1.0.5/hardware/tools/avrdude -C/home/emanuele/arduino-1.0.5/hardware/tools/avrdude.conf -v -patmega328p -carduino -P/dev/ttyACM0 -b115200 -D -Uflash:w:/home/emanuele/sketchbook/GPIB/GPIB.hex:i
A short explanation:

-C/home/emanuele../../avrdude.conf -> configuration file
-v -> verbose; you can omit it or add more (e.g. -v -v -v) to get more output
-patmega328p -> partnumber atmega328p
-carduino -> programmer is arduino
-P/dev/ttyACM0 -> the serial port your arduino is connected to
-b115200 -> baud rate - upload speed
-D -> diasables erasing
-Uflash:w  -> Write to Flash memory
/home/emanuele/sketchbook/GPIB/GPIB.hex  -> path and file name to the hex file
:i   -> optional, indicates an Intel hexfile

Feedbacks

With version one what I am interested in is to have somebody give it a try and report me feedbacks like:
my instrument times out often,
this input string doesn't work as expected,
my instrument gets stuck when ... ,
etc. etc. ...

Future development

I am going to improve it by bug fixing and keep the documentation deep and updated and working on Version 2 that will wide the project scope up to:
  • device mode to accept binary transfers (aimed to screen plots),
  • a closer  "++" compatibility,
  • settings save/restore,
  • serial poll support (if not too difficult),
  • porting to smaller Arduino platforms.

Conclusions

Enjoy you GPIB controller and do not forget to donate some buck just to recognize the effort I made to develop and document this project.
Thank you!
Emanuele.




Download GPIB1_0.hex file by right click and save link as..