==========================================================
 HP 34970A Data Acquisition Unit - communication protocol
==========================================================

:Author: David Douard
:Category: Electronics
:Tags: HP, 34970A, DMM, repair, test equipment
:series: HP 34970A repair
:JavaScripts: default.js, WaveDrom.js

In order to build a replacement display for the HP34970A data
acquisition unit, I needed to understand the communication protocol
between the CPU board and the front panel assembly.

General description
===================

The unit is built with four boards:

- A1 is the main bard, with the PSU, the main controller and the floating logic,

- A2 is the front panel with the display and the keypad,

- A3 is the backplane on which I/O modules are plugged,

- A4 is the (optional) internal 6.5 digits DMM.

.. image:: {static}/images/hp34970a/block_diagram.svg
   :alt: System Block Diagram of the HP34970A.


The commnucation between the different system blocks is done with
asynchronous serial links. They use the rather uncommon bit rate of
187500 baud, with a classic 8N1 schema.


The CPU <-> Display Panel communication protocol
================================================

The communication protocol between the main controller (CPU) board and
the display panel (DP) consists in "datagrams" sent using the general
pattern:

- when a device (CPU or DP) wants to take control of the communication
  bus, it sends a ``Start of Transmission`` (SoT) signal (0x66),

- each sent char (but the end of transmission) must be acknowledged
  (ack value may vary),

- at the end of a communication, the initiator send a "End of
  Transmission" (EoT, 0x55). This sent value is not acknowledged.

- the keyboard can interrupt a CPU->DP communication in progress by
  not acknowledge a received byte, but sending a SoT instead of the
  expected ACK value,

- acknowledge values are:

  - one-complement of the received SoT byte, so

	- 0x99 for the 0x66 SoT byte and
	- 0xCC for the 0x33 SoT byte.

  - 0x00 otherise

- a special packet is sent by the Display Panel at startup, which SoT value is
  ``0x33``, which does not seem to follow the general pattern in which the first
  value after the SoT byte is the number of arguments.

Initialization sequence
-----------------------

The initialization transmission is:

.. wavedrom::

   { signal: [
      {name: "CPU", wave: "zz5x5x5xx", data: ["0xCC", "0x00", "0x00"]},
      {name: "DP",  wave: "z3x4x4x3x", data: ["0x33", "0x02", "0x00", "0x55"]},
      ]}

If a key is pressed during while powering the unit on, then the initialization
of the Display Panel is frozen (with all elements of the display lit) until the
key is released. In this case, the initialization packet adds the key code of
that key, typically used with the Shift key pressed in to force a full test of
the device (in this datagram, ``0x0C`` is the keycode of the Shift key):

.. wavedrom::

   { signal: [
      {name: "CPU", wave: "zz5x5x5x5xx", data: ["0xCC", "0x00", "0x00", "0x00"]},
      {name: "DP",  wave: "z3x4x4x4x3x", data: ["0x33", "0x02", "0xFF", "0x0C", "0x55"]},
      ]}


Shutdown sequence
-----------------

.. wavedrom::

   { signal: [
     {name: "Rx", wave: "z3x4x44|=4", data: ["0x66", "0x86", "0x55", "0x55","0x55"] },
     {name: "Tx", wave: "zx5x5xx", data: ["0x99", "0x00"] },
     ]}


CPU -> DP trasmission
---------------------

The CPU->DP transmission protocol looks like:

.. wavedrom::

   { signal: [
     {name: "Rx", wave: "z3x4x4x=x=x|.=x3x", data: ["0x66", "CMD", "LEN", "D0", "D1", "Dn", "0x55"] },
     {name: "Tx", wave: "zx5x5x5x5x5x|.5x.", data: ["0x99", "0x00","0x00", "0x00", "0x00", "0x00"] },
     ]}

Two (or more) datagrams can be transmitted in a single "transmission",
ie. without sending the EoT byte, eg.:

.. wavedrom::

   { signal: [
     {name: "Rx", wave: "z3x4x4x|=x3x4x|3x",
      data: ["0x66", "0x0C", "0x03", "D3", "0x66", "0x0A", "0x55"] },
     {name: "Tx", wave: "zx5x5x5x|5x5x5x|x",
      data: ["0x99", "0x00", "0x00", "0x00", "0x99", "0x00"] },
     ]}


DP -> CPU transmission
----------------------

When the user press a key on the front panel, a slightly simpler "packet transmission" occurs:

.. wavedrom::

   { signal: [
      {name: "Rx", wave: "zz5x5xx", data: ["0x99", "0x00"]},
      {name: "Tx", wave: "z3x4x3x", data: ["0x66", "KP", "0x55"]},
      ]}


Commands
========

The known command bytes sent by the CPU for now are:

:0x00: show text on the main display. N arguments; the characters to display.

:0x0C: show text in the 'channels' area. 3 arguments; the digits to display.

:0x0A: indicators (or flags) to display. 4 arguments; the flag bytes.

:0x08: to set an indicator in low bright mode. 1 argument; the number of the
       indicator dimm.

:0x09: to set an indicator in hight bright mode. 1 argument; the number of the
       indicator to highlight.

:0x01: clear the 'shift' button. Typically sent as ``0x01 0x01 0x0E``. 1
	   argument; 0x0E to clear the 'shift' flag. Other values unknown.

:0x02: might be a reset or clear for the front panel (typically sent as
	   ``0x02 0x01 0x0C`` packet). 1 argument; unknown.

:0x86: shutdown. 0 argument.

:0x0D: set char at pos dimm (eg 0D 01 02 55 = cursor on the 3rd char)

Sending data to the main display
================================

The main display consist in 13 17-segments digits, in which the
character is displayed by a main 14-digits, and the punctuation with 3
segments (2 dots and a comma, allowing to represent the signs ".",
",", ":" and ";"). Punctuation signs are also very close to the
preceding chracters.

.. image:: {static}/images/hp34970a/digit.jpg
   :alt: 17-segments digit of the main display.

The command used to send text to the main display is ``0x00``. The
character ``0x09`` (tabulation) has a special meaning: it marks the
beginning and the end of a part of the text to be displayed darker
than the usual. This is used to emphasis a portion of the displayed
text. Also, as the punctuation signs do not consume a digit, the
displayed text can be larger than 13 characters.


Sending data to the Channels display
====================================

This area only allows to display 3 7-segments digits. The command is
``0x0C``, the payload is thus 3 bytes long.

.. image:: {static}/images/hp34970a/channel.jpg
   :alt: The display area dedicated to current channel.
   :align: center

Flags
=====

The display also has several flags. Display flags are selected by
sending the ``0x0A`` command. The payload is 4 bytes long.  Each bit
of these 4 bytes represent a flag on the display.

Let's consider the following (we don't represent the acknowledgements here):

.. wavedrom::

   { signal: [
     {name: "Rx", wave: "z344====3x",
      data: ["0x66", "0x0A", "0x04", "F1", "F2", "F3", "F4", "0x55"]}
     ]}

The 29 flags I've identified are (should be complete):

.. wavedrom::

   { signal: [
   {name: "bit", wave: "z========z",
    data: ["7", "6", "5", "4", "3", "2", "1", "0"]},

   {name: "F1",  wave: "z=3333333z",
    data: ["Al. frame", "HI", "Alarm", "LO", "Channel", "Ch. frame", "Mx+B", "<Bell>"]},
   {name: "F2",  wave: "z===33333z",
    data: ["AVG", "", "OC", "4W", "1", "3", "4", "2"]},
   {name: "F3",  wave: "z========z",
    data: ["ERROR", "EXT", "ONCE", "", "MEM", "LAST", "MIN", "MAX"]},
   {name: "F4",  wave: "z=3=333==z",
    data: ["", "CONFIG", "SCAN", "MON", "VIEW", "*", "ADRS", "REMOTE"]},
    ],
    config: { hscale: 2 },
    }


Keypad
======

the keycode byte consists in:

.. wavedrom::

   {signal: [

   {name: "bit", wave: "z========z",
    data: ["7", "6", "5", "4", "3", "2", "1", "0"]},
   {name: "KP", wave: "z344=....z",
    data: ["Knob", "Rel.", "Shift", "Key Code"]},
    ],
    config: { hscale: 1 },
    }

:Bit 5: is set when the key has been pressed while 'shift' indicator was stil
		active.

:Bit 6: is set when the key is released, and clear for the key pressed event.

:Bit 7: of the key event byte is set high for the knob key events.


The key codes are:

:0x00: View
:0x01: Mon
:0x02: Sto/Rcl
:0x03: Scan
:0x04: Alarm
:0x05: Mx+B
:0x06: Measure
:0x07: Interval
:0x08: Card Reset
:0x09: Close
:0x0A: Open
:0x0B: Read
:0x0C: Shift
:0x0D: Write
:0x0E: Left
:0x0F: Right

:0x10: Advanced
:0x11: Step

:0x80: Knob right
:0x81: Knob left
