Showing posts with label testing. Show all posts
Showing posts with label testing. Show all posts

Thursday, April 03, 2014

Cathode board works!

And we have a video!
Pretty neat! I found a bug in my bit angle modulation code which caused some weird things. After I fixed that everything worked like a charm.
My setup is like this:
  • An Arduino Nano on the left side of the breadboard, this microcontroller has a bit of animation code and it streams the resulting led states (on or off for each LED) to the cathode board. It does this roughly 12.000 times per second, creating a very smooth image. It's important to note that it is streaming the data for a full 8x8x8 RGB cube, but only one row of the top level is is shown (since that's the last byte that is streamed). On other words, the same smoothness can be achieved when the complete cube is connected. It's also interesting to note that this code is capable of streaming 100 "frames" per second and has loads of cpu power left.
  • The Arduino is connected to my cathode control board using a ribbon cable. Each of the five wires in the cable is connected directly to one of the pins of the shift register on the cathode board for full control. There's a three wire power cable as well; one wire for logic power supply, one for logic ground and a separate one for LED ground. Finally there's an eight wire ribbon cable connected to the cathodes of the LEDs on the breadboard.
  • The 8 LEDs on the right side of the breadboard have their anodes connected directly to 5V. The green cathodes go to the cathode control board which contains a series resistor for each LED. The other end of each resistor is connected to the collector of a transistor. The emitter of each transistor is connected to the LED ground pin on the board, and the base goes through a series resistor to an output pin of the shift register. If the output pin goes high, then current can flow through the transistor and the LED goes on. If the output pin is low then current is blocked and the LED goes off.
Next up: two more boards for full RGB control :)

Testing the cathode board

Quick update, more will follow.
I've been a bit busy with some other stuff lately, I had to make 35 buzzer games (like this one) for a group of kids, so I spent most of my free time last week putting a bunch of leds, resistors, battery holders and piezo buzzers together. The rest of my time went to miscellaneous stuff like housekeeping and filling in my tax forms. Last night I finally had some time to get back to the cube...

I need some way to test if my cathode boards work after I solder all parts on them, so I populated a breadboard with 8 LEDs and wired them to the cathode board and an Arduino. The Arduino runs pretty much the same code as the cube will eventually in terms of refresh rate and how the cathode board is controlled. It took some time before I had everything working somewhat correctly, always double check your connections and don't mix up the MOSI and MISO pins...

But in the end, it works! One LED didn't light up, I didn't solder the transistor for that one correctly, easy fix. I'm still tweaking the code a bit, there's a bug somewhere that stops the brightness from functioning properly. I don't have any photos or videos at the moment, I'll shoot them after I fix that bug.

One thing that I overlooked is how bright a 0603 LED can be. I have a small power indicator LED on the board and that thing is just blindingly bright. I've already replaced the 150 Ohm series resistor with a 1K Ohm, but it's still too bright. I'll try a 10K tonight; all it needs to do is provide a visual indication, not light up the living room...

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.

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.