Friday, September 15, 2017

Charlieplexing

I really love the Attiny85 processor. This small processor has a lot of processing power (8 Mhz without any tricks) 5 I/O pins (6 if you do not need to reprogram the processor) and 8K memory. More as sufficient for a lot of projects. And best of all it only costs about a dollar.

However sometimes you run out of I/O pins. I needed to control 20 leds for a project I was making. The Tiny only has 5 I/O pins so that raised a problem. I could move over to a larger processor like the Atmega 328 which has 19 free to use I/O pins.But I wanted to stick by the Attiny85.


So here comes a technique that makes it possible to attach 20 leds to an Attiny 85, provided you can use all 5 I/O pins. The technique is called charlieplexing named after its evangelist Charlie Allen. 

First I'll give you the formula which enables you to detremine how many I/O ports you need for controlling a certain amount of leds:

X * X-1 =  number of leds that can be controlled

So with 3 I/O pins you can control  3 * 3-1 = 6 leds
Using 5 I/O pins you can control 5 * 5-1 = 20 leds.

How does charlieplexing work.

An I/O port can have the digital values 0 or 1. But there is a third state and that is called 3-state. This puts the port in a high-impedance state. So if we put an I/O port in 3-state modus it's value is not 0 and not 1.  We will use that with charlieplexing.

So lets first have a look on how we attach 2 leds to an Attiny 85



Nothing special here. Just 2 I/O ports with each a led attached.

So to connect 5 leds to an Attiny85 you can use the following circuit.



Again nothing dramatic.

But now we are going to do things differently. Lets first start simple and attach 2 leds to an Attiny85 using the Charlieplexing technique. The wiring is now completely different.



So we do not attach both leds to ground but we connect the leds to the I/O pins and one led the other way round.

Now if we put a LOW singnal (0) to pin 5 and a High signal (1) to pin 6 one of the leds will light up. If we switch the HIGH and LOW signals the other led will light up. That is still easy to comprehend.

And here comes the trick. Look at the next scheme:



There you go. 6 Leds attached to 3 pins. Remember the formula: 3 * 3-1 = 6.

However there is a problem using this. We can put a HIGH signal at pin 5 and a LOW signal to pin 7. The current will however run through Led 1 and further to Led 3. And both Leds will light up. That is not what we want. We want to be able to light them up individually. Further problem is that the Attiny85 is not capable of supplying enough current for all leds at the same time. So how are we going to solve that ??? And that is where the software comes in.

How to adress the leds.

So let's get back to the first example with two leds Charlieplexed. 


  



Ok the circuit speaks for itself but now I am going to show you how to adress the individual leds.

Normally we put PWM0 to HIGH to set the first led on and put it to LOW to put the Led off. For the second led we would set PWM1 to HIGH to set the second led ON and LOW to put it off.

With Charlieplexing we need to do that differently. We are going to use the Attiny I/O pins to supply the needed current to the leds.


First step is to define the PINS as INPUT to make sure both leds are off.

int led1 = 0; // pen PWM0
int led2 = 1; // pen PWM1
pinMode(led1, INPUT)
pinMode(led2, INPUT)



Now to put the first led on use the following code:


  pinMode (led1, OUTPUT);
  digitalWrite (led1, HIGH);
  pinMode (led2, OUTPUT);
  digitalWrite (led2, LOW);


And to put led 2 on we use the following code:

  pinMode (led2, OUTPUT);
  digitalWrite (led2, HIGH);
  pinMode (led1, OUTPUT);
  digitalWrite (led1, LOW);


Really quite simple. We just reverse the + and Ground on the pins so that first the first led will turn on and then the second one.

This shows that it is impossible to have both leds on at the same time. For that problem is a solution that I will show you later on.

Ok, nice. But what is the practical use.

Well things change if we use 3 Pins of the Attiny. This gives us a lot more possibillities. With 3 pins we can attach 6 leds. Let's look at the schematics again.




As you can see we can attach 6 leds to 3 pins and even have 2 pins left on the Attiny85 to attach buttons or sensors etc.

LED 1 and LED 2 are attached to pins 5 and 6, LED3 and LED 4 are attached to pins 6 and 7 and LED 5 and LED 6 are attached to pins 5 and 7.

Using software we can adress the individual leds.

First step is to define all pins as an INPUT

int led1 = 0; // pen PWM0
int led2 = 1; // pen PWM1
int led3 = 2; // pen ADC1
pinMode(led1, INPUT); 
pinMode(led2, INPUT);
pinMode(led3, INPUT);


To put Led 1 on we use the next code:

pinMode (led1, OUTPUT);
digitalWrite (led1, HIGH);
pinMode (led2, OUTPUT);
digitalWrite (led2, LOW);

Led 2 can be put on with the following code:

pinMode (led2, OUTPUT);
digitalWrite (led2, HIGH);
pinMode (led1, OUTPUT);
digitalWrite (led1, LOW);


For putting Led 3 on we need the next code:

pinMode (led2, OUTPUT);
digitalWrite (led2, HIGH);
pinMode (led3, OUTPUT);
digitalWrite (led3, LOW);


And putting Led 4 ON done the reverse way as putting Led 3 ON.

pinMode (led3, OUTPUT);
digitalWrite (led3, HIGH);
pinMode (led2, OUTPUT);
digitalWrite (led2, LOW);



Led 5 is adressed in the following maner:

pinMode (led1, OUTPUT);
digitalWrite (led1, HIGH);
pinMode (led3, OUTPUT);
digitalWrite (led3, LOW);



And Led 6 is put on by the reversed code of Led 5

pinMode (led1, OUTPUT);
digitalWrite (led1, HIGH);
pinMode (led3, OUTPUT);
digitalWrite (led3, LOW);


After each led has been set on you NEED to use the following code to put it off again.

pinMode(led1, INPUT); 
pinMode(led2, INPUT);
pinMode(led3, INPUT);

You really need to use this last bit off code each time after putting a led ON. If you don't do that the leds will be ON in an uncontrollable way. More as one pin will be HIGH and that put's leds on in places where you do not want them to be on.

You will surely have noticed by now several things.

Firstly the leds are attached in pairs which makes it simple by reversing polarity on the Attiny pins to put them on and off.

Next you will have noticed that the software to control the leds is getting more complex. In this stage it is manageable. However when you are using 4 pins you can control 4 x 3 = 12 leds and with 5 pins we can control 5 x 4 = 20 leds. The code to adress all these leds individually will be very complicated and that is what we are going to adress in the next part of this story.

Before we go to the next part I am going to show you the circuit in which 5 pins of the attiny85 are used.

If you use just 4 pins of the Attiny85 there is 1 pin left to attach a button or a sensor (LDR, Temperature sensor or whatever). The advantage is obvious. However you can 'only' attach 4 x (4 - 1) = 12 leds.

Using all 5 pins of the Arduino we can control 5 x (5 - 1) = 20 leds. The disadvantage is that there are no pins left to measure something or attach anything else. The only control we can use is to attach a button to the RESET pin of the Attiny85 to restart the program.

The next circuit shows you how to attach 20 leds to the 5 pins of the Attiny85.





As you will understand, the software to control the leds will be much longer if we keep on using the methods described above.

I'll give you an example.

Let's first set all pins of the Arduino in the 3-state mode to make sure nu leds are on.

int led1 = 0; // pen PWM0
int led2 = 1; // pen PWM1
int led3 = 2; // pen ADC1
int led4 = 3; // pen ADC3
int led5 = 4; // pen ADC2
pinMode(led1, INPUT)
pinMode(led2, INPUT);
pinMode(led3, INPUT);pinMode(led4, INPUT);
pinMode(led5, INPUT);


First let us put Led 1 on.

pinMode (led1, OUTPUT);
digitalWrite (led1, HIGH);
pinMode (led2, OUTPUT);
digitalWrite (led2, LOW);


Next step is to put Led 2 on

pinMode (led2, OUTPUT);
digitalWrite (led2, HIGH);
pinMode (led1, OUTPUT);
digitalWrite (led1, LOW);


And now Led 13
pinMode (led2, OUTPUT);
digitalWrite (led2, HIGH);
pinMode (led5, OUTPUT);
digitalWrite (led5, LOW);


Turning Led 14 on is again the reverse from Led 13

pinMode (led5, OUTPUT);
digitalWrite (led5, HIGH);
pinMode (led2, OUTPUT);
digitalWrite (led2, LOW);

Again the rule applies that we have to turn every led off after we have put it on so that all lines are in 3 state mode again and no 2 leds can be uncontrolled on at the same time. Forget to do that and you are in for some really unpredictable results.

So to put 1 particular led on (and off again) we need 9 program lines. For putting all 20 led's on we will need therefore 20 x 9 = 180 program lines. That surely is prone to errors and typo's so that unpredicatble things can happen. There must be a simple solution to that.

And there is !!!

The next part of this story will show you how to simplify the software and how to have multiple leds on at the same time.At this time however you have enough background to start experimenting. Try for instance to make a program that puts all odd leds on and off again.

Till next time

Have fun

Luc Volders