Easy font creation for LED matrix from truetype system fonts

Easy font creation for LED matrix from truetype system fonts

PXK50492-2Today I decided to design and build an LED wand, which I’ll detail in a later post, but I knew to show it off correctly would require a good font, one that I certainly wasn’t capable of making. Here’s how you can make a font from one of your computer’s truetype fonts that’s easily scalable to any size LED matrix.

After much thinking and searching, I found a free program called GLCD Font Creator. After installing and downloading, I realized that I could easily port the code from it to the Ardiuno IDE, and include it in one of my sketches.

Once installed, clicking File>>New Font>>Import From An Existing System Font, will allow you to select a font from all the fonts installed on your computer. If you’re not happy with any of the fonts installed on your computer, I suggest trying Dafont.com or 1001fonts.com.

PXK50492

Once you’ve found the system font you want to show on your LED matrix or LED POV wand or POV display, you’ll have to play around with the size, which is an option on the import font dialog box. You may have to do this a couple times to get it right, but in the end you’ll end up will a really sharp looking font. Start with an arbitrary size, such as 10, and click “OK”.

Another dialog box will pop up, allowing you to select various options for the import. Keep the range the same (32 to 127) which is what characters you want to import. Make sure all “remove” boxes are selected. This will take all the blank lines away from the top, bottom, left, and right.

Click “OK”, and after a minute or so of processing, you’ll be looking at your font. Count the vertical lines on the font to make sure that they do not surpass the amount of LEDs you have in a vertical row. For instance, the POV display that I designed has 16 LEDs, which is 2x 8 bit shift registers. I initially used a font size of 16, and ended up with a vertical row with way over 20 pixels in it, so I had to import again and try a different value until the number of pixels was equal to or less than the amount of LEDs I had. The width does not matter in my case, since it was a POV display wand.

Capture

I found that importing a font of size “11” on most fonts resulted in a vertical row that was 16 pixels in length. You’ll have to play with the font size value to get the amount of vertical pixels that works with your application.

Now for the export. You need to export the data for the fonts in such a manner that you can use it and understand it. Clicking File>>Export For GLCD opens up a dialog box with code in it. In my case, using the Arduino IDE and using the C programming language, I selected the tab (on this dialog box) that said “MikroC”, which contained the code I was looking for.

Here’s a sample of the code output:

1
2
3
4
const unsigned short Calibri15x16[] = {
0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Code for char
0x04, 0x00, 0x00, 0x00, 0x00, 0x06, 0x18, 0xFE, 0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Code for char !
0x06, 0x00, 0x00, 0x3E, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Code for char "

Here’s how to decypher and make use of the code that is generated. There’s two options on the code generation screen, mikroc glcd lib, and x-glcd lib. If your LED matrix or POV display is 8 LEDs or less in height, I suggest using “mikro glcd lib”, if it is larger than 8 pixels (or LEDs), then you will be forced to select “x-glcd lib” and have no other choice.

The differnces between the two are as follows:

The mikroc glcd lib is a simple code where each hex value represents a vertical line in binary bits. If your font has 8 vertical rows, then there will be 8 hex values. The hex value converted to binary will tell you what pixels will be on, and what will be off for each vertical row to display the character properly.

The x-glcd lib is a little more complicated, and contains an extra hexadecimal (the first in the series of each character) that represents the decimal number of how mnay vertical rows are occupied with pixels. For instance, the font I used for my initial test was Calibri, size 11. That imported to a character size of 14 pixels wide by 16 pixes tall. Since my font was greater than 8 pixels in height, I was forced to export with the “x-glcd lib” setting. This causes the first hexadecimal value in each row of characters (in the code) to represent the amount of rows that were occupied with pixels.

So Let’s analyze the code ouptput for the first letter, A, exporting using the x-glcd lib.

Capture

1
 0x0A, 0x00, 0x10, 0x00, 0x1E, 0x80, 0x07, 0xF0, 0x02, 0x1C, 0x02, 0x0C, 0x02, 0x78, 0x02, 0xC0, 0x03, 0x00, 0x1F, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Code for char A

The first hexadecimal value, 0x0A, is equal to the decimal number 10, meaning that there are only 10 vertical rows that contain pixels (as shown below).

Capture

So you can see that 0x0A converted to decimal is equal to 10 and there are 10 usable rows of data, and the rest are blank.

Now, if you were using a font that were only 8 vertical pixels or less and had selected mikroc glcd lib, then each hex value would represent each row of pixels in binary from left to right AND WOULD NOT CONTAIN A HEX VALUE THAT INDICATED HOW MANY VERTICAL ROWS WERE OCCUPIED WITH PIXELS (e.g. the first hex value would be the first line). However, In my case, my font was 16 pixels high, so each 2 hexadecimal values (after the first) were required to represent one line, since a hex value can only contain 8 bits.

So, in my “A” code example above, the first eight pixels down are the second hex value in the code, 0x00, (since the first is the number of occupied vertical lines) and the third hex value, 0x10, represents the second 8 pixels in binary bits.

Capture

So the fourth hex value is the 2nd row, first eight bits from the top. The fifth hex value in the exported code is the 9th through the 16 bits on the second row from the top.

It would be much more simple if your LED POV or matrix were less than 8 pixels high, then you could use the “mikroc glcd lib” option on export (which would eliminate the first character bs) then each hex value would represent one row (e.g. first hex value would be row one from top to bottom, second hex value would be row 2 from top to bottom, etc,…).

So, lets take a look at the function I used in the Arduino IDE to properly display the letters on my POV display (keep in mind, this code is for a font that is greater than eight pixels in height):

1
2
3
4
5
6
7
8
9
10
11
void displayletter(char letter)
for(int i=0; i < (Calibri14x16[((letter - 65) * 29)]); i++){
digitalWrite(latchPin, 0);
delay(linedelay / 2);
shiftOut(dataPin, clockPin, MSBFIRST, Calibri14x16[((letter - 65) * 29) + 1 + (i*2)]);
shiftOut(dataPin, clockPin, MSBFIRST, Calibri14x16[((letter - 65) * 29) + 2 + (i*2)]);
digitalWrite(latchPin, 1);
delay(linedelay / 2);
}
letterspacing(2);
}

There’s a lot going on here in just a few lines, so lets look at it line by line.

1
void displayletter(char letter)

The first line just says we have a function called displayletter that returns a value of void (no return) and accepts and input of char. The char is the letter you want to be displayed.

1
for(int i=0; i < (Calibri14x16[((letter - 65) * 29)]); i++){

The second line initializes a loop, controlled by the variable i, which starts at 0. The loop continues until i is less than Calibri14x16[((letter – 65) * 29)] and increments + 1 on each repetition, that much is obvious, but lets look at the Calibri14x16[((letter – 65) * 29)] part.

The first part, which is a defined array in code Calibri14x16 is the name of the array(not to mention the name of the array that was exported by the program, i did not change it), with and index of ((letter – 65) * 29). When I exported the font, I started from character 65, which is the capital letter ‘A’, and each character occupied 29 hexadecimal values (the first to define how many vertical lines are actually used by the character, then 14 pixels width x 2 (14 x for the top 8 bits, 14 x for the lower eight bits) The program I wrote was to accept a serial input, and flash the letter on the display. So, since the variable was defined starting with character 65, we should subtract 65 from the character input.

For instance, if the user inputs the letter ‘A’, in code it will actually be 65 if you perform arithmetic operations on it, so the “letter – 65” in Calibri14x16[((letter – 65) * 29)] will result in 0, If that letter were inputed. The letter B (character 66) would return a 1 (letter – 65, or 66 – 65 = 1).

The result of that is then multiplied by twenty nine, (letter – 65) * 29 So now an ‘A’ input would result in:

(65-65) * 29 = 0

Letter B would be:

(66-65) * 29 = 29

C:

(67-65) * 29 = 58

And so on… So this part actually returns the 1st hex value of the character that is in the variable, letter, which is the amount of lines that contain data. So we’re telling our loop to loop as many times as there are vertical lines in the letter. Easy enough.

1
digitalWrite(latchPin, 0);

I used a couple shift registers since I had limited pins to work with. This line just writes the latch pin low.

1
delay(linedelay / 2);

This line is telling our program to delay half of our line delay time. This will be explained later.

1
2
shiftOut(dataPin, clockPin, MSBFIRST, Calibri14x16[((letter - 65) * 29) + 1 + (i*2)]);
shiftOut(dataPin, clockPin, MSBFIRST, Calibri14x16[((letter - 65) * 29) + 2 + (i*2)]);

The above two lines shift the data out to the shift registers. Notice they are very similar to the start of the loop in the for statement? There’s one difference, we’re adding to the code so it doesn’t return the first hex value of each letter. Looking at the first line, on the first loop it returns:

Calibri14x16[((letter – 65) * 29) + 1 + (i*2)])

or

Calibri14x16[((letter – 65) * 29) + 1 + 0

So it’s returning the second hex value of the variable, letter. The second line is returning the third hex value of the variable letter. Recall that these two make up the first vertical line in the letter. On the next loop, it will return the fourth and fifth (+1 + (i*2)) hex value, otherwise known as the second vertical line in the letter.

1
digitalWrite(latchPin, 1);

Write the latch high to display the letter.

1
delay(linedelay / 2);

This is the other half of the delay. My thinking behind this is that the line is on for as much time as it is off. If you just flash one vertical line right after another, the lines will blur together. If there is as much on time as there is off time, there will be spaces between the lines and they will look more natural. The off time can be played with, but the idea is not to just switch each line without having some off time inbetween.

1
letterspacing(2);

The last line in the code we are looking at just adds two blank lines after each letter so each letter is clearly separated from the next. I’ll detail the build and the full code of the LED wand when I get some free time. For now, that’s all.