EEVblog Electronics Community Forum
Electronics => Projects, Designs, and Technical Stuff => Topic started by: cellularmitosis on September 02, 2017, 05:42:54 am
-
Gentlemen!
Though I've been working on a DIY GPIB project for a few months now, it was only recently that I started making some serious progress.
The two things which got me over the hump were:
- I found a good resource on how GPIB works: http://www.pearl-hifi.com/06_Lit_Archive/15_Mfrs_Publications/20_HP_Agilent/HP_7470A/HP-IB_Tutorial_Description.pdf (http://www.pearl-hifi.com/06_Lit_Archive/15_Mfrs_Publications/20_HP_Agilent/HP_7470A/HP-IB_Tutorial_Description.pdf)
- I started using a 16-channel logic analyzer
In this thread I'll post progress updates on this project, and also make some posts describing how GPIB works, with actual logic analyzer traces.
-
The initial board design lives on github:
https://github.com/pepaslabs/atmega-gpib
However, I made mistake on that board (I swapped the RX / TX pins, which is correctable in software, but prevents you from updating the firmware via the arduino bootloader, which means you have to de-socket the atmel chip every time you change the firmware...). Also, I used the FTDI chip for USB connectivity, and it is a bit of a pain to solder (very tight pin pitch).
In other words, don't use these gerbers and order a copy of the board -- I'll soon follow with an updated board design which corrects the RX/TX mistake and uses the MCP2221A for USB, which is DIP format.
-
Let's go through a worked example of sending some data to a Keithley 196 DMM.
To send a string to display on the K196, you use the "D" command, followed by the string to display. Commands are executed using the "X" command.
So, to display "M", you'd send "DMX" to the K196. To display "EEVBLOG", you'd send "DEEVBLOGX".
In order to send "DMX" to the K196, we first need to "address it to listen". This just means sending it "command byte" with its address in the listen mode.
Before we do that, we might also need to "reset the bus" -- tell all current talkers to stop talking and all current listeners to stop listening.
-
Unlisten, Untalk, and addressing a device to talk or listen
To address a device to listen, you send it a command byte which is simply its GPIB address, plus 32 (i.e. the hex value 0x20, i.e. bit number 6). To address a device to talk, the command byte is its address plus 64 (i.e. the hex value 0x40, i.e. bit number 7).
Valid GPIB address are 0-30. (It seems that by convention, the controller uses address 21).
GPIB address 31 is used for the "untalk" and "unlisten" commands.
My Keithley 196 is currently configured to use address 17 (which is hex 0x11)
To address it to listen, I'd send the command byte 0x31 (17 + 32, or 0x11 + 0x20).
To address it to talk, I'd send the command byte 0x51 (17 + 64, or 0x11 + 0x40).
To command all devices to stop listening ("unlisten"), the command byte would be 0x3F (31 + 32, or 0x1F + 0x20).
To command all devices to stop talking ("untalk"), the command byte would be 0x5F (31 + 64, or 0x1F + 0x40).
-
The handshake: sending and receiving bytes
So, we want to send the following sequence of bytes out on the bus:
- 0x3F: UNLISTEN (optional)
- 0x5F: UNTALK (optional)
- 0x31: Address device 17 to listen
- 0x55: Address device 21 to talk (optional)
- 0x44: "D"
- 0x4D: "M"
- 0x58: "X"
But how do we actually send them? GPIB uses three control lines to perform a "handshake", which gates the sending of each byte.
(GPIB isn't a clocked bus -- it is more like a parallel version of I2C, where the slowest participant on the bus determines the speed)
The three handshake lines are:
- DAV: Data Available
- NRFD: Not Ready For Data
- NDAC: Not Data Accepted
Most of the bus lines in GPIB may be either "driven" (tristate), or be operated in open-collector mode, except for these three handshake lines, which must be operated in open-collector mode.
The logic is active-low. This, combined with the open-collector scheme, allows a many-to-one communication scheme: many devices may pull a line low, and the last one to release the line will cause the line to flow high (via pull-up resistor), indicating to the controller than all devices have responded.
The handshake sequence is a bit confusing because of the inverted (active-low) logic. In the next post I'll describe it using more colloquial terms.
-
The handshake in plain english
First, let's start with a colloquial version of what's going on in the handshake sequence.
This is two iterations of the handshake loop (steps 1-6), with step 0 as a prerequisite.
(see attachment 1)
Now let's turn those colloquial phrases into their equivalent GPIB terminology:
(see attachment 2)
Notice that the talker is flipping one status, while the listener is flipping two statuses. This is because the listener is actually controlling two bus lines, whereas the talker is only controlling one.
Now, let's split these steps up into the three bus lines:
(see attachment 3)
Now let's add a bit of color to highlight the transitions between states (while also showing the state of every bus line at every step)
(see attachment 4)
Next, let's transform the statuses into TRUE / FALSE values
(see attachment 5)
Finally, using active-low logic, we can translate those into electrical logic levels (HIGH / LOW)
(see attachment 6)
-
REN
Also, you'll need to assert the REN line ("remote enable") for the duration of interacting with the listener.
-
ATN
The ATN line ("attention") is what distinguishes data from commands.
If we send the byte 0x3F (Ascii "?") without ATN asserted, then we are just sending an ASCII question mark as data.
But if we assert the ATN line while sending 0x3F, that tells the listener to interpret it as a command byte. 0x3F is the "unlisten" command.
-
Putting this all together, we can see what sending this byte sequence looks like to the logic analyzer:
For whatever reason, Pulseview's GPIB decoder isn't showing the final decoded byte ("X"), but if you look at the logic lines, the byte is there.
-
Looking more in-depth at the handshake, here's how those 6 steps map to the logic analyzer diagram.
-
prototype firmware
Here's the firmware for the current working prototype:
https://github.com/pepaslabs/atmega-gpib/blob/f063d4b4877ea3a536a97403e2d78c42cddd9fce/firmware/firmware.ino
This is currently a "boarduino" wired up to an MCP2221A.
To tell the arduino to talk to device 17, send "++addr 17\n" over the serial port.
Strings which don't start with "++" will be sent directly to the device, e.g. "DMX\n".
(the Arduino will also treat '|' as a newline character, which is useful if you need to send multiple commands at once, e.g. "++addr 17|DMX|").
To read one value (read until "EOI" is asserted), send "++read".
To read continuously in a loop, send "++stream".
As it turns out, simply addressing the Keithley 196 to talk will cause it to stream values forever, so capturing data from this device is as simple as sending "++addr 17\n++stream\n" to the Arduino.
-
You have made great progress. Once you have it all working, do you think it could port to the ESP32? No wires would be pretty slick.
Sent from my iPhone using Tapatalk
-
You have made great progress. Once you have it all working, do you think it could port to the ESP32? No wires would be pretty slick.
That's a fantastic idea!
-
We can also have a bit of fun with the "D" command 8)
(https://imgur.com/cTnzksX.gif)
https://imgur.com/cTnzksX
-
You have made great progress. Once you have it all working, do you think it could port to the ESP32? No wires would be pretty slick.
That's a fantastic idea!
I can't be much help with programming, but I'd be glad to provide some support, maybe getting some ESP32s or making a donation.
Sent from my iPhone using Tapatalk
-
CM, fantastic progress! You've done a super job of explaining the protocol. Even I think I get it now.
I'm looking forward to rev 2 of the board.
-
I triple vote for the ESP32! That would be one heck of an adapter! Not sure how good the Arduino toolchain is yet with the ESP32 though.
-
Here's some GPIB code that I wrote for a Mega Donkey LCD touchscreen micro controller board (MEGA128/MEGA2561). https://github.com/ron-grant/Mega-Donkey
It has a Prologix emulator in it. And, despite some of the comments, it does support DEVICE mode (at least for the device I was emulating at the time). There is a bunch of fluff in the file (like an emulator for another GPIB controller and some test routines).
With a little work you can extract the useful stuff. Should be easy to port to an Arduino, etc. Released under the MIT license.
-
With a little work you can extract the useful stuff. Should be easy to port to an Arduino, etc. Released under the MIT license.
SUUUUUH-WEEEEET!!!
Thanks man!
-
Cellularmitosis, have you verified the v2 board yet? If so, I'll have some made. I just can't take having to swap the chip every time I try and troubleshoot anything |O Thanks!
-
vindoline: I just got the board assembled, I'll make sure to verify it works this evening! 8)
-
vindoline, I was able to confirm that the board works, and that serial comms over the MCP2221 work.
Unfortunately, I neglected to add a reset button to this board design. I tried a work-around, where I simply soldered a jumper wire to ground, and then briefly touched the wire to pin 1 of the atmel chip. This does cause a reset, but I can't seem to get the Arduino software to upload new firmware via USB upon reset.
I'm not sure what I'm doing wrong. Here's a video showing the loop which the Arduino IDE seems to get into: each time I reset the chip, it tries to start transmitting the firmware, but then stops for some reason (just after the first TX activity, it appears). If I reset the atmel again, it tries to upload again, and then gets stuck again. https://www.youtube.com/watch?v=opIr1NTRDw8 (https://www.youtube.com/watch?v=opIr1NTRDw8)
Perhaps uploading via USB simply doesn't work for atmel chips which don't have an external oscillator?
-
The AVR internal oscillator is not very accurate. It is just borderline for UART operation. So the UART connection to the MCP2221 might be not that reliable and could cause trouble. It is especially a problem if there is an additional rounding error in setting the baud rate.
For reliable UART one usually needs a resonator or crystal or individual adjusted clock / baud rate.
-
CM, that's too bad :-[ I'm assuming that the chip has the correct boot loader on it for using the internal oscillator. Other than that, I have no idea.
-
There could also be a problem with the supply voltage / to little decoupling. During writing the flash the µC likely needs a higher current. So a weak regulator could be a problem too. At least I can not see TH decoupling caps. It is OK if there als SMD one on the back - usually no problem to add same afterwords.
The clock is borderline accurate for UART, but with a 5 V supply and not to extreme temperature it usually works, but one should consider the clock a possible error source.
-
Thanks guys, I'll try to reproduce the problem on a breadboard, then throw a logic analyzer at it.
-
Cellularmitosis, has there been any progress on the GPIB project as of late? I'm hoping to be able to put a bit of effort into it and I have a question about your ver 2 pcb. What is the purpose of the "error" led and the configuration jumper? I can't find any reference to these in the code. I may layout a new pcb for this and I'd like it to be compatible with your programming efforts. Thanks.
-
Here's some GPIB code that I wrote for a Mega Donkey LCD touchscreen micro controller board (MEGA128/MEGA2561). https://github.com/mega-donkey
It has a Prologix emulator in it. And, despite some of the comments, it does support DEVICE mode (at least for the device I was emulating at the time).
That's cool, texaspyro. Does that mean that one could use this as a base for making an adapter to add GPIB (e.g., reading values) to pre-GPIB era hardware?
-
Here's some GPIB code that I wrote for a Mega Donkey LCD touchscreen micro controller board (MEGA128/MEGA2561). https://github.com/mega-donkey
It has a Prologix emulator in it. And, despite some of the comments, it does support DEVICE mode (at least for the device I was emulating at the time).
That's cool, texaspyro. Does that mean that one could use this as a base for making an adapter to add GPIB (e.g., reading values) to pre-GPIB era hardware?
It should be able to do so. I added DEVICE support to do one thing that needed to be done one dark and stormy night in the before times. It did what I needed it to do, but have never really banged on it much.
-
Nifty. I'll have to explore that some more when I refurbish my HP 5216A counter. It has a card edge "printer" port on the back.
-
We can also have a bit of fun with the "D" command
Thanks for your research! It got me headed in the right direction for my 196 GPIB efforts. I'm using Keysight's latest Connection Expert, Python 2.7.14 and PyVISA 1.8, so YMMV. Here a couple of little programs:
#Run autoCal
import sys
import time
import visa
visa = visa.ResourceManager()
print(visa.list_resources())
DMM196 = visa.open_resource('GPIB0::8::INSTR',send_end=True, read_termination= '\r\n', write_termination='\r\n')
DMM196.write("DX")
DMM196.write("DAUTO CALX")
DMM196.write("A1X")
time.sleep(10) # 1 sec increments
DMM196.write("DX")
print 'done'
#Read some measurements to a file
import sys
import time
import visa
visa = visa.ResourceManager()
print(visa.list_resources())
DMM196 = visa.open_resource('GPIB0::8::INSTR',send_end=True, read_termination= '\r\n', write_termination='\r\n')
DMM196.write("DX")
DMM196.write("F0R3S3P60X")
DMM196.write("DF0R3S3P60X")
print ''
data = open('dataDMM196.csv','w')
print (data)
for x in range(0, 200):
print (DMM196.read()[4:17])
data.write (DMM196.read()[4:16] +'\n')
time.sleep(1) # 1 sec increments
data.close()
The VISA library (Keysight version at least) makes the communication easier over GPIB, so I don't know how it would translate into Arduino, etc.