Showing posts with label Arduino. Show all posts
Showing posts with label Arduino. 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 :)

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 :)