Sunday, March 23, 2014

Soldering tiny things

Some people make soldering look so easy. It's not. Not for me. I made a bit of a mess of my practice board, but at least it helped me get the hang of it a bit. 0805 sized components are pretty small, 0603 is just tiny! It's pretty difficult to get them straight on the board. SOT-23 is just as awful. SO-16 was doable fortunately, I'd hate to have that one messed up. But I'm going to stay away from TQFP for now, I made a terrible mess out of those.

The first board I finished turned out okay, nothing to be terribly proud of. 

Also did a bit of practicing with my new cable crimp tool, the first couple of cables are pretty horrible, but the last few went pretty well. 

Saturday, March 22, 2014

Cathode boards arrived!

Today I received the cathode boards that I had ordered from OSH Park about two weeks ago. That's a lot faster then I thought it would be. Nice!
They came in a matching purple bubble envelope, the people at OSH Park seem to be really fond of purple :) They even threw in a sticker, awesome! I'll put it somewhere on the base of the cube I think, probably on the inside next to the boards ;)

The boards themselves look pretty much like how I thought they would be. The gold finish looks really nice. But I also noticed that the silkscreen isn't positioned as accurate as I thought it would be.
Here's the worst one, you can clearly see the silkscreen around the mounting holes being off center. At some points the silkscreen has been printed on the pads. Not that it matters that much, the biggest mistake is on my account. I have via's running through a bunch of pads. That's not going to make soldering any easier. I'm going to fix that before I order any more boards. I'm also going to have to do something about the component references, they're pretty much impossible to read for the smaller components because they either overlap with the footprint, or are clipped by the pads.
This one turned out really nice! I still have to trim the tabs; nothing a side cutter and a file can't fix. And I must say, it's really cool to hold something in your hands you designed yourself :)

I've also received a smd soldering practice board this week. I'll give that one a go before I start populating these boards :)

Thursday, March 20, 2014

That's more like it!

So I'm done with bending leads on those LEDs, in multiple ways... I've done about 500 now and am calling it quits. I'll bend the rest when I need them.

It's finally soldering time again! Six done tonight in a bit over an hour. Average soldering time for one pillar is now about twelve minutes instead of twenty. Not having to bend those leads before putting them in the jig really makes it go a lot smoother. Anyway, 13 down, 51 more to go...

Soldering also seems to go faster, I think I'm getting the hang of it :)

Tuesday, March 18, 2014

Moar LEDs!

Phew! 400 done, just a bit over 100 to go until I have 512 perfectly shaped LEDs. That's one bag and a dozen :)

Sunday, March 16, 2014

Bending LEDs

Another weekend well spent :)

I've soldered three more pillars and straightened around fifty wires. I've also started bending the leads on all LEDs, a really boring job, but doing this beforehand will make the soldering go much faster. As it turns out, bending one LED costs about as much time as soldering one. And the more I can do in batch, the better!

Here's what I started with: around 600 LEDs
And the result after an evening on the couch, watching TV while bending leads.
200 done, 400 to go :)

I've marked the green cathode with a marker on each LED, that lead will have point up when the LED is inserted into the jig. It's pretty easy to spot the correct lead by just looking into the package, but more on that later.

All leads are at a 90 degree angle of each other and the LED sits perfectly flat on a flat surface (my hand isn't flat obviously).  It takes about 30 to 40 seconds to bend the leads on one LED, I could've done this faster but I'm a bit of a perfectionist, and I was watching TV :) It costs about 1 hour per 100 LEDs, but hopefully it'll save some time when soldering.

The great thing about this project is that it's easy to spend anywhere from 15 minutes to a few hours on it; you can just grab a box with all the tools/parts, do some work, and put it away when you're done or out of time. Cleaning up and getting started only takes a minute or two.

In other news, the PCBs I've ordered have been shipped last Friday! They'll probably arrive somewhere next week, but at least before the end of the month :)

Update 17-03: and a few more LEDs done, halfway there!

Tuesday, March 11, 2014

Cutting and stripping the time away

2.5 hours well spent. I've cut and stripped about 150 wires. I guess I still have a few wires left to cut and strip, but I'm not going to count them right now. I guess I'll find out when I run out of wires :)

I also just learned that the order for my boards have been sent to the fab. It's expected to arrive at OSH Park in about a week, not bad :)

Theory: shift registers, and the test jig code explained!

Ahh... Shift registers. The heart of most LED cubes.

So, what is a shift register and what does it do? Basically it's a serial input, parallel output IC; you send a stream of ones and zeroes to it on one pin and this makes a bunch of output pins go high or low. Usually you have two more pins: a clock pin and a latch pin. The clock pin is used to tell the shift register when to read a new bit on its input pin. The latch pin is used to tell it when to make the read bits appear on the output pins.

In my cube I use the 74HC595 shift register which is an 8 bit shift register. It simply means that it has 8 outputs. You can find these for almost a dime a dozen on eBay. If you need the smaller SMD type, search for 74HC595D.
The 595 (as I'll refer to it from now on) has two internal registers: the shift register and the storage register. We'll start at the beginning - the input pin - and work our way down to the output pins.

When you want to send data to the 595 you start by setting the DS pin (Serial Data Input) high or low, depending on whether you want to write a one or zero. Then you make the SHCP pin (Shift Register Clock Input) go from low to high to low again. The shift register will update whenever that pin goes from low to high. It will store whatever value is at DS and put it in bit 0 of the shift register. All the other bits of the register are shifted to the next one. So bit 1 will get the old value of bit 0, bit 2 the old value of bit 1, etc etc. The cool thing about this is that the old value of bit 7 will appear at a pin called Q7S. If you connect this pin to the DS pin of a second 595, and also connect the SHCP pins of both 595s, then bit 7 of the first 595 will be shifted to bit 0 of the second 595. You can chain a whole bunch of registers like this, effectively forming one large shift register.

Great, now that you've shifted 8 bits into the 595, you'll want to have them appear at the output pins. To do this you pull the STCP (Storage Register Clock Input, otherwise known as Latch) pin from low to high to low again. Whenever this pin goes from low to high all values from the shift register will be copied to the storage register.
This storage register is connected to the output pins, so any value in it will appear on the output pins. But only if the OE (Output Enable) pin is pulled low. If OE is high all output pins will be low.

One thing that's important to know is that when both the STCP and SHCP pins go high simultaneously, the shift will take place after the contents of the shift register have been copied to the storage register. This means that when you have STCP and SHCP connected to eachother, and you shift in a bit, that this bit will not appear on the output directly (since the content of the shift register has been copied to the output register before the new bit was shifted in).

Let's have another look at my pillar testing code. For this I have connected STCP and SHCP to the same pin on the controller (B4) and DS to B3. OE has been connected to ground.


1:  /*  
2:   * TinyPillarTester.c  
3:   *  
4:   * Created: 6-3-2014 21:48:11  
5:   * Author: Daniel  
6:   */   
7:    
8:    
9:  #include <avr/io.h>  
10:  #include <avr/interrupt.h>  
11:    
12:  int main(void)  
13:  {  
14:      PORTB = 7;  
15:      DDRB = _BV(DDB0) | _BV(DDB1) | _BV(DDB2) | _BV(DDB3) | _BV(DDB4);  
16:    
17:      TCNT0 = 0;  
18:      TIMSK0 = (1 << OCIE0A); // interrupt on compare match  
19:      TCCR0A = _BV(WGM01);  
20:      TCCR0B = _BV(CS01); // F_CPU / 8  
21:      OCR0A = 250;  
22:      asm("sei");  
23:    while(1)  
24:    {  
25:        // do nothing!  
26:        asm("sleep");  
27:    }  
28:  }  
29:    
30:  uint8_t cathodeCounter = 4;  
31:  uint8_t anodeCounter = 0;  
32:    
33:  ISR(TIM0_COMPA_vect, ISR_NAKED)  
34:  {  
35:      uint8_t sreg = SREG;  
36:      static uint8_t counter = 0;  
37:      ++counter;  
38:      if ( counter >= 75 )  
39:      {  
40:          counter = 0;  
41:          ++anodeCounter;  
42:          if ( anodeCounter == 8 )  
43:          {  
44:              anodeCounter = 0;  
45:              PORTB |= _BV(3);  
46:          }  
47:          else if ( anodeCounter == 1 )  
48:          {  
49:              PORTB |= cathodeCounter;  
50:              cathodeCounter <<= 1;  
51:              if ( cathodeCounter >= 8 )  
52:              {  
53:                  cathodeCounter = 1;  
54:              }  
55:              PORTB &= ~cathodeCounter;  
56:              PORTB &= ~_BV(3);  
57:          }  
58:          PORTB |= _BV(4);  
59:          PORTB &= ~_BV(4);  
60:      }  
61:      SREG = sreg;  
62:      asm("reti");  
63:  }  
64: 

Let's go through this line by line.

12:  int main(void)  
13:  {  
14:      PORTB = 7;  
15:      DDRB = _BV(DDB0) | _BV(DDB1) | _BV(DDB2) | _BV(DDB3) | _BV(DDB4);  
Line 14: Pins B0,B1 and B2 are set high, since they are connected to the cathodes of the LEDs this will make the LEDs go off. B3 (DS) and B4 (SHCP, STCP) are set low.
Line 15: All pins are configured as output pins (except B5, which is the reset pin)

17:      TCNT0 = 0;  
18:      TIMSK0 = (1 << OCIE0A); // interrupt on compare match  
19:      TCCR0A = _BV(WGM01);  
20:      TCCR0B = _BV(CS01); // F_CPU / 8  
21:      OCR0A = 250;  
Line 17-21: Timer initialization, it's set to generate an interrupt on compare match. The value to match is 250. The counter will reset when the match occurs (line 19) and its speed is 1/8th of the cpu speed (line 20).

22:      asm("sei");  
23:    while(1)  
24:    {  
25:        // do nothing!  
26:        asm("sleep");  
27:    }  
Line 22: Inline assembler, the "sei" command will enable interrupts
Line 23 - 27: Do nothing. The "sleep" command puts the cpu in idle state until there's an interrupt. This also reduces power consumption from 3 mA to 0.5 mA.

33:  ISR(TIM0_COMPA_vect, ISR_NAKED)  
34:  {  
35:      uint8_t sreg = SREG;  
Line 33: Start of interrupt handler for timer0 compare match. ISR_NAKED means the compiler won't put any code at the start and end specific to handling interrupts. One of the things you need do do is store the SREG register and restore it at the end, as you can see on line 35
Let's skip some stuff

61:      SREG = sreg;  
62:      asm("reti");  
63:  }  
64: 
Line 61: Restore SREG, not really necessary since we don't have any code in our main loop. But hey, it's good practice.
Line 62: Return from interrupt. Required special command if you exit an interrupt handler.

36:      static uint8_t counter = 0;  
37:      ++counter;  
38:      if ( counter >= 75 )  
39:      {  
40:          counter = 0;  
Line 36-40: The timer is configured to generate 600 interrupts per second, I only need 8, so this slows it down a bit :)

41:          ++anodeCounter;  
42:          if ( anodeCounter == 8 )  
43:          {  
44:              anodeCounter = 0;  
45:              PORTB |= _BV(3);  
46:          }  
Line 41: A counter to run through all the anodes. When it reaches 8, I reset it to 0. I also set B3 (DS) high (line 45).
47:          else if ( anodeCounter == 1 )  
48:          {
56:              PORTB &= ~_BV(3);  
57:          }  
Line 47: On the first interrupt (or the first one after the anode counter has been reset) I set B3 low again (line 56). It'll stay that way until the counter reaches 8 again. So it's high for 1 update, and low for 7.

58:          PORTB |= _BV(4);  
59:          PORTB &= ~_BV(4);  
Line 58: Set B4 (SHCP and STCP) high, this will cause the contents of the shift register to be copied to the storage register, and then shift a new bit from DS into the shift register.
Line 59: Set B4 low again.

And that's pretty much it. This clocks one bit to the shift register every 8th of a second, one one and seven zeroes. So one pin will be high and the others low, and the high pin will shift to the next every 8th of a second.

Now there's just a small piece of code left:
49:              PORTB |= cathodeCounter;  
50:              cathodeCounter <<= 1;  
51:              if ( cathodeCounter >= 8 )  
52:              {  
53:                  cathodeCounter = 1;  
54:              }  
55:              PORTB &= ~cathodeCounter;  
Line 49-55: This handles switching between red green and blue (cathodes). The cathodeCounter variable is a bit mask, only one bit will be set, which corresponds to one of the output pins B0, B1 or B2. I first apply this mask to the pins, which makes the current active pin go high (line 49) turning the LED off. Then I shift the variable left one bit to move to the next pin (line 50). If it goes past the last pin (line 51) I reset it back to the first pin (line 53). Finally I negate the mask and apply it, setting the new active pin low (line 55) turning the LED on.

The reason this piece of code sits inside the anodeCounter == 1 block is because the actual output of the 595 lags one clock cycle behind the content of the shift register. If I had put this code in the anodeCounter == 8 block then the jig would switch colors while the last LED was on. Since we don't want that, we have to wait one more cycle.

That's it! I hope this gives a better understanding of the 595 and the test jig :)

Sunday, March 09, 2014

4 down, 60 to go!

This project is going to take some time... I've just finished the fourth pillar and did some timing. I first cut, stripped and straightened 24 wires (for eight columns). This took about an hour, 7.5 minute per pillar. Then I started building pillars.
  • Bend the legs on eight LEDs
  • Trim the leads on the LEDs
  • Insert them in the jig
  • Insert the wires
  • Solder the LEDs
  • Trim the leads on the LEDs further
  • Cut the wires
  • Take the pillar out of the jig
  • Test it using the test jig
That took well over half an hour for the first pillar, 30 minutes flat for the second, and 20 minutes for the third. I did things slightly different for the last pillar. Instead of trimming the leads after bending them I just inserted the LEDs in the jig. I start by slightly pressing the top wire down on the jig and trim the top leads (green) before soldering them. Then I solder the top leads. After that I trim the remaining leads (red and blue). I then slightly bend the leads so they (almost) touch the wires. This makes soldering a bit easier, and you don't risk damaging the solder joint when trimming the leads.

All in all it takes about half an hour to create one pillar. I must admit I'm not that experienced when it comes to soldering, so I might be able to shave a few minutes off on that. It also helps to do things in batches and minimize switching between tools; I've first cut 24 wires, then stripped them and finally straightened them, instead of performing 3 steps on 1 wire after another.

Anyway, at this speed it's going to take about a month to finish all the pillars if I spend one hour a day. Damn...

Saturday, March 08, 2014

You've got mail!

The mailman doesn't seem to be liking me much lately, annoying bubble envelopes every couple of days, and often multiple on the same day. Having delivered mail myself for a few years I can relate to that, but nevertheless it makes me happy when I hear big things fall on the doormat :D
Today's "harvest": 200 LEDs, 5000 91 Ohm resistors, 5000 150 Ohm resistors.

Also visible on the photo are some wires I stripped and straightened. A colleague of mine gave me a golden tip on how to straighten those wires easily, but that's worth its own post and instructional video ;)

Friday, March 07, 2014

Cathode Board ordered!

I decided to go ahead and order a few cathode boards from OSH Park. It's the first time I've ordered a PCB I designed so I'm pretty excited about this. I've ordered six for now, for a total cost of $14.40, just to see if the design is actually going to work or not. Six of these boards is what I need to build a 4x4x4 cube as a proof-of-concept. If they work I can recycle them for the 8x8x8 cube.
OSH Park gives you a rendered preview of what the board is going to look like, pretty neat. Here's the bottom
 And the top:
And now we wait. The boards have been assigned to a panel, once the panel is full it will be manufactured. I believe it takes about 12 days for the board to be shipped, and then another 2 weeks or so before it actually arrives in the mail. So I guess I'll receive them somewhere early April.

Thursday, March 06, 2014

Debugging the pillar test jig

When the cause of a problem is not immediately often it is often good practice to first check for the most obvious mistakes, isolate a few small portions and check if they work and then work your way up, combining the parts you've checked. This approach works pretty well in debugging software and I use it a lot.

I should've used it here as well.

As I wrote in my previous post, only the bottom LED in my pillar would light up properly when I inserted it in the jig. What I also noticed is that this is also when I put the serial data line high (for the other 7 points in the cycle it's low). I also noticed that the serial data pin on the shift register is right next to output pin 0, to which the bottom LED is connected. It's obvious to expect a bad soldering job (if you're familiar with my soldering) so I wanted to rule that out first.
What I did was modify the code a bit, so will put the data line high after 4 cycles as well. This would give me 2 lit LEDs in the loop and would give me a chance to see if only the bottom LED would light up brightly or not. That wasn't the case; both LEDs would light up brightly whenever the serial data pin went high.
Next up was measuring voltages and current on the bright and dim LEDs, this confirmed that the dim LEDs got less volts across them than the bright ones, but it still didn't explain why.
I slowed down the code a bit (one update per two seconds) and started to notice something odd: the shift register would reset after a brightly lit LED would go off. Expecting something more fundamentally to be wrong I ripped all of the jumper wires out of the protoboard and pulled the shift register IC out of its socket. Then I started checking all connections on the protoboard.

I should've started with that really.

I forgot to connect the power supply of the shift register to the power supply of the ATtiny. There was a wire going there and it was soldered to the board, but on the bottom I never connected the wire to the VCC pin... Doh!
I also forgot to solder the pull up resistor on the reset line to 5V and the ceramic capacitor was floating as well. What a mess. I'm a bit puzzled as to why the LEDs would even light up in the first place, probably the shift register got some current through its input pins just enough to keep running. Anyway, I hooked everthing up and it works like a charm now!


Here's the Arduino code. Yes, it's messy and more complicated than it should be since I'm not using any Arduino functions. This way I can simply copy/paste it to AVR studio so it can run on the ATtiny (apart from the timer prescaler setting and counters).I'm using PORTB since that's what the ATtiny13 also has. Arduino pins 8-10 should connect to cathodes R, G and B.Pin 11 should connect to DS and pin 12 to SHCP and STCP.


1:  void setup()  
2:  {  
3:      PORTB = 7; // pull cathode pins high, no current will flow
4:      DDRB = _BV(DDB0) | _BV(DDB1) | _BV(DDB2) | _BV(DDB3) | _BV(DDB4);  
5:      // initialize timer
6:      TCNT0 = 0;  
7:      TIMSK0 = (1 << OCIE0A); // interrupt on compare match  
8:      TCCR0A = _BV(WGM01);  
9:      TCCR0B = _BV(CS02); // F_CPU / 256
10:      OCR0A = 250;  
11:      asm("sei");  // enable interrupts
12:  }  
13:    
14:  uint8_t cathodeCounter = 4;  
15:  uint8_t anodeCounter = 0;  
16:    
17:  void loop()  
18:  {  
19:      // do nothing!  
20:      asm("sleep");  
21:  }  
22:    
23:  ISR(TIMER0_COMPA_vect, ISR_NAKED)  
24:  {  
25:      uint8_t sreg = SREG;  
26:      static uint8_t counter = 0;  
27:      ++counter;  
28:      if ( counter >= 20 )  
29:      {  
30:          counter = 0;  
31:          ++anodeCounter;  
32:          if ( anodeCounter == 8 )  
33:          {  
34:              PORTB |= _BV(3);  
35:              anodeCounter = 0;  
36:          }  
37:          else if ( anodeCounter == 1 )  
38:          {  
39:              PORTB |= cathodeCounter;  
40:              cathodeCounter <<= 1;  
41:              if ( cathodeCounter >= 8 )  
42:              {  
43:                  cathodeCounter = 1;  
44:              }  
45:              PORTB &= ~cathodeCounter;  
46:              PORTB &= ~_BV(3);  
47:          }  
48:          PORTB |= _BV(4);   
49:          PORTB &= ~_BV(4);  
50:      }  
51:      SREG = sreg;  
52:      asm("reti");  // return from interrupt
53:  }
Here is the board with the ATtiny installed. The jumper wires are there to supply power from USB. The second protoboard in the background is my home made programming socket for the ATtiny. It's just a DIP 8 socket with all pins available on female headers. There's a 10 pin male header connected to the necessary ISCP pins so I can just simply connect a flat cable to the USB programmer (shown on the left).
Now all that's left to do is fix the board to the jig and add a power connector, or maybe a 7805 voltage regulator so I can power it from a battery or other external source and make the whole thing more portable :)
As for the ATtiny code:
1:  /*  
2:   * TinyPillarTester.c  
3:   *  
4:   * Created: 6-3-2014 21:48:11  
5:   * Author: Daniel  
6:   */   
7:    
8:    
9:  #include <avr/io.h>  
10:  #include <avr/interrupt.h>  
11:    
12:  int main(void)  
13:  {  
14:      PORTB = 7;  
15:      DDRB = _BV(DDB0) | _BV(DDB1) | _BV(DDB2) | _BV(DDB3) | _BV(DDB4);  
16:    
17:      TCNT0 = 0;  
18:      TIMSK0 = (1 << OCIE0A); // interrupt on compare match  
19:      TCCR0A = _BV(WGM01);  
20:      TCCR0B = _BV(CS01); // F_CPU / 8  
21:      OCR0A = 250;  
22:      asm("sei");  
23:    while(1)  
24:    {  
25:        // do nothing!  
26:        asm("sleep");  
27:    }  
28:  }  
29:    
30:  uint8_t cathodeCounter = 4;  
31:  uint8_t anodeCounter = 0;  
32:    
33:  ISR(TIM0_COMPA_vect, ISR_NAKED)  
34:  {  
35:      uint8_t sreg = SREG;  
36:      static uint8_t counter = 0;  
37:      ++counter;  
38:      if ( counter >= 75 )  
39:      {  
40:          counter = 0;  
41:          ++anodeCounter;  
42:          if ( anodeCounter == 8 )  
43:          {  
44:              PORTB |= _BV(3);  
45:              anodeCounter = 0;  
46:          }  
47:          else if ( anodeCounter == 1 )  
48:          {  
49:              PORTB |= cathodeCounter;  
50:              cathodeCounter <<= 1;  
51:              if ( cathodeCounter >= 8 )  
52:              {  
53:                  cathodeCounter = 1;  
54:              }  
55:              PORTB &= ~cathodeCounter;  
56:              PORTB &= ~_BV(3);  
57:          }  
58:          PORTB |= _BV(4);  
59:          PORTB &= ~_BV(4);  
60:      }  
61:      SREG = sreg;  
62:      asm("reti");  
63:  }  
64:    
Notice how similar it is to the Arduino code. The name of the interrupt handler is a bit different, and I've chosen different values for the timer prescaler and counter, and the setup and loop functions are combined in one main function. This code uses 208 bytes (20%) of ROM and 4 bytes (6%) of SRAM. Even the ATtiny13A is a bit overkill for something like this :)

Anyway, that's it for today, I'm always glad when something is working by the time I decide to call it a day :)

Wednesday, March 05, 2014

Pillar testing jig v1.1

I didn't like my initial version of the pillar testing jig much; it's too much work putting on 11 connectors and I'd have to use quite a bit of force to get the connector on, risking some bent leads. So I came up with the following contraption:
I can just clamp the anode leads between the two pieces of wood. There are connectors running through the top piece into the wires. And on the bottom side they touch the anode leads.
And when the pillar is clamped in it'll look like this:
It's just a few pieces of wire going through the wood, bent 90 degrees. But it works fairly well. As long as I press down on it all leads make contact, just gravity isn't enough. But hey, it only takes a couple of seconds to see if all LED leads are connected or not.
Unfortunately there's not demonstration video yet. I still have a small glitch somewhere in my protoboard which causes the bottom LED to light up brighter than the rest. To be more precise; when the DS line on the shift register goes high, the LED connected to Q0 lights up bright. And the other ones are just dim whenever they turn on.
 Great, I hate debugging hardware... :)

The ATtiny still needs to be installed, but I want to fix the brightness issue first. I also need some different connectors for the cathodes, these Dupont connectors simply aren't suitable for this kind of work.

Tuesday, March 04, 2014

Theory

In this post I want to take some time to explain the schematics. I want this to be as accessible as possible, so we'll start at the very beginning.

Connecting an LED

LEDs arent' like ordinary light bulbs. You cannot (read: should not) connect an LED directly to a battery. The reason for this is that an LED has a very low internal resistance, so you'll effectively be shorting the battery. Sure, it will work if the voltage is right, but you risk damaging the LED. They're also picky about the voltage, so you'll want to provide an LED with just the right voltage.

To accomplish this we put a resistor in series with the LED. To get the right resistor value you need a couple of parameters: the forward voltage of the LED (VF), the input voltage (VI), and the forward current (IF). The forward voltage of an LED depends on its color. Red usually means 2.4V, Green and Blue 3.4V. The input voltage of my cube is 5V. The forward current of an LED is typically 20mA (0.02A). Check your datasheets for your specific LEDs to verify this.
Now we need our input voltage VI to drop to VF, so that's VI - VF Volts. Then we simply apply Ohm's law (I = U/R, or R = U/I) and we get R = (VI - VF) / IF. So for a red LED that's (5 - 2.4) / 0.02 = 130 Ohm. For green and blue it's (5 - 3.4) / 0.02 = 80 Ohm.

Let's wire up a red LED to 5V. 130 Ohm resistors aren't that common, so we'll use the next best thing: 150 Ohm. Remember, LEDs are Light Emitting Diodes, so they'll only let current flow from one lead to the other, specifically from the anode (long lead) to the cathode (short lead, and the side where there's a flat spot).

That was simple enough, now let's try something more interesting.

Connecting an RGB LED

Multicolor LEDs come in two configurations: common Anode and common Cathode. They are basically multiple LEDs in one package with either the anode or cathode lead shared between all LEDs.
Does it matter which one you use? Not really, as long as you know what type you're using/ordering. This also has consequences for where you place the series resistor. You shouldn't connect your resistor to the common lead of your LED, unless you have a bi-color LED where both LEDs have the same forward voltage, or you're using the highest resistor value.

For the rest of this post we'll be using common anode LEDs, since that's what I'm going to put in my cube.

Connecting it is easy, just hook 5V to the common anode, a few resistors to each cathode and the other end of the resistor to ground.

Controlling an RGB LED

So we've got our RGB LED burning, but now we want to control it. We want to be able to turn each color on and off. So we grab our Arduino (or other microcontroller) and hook our LED up. Instead of connecting the resistors to ground, we connect each resistor to a I/O pin of the microcontroller. With an AVR, like the Atmega328 that's on an Arduino Uno/Nano, we can set the pin to OUTPUT mode (low impedance), and by writing a digital LOW we connect the pin to ground (it sinks current), and the LED will turn on. By writing a digital HIGH we connect the pin to 5V (it sources current) and the LED will turn off (since both the anode and cathode are connected to 5V, no current will flow).

While this works fine for one RGB LED, and even for two or three, any more will start to become a problem. Remember how an LED has a forward current of 020mA? If you turn all three colors of an RGB LED on that becomes 60mA. If you connect 4 RGB LEDs and turn them all on you'll be putting 240mA through the microcontroller. Now google the datasheet for the Atmega328 and have a look at chapter 29. Electrical Characteristics, section 1 Absolute Maximum Ratings. It says: DC Current Vcc and GND pins: 200mA. Whoops, we possibly just killed our Arduino. Also note how the DC Current per I/O pin is just 40mA, so don't even think about connecting more than one LED to a pin.

So we'll need to come up with some way to reduce the amount of current going through our microcontroller. Fortunately, there's this thing called a transistor. With just a tiny amount of current you can control a much larger amount of current. A transistor has three leads: Base, Collector and Emitter. The base lead is used to control the amount of current flowing between the collector and emitter. There are two types of transistors: NPN and PNP. In an NPN transistor, a small current entering the base is amplified to produce a large collector and emitter current. (http://en.wikipedia.org/wiki/Bipolar_junction_transistor#NPN)

A PNP transistor works the other way around. When you pull the base low (connect to ground) a larger current will flow from the emitter to the collector (notice how the flow of current between the emitter and collector is reversed compared to a NPN transistor).

We'll be using a NPN transistor. We need a transistor that has a maximum collector current of at least 20mA. Then there's this thing called the gain. This figure indicates how much more current there is going to flow through the collector and emitter, compared to how much flows through the base and emitter. Basically it's your amplification. We need at least 20mA, but we don't want to use that much to control it. So let's use a gain of 10, this way we only need 2mA to control 20mA.

If you have a look at the datasheet of the 2N3904 you can find the following figures:
Collector Current : 200mA
DC current gain (at 1mA IC (input current)) : 70
That's well within specs.

The required base current will be 20mA / 70 = 0.3mA. Now we need to find a resistor to give us at least 0.3mA. First we have another look at the datasheet, we need to find the base-emitter saturation voltage, which happens to be between 0.65 and 0.85V, so 0.75 average. Enter Ohm's law again. (5V - 0.75V) / 0.0003A = 14166 Ohm. So a 10K resistor will do the trick, this will give us (5V - 0.75V) / 10000 = 0.4mA. A lower resistor like 1K will work as well, but it'll increase the power consumption, add extra heat, shorten the life of our components, etc. Don't even think about directly connecting your I/O pin to the transistor base lead since you'll effectively be shorting it to ground and kill your micro controller. If you want to read a bit more, click here.


That's it for now, next time I'll explain the anode driver and shift registers :)

Monday, March 03, 2014

Pillar testing jig

After soldering a pillar of LEDs you'll want to test it to make sure you didn't make any mistakes. It's much easier to fix mistakes at this point than fixing them when the cube's fully assembled. So here's a little setup I came up with to make testing easier:

It's an ATtiny13 connected to an 74HC595 shift register. The outputs of the shift register are connected to the anodes of the pillar. The cathodes of the pillar are connected to pins PB0-2 of the ATtiny and have a few series resistors. By configuring the pins as output pins we can sink some current when we write them low, turning the LEDs on. When we write a high to the pins we source current and the LEDs go off. So with the shift register we can control which LED should be on, and with the input pins we can select the color.
Normally you'd use some transistors instead of connecting the LEDs to the pins/register directly because the ATtiny nor the shift register will be able to handle the current of all LEDs going on simultaneously (3 x 8 x 20mA = 480 mA), but we'll program the ATtiny to only turn on one LED at a time so we can get away with this setup.

Both the storage and shift clock of the shift register are connected to PB4, this causes data that is shifted into the register to appear almost directly on the output pin, which is fine for this setup. The output enable is connected to ground so we'll have continuous output. The reset pins of both ICs are connected to +5V through a 10K pull-up resistor. The DS pin of the 595 is connected to PB3, the Q7S pin is left floating since we're not using it, which seems to be common practice. There's a 100nF ceramic cap added as a bypass for the ICs, and a power connector of course.
And for kicks, here's a dirty PCB:
For my test jig I'm not going to put those LEDs on the board, instead I'll have a three terminal connector near the resistors to connect the cathode wires of the pillar to. And an eight terminal connector for the anodes.

As you can see, I used Fritzing for this quick prototype. It just works a bit faster and the breadboard view is handy for this situation. If you want to download the Fritzing project, click here.

As for the programming: that's easy:
  • Setup
    • DDRB should be set as input for PB5 (reset) and output for PB0-4
    • PORTB should be set high for PB0, PB1 and PB2 so they don't sink any current. 
    • define an eight bit anode counter variable, initialize it with 1.
    • define a cathode counter variable, initialize it with 1.
  • Main loop
    • Start setting PORTB to 7, so we set PB0-2 high
    • Shift the anode counter variable out on PB3 while toggling PB4.
    • Set PB3 low and toggle PB4 twice to shift out a zero, because the 595's output is lagging behind one cycle.
    • Shift the anode counter variable left by one.
    • Toggle one of the output pins by writing the cathode counter variable to PINB.
    • Shift the anode counter variable left one position.
    • If the result is zero, set it to one. Shift the cathode counter variable left one position as well.
    • If the result is eight, set it to one.
    • Add a delay for 1/8th of a second.
It's probably easier to put everything in an interrupt handler and leave the main loop empty. All we need to do is set a timer. Factory default for an ATtiny13 is 9.6MHz (depends a lot on ambient temperature and supply voltage), If we set the timer prescaler to 64 we'll have the timer running at 150,000Hz. If we then set the timer to generate an interrupt every 250 timer ticks we get an interrupt frequency of 600Hz. If we execute our code every 75th interrupt we'll get exactly 8Hz, perfect!
One thing I can't remember correctly is whether or not the system clock prescaler is active by default. If so then it's set to 8, reducing the system clock to 1.2MHz. We can tackle this by changing the timer prescaler to 8, so we'll still have our 150,000Hz timer clock. Easy!

Here's a video of the setup without using the cathode shifting.
And here is the setup on a protoboard, connected to the pillar. Still no cathode shifting and driven by an Arduino; I've stuck some jumper wires into the DIP socket for the ATtiny to connect the Arduino.

I'm not too happy with the custom cable I made. It's a bit too much work to stick those connectors in and I risk bending the anode legs. I think I'll create a wooden jig with some contacts, to place the pillar in.

Sunday, March 02, 2014

Jig: Mk. 2

Sunday afternoon, a perfect moment to spend some time in the man cave :)

I decided to build another jig, since the first one is, well... crap. The main reason for that are my lack of skills. Fortunately there are plenty of tools to compensate for it, and my old man has a shed full of 'em :)

Starting with a nice jig to compensate for my horrible skills with a saw (it even says "no skills required" on the box, perfect!)
 Finally, 90 degree angles! I decided to make the columns in the jig 10mm deep, that will leave 15mm of space left for putting the LEDs in. I want the columns to be about 14mm wide, so there will be around 11mm of space between the LED pillars when they're installed. Unfortunately the wood is 22mm thick. Sawing that off would be a pain in the behind, so enter tool nr 2:
Yes, it's an electric planer. At the highest setting it turns 2mm of wood into a large pile of dust. So after using it four times I end up with a 14mm wood instead of 22, and a work bench covered in wood particles. Nice.
Back to the hand saw, 8 columns of 10mm done. Time to put some holes in them.
Since they're 14 mm wide, I've drawn a line 7mm from the top, and a vertical line right in the center. For the drilling, enter tool nr 3:
It's my trusty Dremel in the Dremel Workstation. Perfect for drilling some perfectly vertical holes.
Spot on, right through the center! That's just a 3mm drill, but the hole needs to be 5mm. I enlarged the holes using my cordless drill. The existing hole will guide the larger drill, so the hole remains in the center.
Then it's simply a matter of drawing a few lines on the base plate. The lines are spaced 25mm apart and there are two lines crossing them to mark the sides of the colums. Those are 14mm apart and 15mm from the edge.
Add glue, apply pressure. This is the fast drying type, takes about 15 minutes to cure. Tightening and loosening the clamps needs to be done carefully. Add the center clamp first, then the outer ones. Don't tighten them completely right away, but tighten each one a bit and move to the next. Removal is done in reverse order (center one last).

In the mean time, I created a small jig for bending the LED's legs.
Simply insert the LED, bend the legs, and press another piece of wood on top. Easy! The front and back plate are done as well:
The outer holes are 14mm apart, the center hole is 7mm above the outer holes.
After the glue has dried, it's time to drill a couple of holes from the bottom into the colums. Again, I used the Dremel for this to make sure the holes are perfectly vertical and spot on down the center of the colums.
Let's put in some screws. It's important to put a load of pressure on the columns so they won't start to rotate when you put the screws in. Clamping the whole thing down seems to work pretty well. The front and back plate had the same treatment.
And after about 3.5 hours it's done! Let's put in some LEDs!
 Nice! Works like a charm, now let's cut the three wires so we can pull the pillar out of the jig.
No problems there, plenty of room!
That's usable, may need a bit of bending, but not bad!
And it works!
Compared with the one from the first jig (at front). The space between the LEDs and the cathode wires has become a lot smaller (20mm to 14mm) and the distance between the LEDs has been reduced from 30mm to 25, awesome.

The next step is rigging up a framework to test a pillar. I'll probably just use one shift register to turn on each anode sequentially while sourcing one of the cathodes. After cycling through all anodes it'll move to the next cathode. So it'll first light up all reds, then all greens, then all blues and then all reds again, all in a matter of a few seconds.Guess I'll wire up an AtTiny on a protoboard to make it a semi permanent setup, I just need to get my hands on a dozen alligator clips :)

Saturday, March 01, 2014

Some PCB tweaking

Digging through some datasheets I discovered that I had the MR pin (Master Reset) of the 74HC595 shift registers tied to 5V, so I wouldn't be able to reset it from a microcontroller. I fixed it by widening the data connector to 5 pins and connecting the extra column to MR. I also realized the footprint on the design doesn't match the package of the chips I've ordered; the footprint should've been slightly narrower.

On the cathode board there was no room for the extra pins, so I had to move the power indicator LED to the other side of the board, It's now located near the power connector. I've also added a bunch vias in various places that are connected to GND. This helps the ground fill occupy a larger part of the board. I've also rerouted a couple of traces to make things prettier :)

On the anode board there was a bit more room for the extra pin, but connecting the extra pin took a bit more work. On the anode board the pins are pretty much right next to the pins on the IC. On the cathode board the traces have to cross each other.
One of my colleagues noticed the 100 Ohm resistor between the MOSFETs drain and GND. Ohm's law tells us that a 100 Ohm resistor at 5 Volts will have 0.05 Ampères running through it (I = U/R). It also tells us that there will be 0.25 Watt to handle (P = U^2/R). That doesn't sound like much, but an ordinary 0603 sized resistor is only rated at 1/8th or 1/10th Watt. I don't want to add through hole resistors, so I ordered a bunch of 2512 sized resistors, they're rated at 1 Watt (and easier to find than 1210s). There's plenty of space on the board for the increased footprint, so no problem there. I may be moving the caps to the other side of the board so the MOSFETs have more room for heat dissipation (and electrolytic caps don't like heat much).