Software

PT6311 VFD Display Controller, Power Supply and Arduino Library

vfd_20700_2.jpg

In this article, we’ll have a look at the PT6311 VFD display driver and controller and see how to design a power supply circuit for it. Since I have a bunch of AOTOM 20070-1A04 (datasheet) 8 digit 14 segment VFDs I took from a trip to China some time ago, we’ll use the PT6311 to control such a display.

Prototype board for PT6311 controlling a Chinese 8 digit 14 segment VFD display and two buttons. Next time, let’s pay more attention to the printing, huh? Don’t you worry, the whole article is dedicated to its inside beauty

Prototype board for PT6311 controlling a Chinese 8 digit 14 segment VFD display and two buttons. Next time, let’s pay more attention to the printing, huh? Don’t you worry, the whole article is dedicated to its inside beauty

Along with other powerful VFD drivers by the Taiwanese IC manufacturer Princeton, it takes care of multiplexing and dimming of the VFD display, has LEDs outputs and offers the input of up to 12x4 keys and 4 general purpose. That’s a whole bunch of work you’d otherwise all have to time within your main microcontroller. The SPI interface makes it very easy to control with any microcontroller of choice. We’ll use an Arduino Uno this time.

The article is targeted at those who have knowledge in electronics, as well as VFD displays and are interested in building something very similar. In case you don’t know how VFDs work, I suggest you to have a look at this Instructable first.

I’ve been upside down

pt6311_1.jpg

Because PT6311 (datasheet) requires the cut off (segment/grid off) voltage to be negative! In fact this is why, for a long time, I was intimidated by the powerful driver. But wait, shouldn’t the VFD display voltage be very high? A teacher of mine once said that voltage is just a matter of perspective. I’ll tell you why it is perfectly applied here. For a VFD display, typically a voltage difference of 20V to 30V between the on and off voltage (and cathode/filament, which needs a small voltage of around 2V itself to generate the flying electrons). But really, all you need is just the voltage difference for the display to properly glow. This can be done by conveniently switching on the anode and grid with the power supply voltage of 5V, and when switching off, it gets pulled down to our negative supply (off voltage), which is 5V - 25V = -20V.

Take me to lower ground

So now we know we want to have a negative voltage for our cut off power supply, let’s design one. If you look into the datasheet of the VFD, the ideal anode/grid voltage is 22V apart from the off voltage. Subtracting this from the positive supply of 5V gives us -17V. This is what we aim for. While we used a positive boost converter to obtain a HV power supply, we’ll just a negative boost converter to get -17V: An LT1931 (datasheet) takes care of this. Designing is as simple as to look into its datasheet, calculating the feedback divider and look for appropriate inductor and capacitor values. Finally, we just replicate the typical application schematics, which is perfect for what we need.

schematics_psu.png

POWER TO THE PEOPLE

LT1931 turns 5V DC into -17V DC

The Filament Supply

Ideally, the filament of the VFD is driven with AC to prevent having a brightness gradient from where the higher voltage of 0V and 2V sits. The datasheet tells that you’ll need 2.4V AC RMS to drive the filament. From our filament, we can two a rectangular pulses with a 50% duty cycle, which will give us an RMS value of roughly 2.5V RMS, and that’s great.

Filament supply with LM4871 (formerly LM9022), decoupling with C7, C8 and re-referencing to -17.0V + 2.7V

Filament supply with LM4871 (formerly LM9022), decoupling with C7, C8 and re-referencing to -17.0V + 2.7V

We need to take the two pulses, and push them into the -17V domain. Have a look at the circuit above. It decouples the two phase inverted pulses generated by the LM4871 (datasheet) into zero mean pulses, and re-biases it to -17V with a zener diode in between. The LM4871 itself serves as a pulse generator with self oscillation connected to an H bridge. A zener diode is necessary to counteract unwanted illumination when the off voltage is higher than the bias voltage. I.e. the off voltage has to be slightly negative than the filament voltage.

 

All on board

pt6311_2.png

As mentioned above, the PT6311 uses SPI to communicate with the outer world, it will use four pins: Data in (MOSI), Data Out (MISO), which in open drain configuration needs a pull up resistor, and Clock (SCK), as well as chip select (SS). The VFD differs between grid and segment pins. The grid pins will be attached to GR pins; the segments will (not fully) occupy the SG pins. Furthermore, two buttons are connected through SW1 and SW2 pins, respectively, and VEE is connected to our negative power supply output.

schematics_io.png

Have a look at the repository to save yourself time creating a library for PT6311 or the 8 grid 14 segment display. It also contains the PCB design in Eagle, putting it all together. The PCB measures 95mm x 25mm, and is part of a project that will be revealed later this year. How exciting!

Creating a PT6311 Arduino Driver

Finally, it’s time to talk about how exactly we want to communicate with PT6311, for that we want to write a library (well, a driver is more accurate, since it contains the lowest level functions only) for Arduino. We won’t be doing it in a classical sense, which is using the object oriented approach to create a class PT6311, but will just use plain functions for the sake of compatibility to upper layers, that will be written in plain C. According to the PT6311 datasheet, we differ between command, and display data:

  • A command can be one of four different types. The first two most significant bits tell what command it is, be it configuring how many digits and segments it has, read switch, write display mode or turning the display on, off or dimming it

  • When in increment address mode, the display data can follow consecutively after setting the base address using command 3. This is what we’ll do by default

We can see that it makes sense to have a basic function we can build everything upon, which simply transfers one byte to the PT6311 using the Arduino SPI library:

void _vfdco_pt6311_set_data(uint8_t data) {
  digitalWrite(VFDCO_PT6311_SS_PIN_ARDUINO, LOW);
  SPI.transfer(data);
  digitalWrite(VFDCO_PT6311_SS_PIN_ARDUINO, HIGH);
}

The commands will consist of the command type OR’d with the actual command, which can be stored inside an enumeration or using macros. This is how a typical command can look like using or set data function:

_vfdco_pt6311_set_data(
  (uint8_t)VFDCO_PT6311_COMMAND_2 
  | (uint8_t)VFDCO_PT6311_OP_MODE_NORMAL 
  | (uint8_t)VFDCO_PT6311_ADDR_MODE_INCR 
  | (uint8_t)VFDCO_PT6311_RW_MODE_WRITE_DISPLAY
);

Now the display data transfer can be put right after the configuration command. Since we’re sending consecutive bytes, we don’t want to use the set data function. Instead, we transfer four times: The address, where the multiplication by 3 takes you to the address of the digit position, followed by the 3 bytes of raw display data.

digitalWrite(VFDCO_PT6311_SS_PIN_ARDUINO, LOW);
SPI.transfer((uint8_t)VFDCO_PT6311_COMMAND_3 | (digit_pos * 0x03));
SPI.transfer((uint8_t)(data      ));
SPI.transfer((uint8_t)(data >>  8));
SPI.transfer((uint8_t)(data >> 16));
digitalWrite(VFDCO_PT6311_SS_PIN_ARDUINO, HIGH);

Finally, there is only the special case left, where we would like to request data from the PT6311. We will see how this is done by asking for the bits of SW1…SW4:

uint8_t vfdco_pt6311_get_sw() {
  digitalWrite(VFDCO_PT6311_SS_PIN_ARDUINO, LOW);
  SPI.transfer(
    (uint8_t)VFDCO_PT6311_COMMAND_2 
    | (uint8_t)VFDCO_PT6311_OP_MODE_NORMAL 
    | (uint8_t)VFDCO_PT6311_ADDR_MODE_INCR
    | (uint8_t)VFDCO_PT6311_RW_MODE_READ_SW
  );
  uint8_t sw_in = SPI.transfer(0xFF) & 0x0F;
  digitalWrite(VFDCO_PT6311_SS_PIN_ARDUINO, HIGH);
  return sw_in;
}

Level up!

vfd_20700.jpg

What do we have so far? We have written a driver, which is able to send bytes, more specifically, bit patterns which PT6311 will pick up and interpret it as turning on and off the segments. So if we want to transfer the capital letter ‘A’, we need to align the bits so that the 8 digit 14 segment display (datasheet) turns on exactly those segments that are needed for an A. When using the send data function from above, it might look like this:

vfdco_pt6311_set_data(0, 0b0100001111110001);

Of course it doesn’t have to. We can comfortably save the ones and zeros into an array, and map it to the ASCII character map. While normally hand crafting the array is a time consuming, cumbersome process, you can feel super lucky that I have done it already, and you can simply make use of it! Yay! This is why it’s called level up. Instead of getting dirty with bits, you can simply use a higher level of abstraction and send characters, or even strings instead. And this is what the self explaining functions are for:

void vfdco_8d14s_write_char(uint8_t digit_position, char character);
void vfdco_8d14s_write_string(char *text);

There are two more functions, finally, that deserve the attention for the last part of this little article. These are the write with overlay variants of write char and write string. Write string is more important:

// Multi bit overlay 0b[0|0|0|DPL|DPR|COL|COC|COR]
void vfdco_8d14s_write_string_with_overlay(char *text, uint8_t overlay);

If you look at the display, you’ll find that it has an upper dot after the second digit, and symmetrically a lower dot after the sixth; and between 2 and 3, 4 and 5 as well as 6 and 7 there are colons. To turn on these, simply make use of the overlay parameter. To turn on the upper left dot and the center colon, the parameter would look like 0b00010010.

Have a happy time!

GitHub Repository

As always, the code is provided to you freely on GitHub. Have a happy time. The PCB files can be downloaded here:

Dev Journal: Simulator for Fluorescence the VFD Clock & Firmware Version 3.0

Dev Journal: Simulator for Fluorescence the VFD Clock & Firmware Version 3.0

Fluorescence by The VFD Collective Developer Journal: Home office, writing a simulator for Fluorescence & introducing how its new firmware 3.0 is structured and works under the hood.

Aesthetic Color Palettes with Qt and OpenCV in C++

Aesthetic Color Palettes with Qt and OpenCV in C++

Use the image processing framework OpenCV with Qt GUI to create aesthetic color palettes: Guide on how to program an app in C++ that generates pinterestable colors from a picture & technical stuff under the hood you need to know about!

Simple Object Oriented Code in Plain C

Simple Object Oriented Code in Plain C

We used C++ to learn all the essentials and beauties of OOP. The language supplies us with tools to create classes, methods and everything that comes with it, like inheritance and polymorphism. Based on our knowledge of structs in C we’ve developed an understanding of how classes work. But can we write object oriented code in plain C?

A brief history of Character Encoding + Printing Emojis using Terminal

This article is part of the series of educational articles for ‘Einführung in die Informatik’. Dieser Artikel ist Teil des Zusatzmaterials zu den Tutorien ‘Einführung in die Informatik’ C/C++.

emojis.png

The ASCII Character Encoding

Until now, we have always been working with a very limited set of characters when creating our programs in C. The ASCII encoding (American Standard Code for Information Interchange) consists of 128 characters in total with 95 of them printable and 33 non-printable. We’re familiar with printable characters, such as ‘a’ or ‘9’ or ‘%’. The unprintable counterpart, e.g. a numeric 7 made your computer beep. In general, we know that every character is mapped to a 7 bit number between 0 and 127, fitting into the data type char with even one spare 8th bit. Which is why we can easily create C strings which is just a sequence of numbers mapped to an ASCII character.

Even LCD controllers such as HD44780 (shown with LCD display left, VFD display right) work with ASCII characters

Getting the Most out of ASCII

So with a byte (char) you can represent 128 characters. That isn’t enough when we consider to include German Umlaute, ‘ä’, the e-acute ‘é’ found in e.g. the French language? Well, we can easily use the remaining 1 bit that’ll give us 128 more characters. Here you have it, the Extended ASCII characters (Find them at the bottom of the ASCII map). For many non English countries though, there are still more characters the extended ASCII doesn’t cover. That’s when in the late 80’s until the turn of the millennium the ‘8th bit space’ was once more extended by an awfully named “ISO/IEC 8859” standard with 16 different parts for different languages as of 2001 we’ll call it ISO for now. ISO-7 for instance covers the modern Greek language characters by replacing the extended ASCII map with the Greek alphabet. The different standards resulted in very uncomfortable switches between website encodings and incompatibilities for basically every non English language.

Recreating encoding ambiguity: Create a text file with ‘ß’ and save it with ISO-1 (Western ISO Latin 1) standard

‘ß’ has turned into ‘п’ in the Cyrillic (ISO-5) encoding!

Try it out yourself by creating a plain text (.txt) file with the German ‘ß’ and saving it with ISO Latin-1. Now open this in your favorite web browser and choose a different encoding, e.g. Cyrillic (ISO-5). See the ‘ß’ being mapped to another character?

Interesting approaches extending ISO 8859 included the ISO 2022 which integrated escape sequences to make switching between ISO 8859 encodings possible.

Coding it right: Unicode

What if 8 bit feels so restrictive? Exactly, we just double the amount of bits to store more characters. Hah it’s that simple! So those who felt uncomfortable with ISO worked on a more universal encoding to encode any modern world character. Unicode, designed with the first draft published in 1988 initially using 16 bit, covering pow(2, 14) = 16,384 different symbols/characters in theory.

Unicode is intended to address the need for a workable, reliable world text encoding. Unicode could be roughly described as “wide-body ASCII” that has been stretched to 16 bits to encompass the characters of all the world’s living languages. In a properly engineered design, 16 bits per character are more than sufficient for this purpose.
— Joe Becker, as cited in 'Unicode 88'

It’s important to note that the Unicode doesn’t define how characters are actually stored in disk. It maps a character to a 16 bit number, known as code point (well, as of today it isn’t limited to 16 bit any more but 1,114,112 different code points). It works in a way that the first 128 ASCII characters are preserved as a simple 7 (8) bit char, so ‘a’ is still at 97 or 0x61 in hex or U+0061 in Unicode code point. The German ‘ä’ is in the Latin-1 Supplement block, mapped to U+00E4 and a bunny emoji ‘🐰’ U+1F430.

The most commonly used implementation of the Unicode is the UTF-8 encoding. As of today (November 2018), nearly 93% of all websites use UTF-8 for text encoding. UTF-8 is absolutely genius as it stores characters in variable length from a single byte (ASCII) up to four bytes. The most significant bits of a character byte sequence tell the length of the sequence. If we have a leading zero,

// Binary representation for one byte ASCII (UTF-8) 'a'
uint8_t a = 0b01100001;

we know the sequence is just one byte. Two bits of 1 followed by a 0 marks the beginning of a two byte character:

uint16_t ae = 0b 11000011 10100100; // Binary representation for 2 byte UTF-8 'ä'

What a surprise now to know that a 3 byte char starts with three ones and four byte with four ones respectively:

// Binary representation for 4 byte UTF-8 bunny:
uint32_t bunny = 0b 11110000 10011111 10010000 10110000;

Please don’t do the 8 bit separation as I did here in real world C code as it won’t compile. This is just for readability here.

If our terminal application has UTF-8 encoding enabled, then it’s perfect for us now to print some special chars or emojis now. Use

printf("\xF0\x9F\x90\xB0\n");

to print a rabbit or look up any hex representation of UTF-8 characters here. This isn’t super intuitive, is it? Having to look up every hex representation for special characters we want to display. Well there is a slightly more intuitive way to enter special characters of UTF-8 format using the wide char data type (wchar_t). When set to UTF-8 you can simply enter the UTF-8 code point of a special character. Here’s the simple program I have used to print the few emojis on my terminal:

#include <stdio.h>
#include <wchar.h>
#include <locale.h>

#define N 6

int main() {
  setlocale(LC_ALL, "en_US.utf-8");

  // Emoji array. Look up on emojipedia!
  wchar_t emojis[N] = {0x1f332, 0x1f341, 0x1f4cd, 0x1f342, 0x1f698, 0x1f387};

  // Print emoji array
  printf("This could be the description of any inspirational insta picture\n");
  printf("#reasontoroam #nrthwst\n");
  for(int i = 0; i < N; ++i) printf("%lc", emojis[i]);
  printf("\n");
}

Turns out that you can even enter emojis directly into your printf sequence. If your compiler interprets UTF-8 characters correctly, it will automatically do the hex translation for you (If you look at the assembly code file (compile with ‘gcc emoji.c -S’ generated for the C code, you can see the emojis translated into hex sequences).

#include <stdio.h>
#include <wchar.h>
#include <locale.h>

#define N 6

int main() {
  // Print emojied text
  printf("This could be the description of any inspirational insta picture\n");
  printf("#reasontoroam #nrthwst\n🌲🍁📍🍂🚘🎇\n");
}
L_.str.1:                               ## @.str.1
	.asciz	"#reasontoroam #nrthwst\n\360\237\214\262\360\237\215\201\360\237\223\215\360\237\215\202\360\237\232\230\360\237\216\207\n"

😊-Coding!


References and further reading:

  • Wikipedia of ASCII, ISO/IEC 8859, Unicode and UTF-8

  • http://www.developerknowhow.com/1091/the-history-of-character-encoding

  • https://www.joelonsoftware.com/2003/10/08/the-absolute-minimum-every-software-developer-absolutely-positively-must-know-about-unicode-and-character-sets-no-excuses/

  • http://www.polylab.dk/utf8-vs-unicode.html

Fluorescence & More: Dear Fellow Creators

Fluorescence &amp; More: Dear Fellow Creators

Just a warm hello from me. It's been a long time since I have made some public blog posts or announcements. So here I am now, with a few really exciting things to announce. Let's get right into it

Preparing Fluorescence Kits & The VFD Collective is now on GitHub!

Preparing Fluorescence Kits & The VFD Collective is now on GitHub!

Berlin. It's one of those days in January where most of the people just get up and go to work because they really have to. Not that it's freezing outside. No not even close. Just the grey, dreary sky and the light drizzle going on, probably for weeks again, already...

The VFD Clock Software

The VFD Clock Software

OpenVFD incorporates a full Arduino® Uno® compatible platform and is built upon the Arduino® environment. The code is written in Arduino® C for everyone to understand, to take apart and to participate.

We show you how the OpenVFD software works!