The BenchPod's analog front-end is only as trustworthy as its calibration. A 16-bit DAC and ADC can report six figures of precision and still be wrong by tens of millivolts if nothing ever checked them against a real reference. The fix is unglamorous but non-negotiable: put a calibrated, traceable instrument on the bench and sweep the pod's outputs against it. That instrument is an Agilent 34401A 6½-digit multimeter with a calibration certificate — the standard reference-grade DMM found on most electronics benches and in most metrology labs.
The interesting part of this log isn't the calibration math, which is a routine linear fit. It's what it took to get the 34401A talking to a computer at all — and it's relevant if you're integrating your own reference instruments with a BenchPod, not just for this specific calibration.
Why GPIB is still the obstacle in 2026
The 34401A only speaks GPIB (IEEE-488), a bus that predates USB by a decade and has no native path onto a modern laptop. The standard bridge is a National Instruments GPIB-USB-HS adapter, and the standard software is either NI's own NI-488.2 driver or the open-source linux-gpib kernel module. Neither one was a straight shot here:
- NI ships no NI-488.2 driver for Apple Silicon — the macOS kernel extension doesn't load past macOS 12, so the M-series Mac was out.
- The fallback was a Raspberry Pi running
linux-gpib, since NI has no ARM build either. That got the DMM enumerating and the software stack fully built and installed — but every addressed GPIB transfer failed deterministically withNIUSB_ADDRESSING_ERROR, even after ruling out the cable, the DMM's address, USB autosuspend, and both the released and git-master versions of the driver.
At that point the usual suspects were exhausted: genuine adapter (Hungary-made, boxed, correct USB PID), genuine instrument, current software, clean config. The addressing failure was uniform across every GPIB address on the bus, which pointed at the adapter's kernel driver interaction, not the wiring or the DMM.
Reverse-engineering the adapter instead of the bus
Rather than keep fighting linux-gpib on the Pi, the question became: does the adapter actually work, independent of that driver? A bare pyusb/libusb probe against the adapter's USB endpoints — no kernel module, no NI driver, no VM — answered that in two stages. First, the adapter's vendor control handshake (serial number query, poll-ready) came back clean. Second, a raw bulk register read against its NI TNT4882 GPIB-controller chip returned a perfectly framed response with no timeout — the exact operation that had been failing with a USB -110 error under linux-gpib on the Pi. The adapter's own firmware and GPIB controller were fine; the fault was in how the Linux driver's interrupt-endpoint handling interacted with this Pi's USB host controller.
That result reframed the whole problem: don't drive the adapter through a general-purpose kernel driver at all — talk to it directly. Claude Opus 4.8 wrote a from-scratch, pure-Python driver that speaks the adapter's wire protocol over libusb: the vendor handshake, a 26-register TNT4882 init sequence, GPIB addressing (UNL/talk-address/listen-address command bytes), and synchronous bulk writes/reads — deliberately skipping the interrupt-endpoint monitoring that was the likely point of failure on Linux. Because it's synchronous request/response over plain bulk transfers, it doesn't care whether it's running on the Pi or the Mac.
It worked on the first real test against the 34401A:
*IDN? -> HEWLETT-PACKARD,34401A,0,10-5-2
READ? -> five clean DC samples, ~33 µV noise floor on an open inputThat overturned the original assumption that the Mac couldn't host GPIB at all — it just needed a driver that didn't route through the parts of linux-gpib that were choking. The result is now a small open-source package, `ni-gpib-usb-hs`: a general-purpose GPIB controller class plus a ready-made Agilent34401A wrapper, installable with pip install ni-gpib-usb-hs and no kernel module on either macOS or Linux.
from ni_gpib_usb_hs import Agilent34401A
with Agilent34401A(addr=22) as dmm:
print(dmm.idn()) # HEWLETT-PACKARD,34401A,0,10-5-2
dmm.configure_dc_volts(rng=10, nplc=10)
print(dmm.read_average(10))Running the actual calibration
With a working DMM link, the calibration itself is a straightforward sweep: step the pod's DAC through its code range, let the output settle, and read back the true voltage on the 34401A alongside the pod's own ADC count at the same node. Fitting V = a + b·code for the DAC and V = a + b·count for the ADC turns two raw digital paths into two DMM-referenced linear equations — the difference between "the pod says 2.500 V" and "the pod outputs 2.500 V, verified against a 6½-digit reference."
python3 dac_cal.py --host <bench-host> --channel 0
# code DMM_V ADC
# 0 ... ...
# 8 ... ...
# ...
# [cal] DAC : V = a + b*code R2=... max|resid|=... mV
# [cal] ADC : V = a + b*count R2=... max|resid|=... mV (lower range)The DAC sweep does double duty: since the DAC output feeds straight back into the ADC through the pod's on-board loopback relay, the same sweep calibrates the lower portion of the ADC's range for free. Only the upper range — beyond what the DAC can reach — needs a second pass against the DMM as an external source.
Why this matters for CI, not just the bench
A calibration that only exists as a one-time bench exercise isn't worth much — the value is in making it repeatable enough to redo whenever the hardware revs, without a metrology lab visit each time. Publishing the driver as `ni-gpib-usb-hs` means anyone integrating a GPIB reference instrument — a 34401A or otherwise — into a BenchPod-based test bench can reuse the same path: no NI software license, no kernel module, no platform restriction, works the same on macOS and Linux. The fit coefficients feed back into firmware and the signal record/replay pipeline, so voltages captured or generated by the pod are numbers you can trust against a real reference — not just numbers the ADC happened to report.
Getting started
If you're setting up a BenchPod and want your own analog measurements DMM-referenced, the pattern here generalizes directly: pip install ni-gpib-usb-hs, point it at your GPIB adapter and instrument address, and drive it alongside the BenchPod SDK from the same host — no separate bench-head machine required. For the full picture of what the analog front-end can do once it's calibrated, see Recording and Replaying Analog Signals, and for driving the rest of the bench conversationally, see Driving the BenchPod with Claude.