Monday, January 26, 2009

Charlieplexing on the Arduino

Charlieplexing is a way to drive many LEDs with just a few pins on a microcontroller. The technique exploits the microcontroller's ability to put arbitrary pins into high impedance input mode, essentially removing its effect (either sinking or sourcing current) from the circuit. The AVR chips can do this, so can the Arduino.

The easiest way to explain Charlieplexing is to just show you. Take a look at this two pin charlieplex network. The LEDs are connected in opposite directions. By setting both pins 3 and 4 to output mode, and writing HIGH to one and LOW to another, you can light either LED independently. Setting a pin to HIGH will make it source current, connecting it to +5v, while setting a pin to LOW will make it sink current, connecting it to ground. Since the LEDs are connected in opposite directions, only one will light depending on which pin is HIGH and which is LOW. So, to light LED 1, set pin 4 to HIGH and 3 to LOW.

From Arduino Charlieplex

You'll notice that a 2 LED charlieplex network is not very useful. You're lighting 2 LEDs with 2 pins and you can't even light them both at the same time. However, understanding, building and playing with this will help you understand larger charlieplex networks. You'll also notice that one of the resistors is not needed. The only reason two resistors are used here is to keep with the same pattern as the larger charlieplex networks.

Next, take a look at this larger charlieplex network. It's using 3 pins, so now there are 3 possible pairs of LEDs: pins 3+4, 4+5, and 3+5. To address any particular LED, put any pins not directly connected to the LED into input mode, essentially removing it from the circuit. You've reduced the circuit to a 2-pin charlieplex network that you can manipulate in the same way as the previous example. To light LED 5, which is addressed by pins 3+5, first put pin 4 into input mode. Next, set 5 to HIGH and 3 to LOW. Only LED 5 will light.

From Arduino Charlieplex

The natural progression to 4 pins is simple. There are now 6 pairs: 3+4, 4+5, 5+6, 3+5, 3+6, 4+6. To address any particular LED, put the two pins not directly connected to it in input mode and use it like a two pin charlieplex network in the first example. To light LED 9 (which is connected to pins 3+6), put pins 4 and 5 into input mode. Next, set pin 6 to HIGH and pin 3 to LOW.

From Arduino Charlieplex

The major limitation of charlieplexing is the inability to light more than one LED at a time. If more than one LED must be lit, you have to switch between the LEDs to be lit very quickly. This isn't very hard to do though, so it's not that much of a limitation. However, the amount of time any LED gets lit is proportional to the number of LEDs lit. If you have a very large LED matrix with every single LED lit, you may be able to see the LEDs flicker. In general, if an LED isn't being lit at at least 50Hz or higher, you'll be able to see it flicker. Also, since the LED is only being lit for a short period of time (a very low duty cycle), it will appear dimmer than it actually is.

However, it does save you significantly on external components. This LED matrix requires only 4 resistors. If I were using 12 pins, it would require 12 resistors. This can make it easier to make boards with charlieplexed LEDs, though the routes for the network itself are more complex.

Here are some pics of the charlieplex array I made. It's 12 big fat blue LEDs. Those are 10mm LEDs, which I ordered by mistake. However, they were also the only 12 I had of the same type, which is important as I'll explain after the pics.

From Arduino Charlieplex

Choosing your resistor size is important. If you go back to the 3 pin charlieplexing array, you'll see that when you light LED 1, there's an alternate path from pin 4 to pin 3 through LEDs 4 and 5. If your resistor is too small, you will have enough voltage to drive 2 LEDs in series, so LEDs 1, 4 and 5 will light. The fact that I used blue LEDs didn't help either, as they work on a slightly larger voltage range than other LEDs of longer wavelengths.

To choose your resistor, use the normal calculation to choose an optimal resistor size for the LED at 5v. My blue LEDs want 20mA @ 3.2V, so by using Ohm's law, I calculate resistance as 3.2v / 0.02A = 160 Ohms. Since there are two resistors on any pair of pins, divide this in half for 80 Ohms. Since you probably don't have resistors of this value, go slightly higher. To prevent LEDs on an alternate path from lighting up, I had to use 100 Ohm resistors. You'll want to find a resistance high enough to prevent LEDs from alternate paths from lighting up, but as low as possible if brightness is an issue.

So anyway, here's the code I used. It's not the most sophisticated, but it works. I'm going to re-do this in AVR assembly on the ATTiny13 anyway. Blogger doesn't like to format code correctly, so here's the code on Pastie.


evylrat said...

This has been very helpful with my first Arduino project, which I decided was to be Charlieplexing.
Being very new to using breadboards too, I found this link very useful.
I had to redo the sequence in the code a bit but it works great. I can try my own animations now

Andreas Viruly said...

I still have a problem with two led's lighting up at the same time, when only 1 should. I've tried multiple resistors but that would not make any difference. I have 18 LED's on 5 pins. When I set pin 12 on HIGH and 11 on LOW, it seems like pin 10 is LOW as well, even though I've programmed it as INPUT.

Are there things I could be missing? It is a very important project for school, so any help would be appreciated.

Andreas (the Netherlands)

evylrat said...

Andreas, quick question;
are all the LEDs ok? I'm very inexperienced with LEDs etc, and tried connecting mine direct to 5v. It worked for a bit, but I noticed it began to go dimmer and I put it back in matrix of other LEDs and I got the same fault as you, two LEDs lighting at the same time. change the LED i knew I'd damaged and it worked.
Another problem I had was using the wrong holes on the breadboard for one LED which caused 2 LEDs to light.

Jon said...

I was extremely confused by all of the other "tutorials" for charlieplexing. After just the first 2 diagrams, I completely understood everything. Thank you so much!

Jeff V said...

I also found this tutorial helpful. Thanks for the very clear explanation!

Anonymous said...

Since you are running the led at 5V and the led take 3.2V, dont you want the resistor to drop 1.8V (5-3.2).
So R = 1.8/0.02 = 900. Since there are 2 resistors, they should each be 450ohm.

Chris said...

Excellent tutorial...thanks. I can now cross Charlieplexing off the list...

Anonymous said...

Nice article but I should perhaps say that you are being pessimistic about only being able to light one LED at once. If you hold one pin HIGH you can pull any combination of the other pins low to light an LED each - for the 4 pin charlieplex circuit you can light 3 LEDs at once. By adding diodes in parallel with the resistors the LEDs can be made to light evenly.

This way the overall brightness can be improved if the microcontroller can source enough current.

UziMonkey said...

That's only half correct. You can light more than one LED at a time. However, once you start sourcing from one pin and sinking through more than one pin, you lose control over which LEDs can be lit exactly. You may only want to light LEDs 1 and 3, but since there's also a path through 1 and 2 to the sink you're using to light 3, LEDs 1, 2 and 3 will be lit.