Friday, January 27, 2012

Transdescending Arduino: Going cheap and small

The Arduino is great; a microController you can actually do something with for 30 bucks!  Ok, but your train layout needs 5 of them ($150), your home sensor network needs 10 + $40 xbee cards (clocking in at $700!).  Or the mere fact that your want to KEEP your projects around means that you get nailed for 30 bucks over and over again.

But wait a second... the AVR328p is a 3 dollar chip!  And the AVR ATMega48 (pin compatible but with a LOT less space) is 2 bucks (for 10)!  And if your requirements are extremely minimal, there's the ATTINY13 which comes in as little as 60 cents -- but in an inconvenient package (you'll be better off spending another 4 dimes and getting one for 1 buck).

Let's hack up a bunch of these chips so next project we'll have lots of choices...

Note: If you've figured out the hardware part and just need some software help check out this posting: AVRez -- "arduino" style APIs for other chips

Choosing Parts

The first step is picking and getting your chip.  This can be tricky because paradoxically there are both too many parts and too few.  By "too many" I mean is that since there are literally hundreds of AVR parts to choose from, it can be hard to find what you need.  You are overwhelmed with data.  So your first stop should be the Atmel "parametric" selector here (most vendors have parametric selectors on their web sites but they can be hard to find).  If you use my link you'll see that I've already selected the basic stuff in that link (like 8 bit AVR) but there are still hundreds of possibilities.

Another excellent way to narrow it down is to pick choices that other people have already used.  These can be found by looking in the Arduino or Adafruit forums,, or the eye candy sites like

Also its a safe bet to pick from these popular choices:  ATMEGA328 (Uno), ATMEGA168 (like Uno but 16k flash), ATMEGA48 (Uno, 4k flash).  ATTINY24, ATTINY13 (no serial), ATTINY2313 (a "tiny" with serial).

Navigating Parts Suppliers

Once you've found some candidates, you'll want to head over to to see if there are any for sale in a package you can handle.  This is where you may find there are "too few" parts -- that awesome device perfect for your job is not stocked and only available in 1000 units! :-(

So you'll need to do a bit of back-and-forth between the parametric table and the marketplaces to find what you need.

Another method is to head directly to which has a large selection and a great interface.  Basically, type your part name prefix in (like ATTINY, or ATTINY13).  You should see a product selector.  Click "in stock" and then refresh.  Now for the secret that took me a year to discover: head over to the "price" column (far right), click on the triangles, and enter ascending sort with 5-10 units (never buy just one or 2, if you do Murphy's law guarantees you'll burn them out!)  Personally, I find that digikey has the best prices on average, but other suppliers sometimes sell particular parts for significantly cheaper.

Once you've picked out your part, pop up the datasheet just to make sure the parametric table was correct and to verify that it is "in-system programmable" -- or ICSP (in-circuit-serial-programming).  I think all AVRs have this feature but you never know...  Its also good if they have an internal oscillator so you don't have to hook up a crystal.  Again, I think they all have it :-).

Most importantly, it will be nerd-enhancing for you to actually read (actually skim) the datasheet; you'll learn valuable data mining skills :-).

Other Stuff

If you bought a thru-hole version, you'll want a breadboard to solder it on to (or use a solderless breadboard).  If you bought a SMT chip (congrats!), you'll need to either buy or make a break-out board and to learn how to bake surface mount parts.

Next, you need a device programmer.  You can actually use your Arduino as described here, or buy a standalone one like the one I use:  You'll also want the standard electronics stuff; a bunch of jumper wires, a soldering iron, a multimeter.

Ok, it will take a few days for the stuff to arrive... when it does we will hook up the chip, write a simple program and upload it.

Using The Chips

Ok, everything arrived?  Next let's hook it up!

The first step is to mount the chip into a solderless (or soldered) breadboard.  If you bought a SMT chip, you'll have to first bake it onto a breakout board.

Next, take a look at the datasheet of your chip.  Right at the top of AVR datasheets you'll see a section called "Pin Configuration" that shows the physical layout of the chips.  Here is what the ATMEGA 328/168/88/48 PDIP package looks like:
And the ATTINY13:

And finally the ATTINY24:

On all chips, we have power and ground (yellow), reset (orange) and a SPI programming interface (red).  When the chip is in reset, the SPI interface can be used to upload programs.

Now take a look at the Arduino ICSP header:

This is what the 6 pins look like coming into the Arduino's ICSP port.  Your programmer should have the equivalent pins (but see caveat below).  These are the same pins located on each of the chips.  So, hook 'em up (connect the same named pin together)!

Some caveats: If you are using the ArduinoISP project to program your chip, don't hook the "reset" lines together.  The "reset" in the Arduino's ICSP header will reset the Arduino.  You want to hook a general purpose IO to the chip's reset so that the ArduinoISP can put it into reset.  For more details:

The ICSP header is symmetrical, (and the "top" view vs the "bottom" view will mirror the pins) so if you can't tell where pin 1 is, use a multimeter to look for the 5 volt difference across the power and ground pins (2 & 6).  That way you can be sure you've found the correct orientation!

Ok, so here I've hooked my USBtinyISP up to a MEGA48.  I've also added a resistor and LED in series connecting to one of the pins so I can try the "hello world" of embedded programming -- blinking a LED.

This might be hard to make out, because I can't focus on both the programming header and the chip... its just the foreground center chip, and connections, the other stuff is just that -- other stuff :-).

Ok, next step is to use avrdude to verify that we can talk to the chip!

Programming the Chip

You've got to get the software first.  On Debian descended Linux distros (Ubuntu, Mint) you can run the following:

sudo apt-get install avrdude gcc-avr avr-libc binutils-avr

But on other OSes, if you've got the Arduino IDE installed and working, then you've got these programs somewhere.

Next, let's just check to make sure you hooked it up correctly.

First, plug your programmer in and verify that you see +5v across the power (VCC) and ground (GND) pins.  Next run:
avrdude -c usbtiny
It will complain that you did not specify a chip and provide you a list of options.  Pick your chip out of the list and run the same command with -p .  I chose the tiny24:
avrdude -c usbtiny -p t24
It should verify the chip's device ID and then quit.  It can also complain in a bunch of different ways.  Check out my AVR programming cheatsheet if you get an error.

Next let's figure out what the compiler thinks your chip is named.  Run:
avr-g++ -mlist-devices --target-help

and pick your chip out of the list.  You'll need that in the next section.

Writing A Simple Program

Next, we need to write a simple program to get started.  This should be the subject of an entirely new blog entry, so I'll just skip it for now and point you to a simple framework for building the code, located on github, named avrez.  I'm not entirely sure what "social coding" is :-) but github is still pretty cool.

Next "fork" that onto your machine and then run:
make CPU=
So for the chips I'm using its one of:
make CPU=attiny24
make CPU=attiny13a
make CPU=atmega48
Did it work or did it put up an error message saying "Sorry I don't know that chip!"  If the latter, be happy because you're off the reservation -- you can ADD the chip to the project and feel happy about being the first! :-)

This make line will build all the source files in the directory AND upload them to your board using the attinyISP programmer (by default, you can change that in the Makefile).

If it seems to have worked, then hook up a resistor (100-1kohm) and LED as follows:

5v->resistor->__LED_ ->PB0

where PB0 is a pin on the chip (check out the pin outs in the datasheet).  If your chip does not HAVE a PB0, you'll have to change the code to a pin you do have.  I've drawn the LED with the long wire on the left to remind you to put it in that way.

You should see the LED blink once every 10 to 20 seconds.  If it is not (and you are new to electronics), let me recommend that you flip the LED around, or even put 2 in in opposite directions...

Hooray!!  You successfully uploaded a program to the chip!  And I've written one monster-long blog post whose length shall never be repeated!!! :-)

If you are a noobie programmer, stay tuned for another SEPARATE posting about how to hack that "avrez" project into a real program -- if you are a software person then jump right in!


  1. How does one add a new chiptype to pins.h?

  2. Hi! I have updated the pins.h with a comment describing the procedure, but here is what I said in it:
    To define a new chip:
    Discover what the compiler calls your chip. You need 2 names:
    1. The name specified when running avr-g++, for example avr-g++ -mmcu=attiny24
    run: avr-g++ -mlist-devices --target-help
    2. The name of the chip within C code, for example "__AVR_ATtiny24__"
    look at: /avr/include/avr/io.h On Linux: /usr/lib/avr/include/avr/io.h

    Next, check the datasheet to determine whether your chip is exactly the same (programmatically) as a chip that's already been defined. If that is the case you can easily add your chip name to one of the existing definitions below.

    But if your chip is different, in this file you need to create a section for your chip near the bottom of the file. Just before the "#else #error" sections. Do it like this:

    [In this description, Things you need to change are bracketed in * since normal parens is valid c]

    #elif defined (*C CODE NAME*) || defined (*ANOTHER C CODE NAME*)

    Inside you need to define the chip as follows.

    #elif defined (*C CODE NAME*) || defined (*ANOTHER C CODE NAME*)

    // First pick a name for the chip "family". This will be the name for ALL chips that are programatically the same as yours. If nothing is obvious, use the name of the smallest, cheapest variant.
    #define PINOUT_*your canonical name*

    // Next define the pins. Use the following format:
    #define pin*Name from datasheet* *bit index*,*direction register*,*port register*,*pin register*,*analog bit index*

    // Normally the "io.h" file (or files it includes) should have defined constants for the values you need. So it can be as easy as:
    #define pinA0 PA0,DDRA,PORTA,PINA,0
    // And note if your pin does NOT support an analog function, use "invalidPinFunction" as the last item, like this:
    #define pinB0 PB0,DDRB,PORTB,PINB,invalidPinFunction

    // Analog Section: Note if you are not using analogRead() you *could* cheat and just define this to all zeros...
    // Next, look up "analog reference" in the datasheet and make constants for the various references. These constants allow you to choose the reference voltage for the analogRead function. Here are all possible values:

    AnalogReferenceVin = *a number here*,
    AnalogReference1_1volt = *a number here*,
    AnalogReferencePin = *a number here*

    // Finally, you have to tell the system how many bits are used to select the analog reference voltage as follows.
    #define AnalogMuxMask (1<<MUX0)|(1<<MUX1)|(1<<MUX2)|(1<<MUX3)

    // Next, head over to the "Makefile" and add some logic to handle the different CPU= parameters... you should be able to look at the existing examples to figure that out.
    #else // done!

  3. thnx for this post...I just ordered some chips will try this soon for an outdoor project that seems to have to many extraneous pieces already...

  4. Super awesome info, thanks! but this web2.5(orWhateverWereInNow) pop-up pane is super distracting. This kind of pop-up is great for quickly viewed content, like pictures in a series, but with that 'X' looming in the upper right corner, I feel like I should read quickly and then close the pop-up (the 21st century lizard brain response?)

    Awesome info though!