ATmega328 Bootloader

Introduction

The bootloader is cheifly resonsible 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 deffinition 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 premodified 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 (the entire reservable area), gives a bootloader section that starts at 0x3800 words; 0x3800 words == 0x7000 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__.