Monday, August 25, 2014

Font issues with BeagleBone Black and ILI9341 TFT display

In my continuing quest to build a really cool digital speedometer for my car I have been experimenting with an Adafruit 2.2" color TFT display. This past weekend I loaded up Ubuntu 14.04 on my BeagleBone Black and wired up the TFT display to it. Adafruit has a python library that works on both the BeagleBone Black and a Raspberry Pi. After trying out the example code I decided I wanted to try using a nicer font than the default one in the example code. The first font I tried seemed to look fine but the second font I tried had the bottom third of the characters not displayed. To figure out which fonts were affected I wrote a python script that cycled through displaying a bunch of fonts on the screen. Here is a video of the results:

As you can see some fonts are affected more than others. A few have over half the line cut off. I started digging into the code that displays the text. I figured out the code is determining the height and width of the text and then turning the text into an image to be displayed on the screen. This is done so text can easily be rotated on the display.

Line number 17 in this snippet of code is where the height and width is determined before making the image.
The Adafruit library is using PIL (Python Image Library) to create an image from the text. Ubuntu 14.04 actually uses a fork of PIL called Pillow. I did some google searches and discovered that the textsize function has a bug that does not account for the font offsets which causes the clipping on some fonts. The Ubuntu 14.04 I installed on my BBB came with Pillow 2.3.0 which was broken. I updated it to latest available package which was Pillow 2.5.3 and it was still broken. I looked at the bug fix on the master branch of Pillow and it was just a small change to one file, PIL/, so I decided to apply that change to my 2.5.3 install of Pillow.

Here is how I fixed it.

cd /usr/local/lib/python2.7/dist-packages/PIL
sudo vi

At about line 142 look for the getsize function. Here is what it looked like before the change.

And here it is after the change.

Save the file and then you need to compile it into python byte-code.
sudo pycompile

This creates an ImageFont.pyc file. Now to test it again.

All fixed! I'm sure that fix to getsize will be pushed out soon so this won't be a problem in the future but until then this will let me continue my experimentation.

Thursday, August 7, 2014

Arduino - TFT LCD display refresh rate part 2

Since January I have been thinking about how to reduce the flashing effect of redrawing characters on the Adafruit 2.2" TFT display running off of an Arduino. Initially I thought I was doing something wrong but then I saw that other projects experience the same slow screen redraw performance. This post isn't about rewriting/optimizing the ILI9340 library that talks to the display. I'm not a good enough programmer to even think about digging into that code. Also I don't think it really is a problem with the library or the display itself. I've seen videos with this display hooked up to a Raspberry Pi smoothly playing video files. I suspect the limitation is the CPU and/or RAM of the Arduino. For my speedometer project I wanted to use an Arduino because it starts up almost instantly and I don't have to worry about shutting it down which is not the case with a Raspberry Pi.

So my goal was to optimize the refresh rate by reducing the amount of screen redraw to the smallest amount possible. To do this I first draw the static elements on the screen (the red box and the mph text). These are never redrawn. Redrawing static items causes a flashing effect. Then the speed value is only updated if it changes. When it does change only digits that have changed are redrawn. For example say the speed is 35 mph and then on the next loop the speed is 36 mph. The 5 would be drawn over with black and then the 6 is drawn in white. This performs the least amount of screen drawing possible.

Here is a video of the progress so far. The code is below the video.

Here is the code