Sunday, March 15, 2015

Programming an ATmega (168, 328) using your Arduino as a programmer

You might be working on a project with your Arduino, and you've decided that it is time to move your project OFF of the Arduino board.  There are a lot of reasons for doing so:
  • Make your project smaller
  • Eliminate the stuff you don't need (voltage regulator, USB to serial converter, etc)
  • Consume less power by not having the extra stuff
  • Reduce cost
Before continuing you should know these definitions:

ATmega168, ATmega328:  An 8-bit microcontroller made by Atmel.  This is a "chip" with some pins on it, it fits in the palm of your hand.  
Arduino:  A circuit board for hobbyists, usually containing an ATmega168/328.  It has an onboard voltage regulator, USB port, header pins, LEDs, and protection circuitry.  

When I mention the "Arduino" I want to be clear that I am talking about the development board, not the microcontroller that is on it.  I will try to use "ATmegaxxx" when I am talking about the microcontroller IC.

Turn your Arduino into an In-System Programmer (ISP)

I had an ATmega168 in a drawer and I wanted to use it on a breadboard without the Arduino.  I needed to know also how to program the device without a programmer.

Well, included with the Arduino IDE is a sketch under examples called ArduinoISP:

  


Stop and just FORGET ABOUT the breadboard for a second!  Some other tutorials and having you change the board type and so forth right now.  NO.

Upload the ArduinoISP sketch to your Arduino board as you would any other sketch.

Did it upload successfully?  If so, your Arduino is now a programmer.

Thank you to Randall Bohn for writing the ArduinoISP sketch, this is really pretty amazing.

Some more info can be learned from the comments in the first few lines of the sketch:
// ArduinoISP version 04m3
// Copyright (c) 2008-2011 Randall Bohn
// If you require a license, see 
//     http://www.opensource.org/licenses/bsd-license.php
//
// This sketch turns the Arduino into a AVRISP
// using the following arduino pins:
//
// pin name:    not-mega:         mega(1280 and 2560)
// slave reset: 10:               53 
// MOSI:        11:               51 
// MISO:        12:               50 
// SCK:         13:               52 
//
// Put an LED (with resistor) on the following pins:
// 9: Heartbeat   - shows the programmer is running
// 8: Error       - Lights up if something goes wrong (use red if that makes sense)
// 7: Programming - In communication with the slave

Getting ready to burn the bootloader


At this point we are ready to flash an ATmega168 or 328 IC, using our Arduino board as a programmer.

Wait, why do we need to burn a bootloader anyway?

The bootloader is just a small piece of code on the micro that sets up the execution environment in which your programs (sketches) will run.  Most of the Arduino boards come with the ATmega chip already on it, and it thus already has a bootloader that, among other things, tells it to expect a 16 MHz oscillator.  So if the chip you want to use on a breadboard has already been in an Arduino, it almost certainly is configured this way.  This is important to know going forward.

The Arduino webpage gives some more details about connections, one method includes a crystal (external oscillator) and some capacitors (on the right below), while the other doesn't (on the left below).



Let's stop and take a breather before we panic about not having a 16 MHz crystal and some tiny caps in our junk drawers.

IF the chip you want to use ALREADY HAS a bootloader on it, chances are quite good that it requires the external oscillator, as I mentioned a few paragraphs earlier.  You won't know until you actually try to burn the bootloader and get a message like this in the Arduino IDE:
avrdude: Yikes!  Invalid device signature.
        Double check connections and try again, or use -F to override
        this check.

Optionally, you can confirm what the Arduino IDE is telling you with avrdude from the Linux command line:
wskellenger@marquette ~ $ avrdude -p m168 -P /dev/ttyUSB0 -c avrisp -b 19200

avrdude: AVR device initialized and ready to accept instructions

Reading | ################################################## | 100% 0.05s

avrdude: Device signature = 0x000000 (retrying)

Reading | ################################################## | 100% 0.05s

avrdude: Device signature = 0x000000 (retrying)

Reading | ################################################## | 100% 0.05s

avrdude: Device signature = 0x000000
avrdude: Yikes!  Invalid device signature.
         Double check connections and try again, or use -F to override
         this check.

In this case you *must* use the design on the right, OR, follow this great tip from from the comments here:

If you don't have any crystal, this is a workaround you can use:
1- Before to start the burn the bootloader, connect a jumper wire between the physical pin 9 (XTAL1) of your ATMEGA in the Arduino UNO board and the same pin 9 on the ATMEGA in the breadboard. This will feed temporarily to your standalone chip with a clock signal.

2- Burn the bootloader from the Arduino IDE menu.

3- Disconect the temporary jumper wire, and thats it. Now you can upload the sketches as usual with your Arduino UNO as an ISP.

It also helps to have a sticker on your ATmega chip so you know which pins are where.  I used one from here and some double-sided tape to affix it to the top of my ATmega168.  Note the little half-circle at one end needs to be aligned over the similar shape on the chip itself.  This will help greatly when you are breadboarding with this guy.

With the connections made between your breadboard and the Arduino, you can probe the XTAL1 or XTAL2 pins with a scope (marked XT1 and XT2 on the sticker above), and you should see a nice 16 MHz sine wave already.  If you don't have a scope, assume that signal is there, because if your Arduino is working, it is.

(Here is what avrdude says when I have XTAL1 jumped as described...)
wskellenger@marquette ~ $ avrdude -p m168 -P /dev/ttyUSB0 -c avrisp -b 19200

avrdude: AVR device initialized and ready to accept instructions

Reading | ################################################## | 100% 0.07s

avrdude: Device signature = 0x1e9406

avrdude: safemode: Fuses OK (H:00, E:DD, L:FF)

avrdude done.  Thank you.

Burning the bootloader

  • Okay, we've got the ArduinoISP sketch uploaded onto our Arduino board.
  • We have the appropriate connects made between the Arduino and our breadboard.
  • Our ATmega chip is installed on the breadboard.
  • The Arduino is plugged into our PC and we are ready to burn the bootloader.

Select what type of chip you are going to burn first (If you don't see these options, scroll to the bottom of this post).



Make sure you've selected "Arduino as ISP":



Now select "Burn Bootloader":



Hopefully you see this:



If not:

  • you haven't made the correct connections 
  • possibly you need a 10 uF cap across reset and ground (Arduino Uno)
  • there is a change you need to make to the ArduinoISP sketch (Arduino v1.0)
  • you don't have the external oscillator, so you need to add it or jump from XTAL1 on the Arduino to XTAL1 on the target ATmega IC on the breadboard, as described above.
See these notes from here under "Instructions":



Now what?

Okay, now you have an ATMega168 or 328 on a breadboard.  You've cut the apron strings.  Now in order to flash it, you can still use your Arduino board, but you need to remove the ATmega IC from the Arduino board in order to use it as a programmer to flash sketches onto the breadboarded microcontroller.

Flashing sketches onto the breadboarded ATmega IC:

Adding the "ATmegaxxx on Breadboard" options to the Arduino IDE:

It looks like there are two ways to do this.

Method 1:
In your sketchbook folder, add a folder called "hardware" and unzip this file (Arduino IDE 1.5) or this file (Arduino IDE 1.0) into it.  Reload the IDE, and open the sketch you were working on, and the additional option will be there.  This is discussed under "Minimal Circuit" here.

Method 2:
Modify boards.txt in /usr/share/arduino/hardware/arduino (Linux location):

Here is the text I've added to the end of boards.txt:
##############################################################

atmega328bb.name=ATmega328 on a breadboard (8 MHz internal clock)

atmega328bb.upload.protocol=stk500
atmega328bb.upload.maximum_size=30720
atmega328bb.upload.speed=57600

atmega328bb.bootloader.low_fuses=0xE2
atmega328bb.bootloader.high_fuses=0xDA
atmega328bb.bootloader.extended_fuses=0x05
atmega328bb.bootloader.path=arduino:atmega
atmega328bb.bootloader.file=ATmegaBOOT_168_atmega328_pro_8MHz.hex
atmega328bb.bootloader.unlock_bits=0x3F
atmega328bb.bootloader.lock_bits=0x0F

atmega328bb.build.mcu=atmega328p
atmega328bb.build.f_cpu=8000000L
atmega328bb.build.core=arduino:arduino
atmega328bb.build.variant=standard

##############################################################

atmega168bb.name=ATmega168 on a breadboard (8 MHz internal clock)

atmega168bb.upload.protocol=stk500
atmega168bb.upload.maximum_size=14336
atmega168bb.upload.speed=19200

atmega168bb.bootloader.low_fuses=0xE2
atmega168bb.bootloader.high_fuses=0xDD
atmega168bb.bootloader.extended_fuses=0x00
atmega168bb.bootloader.path=arduino:atmega
atmega168bb.bootloader.file=ATmegaBOOT_168_pro_8MHz.hex

atmega168bb.bootloader.unlock_bits=0x3F
atmega168bb.bootloader.lock_bits=0x0F

atmega168bb.build.mcu=atmega168
atmega168bb.build.f_cpu=8000000L
atmega168bb.build.core=arduino:arduino
atmega168bb.build.variant=standard

1 comment:

  1. How neat is that? Left Brain Tinkering took a technical task and broke it down to be understandable for the masses. Well done, William!

    ReplyDelete