Intro
A few weeks ago I ran across a small display called the PicoLCD 4×20 Slideshow, which sells for an incredibly low $50. I used to have a CrystalFontz serial LCD on one of my old Linux boxes and I’ve wanted to mess with one again for a while, but they usually don’t come with cases and the USB version (which I’m interested in) are usually expensive. This was cheap. A few days later it even made Slashdot. Currently it does a tiny bit but isn’t that functional.
Downloads
Note that my source is GPL since it is derived from LCDProc.
- Version 0.1: source
- LibusbJava 0.2.3.0: binary DLL
- LCDProc: source
- Libusb Win32 0.1.12.1: binary
Start of Development
There was only one problem with this device for my purposes: it doesn’t run on Windows XP.
I wanted to use it with my work computer (which runs XP), but the drivers are only for Linux or Vista. When I went to look at the Linux drivers I discovered not only were they open source, they were distributing LCDProc which is what I used to run my old serial LCD with.
This meant only one thing: programming! Since I’m a Java developer, that’s straight where I went. I ordered by LCD and started playing with it almost immediately. The first thing that happened was fun of getting it to work with USB in Java.
USB Fun
Java doesn’t have much going for it in the way of USB access at this moment. There is a proposal for something to integrate into the language (JSR 80) but that’s rather old. The main way to do things seems to be through an implementation of it using the LibUSB library and the Java LibUSB wrapper. Luckily the wrapper has a Win32 version that I can use. It took a bit of research to find this. I also had to go find out how to get Java to load a DLL (found here).
So I spent the afternoon of Friday, September 26th, 2008 translating the PicoLCD driver in the LCDProc source over to Java. Luckily it was a pretty easy translation. I had to change a few types and deal with a few other oddities but it was quite easy.
When it came time to start trying things is when the problems developed. I translated the LibUSB calls directly using the LibUSB RMI interface in the Java wrapper mentioned above. This became problematic when I discovered that there are some functions (like that to ask someone else to hand over the USB device) that aren’t included in the wrapper. Because of this, I had to translate things over to using the JSR 80 interface, which worked well.
So at this point, I have a little LCD, code to drive it, and I start testing. This is when I run into my next problem. I couldn’t get the LCD to initialize, it would just sit there running it’s little start-up routine (telling you where to find drivers). After poking around for quite a while I downloaded the excellent USBSpy to see what was going on. I found two problems in quick succession.
The first is that I translated things a little too well. There are many places where chars are used in the C source to refer to bytes. The problem is that chars in Java are multi-byte, which I didn’t think about until I started having problems. This meant I had to convert all the char arrays and such into byte arrays. This is where I ran into the second problem: everything in Java is signed.
Many of the commands for the LCD contain bytes like 0×95. The problem is that Java won’t let you store 0×95 in a byte, the value is greater than 127 and thus impossible. That means you have to do the 2s compliment 8 bit math to convert it into the correct negative number that it holds the bit representation you want (answer in this case: 0×95 = -107). Once I got a hold on that I was able to make the screen initialize properly.
So today (Monday the 29th) I’ve spent some trying to get something displayed on the screen (culminating in the poor picture above). The command to write something to the screen was being sent but it wasn’t being displayed. This turned out to be because I used a StringBuffer to collect some stuff and then get the values back out with StringBuffer.getBytes(). The first problem was the double byte character thing which cropped up for a second. The second was I was adding bytes with
variable.append((byte) 0x01);
Java, being helpful, turned 0×01 into the String “1″ and appended that which is a very different value from 0×01. Once those two problems were fixed I was able to get “Hello, world!” to display without any trouble.
Buttons and Backlight
With all the commands to send data to the LCD working, I enabled some code that was commented out during testing which set the contract and backlight. When my program started with these things enabled, the LCD was much darker than it should have been.
What I could glean from the LCDProc driver was that the backlight was set as a boolean value: on or off (technically 1 or 0). After some experimenting, I found out that it wasn’t a boolean value, it was a value between 0 and 20 (inclusive). This meant I had to change some of the code (which I had translated with booleans). How did I find out 20? I increased the value until I couldn’t see a difference.
After that I setup the button handling code to get button presses and tell me what was pressed. While doing this I noticed that the buttons in the code didn’t map to the buttons on the device. This didn’t surprise me as the code has extra buttons (plus and minus) and was missing some my device had (OK, for example). So I setup a little program to read button presses and print out what was pressed so I could get all the labels right.
After that was done, I hooked the two bits together and right now pressing up or down will increase or decrease the backlight, proving things generally work correctly. That’s as far as I’ve gotten.
Custom Characters and Graphs
I spent part of Tuesday the 30th trying to make custom character generation work, which is a requirement for making line graphs on the display. It seems that it won’t be capable of seamless graphs (like a CrystalFontz display) but that’s OK. Either way I need to get it working.
I am unable to set custom characters correctly at this point. I thought I was at least getting something (striped bit patterns) but I later determined that those were part of ROM and not something I was setting. I’m guessing this is more bit setting madness (it turns out that the bitwise operators in Java seem to return integers, which is a problem). I may have to make a little function to do arbitrary bit setting for me.
I spent some the next day (October 1st) trying to get custom character generation work again, but it was still to no avail. I was able to document the full character set I have at my disposal but I can’t make new ones. There is only one weird thing going on I can find: the picolcd_set_char function in the Linux driver sends a packet of 10 bytes, but never fills in the 10th (it’s just random). It doesn’t seem to matter whether I send 9 or 10 bytes to the LCD, it doesn’t change anything. I must be missing something. Having some documentation would help. It occurred to me earlier today that the custom character code in the Linux driver may not even work. I’ve got to ask for documentation again. I don’t think I can fix this without more information. I also documented where all the various symbols in the data set were (there is a discussion in this blog entry.)
Issues
There are issues with the code as it is:
- Based on LCDProc driver means there is missing code to do some things
- The driver structure means you need to do all the management by hand right now
- The driver contains extra code that isn’t needed or could be cleaned up
- Many functions are basically untested
And that sums up version 0.1. Right now it displays “Hello, world!” and a few of the buttons adjust the backlight.

