As mentioned in a previous post, I recently bought an RGB LED Matrix “backpack” (with 8×8 RGB LED display) created by Logos Electromechanical. It’s an open design, and you can find both the hardware design/schematic and firmware on that page. And again, kudos for this: it’s one thing to fabricate and ship a product, but it’s makers like you that give the community the opportunity to turn what would otherwise be a single-purpose device into a learning and extending opportunity!)
When I got the backpack/LED combo, I was a little confused as to how to get it working, especially with a Raspberry Pi (see my previous post for more about that). However, after some emails and over-thinking I got it working with both the Arduino and the Raspberry Pi and it’s solid for what it’s programmed to do!
However, it does have a few quirks that I’m not entirely happy with (e.g., no apparent way to reset it short of a power cycle, so if somehow your data gets out of sync so will the display, sometimes indefinitely until it’s power cycled) and so I decided to see if I could update its firmware myself (because, hey! Open hardware!) and in doing so I realized that this is an excellent device for a relatively proficient hardware hacker / maker to get their feet wet in a variety of skills they might not normally learn!
Before we move forward, the disclaimers: this is all at your own risk. Question everything! Expect that this sort of hacking / modding will void whatever warranty the unmodded backpack may have had. Wire things up correctly and you should get the same results that I did. Wire them wrong and buy another board! Try feeding 5V into a 3.3V-only pin and… buy another board. You’ve been warned.
Still undaunted? Let’s go then!
First, you’ll need to add an ICSP (aka ISP) header to your backpack. I used the same sort of 2×3 male header you’d find on an Arduino board. Here’s a photo, along with a handy guide to the pin numbers and names:
Let’s not comment on that rosin residue, shall we?
Once you have the header on there you can program the board with your handy in-system programmer (ISP)!
What’s that? You don’t have a dedicated programming device? Well, if you have a Arduino Uno with 5V I/O you can temporarily turn it into an AVR-ISP in a snap!
- I did my work using Windows 7, but the process should be similar for other platforms.
- An Arduino Mega should also work for this, as long as it has 5V I/O.
- Some of the following instructions are adapted from this page, which has lots of other info but which is also rather outdated.
- Plug your Arduino Uno into a USB port. Ensure no other extraneous components or wires are attached.
- Note the serial port number it is assigned, e.g., COM6!
- Get a clone of the code for the TinyISP that I decided to use.
- Use the Arduino IDE to open up TinyISP.pde (which should get auto-converted to the newer .ino format). This should work equally well in the 1.0.x and 1.5.x IDE series.
- Upload the TinyISP code to your Arduino Uno just like any other sketch.
- Connect a 10 μF capacitor between Reset and GND on your Arduino. (“Why?” you ask?)
- If you are using a polarised cap, ensure the negative side goes to ground, or the insides will come spewing to the outside!
Huzzah! You now have an AVR-ISP! That’s great… now what?
First, it’s wise to de-power things. Unplug your AVR-ISP from the USB connection and any other power sources.
Remove extraneous wires. The only connections will be directly between your newly-created AVR-ISP and the RGB Backpack. You can leave the LED matrix itself attached to the backpack… that won’t interfere.
Now, using your choice of wiring, connect the AVR-ISP to the ICSP header on the backpack as follows (the ultimate destination on the ATtiny2313’s pins is presented for reference only):
Programmer --> Device being programmed AVR-ISP 5V --> ICSP Vcc (pin 2) [== ATtiny2313 Vcc (pin 20)] AVR-ISP GND --> ICSP Gnd (pin 6) [== ATtiny2313 Gnd (pin 10)] AVR-ISP pin 13 --> ICSP SCK (pin 3) [== ATtiny2313 PB7 (pin 19)] AVR-ISP pin 12 --> ICSP MISO (pin 1) [== ATtiny2313 PB6 (pin 18)] AVR-ISP pin 11 --> ICSP MOSI (pin 4) [== ATtiny2313 PB5 (pin 17)] AVR-ISP pin 10 --> ICSP Reset (pin 5) [== ATtiny2313 PA2 (pin 1)]
Now you’re all wired up and ready to program! You can plug your AVR-ISP into the USB port now.
Create a folder and get the firmware sources
from the Logos page for this device from Logos’ new Github repo for this device! You can find my fork of their code on Github as well (but be warned that mine is a work in progress). As of this writing there’s a problem though: the USI_TWI_slave.* files aren’t going to work! This project appears to be based on some open source driver files that are functionally equivalent to this reference driver. The correct usiTwiSlave library is included with Logos’ code now. Additionally, a few typos and bugs have been corrected as well.
Note that I changed the target name in the new makefile from “rgb_backpack_pwm” to “rgb_backpack” to be the same as it was originally. You will want to either make that change in my examples here or in the makefile (it doesn’t matter what you call it but it has to be the same name as the hex file you’re trying to make via the command line). Since this backpack doesn’t seem to use the PWM functionality of the LED driver chip, I think it’s a misnomer.
There are many variants on the I2C driver theme when it comes to AVR firmware, starting with the GPL I2C library code originally created by Don Blake on the AVR Forum. This might be worth a new post at some point (I’ve cataloged almost a dozen variants of his library so far, in different projects!) If you’re curious, until Logos created the new repo I was successfully compiling against a recent variant of the usiTwiSlave library posted by Grist. It worked, quirks and all, so the differences aren’t very major.
To put it all together you need WinAVR. Development of it seems to have slowed in recent years, but I was able to use the latest (2010) version without any problems. You can get that one at the WinAVR-20100110 download link.
Install it somewhere easy with no spaces in the path – like C:\WinAVR-20100110
Personally, I would UN-check the extra notepad it wants to install, and UN-check the “add it to my path” part too (we’ll do that manually right before we use the compiler). There’s a bug in the installer… it goes quickly and then it’ll hang for a few minutes (yeah, minutes). It’ll finally exit eventually.
So, at this point you should have an Arduino programmed to be an AVR-ISP, your Logos RGB backpack, WinAVR installed, and the firmware (makefile, rgb_backpack.c, usiTwiSlave.h and usiTwiSlave.c) in a folder (say, C:\rgb_hacking). Here we go:
- Check your ICSP connection between the AVR-ISP and the Logos RGB backpack
- Plug the AVR-ISP into your USB port
- Note the COM port it uses. Mine used COM6, which will appear in the command line
Now, program it by opening a command window where your work is and running the following (changing COM port and path names if necessary):
PATH=C:\WinAVR-20100110\utils\bin;C:\WinAVR-20100110\bin;%PATH% make clean make avrdude -P COM6 -b 19200 -v -e -c avrisp -p t2313 -Ulfuse:w:0xe4:m -Uhfuse:w:0xdf:m -Uefuse:w:0xff:m -Uflash:w:rgb_backpack.hex
As long as no errors appeared you can unplug the USB cable, disconnect the programmer from the backpack, connect the freshly-reprogrammed backpack in as an I2C slave to an Arduino or Raspberry Pi (see my previous post on that) and test it out!
If all went well, you should see… no difference. Well, at least you didn’t break it, but it’s nice to make a quick and simple hack to see if your code actually had an effect.
I had mine connected as device 0x42 (0x40+0x02 on the jumper pad). Try swapping bits 0 and 1 of the address in the firmware and upload that modified firmware. If you were on address 0x42 before, now the device will communicate on address 0x41!
//Original code: if ((PINB & _BV(PB4)) != 0) address |= 0x01; if ((PINB & _BV(PB2)) != 0) address |= 0x02; //Modded code: if ((PINB & _BV(PB4)) != 0) address |= 0x02; // see? if ((PINB & _BV(PB2)) != 0) address |= 0x01; // ^^^
That was (or should have been) pretty easy! But the party train quickly runs out of track… programming firmware is NOT for the faint of heart!
First of all, you’re dealing with an Atmel ATtiny 2313-V (datasheet linked). It’s a great chip but it’s got very little memory… 2 KB is all the room you get for your firmware, and 128 bytes more for SRAM (you also get 128 bytes of EEPROM on-board as well, FWIW). Consider that the original firmware seems to take about 1.4KB and you don’t have a ton of room for making mods.
Second of all, the purpose of the ATtiny in this circuit is to act as a read-only I2C interface to a special LED driver chip on the same backpack board, the Holtek HT1632C (datasheet linked). Don’t ask me more about how that all works because I’m still figuring it out myself.
As you delve into the code, you’ll see many cool techniques for bit manipulation, such as the _BV(n) macro, which is optimized into your code at compile-time. From avr/sfr_defs.h:
#define _BV(bit) (1 << (bit))
As you look through the firmware you will see a TON of this sort of thing… as well as the manipulation of myriad arcane registers, manual _delay_ms() calls, lots of bit-packing and bit-arithmetic – and a fair amount of dead code as well (which is also educational, as long as you don’t get too far down the “I modified this code but it has no effect!!!” road because what you modified is never in the final compiled object.
Right now the firmware is pretty simple: detect when you’re being addressed, and if that’s the case read 24 bytes and pack and forward them to the LED controller chip. I aim to add command functionality to this (thus, you would send up to 25 bytes, the first one being a command). That would allow the addition of a “reset” command – assuming that’d even be effective. If I get anywhere I’ll add a followup post.
A note on licensing (I am not a lawyer):
I asked Logos for followup on my driver question (since what’s currently posted won’t compile) and am awaiting a reply. The code on the Logos repo statically links with the GPL v2 usiTwiSlave library. Since linking GPL code with other code makes it all GPL, it would be prudent to treat any fork of this firmware as GPL (in other words, don’t fork it and try and slap some more restrictive license on it as that’d be violating GPL). If this is somehow NOT GPL code by design or by linkage, then it’s whatever license they want it to be. See above. I take the publication of the firmware source as a sign that this is hacker-friendly though, and am encouraged by that, however the firmware doesn’t say either way. See above. Also, it’d be great if Logos posted the firmware hex file. Logos’ repo includes the original firmware .hex file! It’s always nice to be able to flash back to a known-good firmware in case something goes wrong (unless you fry the board or flash the device 10,000+ times and wear it out, you can always flash to a known-good firmware build you’ve made). Note: I can’t replicate that firmware file exactly yet – it may be due to a difference in compiler versions or even the OS used to build it but I doubt it’s anything major.
I suspect I could’ve pulled the firmware off as a first step, but it didn’t occur to me at the time (living dangerously!) If someone manages to do that let me know.
A note to the advanced user: Don’t bother to try and leave the device connected to both the programmer and the device you’ll use to test it… I did that (I’ve got a few different Arduinos) and was able to program the backpack’s firmware but couldn’t get it to run until I disconnected it from the programmer. (I suspect it’s the reset line that hangs it.)
A second note: This may not work for everyone, but if you unplug both the I2C lines from the driving device, you might get an interesting effects as the display slowly fills to white – I mean to post a video of it sometime. I thought it was a cool reset feature but it’s not in the code at all. I suspect it’s an antenna or capacitive coupling effect involving either the clock circuits or possibly ambient RF (if I plug the wires into separate unused breadboard holes the effect goes away, and it goes away in the command-code variant of the firmware I’ve been working on). It’s surprising how a seemingly-designed effect can actually be the result of random noise… 😀
Next time, on MacGyver: I’ll talk about the firmware updates I’m making, particularly one to change the rather quirky way green is handled by this design and how I fix that, as well as the (attempted) addition of command channels (to allow for greater functionality).
Happy hacking / modding!