Using an Arduino Uno or an ISP to program bootloaders...

Using an Arduino Uno or an ISP to program bootloaders onto Atmega328 devices including 8MHz internal clock option(This information only applies to burning bootloaders onto Atmega328x devices and does not apply to uploading sketches to devices using the Arduino as an ISP. This is a separate subject dealt with in another section of the site.

I don't claim to know it all and if I have made any mistakes or given any incorrect information, please tell me here.

Pros and Cons of using an 8MHz internal clock:

Pros...

Cons...

Programming:

Arduino programming

Programming an MCU isn't just writing the bootloader or sketch code to the device. There are a number of "Fuses" or Flash memory bits that tell the MCU about it's speed, amount of bootloader space etc. which are also written during programming.

To program an MCU you need two things, software with a means of creating the code for the device and hardware to program (or Burn) the code onto the device. The diagram above shows the main components required to do the job and also illustrates that AVRDUDE can be used from the Command Line Interpreter.

Arduino sketches are written in C++ which is a language intended to be understood by you, the programmer. The MCU doesn't understand C++ so, the C++ sketch is compiled and converted into binary machine code instructions (binary commands are the language of the MCU). The software is created using an IDE (Integrated Development Environment), either the Arduino IDE or the Atmel Visual Studio for example, which allows you to write your sketch in C++ and then produces the binary code. We then need another program to send the completed binary code to the MCU which is called AVRDUDE. To interface with and program the MCU we need some hardware in the form of a programmer. The IDE creates the binary code and passes it on to AVRDUDE which in turn writes the binary code onto the MCU using the programmer hardware.

The programmer can be any one of a number of ISPs (In System Programmers) such as the AVRISP MKII or even an Arduino board loaded with a sketch to act as an ISP. If the MCU has a bootloader (a small program to facilitate communication via the MCU's Serial Port), we can send our code directly to the MCU using the Serial Port and eliminate the programmer. The bootloader also configures aspects of the MCU's operation but that is not of importance to us here.

Memory layout

The picture above (this is not the actual memory layout) shows the available memory (bootloader size is for example only and will vary) on an Atmega328 device to illustrate that the bootloader uses part of the Flash memory. Your sketches are written to the Flash memory and executed from there by the CPU in the device. The RAM is used by the MCU/your program for temporary storage and the EPROM is available to you for permanent storage of data. Both Flash and EPROM are non-volatile memory which stays intact when power is removed. RAM memory is lost when power is removed.

All code created by your chosen IDE uses "relative addressing" i.e. the addresses used within the code are not fixed which means the same code can be written into Flash either at the start of memory or where the bootloader ends. All the bootloader affects is the amount of space for your program i.e. available Flash memory = Flash - bootloader. If a bootloader is used, there is a short ~2 Second delay when the MCU starts up which is the time the bootloader takes to run and prepare for communication.

If you upload a sketch via the serial Port using a bootloader, the bootloader remains intact. If you use an ISP to program your sketch, any bootloader present will be overwritten.

You are now aware that with an ISP (In System Programmer) you can do away with the bootloader altogether and gain some extra program memory. You will also do away with the 2 second delay when you reset your device. However, if you do away with the bootloader you will no longer be able to upload sketches using the USB Serial port because this is one of the main functions of the bootloader.

I tend to use the serial upload method for development and once this is completed, program the sketch directly to the device.

The Olimex AVRISP MKII In System ProgrammerAn ISP provides the necessary interface between the programming application, AVRDUDE in the case of the Arduino IDE and the MCU. AVRDUDE will typically "talk" to the ISP via a USB Serial Port and the ISP will "talk" to the MCU via its own ICSP interface. The ISP carries out instructions given by AVRDUDE and translates/transmits information from the MCU back to AVRDUDE.

The AVRISP MKII (The Olimex version is shown left) is commonly used with both the Arduino IDE, AVRDUDE and Atmel's own suite of development software. There are a number of other ISP devices but, you can also use your Arduino as an ISP.

If you select the "File" option on the Arduino IDE menu and then select "Examples" you will see "ArduinoISP" in the list. This is a sketch which turns your Arduino into an ISP which will perform like an AVRISP.

The ArduinoISP sketch requires the target MCU to have a crystal oscillator or some other form of external clock signal which is a bit limiting. One other issue that complicates programming is that AVRDUDE will not handle Atmega328-P MCUs as the AVRDUDE configuration files do not contain the correct parameters*. This applies to both the AVRISP and ArduinoISP methods of programming.

*At the time of writing, January 2014, there is a new version of the AVRDUDE software i.e. version 6.0.1 which does support the Atmega328 but, it does not work with all programmers at the moment including the AVRISP MKII so we are stuck with the old software for now.

The author of ArduinoISP, Randall Bohn, originally wrote this excellent sketch in 2008 and it provides the basic requirements for an Arduino ISP. With the cheaper Atmega328-P becoming more popular, the sketch needed updating.

I have made some improvements to the original ArduinoISP sketch and put together all the information that should be required to program both Atmega328-P and Atmega328P devices using an Arduino Uno as the ISP. I will also tell you how to use an AVRISP MKII or any supported ISP to program Atmega328s.

The updated ArduinoISP sketch is here

The main changes to the sketch are the generation of an 8MHz clock signal on Arduino pin 9 and a change to allow the programming of Atmega328 devices without having to change the avrdude.conf files as suggested in some other blogs/tutorials. The original pin assignments have also been changed. By providing a constant 8MHz clock signal regardless of the final clock source, some tricky situations can be avoided such as "bricking" the device i.e. putting it in an unrecoverable state. A lot of so called bricked devices can be recovered.

Disclaimer: All the information presented here is, as far as I know, correct and has been tested on a variety of devices without any problems. However, I cannot be held responsible for errors on the part of the user, nor can I be held responsible if, for whatever reason, it doesn't work for you in your application.

The Hardware:

Using an Arduino as an ISP

The picture above shows the minimum Arduino ISP configuration for the revised "ArduinoISP_8MHz" sketch which can be downloaded from here. Please note: this is the minimum configuration for programming bootloaders only. No provision is made for the on-board ADC voltage requirements on pins 20 - 22! The sections of PCB shown above are from an Arduino Uno.

You can mount your target MCU on a breadboard or preferably use a ZIF (Zero Insertion Force) socket if you intend to program a number of devices. The pin assignments are shown in the table below. The LED pins (shown in red) are optional but are useful so I do advise attaching a small LED with a 1K series resistor between these pins and Ground. I use RED for pin 8, YELLOW for pin 7 and GREEN for pin 6.

Arduino Pin Atmega328x Pin Function
13 19 SCK
12 18 MISO
11 17 MOSI
10 1 RESET
9 9 8MHz Clock
8 NA Error LED (Red)
7 NA Program LED (Yellow)
6 NA Heartbeat LED (Green)
5V 7 5V
GND 8 0V

Please note: If you choose the 16MHz crystal option, even though we provide an 8MHz clock to the MCU for programming, it will run perfectly once a 16MHz crystal is connected with the supporting capacitors when you move the device to its final location.

WARNING: NEVER INSERT OR REMOVE THE TARGET AVR DEVICE WITH POWER APPLIED. CONNECT THE POWER AFTER INSERTING AND BEFORE REMOVING THE AVR DEVICE!!!!

All you have to do now, for 16MHz crystal operation, is:

How do we do away with the crystal?:

We can choose to make the Atmega328x device use its internal clock by changing the "fuses" (they're really electronic switches that can be turned on or off) that are set during programming. Every MCU has a set of fuse definitions that tell the device a variety of things about how to perform and the ones we are interested in are the speed and clock source. It is worth mentioning that some of the fuse changes are necessary because the definitions below specify differences in the size of the bootloader.

This information is contained in a file called "boards.txt" which the Arduino IDE/AVRDUDE use as a reference. Different board types can be added in additional files but I favour adding my additional boards to the original file.

If you are wondering why there is a different bootloader specified for 8MHz internal clock operation, this is because the 16MHz Arduino Uno bootloader does not work properly at 8MHz on a 5Volt Atmega328. If you drop the supply voltage to 3.3 Volts it will work properly.

The Arduino IDE "boards.txt" file can be found at: "C:\Program Files\Arduino\hardware\arduino\boards.txt" and it is worth looking at this file to understand what information it contains. Here is the first entry from "boards.txt" with some added comments:

uno.name=Arduino Uno
uno.upload.protocol=arduino
uno.upload.maximum_size=32256 // maximum upload size. It's a 32K flash memory device
uno.upload.speed=115200
uno.bootloader.low_fuses=0xff
uno.bootloader.high_fuses=0xde
uno.bootloader.extended_fuses=0x05
uno.bootloader.path=optiboot // folder to use in the bootloaders repository
uno.bootloader.file=optiboot_atmega328.hex
uno.bootloader.unlock_bits=0x3F
uno.bootloader.lock_bits=0x0F
uno.build.mcu=atmega328p // MCU type for this profile (Used with avrdude.conf file)
uno.build.f_cpu=16000000L
uno.build.core=arduino

 Here's a board profile for an Atmega328P or Atmega328 using an 8MHz internal clock:

atmega328.name=ATmega328 (8 MHz internal clock)
#UPLOAD
atmega328.upload.protocol=stk500
atmega328.upload.maximum_size=30720
atmega328.upload.speed=57600
#BOOTLOAD
atmega328.bootloader.low_fuses=0xE2
atmega328.bootloader.high_fuses=0xDA
atmega328.bootloader.extended_fuses=0x05
atmega328.bootloader.path=arduino:atmega
atmega328.bootloader.file=ATmegaBOOT_168_atmega328_pro_8MHz.hex
atmega328.bootloader.unlock_bits=0x3F
atmega328.bootloader.lock_bits=0x0F
#BUILD
atmega328.build.mcu=atmega328p
atmega328.build.f_cpu=8000000L
atmega328.build.core=arduino:arduino
atmega328.build.variant=arduino:standard

Compare the differences between the board definitions above but don't worry, you just need to add the second one to your boards.txt file or download this one, rename the original to "board.txt.bak" or whatever you choose and save the new one in its place. When you start up the Arduino IDE you will see the new board type in the list.

All you have to do now, for the 8MHz internal clock option, is repeat the steps above using the new board type and you can do away with the crystal. The modified ArduinoISP_8Mhz sketch works exactly the same with Atmega328s or Atmega328Ps.

Where are the extra pins on the 8MHz internally clocked devices you mentioned?

Well, they're there but they were being used for the crystal on the Atmega328x pins 9 & 10. If you have programmed your device with an internal 8MHz clock the new pins are available in the PORTB registers which were assigned as follows on the Arduino Uno:

PORTB bit Arduino Uno pin Atmega328x pin Current use 8MHz internal clock use
0 D8 14 ICP ICP
1 D9 15 OC1 OC1
2 D10 16 SS SS
3 D11 17 MOSI MOSI
4 D12 18 MISO MISO
5 D13 19 SCK SCK
6 (D20) 9 XTAL1 input/output PB6 (D20)
7 (D21) 10 XTAL2 input/output PB7 (D21)

You can control/access the new pins by directly accessing the DDRB & PORTB registers or you can use some functions within your sketches. An example sketch can be downloaded here:

Programming Atmega328 devices using the AVRISP MKII or other supported ISP programmers:

As already mentioned, AVRDUDE has a problem with the device signature of the Atmega328 and refuses to program it. They are, as far as we're concerned, the same devices with a few different features so we need to fool AVRDUDE. I have seen many suggestions for ways around the problem but, in my opinion, the safest way is to present AVRDUDE with mis-information.

The file which contains the signature information is called "avrdude.conf" and it is found in "C:\Program Files\Arduino\hardware\tools\avr\etc\". This file is a huge repository of information (16917 lines long) about the different device types but, it only contains information about the Atmega328P, not the Atmega328. If you open this file and search for "Atmega328P" you will see an entry that starts with the left-hand section shown below.

The original "avrdude.conf" entry for the Atmega328P The modified "avrdude.conf" entry for the Atmega328
#------------------------------------------------------------
# ATmega328P
#------------------------------------------------------------

part
id = "m328p";
desc = "ATMEGA328P";
has_debugwire = yes;
flash_instr = 0xB6, 0x01, 0x11;
eeprom_instr = 0xBD, 0xF2, 0xBD, 0xE1, 0xBB, 0xCF, 0xB4, 0x00, 0xBE, 0x01, 0xB6, 0x01, 0xBC, 0x00, 0xBB, 0xBF, 0x99, 0xF9, 0xBB, 0xAF;
stk500_devcode = 0x86;
# avr910_devcode = 0x;
signature = 0x1e 0x95 0x0F;
#------------------------------------------------------------
# ATmega328P
#------------------------------------------------------------

part
id = "m328p";
desc = "ATMEGA328P";
has_debugwire = yes;
flash_instr = 0xB6, 0x01, 0x11;
eeprom_instr = 0xBD, 0xF2, 0xBD, 0xE1, 0xBB, 0xCF, 0xB4, 0x00, 0xBE, 0x01, 0xB6, 0x01, 0xBC, 0x00, 0xBB, 0xBF, 0x99, 0xF9, 0xBB, 0xAF;
stk500_devcode = 0x86;
# avr910_devcode = 0x;
signature = 0x1e 0x95 0x14;

The right-hand section shown above is the modified section for the Atmega328 and all that's changed is the last line i.e. we've changed:

"signature = 0x1e 0x95 0x0F;" to "signature = 0x1e 0x95 0x14;"

This means that if we use the modified entry and tell AVRDUDE to program an Atmega328P it will look for the signature of the Atmega328 instead.

The simplest way to "fool" AVRDUDE is to swap the "avrdude.conf" file for a modified one for Atmega328s and swap it back for normal use.

OK, with it so far? Weird things happen in Arduino IDE world so get ready to be confused. We have seen that by altering a single entry in the avrdude,conf file, we can fool AVRDUDE into believing that it is programming an Atmega328P even when the target device is an Atmega328 but when it comes to using the Arduino IDE to Serial Upload (USB Interface) sketches, the rules change a bit.

The "avrdude.conf" file for Atmega328 devices is used for:

The "avrdude.conf" file for Atmega328P devices is used for:

Here are the avrdude.conf files and the batch files if you want use them...

I keep a copy of the modified versions of the "avrdude.conf" file along with a couple of batch files, which make the config change for you, in the:

"C:\Program Files\Arduino\hardware\tools\avr\etc\" folder. The batch files copy and rename the relevant "avrdude.conf" file for you. If you get the wrong file, AVRDUDE will soon tell you.

If you want to use separate icons as I do, simply create 2 Desktop Shortcuts, one to each batch file, and change/name the icons as you wish.

All you need to do is double-click the required icon and the correct "avrdude.conf" file is automatically created.

Oh, one last point! The Arduino IDE does not have to be closed and restarted if you change the "avrdude.conf" file before it will take effect. Happy programming!