content/hp34970a_4.rst

Thu, 10 Nov 2022 20:56:16 +0100

author
David Douard <david.douard@sdf3.org>
date
Thu, 10 Nov 2022 20:56:16 +0100
changeset 148
2f87039dd0b5
parent 130
56ffb9577050
permissions
-rw-r--r--

Replace video links with working ones from new peertube instance

==========================================
 HP 34970A Data Acquisition Unit - part 4
==========================================

:Author: David Douard
:Category: Electronics
:Tags: HP, 34970A, HP34970A, DMM, repair, test equipment
:series: HP 34970A repair
:series_index: 4


After a summer pause, I'm back on my HP34970A repair project. In
`the previous post in this series <{filename}/hp34970a_3.rst>`_, I've
started to reverse engineer the serial protocol between the CPU board
and the front panel, and implement a prototype of replacement display.


OLED display
============

I bought the bigest OLED display I could find (at a reasonable price)
that would fit in the front panel assembly. It's a `blue 256x64 OLED
display`_ drived by a SSD1322 controler.

.. _`blue 256x64 OLED display`: http://www.buydisplay.com/default/oled-3-2-inch-displays-module-companies-with-driver-circuit-blue-on-black

.. image:: {static}/images/hp34970a/oled_module.jpg
   :alt: 3"2 blue OLED module used as a replacement display for the HP34970A.

My first problem was to drive the display from my Nucleo board. I
couldn't find graphic library that worked directly. I was already
using the UniGraphic_ library with the small TFT display, so I decided
to implement support for this OLED module in the library.

.. _UniGraphic: https://developer.mbed.org/teams/GraphicsDisplay/code/UniGraphic

I spent quite some time to make this work for several reasons, among
others:

- I was first using my Nucleo F031K6 board; it's nice, it's small, but
  it only have 4k of RAM, so the malloc I as doing in my test code to
  allocate the "framebuffer" in which drawings are done before being
  tranferred to the display module... well let's say if I took time to
  check the return value of the malloc call (which one should always
  do, even on small embedded devices), I would have not lost a couple
  of hours, so to speak (tip: allocating 8k in a 4k RAM will not fit),

- The SSD1322 controller is *reasonnably* well documented, but what's
  not documented is how it is used on the OLED display... In fact,
  once I could at least see some pixels on my display, I spent quite
  some time trying to control where my pixels are located on the
  module. There is not that much demo material available for this
  module besides a `poorly written sample C code`_ (in a .txt file!)
  for the 80C51 processor. What's hidden in this file (which I could
  not fing any where else) is the magic 0x1C value which must be given
  as first argument to the SET_COLUMN_ADDR "function" of the SSD1322.

- I also lost some time trying to implement the support for this module
  as a class derived from UniGraphic's `LCD class`_ (like several
  other supported modules like the SSD1306_), but that was a mistake,
  since this kind of OLED module is too different from both a TFT
  display or a monochrome LCD display. So I've reimplemented the class
  as a derived class of the GraphicDisplay_. This work is far for being
  finished yet (and ready for a *Pull Request* to submit to the
  UniGrahic project), but at least, I can continue my work on the
  HP34970's display.


.. _`LCD class`: https://developer.mbed.org/teams/GraphicsDisplay/code/UniGraphic/file/tip/Display/LCD.h
.. _SSD1306: https://developer.mbed.org/teams/GraphicsDisplay/code/UniGraphic/file/tip/Inits/SSD1306.h
.. _GraphicDisplay: https://developer.mbed.org/teams/GraphicsDisplay/code/UniGraphic/file/tip/Graphics/GraphicsDisplay.h
.. _`poorly written sample C code`: http://www.buydisplay.com/download/democode/ER-OLEDM032-1_DemoCode.txt

.. image:: {static}/images/hp34970a/oled.jpg
   :alt: The replacement 3"2 blue OLED module for the HP34970A.



Improving the serial sniffer
============================

Once I could draw pixels on my OLED module, I put this code in my
existing prototype replacing the simple display code I used with the
TFT module.

And one problem I already had with the previous "working" prototype
became bigger: I was missing many characters on the serial bus between
the CPU and the front panel.

My first implementation of the protocol sniffing was very tedious and
poorly written. It was not reading at all the traffic on the Tx line
(ie the key strokes), so I was never sure if a 0x66 was the beginning
of a transmission or some payload for which I missed the beginning.

Using the interrupt-based (asynchronous) BufferedSerial_
implementation did not help that much.

So I rewrote this part of the using 2 serial ports, using only the Rx
line on both of them, one plugged on the Rx line of the serial
communication, and the other on the Tx line of this comm. Doing so I
can sniff the whole communication between the CPU and the display
panel and make a way better protocol interpreter.

The result was way better than before, and now I was able to detect
the protocol interpretation errors, but still, I was missing many
parts of the transmission.

I ended up to figure that the culprit was my
``SSD1322::copy_to_lcd()`` method: it takes almost 20ms to transmit
the whole display content the module. And with the way my code was
written, even with interrupt driven serial handlers, these interrupt
were not captured during the execution of this copy routine.

At this point, I've started to read a bit more the asynchronous and
event driven APIs of the mbed platform, but could not clearly see a
pattern to prevent this long "frozen" periods during which I was
unable to capture serial communications.

.. _BufferedSerial: https://developer.mbed.org/users/sam_grove/code/BufferedSerial/

I was almost ready to use 2 microcontrollers for the job: one to sniff
and interpret the serial communication and one to drive the display.

.. image:: {static}/images/hp34970a/poc_oled.jpg
   :alt: Improvment of the POC based on the Nucleo F446RE and using a blue OLED module.

Improving the tasks
===================

But I've discovered a few days ago that the RTOS project is now part
of the mbed platform, allowing to use threads instead of pure event
driven code. So I tried to put the copy_to_lcd routine executions in a
dedicated thread, and bingo, I've got now something that begins to
work enough to make it usable.



What's next
===========

There is still a lot of work to do:

- improve the display reactivity: I'll probably try to implement
  partial copy of the display instead of sending the whole
  "framebuffer" each time something is changed on the display (the
  SSD1322 allows to specify a "window" in which to send data),

- improve overall display organisation and find the missing flags (I
  still have not found the flag values for OC, MIN, MAX, AVG, ONCE,
  AUTO and MEM),

- try to install the display module and the Nucleo board in the front
  panel assembly (I don't want to go for a specifically designed PCB,
  at least for now),

- publish the code.

mercurial