Sunday, 23 May 2021

Making Elektronika MK-52 VFD scanner

One of my Elektronika MK-52 (Электроника МК-52) Soviet era micro calculators decided to show its age by turning off a couple of VFD positions. In this case the ‘minus’ sign and the first digit are almost invisible, so instead of ‘-123’ you can see only ‘  23’. I have a few spare VFDs and could just replace the faulty one, but that would be a bit boring. Plus, all spare ones I have are from Soviet era as well and there is no guarantee that they will last.

So I’ve decided to replace original VFD with something else, preferably some ready to use parts. Having a few STM32F103C8T6 boards laying around it was the obvious choice – use STM32 to scan VFD pins to read the values being displayed and send them to anything connected to the STM (to be yet decided).

MK-52 drives its VFD using -27V, so direct connection with STM is not possible. But simple resistive voltage divider works just fine. There is how I’ve connected VFD to the STM:

Note that only of VFD grid controls is connected, below I’ll explain why.

This is how VFD digits multiplexing works:

VFD/keyboard controller sets all relevant segments for digit 8 and then pulses grid 8 signal for about 135 micro seconds to illuminate the segments, then it sets segments for digit 7 and pulses grid 7 signal, eventually rolling over to exponent and lightning up digits 12, 11 and then finishing display update cycle at the exponent sign at grid 10.

But because the same controller also read the keyboard, it needs extra two pulses to scan the keys. It is why there is an ISG (Inter Scan Gap) on the picture above.

We can easily check how this works with an oscilloscope:

Here yellow channel connected to GRIG_8 signal, red channel to SEG_G,  blue to SEG_A and green – to SEG_DOT. ‘-88888888.-88’ is displayed on the VFD. As you can see, there is a two pulses Key Scan interval before the next cycle of multiplexing starts. Interesting to note that even for key scan pulses segments are being lit.

The same picture, but with a logic analyzer connected to all segments and to GRID_8 signal:

Here D0 connected to SEG_A, D1 to SEG_B, …, D7 to SEG_DOT and finally D8 to GRID_8. Cursor shows the keyboard scan pulses. The controller turns off all segments before setting them for the next digits, so there a short negative pulses for SEG_A to SEG_G. Zoom into the inter-grid gap looks  like this:

Here channel D8 connected to GRID_2, D9 to GRID_3 and you can see ~4.6 microsecond between grid 3 turned off and grid 2 turned on.

Now we can connect our voltage dividers to STM32F103 and try to scan the VFD.

Segments signals SEG_A to SEG_DOT connected to A0 to A7 and signal from GRID_8 connected to B0. Also B10 & B11 are used for UART#3 and B12-B15 are reserved for SPI to connect OLED display in the future. C13, connected to on-board Blue LED, and A12, connected to on-board 4.7K pull-up, can be used for pulsing on some events, like interrupts, and will be useful for connecting to an oscilloscope for debugging.

So, why only GRID_8 is connected? Rising edge of this signal will be used to fire an interrupt which will scan segments and then will start timer to fire timer interrupt to scan the next digits. After the last digit is scanned timer will stop itself and the next scanning cycle will start when grid 8 signal will rise again. To make sure that timer interrupts are fired at proper interval, first two interrupts from GRID_8 signal will be used to calculate the multiplexing period. This period then will be constantly adjusted to make sure that we are scanning at the right time even if multiplexing period is drifting because of battery running low.

STM32CubeMX pinout for this project:

Scanning code is quite simple, with interrupts storing scanned data and sending events to the main loop using ring buffers, so the main loop and interrupts never overlap.

Serial port is used to show scanned data on the terminal for logging. This an example of a few commands:

What is going on here:

  • Lines 1-6:  ‘12’ entered
  • Lines 7-8: ‘12’ moved to the stack
  • Lines 9-11: ‘4’ is entered
  • Lines 12-14: multiplication is executed.
  • Lines 15-16: display is cleared by CX command.
  • Lines 17-19: division by zero caused MK-52 to think for almost 5 seconds before deciding that this is impossible and throwing out ERROR message. Actually, on the real VFD it looks like this: ‘ЕГГ0Г’ as VFD segments cannot display letter ‘R’.
  • Lines 20-21: ВП key is pressed, causing VFD to display ‘Г.ГГ0Г    00’.
  • Lines 22-23: В key is pressed, causing the only single dot to be displayed

There are a few interesting patterns we can see on this terminal example.

When new digits are being entered:

  • display controller first turns off SEG_DOT (actually, not for all the time, only if 1-4 is entered in the first 4 positions)
  • then turns off all digits – screen goes to blank state for some period of time
  • the it displays new digits

When some command is being executed, for example, multiplication at line 12:

  • display controller turns off SEG_DOT
  • scan code for the second key pulse (digits in []), changes ‘L’
  • screen goes blank for command execution time
  • result is displayed on the screen

When program is being executed, for example, sample program for a circle calculation from the user manual:

  • every step values are quickly flashing on the VFD
  • scan for the first key pulse returns ‘9’

Some other examples.

Entering a program for calculating the area of a circle for a given diameter



BLANK 11 cycles (20,482 ms)
'_0.__________' [8_.]

BLANK 29 cycles (53,998 ms)
'__________00' [33.]



BLANK 11 cycles (20,482 ms)
'__________00' [8_.]

BLANK 183 cycles (340,746 ms)
'_22_______01' [53.]



BLANK 11 cycles (20,482 ms)
'_22_______01' [8_.]

BLANK 274 cycles (510,188 ms)
'_20_22____02' [53.]


BLANK 369 cycles (687,78 ms)
'_12_20_22_03' [53.]


BLANK 358 cycles (666,596 ms)
'_04_12_20_04' [53.]


BLANK 334 cycles (621,908 ms)
'_13_04_12_05' [53.]


BLANK 327 cycles (608,874 ms)
'_50_13_04_06' [53.]



BLANK 11 cycles (20,482 ms)
'_50_13_04_06' [8_.]

BLANK 96 cycles (178,752 ms)
'_0.__________' [53.]

 And execution of this program, with  d = 5:


'_0__________' [5C]
BLANK 16 cycles (29,344 ms)
'_0.__________' [33.]


'_0__________' [54]
BLANK 90 cycles (166,320 ms)
'_5.__________' [53.]


'_5__________' [5C]
BLANK 15 cycles (27,720 ms)
'_5__________' [35]
BLANK 76 cycles (140,448 ms)
'_5_______22.E.' [99] RUNNIG
BLANK 134 cycles (247,632 ms)
'_5000000020.E.' [99] RUNNIG
BLANK 119 cycles (219,912 ms)
'_2500000012.E.' [99] RUNNIG
BLANK 119 cycles (219,912 ms)
'_3141592604.E.' [99] RUNNIG
BLANK 164 cycles (303,72 ms)
'_4_______13.E.' [99] RUNNIG
BLANK 119 cycles (219,912 ms)
'_4000000050.E.' [99] RUNNIG
BLANK 115 cycles (212,520 ms)
'_19.634953___' [53.]


Project's github.

No comments:

Post a Comment