ATmega328 Origins - IDE

The Arduino IDE has included official ATmege328 support since Arduino 12. If you just want to use your ATmega328, you should .

Introduction

Arduino 11 did not natively support compiling code for the ATmega328P. The following changes had to be made:

  • Install a more recent avr-gcc tool-chain with support for the ATmega328.
  • Update all the core and library files to include proper #if define's for the ATmega328.
  • Update the avrdude config file to support the ATmega328P.
  • Update the boards.txt file to include an ATmega328P based board.
  • Update iom328p.h to use the iomx8.h defines instead of it's newer defines. (Based on iom168.h and iom88.h).

avrdude Configuration File

Current avrdude builds do not include native support for the ATmega328P, and I couldn't find a config file, so the following addition has been built from the ATmega168 section and much datasheet reading. The config file is normally kept in hardware/tools/avr/etc/avrdude.conf.

#------------------------------------------------------------
# ATmega328
#------------------------------------------------------------

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;
    pagel           = 0xd7;
    bs2             = 0xc2;
    chip_erase_delay = 9000;
    pgm_enable       = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1",
                       "x x x x x x x x x x x x x x x x";

    chip_erase       = "1 0 1 0 1 1 0 0 1 0 0 x x x x x",
                       "x x x x x x x x x x x x x x x x";

    timeout         = 200;
    stabdelay       = 100;
    cmdexedelay     = 25;
    synchloops      = 32;
    bytedelay       = 0;
    pollindex       = 3;
    pollvalue       = 0x53;
    predelay        = 1;
    postdelay       = 1;
    pollmethod      = 1;

    pp_controlstack     =
        0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F,
        0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F,
        0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B,
        0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00;
    hventerstabdelay    = 100;
    progmodedelay       = 0;
    latchcycles         = 5;
    togglevtg           = 1;
    poweroffdelay       = 15;
    resetdelayms        = 1;
    resetdelayus        = 0;
    hvleavestabdelay    = 15;
    resetdelay          = 15;
    chiperasepulsewidth = 0;
    chiperasepolltimeout = 10;
    programfusepulsewidth = 0;
    programfusepolltimeout = 5;
    programlockpulsewidth = 0;
    programlockpolltimeout = 5;

    memory "eeprom"
        paged           = no;
        page_size       = 4;
        size            = 1024;
        min_write_delay = 3600;
        max_write_delay = 3600;
        readback_p1     = 0xff;
        readback_p2     = 0xff;
        read            = " 1 0 1 0 0 0 0 0",
                          " 0 0 0 x x x a9 a8",
                          " a7 a6 a5 a4 a3 a2 a1 a0",
                          " o o o o o o o o";
    
        write           = " 1 1 0 0 0 0 0 0",
                          " 0 0 0 x x x a9 a8",
                          " a7 a6 a5 a4 a3 a2 a1 a0",
                          " i i i i i i i i";

        loadpage_lo     = "  1   1   0   0      0   0   0   1",
                          "  0   0   0   0      0   0   0   0",
                          "  0   0   0   0      0   0  a1  a0",
                          "  i   i   i   i      i   i   i   i";

        writepage       = "  1   1   0   0      0   0   1   0",
                          "  0   0   x   x      x   x   a9  a8",
                          " a7  a6  a5  a4     a3  a2   0   0",
                          "  x   x   x   x      x   x   x   x";

        mode            = 0x41;
        delay           = 5;
        blocksize       = 4;
        readsize        = 256;
        ;

    memory "flash"
        paged           = yes;
        size            = 32768;
        page_size       = 128;
        num_pages       = 256;
        min_write_delay = 4500;
        max_write_delay = 4500;
        readback_p1     = 0xff;
        readback_p2     = 0xff;
        read_lo         = " 0 0 1 0 0 0 0 0",
                          " 0 0 a13 a12 a11 a10 a9 a8",
                          " a7 a6 a5 a4 a3 a2 a1 a0",
                          " o o o o o o o o";
        
        read_hi          = " 0 0 1 0 1 0 0 0",
                           " 0 0 a13 a12 a11 a10 a9 a8",
                           " a7 a6 a5 a4 a3 a2 a1 a0",
                           " o o o o o o o o";
        
        loadpage_lo     = " 0 1 0 0 0 0 0 0",
                          " 0 0 0 x x x x x",
                          " x x a5 a4 a3 a2 a1 a0",
                          " i i i i i i i i";
        
        loadpage_hi     = " 0 1 0 0 1 0 0 0",
                          " 0 0 0 x x x x x",
                          " x x a5 a4 a3 a2 a1 a0",
                          " i i i i i i i i";
        
        writepage       = " 0 1 0 0 1 1 0 0",
                          " 0 0 a13 a12 a11 a10 a9 a8",
                          " a7 a6 x x x x x x",
                          " x x x x x x x x";

        mode        = 0x41;
        delay       = 6;
        blocksize   = 128;
        readsize    = 256;

        ;
        
    memory "lfuse"
        size            = 1;
        min_write_delay = 4500;
        max_write_delay = 4500;
        read            = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0",
                          "x x x x x x x x o o o o o o o o";
        
        write           = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0",
                          "x x x x x x x x i i i i i i i i";
        ;
    
    memory "hfuse"
        size            = 1;
        min_write_delay = 4500;
        max_write_delay = 4500;
        read            = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0",
                          "x x x x x x x x o o o o o o o o";
        
        write           = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0",
                          "x x x x x x x x i i i i i i i i";
        ;
    
    memory "efuse"
        size            = 1;
        min_write_delay = 4500;
        max_write_delay = 4500;
        read            = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0",
                          "x x x x x x x x x x x x x o o o";
        
        write           = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0",
                          "x x x x x x x x x x x x x i i i";
        ;
    
    memory "lock"
        size            = 1;
        min_write_delay = 4500;
        max_write_delay = 4500;
        read            = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0",
                          "x x x x x x x x x x o o o o o o";
        
        write           = "1 0 1 0 1 1 0 0 1 1 1 x x x x x",
                          "x x x x x x x x 1 1 i i i i i i";
        ;
    
    memory "calibration"
        size            = 1;
        read            = "0 0 1 1 1 0 0 0 0 0 0 x x x x x",
                          "0 0 0 0 0 0 0 0 o o o o o o o o";
        ;
    
    memory "signature"
        size            = 3;
        read            = "0 0 1 1 0 0 0 0 0 0 0 x x x x x",
                          "x x x x x x a1 a0 o o o o o o o o";
        ;
;

The boards.txt File

To actually use the ATmega328, we need to give the Arduino IDE a build target in the form of a board. These are defined in hardware/boards.txt.

diecimila_328.name=Arduino w/ ATmega328

diecimila_328.upload.protocol=stk500
diecimila_328.upload.maximum_size=30720
diecimila_328.upload.speed=19200

diecimila_328.bootloader.low_fuses=0xff
diecimila_328.bootloader.high_fuses=0xdd
diecimila_328.bootloader.extended_fuses=0x00
diecimila_328.bootloader.path=atmega328
diecimila_328.bootloader.file=ATmegaBOOT_328_diecimila.hex
diecimila_328.bootloader.unlock_bits=0x3F
diecimila_328.bootloader.lock_bits=0x0F

diecimila_328.build.mcu=atmega328p
diecimila_328.build.f_cpu=16000000L
diecimila_328.build.core=arduino

Update iom328p.h

This was likely the trickiest bit of all; without this modification, code will build and upload, but it just won't run.

This discrepency was found by running the Arduino IDE's build script with all calls to avr-gcc suffixed with -E to generate the post-preproccessor code. This was done twice, once for an ATmega168 build and once for an ATmega328P build. The resulting files were then run through diff to discover any differences.

Anyhow, modify hardware/tools/avr/avr/include/avr/iom328p.h to use the below code. You'll notice this is very very similiar to the code from iom168p.h.

#ifndef _AVR_IOM328P_H_
#define _AVR_IOM328P_H_ 1

#include 

/* Constants */
#define SPM_PAGESIZE 128
#define RAMEND       0x8FF     /* Last On-Chip SRAM Location */
#define XRAMSIZE     0
#define XRAMEND      (RAMEND + XRAMSIZE)
#define E2END        0x3FF
#define FLASHEND     0x7FFF



/* Fuses */
#define FUSE_MEMORY_SIZE 3

/* Low Fuse Byte */
#define FUSE_CKSEL0 ~_BV(0)  /* Select Clock Source */
#define FUSE_CKSEL1 ~_BV(1)  /* Select Clock Source */
#define FUSE_CKSEL2 ~_BV(2)  /* Select Clock Source */
#define FUSE_CKSEL3 ~_BV(3)  /* Select Clock Source */
#define FUSE_SUT0   ~_BV(4)  /* Select start-up time */
#define FUSE_SUT1   ~_BV(5)  /* Select start-up time */
#define FUSE_CKOUT  ~_BV(6)  /* Clock output */
#define FUSE_CKDIV8 ~_BV(7) /* Divide clock by 8 */
#define LFUSE_DEFAULT (FUSE_CKSEL0 & FUSE_CKSEL2 & FUSE_CKSEL3 & FUSE_SUT0 & FUSE_CKDIV8)

/* High Fuse Byte */
#define FUSE_BODLEVEL0 ~_BV(0)  /* Brown-out Detector trigger level */
#define FUSE_BODLEVEL1 ~_BV(1)  /* Brown-out Detector trigger level */
#define FUSE_BODLEVEL2 ~_BV(2)  /* Brown-out Detector trigger level */
#define FUSE_EESAVE    ~_BV(3)  /* EEPROM memory is preserved through chip erase */
#define FUSE_WDTON     ~_BV(4)  /* Watchdog Timer Always On */
#define FUSE_SPIEN     ~_BV(5)  /* Enable Serial programming and Data Downloading */
#define FUSE_DWEN      ~_BV(6)  /* debugWIRE Enable */
#define FUSE_RSTDISBL  ~_BV(7)  /* External reset disable */
#define HFUSE_DEFAULT (FUSE_SPIEN)

/* Extended Fuse Byte */
#define FUSE_BOOTRST ~_BV(0)
#define FUSE_BOOTSZ0 ~_BV(1)
#define FUSE_BOOTSZ1 ~_BV(2)
#define EFUSE_DEFAULT (FUSE_BOOTSZ0 & FUSE_BOOTSZ1)



/* Lock Bits */
#define __LOCK_BITS_EXIST
#define __BOOT_LOCK_BITS_0_EXIST
#define __BOOT_LOCK_BITS_1_EXIST 


#endif  /* _AVR_IOM328P_H_ */