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

No comments:

Post a Comment