# HP3478A Internal USB-GPIB Extension

An internal extension board for the HP3478A Multimeter. USB-CDC-GPIB bridge (Prologix-style) and an internal feature controller.

Uses WCH CH32V203 (RISC-V) MCU.

It enumerates as a standard serial device (e.g., /dev/ttyACM0 or COMx).

PCB [here](https://git.ayau.me/mira/mhardware/src/branch/master/hp3478a-ch32-ext)

More photos in [img/](./img/)

<video src="./img/feats.mp4" controls preload></video>

## Menu System

Extended features (Continuity, Temp, etc.) can be accessed using the SRQ button of HP3478A without a PC

1.  **Enter Menu:** Press the Front Panel **SRQ**.
2.  **Nav:** Press the button again to cycle through modes (`M: REL` -> `M: TEMP` -> `M: DBM`...).
3.  **Selection (Hover):** Stop pressing the button.
    -   The display will animate dots (`...`) after 500ms.
    -   After ~2.5 seconds of inactivity, the selected mode is activated.
4.  **Sub-Menus:** Some modes (like Temp) have sub-menus for sensor type and 2W/4W mode. Same cycle logic to select these.
5.  **Exit:** Press the SRQ button to exit back to initial mode (one we entered menu from).

## Features

These can be triggered via the Menu or the serial commands below.

Relative and Statistics depend on the mode you enter the menu from, i.e. if you enter relative from DCV it saves your state and you get relative voltage, from 2W relative 2W etc.

```
++help

HP3478A Internal USB-GPIB 1.2.0

[GPIB Setup]
  ++addr <0-30>     Target Address
  ++auto <0-2>      0:Off, 1:Read-After-Write, 2:Query-Only
  ++read_tmo_ms <t> Timeout in ms
  ++eoi <0|1>       Assert hardware EOI on write end
  ++eos <0-3>       Write Term: 0:CRLF, 1:CR, 2:LF, 3:None
  ++eor <0-7>       Read Stop:  0:CRLF ... 7:EOI-Only
  ++eot_enable <B>  Append extra char to read output
  ++eot_char <dec>  The char to append
  ++dmm_loop <0|1>  Toggle HP3478A loop, if it conflicts w/ GPIB bus

[System Configuration]
  ++config          List all configurable parameters
  ++get <name>      Get parameter value
  ++set <name> <v>  Set parameter value
  ++savecfg         Save config to flash
  ++ver             Firmware Version
  ++rst             System Reset

[GPIB Bus Operations]
  ++read            Read from target
  ++write <data>    Write to target
  ++trg             Device Trigger (GET)
  ++clr             Device Clear (SDC)
  ++dcl             Universal Device Clear (DCL)
  ++ifc             Interface Clear (Bus Reset)
  ++spoll [addr]    Serial Poll
  ++srq             Query SRQ Line (0=High/Idle, 1=Low/Active)
  ++loc             Local (Drop REN)
  ++llo             Local Lockout

[Internal HP3478A Features]
  ++cont, ++hold, ++rel, ++xohm
  ++dbm, ++diode, ++math, ++norm
  ++temp <l1> <l2>  Temperature sensor mode
  ++env [temp|hum]  Internal AHT20 Sensor
  ++disp <text>     Write text to LCD
```

There's also a configuration which can be saved using `++savecfg` if you want to make it persist (it's saved to v203's "undocumented" flash).  
Also see [inc/config.h](./inc/config.h).

```
++config
my_addr: 0
dmm_addr: 18
target_addr: 18
eot_char: 0
eot_enable: 0
eoi_assert: 1
eos_mode: 0
eor_mode: 0
auto_read: 0
gpib_timeout_ms: 1200
poll_interval_ms: 100
env_sensor_read_interval_ms: 1000
dmm_recovery_delay_ms: 1000
usb_debounce_connect_ms: 50
usb_debounce_disconnect_ms: 200
usb_timeout_target_ms: 5
menu_dot_interval_ms: 500
menu_commit_delay_ms: 2400
menu_sublayer_delay_ms: 500
menu_debounce_ms: 100
menu_lockout_ms: 1000
stats_cycle_time_ms: 3000
cont_disp_update_ms: 150
diode_stable_ms: 20
buzzer_chirp_hz: 3000
buzzer_chirp_ms: 75
buzzer_cont_hz: 2500
rtd_a: 0.003908
rtd_b: -0.000001
rtd_r0: 1000.000000
cjc_fallback_temp: 22.000000
cjc_self_heating_offset: 4.000000
type_k_scale: 24390.240000
dbm_ref_z: 50.000000
diode_th_short: 0.050000
diode_th_open: 2.500000
autohold_threshold: 1.000000
autohold_change_req: 2.000000
autohold_min_val: 0.050000
cont_threshold_ohms: 10.000000
autohold_stable_count: 3
rel_stable_count: 3
```

i.e.

```
++set dbm_ref_z 60
++savecfg
```

Now your dBm feature will use 600 ohm ref instead of 50.

## Known Issues

1.  I did NOT use the brain when routing the USBLC6. Either have to DNP the IC and jumper the data lines, or rely on the software hack to check USB `SUSPEND` to guess if the host is connected. I do the latter, works but meh. VBUS detection would be nicer.
2.  The buzzer is **not on a hardware TIM pin**. It's on a generic GPIO... This means it can't be hardware/timer PWMed. Instead, the firmware is firing a TIM IRQ thousands of times a second just to manually toggle the pin in the ISR..
3.  There is a microSD card footprint on the board. The fw does absolutely nothing with it. Data logging?
