Sat, 17 Sep 2016 02:08:03 +0200
[hp34970a] part 4
66 | 1 | ========================================== |
2 | HP 34970A Data Acquisition Unit - part 4 | |
3 | ========================================== | |
4 | ||
5 | :Author: David Douard | |
6 | :Category: Electronics | |
7 | :Tags: HP, 34970A, DMM, repair, test equipment | |
8 | :series: HP 34970A repair | |
9 | :series_index: 4 | |
10 | ||
11 | ||
12 | After a summer pause, I'm back on my HP34970A replair project. In | |
13 | `the previous post in this series <{filename}/hp34970a_3.rst>`_, I've | |
14 | started to reverse ingineer the serial protocol between the CPU board | |
15 | and the fonrt panel, and implement a prototype of replacement display. | |
16 | ||
17 | ||
18 | OLED display | |
19 | ============ | |
20 | ||
21 | I bought the bigest OLED display I could find (at a reasonable price) | |
22 | that would fit in the front panel assembly. It's a `blue 256x64 OLED | |
23 | display`_ drived by a SSD1322 controler. | |
24 | ||
25 | .. _`blue 256x64 OLED display`: http://www.buydisplay.com/default/oled-3-2-inch-displays-module-companies-with-driver-circuit-blue-on-black | |
26 | ||
27 | .. image:: {filename}/images/hp34970a/oled_module.jpg | |
28 | :alt: 3"2 blue OLED module used as a replacement display for the HP34970A. | |
29 | ||
30 | My first problem was to drive the display from my Nucleo board. I | |
31 | couldn't find graphic library that worked directly. I was already | |
32 | using the UniGraphic_ library with the small TFT display, so I decided | |
33 | to implement support for this OLED module in the library. | |
34 | ||
35 | .. _UniGraphic: https://developer.mbed.org/teams/GraphicsDisplay/code/UniGraphic | |
36 | ||
37 | I spent quite some time to make this work for several reasons, among | |
38 | others: | |
39 | ||
40 | - I was first using my Nucleo F031K6 board; it's nice, it's small, but | |
41 | it only have 4k of RAM, so the malloc I as doing in my test code to | |
42 | allocate the "framebuffer" in which drawings are done before being | |
43 | tranferred to the display module... well let's say if I took time to | |
44 | check the return value of the malloc call (which one should always | |
45 | do, even on small embedded devices), I would have not lost a couple | |
46 | of hours, so to speak (tip: allocating 8k in a 4k RAM will not fit), | |
47 | ||
48 | - The SSD1322 controller is *reasonnably* well documented, but what's | |
49 | not documented is how it is used on the OLED display... In fact, | |
50 | once I could at least see some pixels on my display, I spent quite | |
51 | some time trying to control where my pixels are located on the | |
52 | module. There is not that much demo material available for this | |
53 | module besides a `poorly written sample C code`_ (in a .txt file!) | |
54 | for the 80C51 processor. What's hidden in this file (which I could | |
55 | not fing any where else) is the magic 0x1C value which must be given | |
56 | as first argument to the SET_COLUMN_ADDR "function" of the SSD1322. | |
57 | ||
58 | - I also lost some time trying to implement the support for this module | |
59 | as a class derived from UniGraphic's `LCD class`_ (like several | |
60 | other supported modules like the SSD1306_), but that was a mistake, | |
61 | since this kind of OLED module is too different from both a TFT | |
62 | display or a monochrome LCD display. So I've reimplemented the class | |
63 | as a derived class of the GraphicDisplay_. This work is far for being | |
64 | finished yet (and ready for a *Pull Request* to submit to the | |
65 | UniGrahic project), but at least, I can continue my work on the | |
66 | HP34970's display. | |
67 | ||
68 | ||
69 | .. _`LCD class`: https://developer.mbed.org/teams/GraphicsDisplay/code/UniGraphic/file/tip/Display/LCD.h | |
70 | .. _SSD1306: https://developer.mbed.org/teams/GraphicsDisplay/code/UniGraphic/file/tip/Inits/SSD1306.h | |
71 | .. _GraphicDisplay: https://developer.mbed.org/teams/GraphicsDisplay/code/UniGraphic/file/tip/Graphics/GraphicsDisplay.h | |
72 | .. _`poorly written sample C code`: http://www.buydisplay.com/download/democode/ER-OLEDM032-1_DemoCode.txt | |
73 | ||
74 | ||
75 | Improving the serial sniffer | |
76 | ============================ | |
77 | ||
78 | Once I could draw pixels on my OLED module, I put this code in my | |
79 | existing prototype replacing the simple display code I used with the | |
80 | TFT module. | |
81 | ||
82 | And one problem I already had with the previous "working" prototype | |
83 | became bigger: I was missing many characters on the serial bus between | |
84 | the CPU and the front panel. | |
85 | ||
86 | My first implementation of the protocol sniffing was very tedious and | |
87 | poorly written. It was not reading at all the traffic on the Tx line | |
88 | (ie the key strokes), so I was never sure if a 0x66 was the beginning | |
89 | of a transmission or some payload for which I missed the beginning. | |
90 | ||
91 | Using the interrupt-based (asynchronous) BufferedSerial_ | |
92 | implementation did not help that much. | |
93 | ||
94 | So I rewrote this part of the using 2 serial ports, using only the Rx | |
95 | line on both of them, one plugged on the Rx line of the serial | |
96 | communication, and the other on the Tx line of this comm. Doing so I | |
97 | can sniff the whole communication between the CPU and the display | |
98 | panel and make a way better protocol interpreter. | |
99 | ||
100 | The result was way better than before, and now I was able to detect | |
101 | the protocol interpretation errors, but still, I was missing many | |
102 | parts of the transmission. | |
103 | ||
104 | I ended up to figure that the culprit was my | |
105 | ``SSD1322::copy_to_lcd()`` method: it takes almost 20ms to transmit | |
106 | the whole display content the module. And with the way my code was | |
107 | written, even with interrupt driven serial handlers, these interrupt | |
108 | were not captured during the execution of this copy routine. | |
109 | ||
110 | At this point, I've started to read a bit more the asynchronous and | |
111 | event driven APIs of the mbed platform, but could not clearly see a | |
112 | pattern to prevent this long "frozen" periods during which I was | |
113 | unable to capture serial communications. | |
114 | ||
115 | .. _BufferedSerial: https://developer.mbed.org/users/sam_grove/code/BufferedSerial/ | |
116 | ||
117 | I was almost ready to use 2 microcontrollers for the job: one to sniff | |
118 | and interpret the serial communication and one to drive the display. | |
119 | ||
120 | .. image:: {filename}/images/hp34970a/poc_oled.jpg | |
121 | :alt: Improvment of the POC based on the Nucleo F446RE and using a blue OLED module. | |
122 | ||
123 | Improving the tasks | |
124 | =================== | |
125 | ||
126 | But I've discovered a few days ago that the RTOS project is now part | |
127 | of the mbed platform, allowing to use threads instead of pure event | |
128 | driven code. So I tried to put the copy_to_lcd routine executions in a | |
129 | dedicated thread, and bingo, I've got now something that begins to | |
130 | work enough to make it usable: | |
131 | ||
132 | .. dailymotion:: x4tib5s | |
133 | :width: 270 | |
134 | :height: 480 | |
135 | ||
136 | ||
137 | What's next | |
138 | =========== | |
139 | ||
140 | There is still a lot of work to do: | |
141 | ||
142 | - improve the display reactivity: I'll probably try to implement | |
143 | partial copy of the display instead of sending the whole | |
144 | "framebuffer" each time something is changed on the display (the | |
145 | SSD1322 allows to specify a "window" in which to send data), | |
146 | ||
147 | - improve overall display organisation and find the missing flags (I | |
148 | still have not found the flag values for OC, MIN, MAX, AVG, ONCE, | |
149 | AUTO and MEM), | |
150 | ||
151 | - try to install the display module and the Nucleo board in the front | |
152 | panel assembly (I don't want to go for a specifically designed PCB, | |
153 | at least for now), | |
154 | ||
155 | - publish the code. | |
156 | ||
157 | ||
158 | ||
159 | ||
160 | ||
161 |