Monday, May 18, 2009

ATtiny header board


I've been programming my AVRs using the SparkFun set-up since I started. This is fine for the odd bit of tinkering, but it's a pain having all those wires poked into the programming cable and getting in the way on the breadboard. With an 8-pin dip, there's not a lot of room around the chip for my fat fingers to add wires.


I'd seen these breadboard headers over at Tinkerlog.com and fancied having a go at making my own using the components I'd got lying around (well, ok, I bough the male/female header pins from eBay).

First a rough idea of how I thought it should look:

Then I tried to figure out where the wires should go based on my original set-up (pic of wire mess above) and the ATtiny13 datashet.

Finally I gave a little thought as to where the physical wires were going to go on the perfboard. I decided to swap the position of the 6-pin programming header to make the wiring a little easier. I'm sure there's a better solution, but I was impatient and wanted to get on with it.


Then it was a matter of soldering everything together. I am not an accomplished solderer - this is only my 3rd real soldering project and I'm sure most people wouldn't even consider the ones I've done so far 'projects'.

First off I soldered the headers, push switch (cannibalized from a broken kids toy) and IC socket. This is pretty much how the finished project looks from the top.

Then I realise that I could bridge pins 1 and 8 using the 10K resisitor and have the resistor out of the way of the rest of the wires by having it on the front of the board.

After that it all got a little messy... I need to give myself more time to figure out wiring/routing! I guess this is all a learning experience :)




I kept the insulation on the long wires to prevent short circuits, unfortunately I also ended up melting a lot of the plastic which caused a few issues around pin 5 of the IC socket hence the blackened mess and excess solder around there... I think I managed to sort out my technique a bit better after than and the remaining solder bridges are ok (tips on creating these gratefully received!).

Here it is in action (note that I have to bring in power from the breadboard with my particular programmer).

Saturday, May 9, 2009

Basic AVR IO

I found this very confusing when I started to program my ATtiny13. I read a bunch of different sites/blogs/datasheets to get a feel for it (and am still slightly confused tbh). So, I thought I'd give a brief overview of the basics in a way that makes sense to me. I'm not going to cover input here, just output; but it's a good start.

Here's the key concepts:
  1. AVR uCs are 8-bit devices.
  2. Every AVR has at least some pins which can act as either Input or Output (I/O) devices.
  3. The voltage on the pins can be sensed or controlled via software.
  4. Because of 1. physical pins are logically grouped in sets of 8 as I/O ports. For my ATtiny13 there is only one port (port B) as there are only 8 pins.
  5. Each I/O port has 3 registers associated with it: DDRx, PINx and PORTx (more on this later), where x represents the port (in my case there's only BBRB, PINB and PORTB available).
  6. I/O pins exists as registers inside the processor. It's the software controlled contents of these registers that controls the state and operation of the I/O ports and pins.
  7. The registers are 8-bits in size. Each bit in the register determines the operation of the corresponding number pin (0-7).
DDRx
This register the direction (input/output) of the pins on port x. Again, for the ATtiny13 there is only a port B so we only have DDRB available but on other AVRs there can be many ports (e.g. the atmega168 has 3 ports B, C and D controlling 23 programmable I/O pins) .

A '0' bit makes that port pin act as input.
A '1' bit makes that port pin act as output.

PORTx
This register contains the output state of the pins on port x.

A '0' bit is considered LOW (~0V)
A '1' bit is considered HIGH (~Vcc)

PINx
This register contains the input state of the pins on port x.

A '0' bit indicates that the port pin is LOW (~0V).
A '1' bit indicates that the port pin is HIGH (~Vcc).

So let's take a quick look at the simple code I posted in "Starting with the AVR uC":

1:  #include 
2: #include
3:
4: //LED is wired into pin 7 (PB2)
5: #define LED PB2
6:
7: int main(void){
8: //set data direction register for pin 7 to output
9: DDRB |= _BV(DDB2);
10:
11: //infinite loop
12: while (1) {
13: //turn on the LED
14: PORTB |= _BV(LED);
15: //wait for 1/4 of a second
16: _delay_ms(250);
17: //turn off the LED
18: PORTB &= ~_BV(LED);
19: //wait for 1/4 second
20: _delay_ms(250);
21: }
22: }
5: define LED as PB2. This is just a convenience to allow us to refer to pin 7 as the variable LED. I have the LED wired into pin 7 and this pin is called PB2 according to my datasheet (this can be different for different uCs). PB2 is actually another variable which has been defined thanks to the avr/io.h import statement. I could have used the number 7 instead but I decided to use the name of the pin from the datasheet.

9: This sets bit 7 of DDRB to '1' without affecting any of the other bits in the register. This is the data direction register (DDR), setting a pin in this register to a '1' makes that pin act as an output. I think I should have used the LED variable (defined earlier) rather than DDR2, just for clarity. Ok, next time.

14: Here we manipulate the bits in the PORTB register. This statement sets bit 7 to '1' without affecting any of the other bits in the register. Assigning a '1' to bit 7 of PORTB sets pin 7 to HIGH (~Vcc). This allows current to flow through our LED, lighting it up (or burning it out if you've not added a resistor in serial with it).

18: This statement sets bit 7 of the PORTB register to '0' without affecting any of the other bits. Pin 7 is now LOW, no current flows through the LED (so we've turned it off).

Now, here's a little nugget of info that didn't click until my trip to Noisebridge and a chat with Mitch Altman: I/O pins, by their very nature, are ambivalent towards the direction of current flow. Let me say that again as it's something I didn't realise to begin with and it has an impact on programming LEDs with the AVR. I/O pins don't care which way current flows through them. So, if you have an LED attached to an I/O port (via a resistor) then it can be orientated in either direction (i.e. connected to ground or Vcc, it doesn't matter), the only difference will be whether or not a '1' or a '0' on the corresponding PORTB pin switches it on or off. If the LED is connected to ground, then a '1' in the PORTB register will turn it on; on the other hand, if it's connected to Vcc, then a '0' will switch the LED on.

I know I laboured that last point, but it was non-obvious to me (as a beginner) so I wanted to share. It also meant that those common cathode RGB LEDs I bought aren't as useless as I thought - I was under the wrong impression that I'd only be able to program them using 3 transistors attached to the AVR as switches, because I thought you could only turn on LEDs [with an AVR] by placing a '1' in the PORTB register... doh!

Saturday, May 2, 2009

Jar o' Fireflies

I've seen a few good examples of micro controller controlled fireflies "in a jar" and I wanted to try this for myself. This is by no means a new idea (just take a look at this youtube search and you'll see tons of examples) but I like the idea and I'd already got the basic set-up (see my previous post on AVR programming). All I needed to do was work out the programming (the wiring seems pretty obvious - wire LEDs to uC, wire uC to battery).

What I wanted to do was use all the ATtiny13's 6 output pins to control 6 "fireflies". I'd be happy with just randomly pulsing green LEDs, but I thought it was important to have the LEDs pulse on and off rather than just switch on an off. Here's a youtube video showing fireflies in New York as an example of how the real thing looks. I have a very fond memory of sitting out on a boulder with my brother in Nepal and looking out at a hillside with thousands of fireflies blinking away; we stayed there for ages captivated by the hypnotic display.

So, the standard way to create pulses with an AVR seems to be with pulse width modulation (PWM). Unfortunately mine only has 2 PWM outputs and I wanted to use the parts on hand. A quick search brought up a few possible solutions, but this post on Kevin Mehall's blog was the winner for me. I ended up implementing a software PWM solution based on the code Kevin made public - thanks, Kevin! I've not quite worked out the best way to post code on blogger, when I do I'll post the actual code.

Here's an overview of the parts that went into the project:


The jar was found in the local Savers, the perf board was bought on eBay as were the IC socket, uC, green LEDs and battery pack (all in batches of 10 or more). The wire on the bottom left was scavenged from a broken kids princess wand. The hair clip was an interloper.

My lovely missus decided to improve my project by drawing a few fireflies on shrinkydinks so that I could glue them onto the LEDs after the project was finished:



Here's some photo pr0n of the project in various stages of completion:





And here's something we bought to scare the fireflies:


We got these from Lowes; I think the kids enjoy the venus fly traps much more than the fireflies... c'est la vie.

And, finally, a little video. The flicker isn't actually as bad in real life as it appears in the video, hopefully I'll find a way to remove it completely.

video