ATmega328 Origins - Bootloader

The Arduino IDE has included official ATmege328 support since Arduino 13. The are available.

Update

The following is a much older version of the ATmega328 bootloader and contains several known issues that have been fixed in the official Arduino Bootloader. While it's a nice overview of the changes between the ATmega168 and the ATmega328 bootloader, you should look at the or take a look at the 1KB bootloader. Both of these contain much newer code.

Introduction

The bootloader is chiefly responsible for downloading code from the IDE using a UART, then writing the code into flash memory. Additionally it's responsible for an initial check to decide between entering bootloader mode or jumping into user code.

Because the '328 has a different memory map (larger flash), ID values, and fuses, it is nessessary to modify both the bootloader itself and it's make file. As it's the most current, I've used the Diecimila bootloader from Arduino IDE 11.

The Make File

# program name should not be changed...
PROGRAM    = ATmegaBOOT_328

New target, new program name. When we make this change, we also need to rename the bootloader code to ATmegaBOOT_328.c.

# current avrdude versions (5.4) require a modified config file
# to support the ATmega328p. Point this to such a file.
AVRDUDE_CONFIG = ../../tools/avr/etc/avrdude.conf

Because the current avrdude version doesn't contain a definition for the ATmega328, we need to point it to a config file that does. Assuming your in the hardware/bootloaders/atmega328 directory, this points to the Arduino environments pre-modified avrdude.conf file.

MCU_TARGET = atmega328p

This just sets the correct chip for the avr-gcc calls.

LDSECTION  = --section-start=.text=0x7000

The ATmega328 has 32KB of flash, using a 2K-word bootloader section, gives a bootloader section that starts at 0×3800 words; 0×3800 words == 0×7000 bytes.

ISPFUSES = avrdude -c $(ISPTOOL) -C $(AVRDUDE_CONFIG) -p m328p -P $(ISPPORT) $(ISPSPEED) -e -u -U lock:w:0x3f:m -U efuse:w:0x03:m -U hfuse:w:0xd8:m -U lfuse:w:0xff:m
ISPFLASH = avrdude -c $(ISPTOOL) -C $(AVRDUDE_CONFIG) -p m328p -P $(ISPPORT) $(ISPSPEED) -U flash:w:$(PROGRAM)_$(TARGET).hex -U lock:w:0x0f:m

In addition to the obvious change of -p m328p, we've added -C $(AVRDUDE_CONFIG) to reference the config file defined earlier. Finally, the efuse and hfuse values have changed from the ATmega168. These were determined in the usual way, by setting them with AVR Studio's graphical fuse editor, programming the chip, and reading it back with avrdude.

The Bootloader

/* the current avr-libc eeprom functions do not support the ATmega168 */
/* own eeprom write/read functions are used instead */
#if !defined(__AVR_ATmega168__) && !defined(__AVR_ATmega328P__)
#include 
#endif

The ATmega328 also doesn't use the default eeprom code, so we check to make sure we're not compiling for either a m168 or a m328p.

#elif defined __AVR_ATmega328P__
#define SIG2  0x95
#define SIG3  0x0f
#define PAGE_SIZE     0x40U   //64 words

The ATmega328's signiture and flash page size, both of which can be taken from the “memory programming” section of the datasheet.

#if defined __AVR_ATmega168__ || defined __AVR_ATmega328P__

This line, or the #elif version, appears 7 times in the rest of the code. Basically, what's true for the '168 is equally true for the '328. Search for defined AVR_ATmega168 and replace with defined AVR_ATmega168 || defined AVR_ATmega328P.