Why I wrote HT1632-AVR.
Adam — Fri, 28/05/2010 - 2:33pm
I, like many people, was excited to learn of the Sure Electronics LED Matrix displays going for cheap on ebay. Sure' makes several different LED displays, the most common being the 0832; in red (DE-DP104) or green (DE-DP105) and the 2416; also in red (DE-DP016) or green (DE-DP017).
This is the story of why I wrote my HT1632-AVR library. If that's of interest to you; read on, if you're just after the code; it's in devdsp/HT1632-AVR on GitHub.
For somewhere between $10 and $15 (USD) you can get 256 or 384 (from the 0832 model or the 2415 model, respectively) addressable LEDs with 16 steps of PWM brightness control over the display (not over each individual LED unfortunately), all neatly laid out in 8x32 or 16x24 (rows by columns. [their naming convention is one of a few inconsistencies you are likely to encounter]) LED matrix display panels which can be cascaded together using IDC cables. The pin-outs on the cables and the documentation say that you can only cascade four displays but I believe you could get away with more if you have access to enough chip select lines and are willing to wire up more than one wiring harness.
The devices are cheap and easily available. Getting the devices from Sure' is a breeze. You hop onto their ebay store, find the display you want, enter how many displays you need, hit "buy it now" and jump through the ebay hoops. A few days/weeks later (depending on your location on this great rock) they will arrive, neatly packed in foam, bubble wrap and anti static bags. This is how buying electronics should be. Getting them to light up takes a bit more work...
All of the 0832 and 2416 displays (so far...) use the Holtek HT1632 LED Matrix Driver IC. This IC implements a frame buffer and matrix scanning for up to 384 LEDs in a single package. It exposes the frame buffer on what it calls an "SPI like" interface. The interface is similar enough to SPI that it's easily implemented on a micro controller that has 5 volt IO pins but different enough that you can't just use a hardware or software SPI implementations.
If, like me, you are using an Arduino and have looked into these displays before, you're likely to have seen the arduino.cc forum thread "Arduino to 384 LED display module (MCU Interface)" where forum user westfw offers to help the original poster out by writing a driver if the original poster had an example of the hardware shipped to him. It's only a few weeks after the negotiation before westfw posts enough code in the thread to write to the displays. Not long after that, lots of people started posting examples using westfw's code and some other people started posting and linking to new libraries. The open source ecosystem works!
Some user's reported strange behaviour with the DE-DP017 (green 16x24) displays. It turns out that for some reason (probably the pin layout out on the batch of green 8x8 LED sub matrices Sure' bought) the memory addresses didn't scan from left to right, top to bottom as they do on the DE-DP104, DE-DP105 and the DE-DP016. The Arduino forum users, using the datasheets provided by Sure', worked out the correct bit maths to determine the address and bit mask needed to turn on or off the LED at any given row and column. Various hacks and forked code bases sprung up to deal with the strange addressing scheme.
We've skipped forward a bit. I was introduced to the displays by Alastair when he wrote up a post on his library, DEDP105, for the green 8x32 displays he bought to use in an ongoing project of his. I didn't even have anything in mind for them but decided to buy four of them anyway. I used a potential project to justify buying them and ended up going with the DE-DP104 (red 8x32) in case I wanted to use them with the ridiculous huge 7 segment displays Sparkfun sell which I have had my eye on for a while now.
I read through Alastair's code, the code posted in the Arduino forum thread and looked at lots of demos of Conway's Game of Life and some simple line rasterisations; but I just wasn't happy with how the other libraries were structured. As far as I could see, none of them supported reading off the display, so none of them could push single pixel changes without using shadow ram; none of them cleanly supported multiple displays; none of them supported the two different sized display sizes without hacking on the library directly; and none of them were encapsulated enough for my liking. I had such a massive case of not invented here that I started working on my own library from scratch.
My goal for the library was to have it as abstracted as was reasonable, support all the functionality of the chipset, be useful for Arduino & raw AVR users and operate at a decent speed. I decided early on that my code would be encapsulated in a class and that the class was going to be focused on interfacing with the IC rather than focus on the particular display that I had from Sure'. The advantage of this was that users could easily use my library regardless of whether their display's memory mapping was contiguous or not and regardless of whether they were configured as 8x32 or 16x24 matrices.
I started working from the datasheet provided by Holtek and soon had all the low level code written to implement the bit-banging to setup the device; send the command, address and data payloads; and send the command, address and then read data out. Each of these steps was broken down into separate functions to make it more adaptable. From there, it was a matter of adding convenience functions to read or write bulk data to the display. After the first few demos were written I decided it was time to speed up the library.
For the first few weeks I was using the Arduino environment's digitalRead and digitalWrite functions which are notoriously slow. I had always planned to replace the Arduino IO functions with direct port manipulation, so when my fellow hacker made the MHVlib IO macros available, I imported the library and ran a few search/replace commands in VIM. This had a drastic affect on the time it took to interact with the display controller. Before the change I had an 8x128 LED scrolling marquee that was a little sluggish, with the new IO macros in place it's hard to read the text as it flies by unless I put delay() statements at the end of each frame. It was about this time that I started tracking the code in git and after a few commits I posted it on GitHub.
I'm confident that I have achieved most of my goals already. With the use of the MHV_IO macros and the helper functions, the code is fast and reasonably easy to use. It's only dependency on the Arduino environment is some trivial macros that I will, one day soon, replace with their static values. I'm currently at a bit of a cross roads. Theres a few places that can be optimised but they may come at the cost of usability.
One idea, as suggested by the main author of MHVlib and writer of DEDP105 for Arduino, is to replace the class members which contain the addresses of data, wclk and rclk ports & pins, replace them with single shot macro definitions and only pass the chip select lines to the class. This would reduce the time it takes to read and write each bit by not requiring the Atmega to load in and dereference the port & pin addresses. This would work if the user only wanted to run a single bus for all their HT1632 displays. I don't think this is an unreasonable limitation and it's one I'm keen on exploring. What do you think?
I could even run with this further and remove the need to pass in chip select pins for each display. The user could implement a function to select the correct display by pulling the right lines low themselves and then run the functions in my class to communicate over the bus. This has the distinct advantage of allowing the user more freedom on how they connect the select lines, making the use of active-low decoder/demuxer chips possible. Being able to use a 74LS154 (4 to 16 decoder) or a CD4515 (roughly equivalent CMOS chip) to control the chip select lines on 16 individual 16x24 displays, thats 6144 LEDs for 8 DIO lines, has a fair amount of appeal.
It would also mean you only need one instance of the class... that is until I patch the code to make it all procedural! One of the very things I set out to change about the existing solutions. Maybe I am mad after all.
Currently the code is most useful in the cases where the displays memory location to LED mapping is contiguous, i.e. the memory addresses run top-to-bottom and left-to-right. That's not to say that it's not useful in the other cases, the user just has to do more work to map the location of the LED they want to change to the memory address and bitmask that controls that LED. Other people have done this by using shadow ram on the micro controller and using a plot function which runs the required bitmath to re-map the location to a page in the shadow ram then setting/clearing the correct bit in that page. This ends up being fairly slow and wasteful. I'm considering writing a subclass to handle the case of the DE-DP017 and dealing with streaming buffers to the display by using some, possibly convoluted, pointer math and multiple 'start writing at address' commands, one for each time the buffer would cross a sub matrix boundary. I have an idea in my head on how this could work but without a display to test it on it will be difficult to write and quite hard to debug. If anyone is interested in working on this with me or shipping me one of the affected displays; drop a comment here, on the project page or on GitHub.
I've done a bit of work on the project since the original push to GitHub and I've done a little bit of promotion here, in the Arduino forum thread I mentioned earlier and on a couple of blog posts around the place that mention the displays from Sure'. A couple of comments on those posts have spurred the development a little but it's been a back-burner project for a while now. With this blog post I hope do drive some traffic to my project page and code repo, if there is sufficient interest I'll try out some more experimental features, actually fix up the project page, post the videos I have recorded of my displays in action and maybe one day I'll mount my displays into a more permanent case.
Those links again are: The project page here on Make, Hack, Void; HT1632-AVR and the code repository on GitHub; devdsp/HT1632-AVR.
- Login or register to post comments
- Printer-friendly version



