HP 3458A GPIB remote control guide



HP 3458A instrument is really meant to be remotely controlled via GPIB interface, to use all it’s capabilities. Front panel is not meant for easiest operation, and require decent amount of time invested into programming button scripts and subroutines to perform common tasks quickly.

If you interested in internal construction, hardware design and/or repair of your instrument, refer to this HP3458A restoration worklog article. This article is focused on remote GPIB operation only.

HP 3458A does not support popular SCPI command protocol, so it’s programming differ to most of modern instruments and need some time to get familiar with.


Redistribution and use of this article or any images or files referenced in it, in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

  • Redistributions of article must retain the above copyright notice, this list of conditions, link to this page (/article/hp3458a_gpib/) and the following disclaimer.
  • Redistributions of files in binary form must reproduce the above copyright notice, this list of conditions, link to this page (/article/hp3458a_gpib/), and the following disclaimer in the documentation and/or other materials provided with the distribution, for example Readme file.

All information posted here is hosted just for education purposes and provided AS IS. In no event shall the author, xDevs.com site, or any other 3rd party, including HP/Agilent/Keysight be liable for any special, direct, indirect, or consequential damages or any damages whatsoever resulting from loss of use, data or profits, whether in an action of contract, negligence or other tortuous action, arising out of or in connection with the use or performance of information published here.

If you willing to contribute or add your experience regarding HP/Agilent/Keysight instruments or wish to provide extra information, you can do so following these simple instructions

Manuals references

Raspberry Pi + Python GPIB

HP3458 uses “ID?” instead of “*IDN?” to return ID string.


Example program to sample 10V DCV and output display data. To save VFD life, you may want to output just empty spaces.

# xDevs.com Python test GPIB app for HP 3458A, GPIB ADDR 1
# https://xdevs.com/guide/ni_gpib_rpi/
# https://xdevs.com/article/hp3458a_gpib/
# https://xdevs.com/fix/hp3458a/
import sys
import Gpib
import time

with open('10v.csv', 'a') as o:

    inst = Gpib.Gpib(0,1) # Instrument GPIB Address = 17
    inst.write("PRESET NORM")
    inst.write("OFORMAT ASCII")
    inst.write("DCV 10")
    inst.write("TARM HOLD")
    inst.write("TRIG AUTO")
    inst.write("NPLC 200")
    inst.write("NRDGS 1,AUTO")
    inst.write("MEM OFF")
    inst.write("END ALWAYS")
    inst.write("NDIG 9")
    inst.write("DISP MSG,\"                 \"")
    inst.write("DISP ON")
    #data = inst.read()
    #print data

    min = 0
    while min <= 10000000:
        inst.write("TARM SGL,1")
        data = inst.read()
        print time.strftime("%d/%m/%Y-%H:%M:%S;") + ("[%8d]: %16.16f" % (min, float(data) ) )
        o.write (time.strftime("%d/%m/%Y-%H:%M:%S;") + ("%d;%16.16f;\r\n" % (min, float(data) ) ))

Long operations

ACAL DCV procedure takes about 150 seconds to complete. Full ACAL ALL takes 832 seconds to complete.
This can be useful to set delays in code to allow meter perform auto-calibration to minimize errors.

Calibration examples

There is a way to read internal voltage and resistance references by issuing next commands:

Command Result before cal Result after cal and A9 tweak Meaning
CAL? 1,0 40.0000000E03 40.0000000E03 default value
CAL? 1,1 39.9995999E03 39.99987145E03 actual value = cal value
CAL? 1,0 40.0800000E03 40.0800000E03 max. actual value
CAL? 1,0 39.9200000E03 39.9200000E03 min. actual value
CAL? 2,0 7.20000000E00 7.20000000E00 default value
CAL? 2,1 7.07422543E00 7.06747856E0 actual value = cal value
CAL? 2,0 7.50000000E00 7.50000000E00 max. actual value
CAL? 2,0 7.00000000E00 7.00000000E00 min. actual value

Also here’s toolkit to read calibration ROM via GPIB interface:

Windows utility to read CALRAM

Win version, after ACAL DCV,OHMs, decode
Win version, after ACAL DCV,OHMs, binary

ELF-exec for Raspberry Pi Linux version – this one can also read firmware ROM

Linux version, RPI, text decode
Linux version, RPI, binary

Credits go to KE5FX and folks on EEVBlog

root@pi2:/repo/3458_cal# ./hp3458
HP3458A NVRAM data dumper program. Version 1.10
   Who knows if this thing really works?
   Trust, but verify... use at your own risk.

Program usage:
   HP3458 file_name /option /option ...
   (ROM image binary data is written to file_name.hi and file_name.lo)
   (text data is written to file_name)

Valid opations are:
   /a=addr - use GPIB device address *addr* (default is 22)
   /d      - dump DATA rams (default is CAL ram)
   /e=#    - set end-of-string char (default=13, 0=none)
   /o[=#]  - reset destructive overload counter in CAL RAM image
   /x      - ignore GPIB errors.

This tool also can reset destructive overload counter in readed dump, if you doing service on the unit and need fresh calibration.

Automatic Python-tool to log data to FTP

For remote long-time (days and weeks) it’s useful to setup automatic script to perform add the monkey job. Crude python application below will interact with three instruments on GPIB interface. Program is tested and running on Raspberry Pi with NI USB-GPIB-HS dongle.

Instruments under control are:

Source set manually to output +10.00000 VDC, which we will sample with DMMs and format into CSV-file (actually it’s DSV, with semicolor delimiter).
This file will be written to remote FTP location for automatic graph plotting. In this case we used data storage for DMM logs, datashort, which probably familiar to our readers by this article.

# xDevs.com Python test GPIB app.
# https://xdevs.com/guide/ni_gpib_rpi/
# https://xdevs.com/article/hp3458a_gpib/
# https://xdevs.com/fix/hp3458a/
import sys
import Gpib
import time
import ftplib

port = 21
ip = ""
password = "datashort"
user = "datashort"

gen = Gpib.Gpib(0,2, timeout=20) # 3245A GPIB Address = 2
inst = Gpib.Gpib(0,3, timeout=20) # 3458A GPIB Address = 3
kei = Gpib.Gpib(0,16, timeout=20) # K2001 GPIB Address = 16
#Setup HP 3245A
gen.write("DISP MSG,\"             \"")     # Turn off 3245A display
gen.write("DISP ON")
#Setup HP 3458A
inst.write("PRESET NORM")
inst.write("OFORMAT ASCII")
inst.write("DCV 10")                        # Range set to 10VDC
inst.write("TARM HOLD")
inst.write("TRIG AUTO")
inst.write("NPLC 60")                       # Set NPLC speed 60 cycles
inst.write("AZERO ON")                      # Autozero on
inst.write("NRDGS 1,AUTO")                  # Take single reading
inst.write("MEM OFF")
inst.write("END ALWAYS")
inst.write("NDIG 9")                        # 8.5-digit resolution
# Setup Keithley 2001
kei.write("*RST")                           # Reset DMM to factory default
kei.write(":SYST:AZER:TYPE SYNC")           # Syncronous autozero on
kei.write(":SYST:LSYN:STAT ON")             # Sync ADC to line frequency
kei.write(":SENS:FUNC 'VOLT:DC'")           # DCV mode
kei.write(":SENS:VOLT:DC:DIG 9; NPLC 10; AVER:COUN 5; TCON REP")  # 8.5-digit mode, 10 NPLC, average 5 readings
kei.write(":SENS:VOLT:DC:AVER:STAT ON") 
kei.write(":SENS:VOLT:DC:RANG 20")          # Range set to 20VDC
kei.write(":FORM:ELEM READ")                # Read just voltage output
kei.write(":DISP:WIND:TEXT:DATA \"               \";STAT ON;") # Turn off K2001 display
kei.write(":DISP:WIND2:TEXT:DATA \"               \";STAT ON;") # Turn off secondary K2001 display

cnt = 0
tread = 0
temp = 41.0
level = 10.000000                           # Reference level for 3458A data
klevel = 10.0000000                         # Reference level for K2001 data
ppm = 0                                     # deviation from ref level, in ppm

with open('10v_keihp_nplc100.csv', 'a') as o:
#    o.write("date;hp3458a;level;kei2001;temp;ppm_level;kppm;\r\n")

ftp = ftplib.FTP(ip)                        # Use ftplib
ftp.login(user,password)                    # Login to FTP

while cnt <= 10000000:                      # Main loop, take 10M samples
    tread = tread - 1
    with open('10v_keihp_nplc100.csv', 'a') as o:   # Open file to addition
        if (tread == 0):
            tread = 25                      # Send TEMP? to 3458A every 25th measurement
            inst.write("TARM SGL,1")
            temp = inst.read()
        inst.write("TARM SGL,1")            # Take single reading
        data = inst.read()
        ppm = ((float(data) / level)-1)*1E6  # Calculate ppm dev
        inst.write("DISP OFF, \" %8.4f ppm\"" % float(ppm))  # Display ppm dev on 3458A screen
        time.sleep(1)                       # Do nothing for 1 second
        kei.write("READ?")                  # Read Keithley's data
        keival = kei.read()
        kppm = ((float(keival) / klevel)-1)*1E6 
        kei.write(":DISP:WIND2:TEXT:DATA \"  %8.4f ppm\";STAT ON;" % float(kppm))
        khp = (((float(data) / float(keival))-1)*1E6)  # 3458A/K2001 deviation in PPM
        print time.strftime("%d/%m/%Y-%H:%M:%S;") + ("[%8d]: %2.8f , dev %4.4f ppm, K:%2.8f, dev %4.4f ppm, TEMP:%3.1f, K/H %4.2f" % (min, float(data),float(ppm),float(keival),float(kppm),float(temp),float(khp) ) )
        o.write (time.strftime("%d/%m/%Y-%H:%M:%S;") + ("%16.8f;%16.8f;%16.8f;%3.1f;%4.3f;%4.3f\r\n" % (float(data),float(level),float(keival),float(temp),float(ppm),float(kppm) ) ))
        o.close()                           # close file 
    file = open('10v_keihp_nplc100.csv','rb')  # link to datafile
    ftp.storbinary('STOR 10v_keihp_nplc100.csv', file) # send file to FTP
    file.close()                               # close file

While this program does the job, there are many ways to improve it, which I’ll leave to you. Output test data can be viewed on this datalogging page

Summary and example programs

Hope these few examples help you to set data capture with ease, and if you have any questions left, feel free to jump in comments.

Few other related forum threads might be useful:


Author: Illya Tsemenko
Published: Nov. 9, 2015, 11:19 a.m.
Modified: Jan. 5, 2017, 1:14 p.m.