This part is about the real ATmega328P, with 32 KB of flash, running our Arduino programs/sketches.
In the Uno R3 case, ATmega328P does not interact directly with our computer (no USB support), but uses UART communication via the ATmega16U2 supporting USB (ATmega328P (UART) ↔ ATmega16U2 (USB) ↔ our computer).

You can find information about ATmega16U2 on the Arduino Uno R3: Arduino Uno R3 - ATmega16U2 (for USB to serial and its DFU)

The Arduino’s ATmega328P uses a minimalist bootloader called optiboot, which is slightly under 512 bytes, leaving more space for our programs/sketches, and allows UART flashing via the ATmega16U2.

You can find original optiboot bootloader in :

Our Arduino Uno R3 uses optiboot_atmega328.hex file, by default in its version 4.4.

With default fuses values, the memory map for Intel HEX files is:

Start End Size Section Contents
0x000000 0x007fff 32 KB Flash (see below) User program + Bootloader
0x000000 0x007dff 31.5 KB Flash (Program) User program code
0x007e00 0x007fff 512 bytes Flash (Bootloader) Bootloader code
0x810000 0x8103ff 1 KB EEPROM User data
0x820000 0x820002 3 bytes Fuses Low, High, and Extended fuse bits
0x830000 0x830000 1 byte Lock Bits Protection flags

You can see other values in the datasheet:

  • ATmega328P uses an addressing mode in words (16 bits), not bytes (8 bits): so bootloader start at 0x3f00 in words… but also 0x7e00 in bytes
  • EEPROM is not really @ 0x810000, as fuses or lock, but programmer softwares are using different addresses to not mix different memory areas.

Building firmware

You can build a new version of Optiboot thanks to: https://github.com/Optiboot/optiboot

sudo apt update
sudo apt upgrade --assume-yes
sudo apt install build-essential avr-libc binutils-avr gcc-avr srecord git
git clone https://github.com/Optiboot/optiboot.git
cd optiboot
make --directory=optiboot/bootloaders/optiboot AVR_FREQ=16000000 LED_START_FLASHES=2 atmega328
srec_info optiboot/bootloaders/optiboot/optiboot_atmega328.hex -intel

You now need an external programmer (not arduino) in order to replace the bootloader, see below.

Programming

Tested with arduino (with limitations), avrispmkII & pickit4_isp

arduino

In this mode, only flash is available (and the bootloader part is not writable).

This is the normal programming mode used by Arduino IDE (calling an old version of avrdude)

Check connection

> avrdude -c arduino -P COM5 -p ATmega328P -v
[...]
Using port            : COM5
Using programmer      : arduino
AVR part              : ATmega328P
Programming modes     : SPM, ISP, HVPP, debugWIRE
Programmer type       : Arduino
Description           : Arduino bootloader using STK500 v1 protocol
HW Version            : 3
FW Version            : 4.4

AVR device initialized and ready to accept instructions
Device signature = 1E 95 0F (ATmega328P, ATA6614Q, LGT8F328P)
[...]

Before flashing

Make backup of flash before any write operation: avrdude -c arduino -P COM5 -p ATmega328P -U flash:r:backup_flash.hex:i
You can restore memories avrdude -c arduino -P COM5 -p ATmega328P -U flash:w:backup_flash.hex:i

Flash

You can flash an application, such as blink.hex, with the following command:

> avrdude -c arduino -P COM5 -p atmega328p -U flash:w:blink.hex:i
Reading 924 bytes for flash from input file blink.hex
Writing 924 bytes to flash
Writing | ################################################## | 100% 0.18 s
Reading | ################################################## | 100% 0.13 s
924 bytes of flash verified

pickit4_isp or avrispmkII

Notes

When using a hardware programmer, connect it to the ATmega328P ISP connector (located at the bottom middle)

RESET  CLK  MISO
    \---|---/     
   | 5  3  1 |
   | 6  4  2 |
    /---|---\
  GND  MOSI VCC

When using a programmer, you can interact with fuses, lock, eeprom, and bootloader part of flash

When using pickit4, you may need to switch mode to avr: avrdude -c pickit4_isp -p ATmega328P -x mode=avr (-x mode=pic to switch back)

Original fuses

Fuse Name Value
LOW 0xff
HIGH 0xde
EXTENDED 0xfd
LOCK 0xcf
  • Bootloader 256 words (512 B when in bytes), @ 0x3f00 (0x7e00 when in bytes)
  • LPM and SPM prohibited in Boot Section

You can check them with:

  • version < 8.0: avrdude -c pickit4_isp -p ATmega328P -U lfuse:r:-:h -U hfuse:r:-:h -U efuse:r:-:h -U lock:r:-:h
  • version >= 8.0: avrdude -c pickit4_isp -p ATmega328P -U lfuse,hfuse,efuse,lock:r:-:h

Check connection

> avrdude -c pickit4_isp -p ATmega328P -v
[...]
Using port            : usb
Using programmer      : pickit4_isp
AVR part              : ATmega328P
Programming modes     : SPM, ISP, HVPP, debugWIRE
Programmer type       : JTAG3_ISP
Description           : MPLAB(R) PICkit 4 in ISP mode
ICE HW version        : 6
ICE FW version        : 1.15 (rel. 20)
Serial number         : BUR222474515
Vtarget               : 0.0 V
SCK period            : 8.0 us
Vtarget               : 4.99 V

AVR device initialized and ready to accept instructions
Device signature = 1E 95 0F (ATmega328P, ATA6614Q, LGT8F328P)
[...]

Before flashing

  • Make backup before any write operation: avrdude -c pickit4_isp -p ATmega328P -U flash:r:backup_flash.hex:i
  • You can restore the flash by: avrdude -c pickit4_isp -p ATmega328P -e -U flash:w:backup_flash.hex:i
  • if not using -D when writing, flash is erased (including bootloader): do not forget it, or be sure to include bootloader memory.

The -e will erase the eeprom too (if previous fuses values were wrong, it may be not erased, feel free to check with: avrdude -c pickit4_isp -p ATmega328P -U eeprom:r:-:h before trying again)

Flash

Only program

File: blink.hex

Prefer -c arduino programming mode when dealing with programs only

avrdude -c pickit4_isp -p ATmega328P -D -U flash:w:blink.hex:i
Program with bootloader

Files: blink.hex & optiboot_atmega328.hex

avrdude -c pickit4_isp -p ATmega328P -e -U flash:w:blink.hex:i -U flash:w:optiboot_atmega328.hex:i
Program with bootloader & fuses/lock

Files: blink.hex & optiboot_atmega328.hex

avrdude -c pickit4_isp -p ATmega328P -e -U flash:w:blink.hex:i -U flash:w:optiboot_atmega328.hex:i -U lfuse:w:0xff:m -U hfuse:w:0xde:m -U efuse:w:0xfd:m -U lock:w:0xcf:m

or with all combined (avrdude version >= 8.0):

File: blink_optiboot_fuses_lock.hex

avrdude -c pickit4_isp -p ATmega328P -e -U flash,lfuse,hfuse,efuse,lock:w:blink_optiboot_fuses_lock.hex:i

You can produce this combined file with fuses & lock with:

srec_cat -output blink_optiboot_fuses_lock.hex -intel ^
  blink.hex -intel ^
  optiboot_atmega328.hex -intel ^
  -generate 0x820000 0x820003 -repeat_data 0xff 0xde 0xfd ^
  -generate 0x830000 0x830001 -constant 0xcf

You can add -generate 0x810000 0x810200 -constant 0xff ^ before the first -generate if you really want the EEPROM data (normally erased when programming)

New bootloader

If you flashed a new Optiboot bootloader version, you can test it and see new FW Version:

> avrdude -c arduino -P COM5 -p ATmega328P -v
[...]
Using port            : COM5
Using programmer      : arduino
AVR part              : ATmega328P
Programming modes     : SPM, ISP, HVPP, debugWIRE
Programmer type       : Arduino
Description           : Arduino bootloader using STK500 v1 protocol
HW Version            : 3
FW Version            : 8.3

AVR device initialized and ready to accept instructions
Device signature = 1E 95 0F (ATmega328P, ATA6614Q, LGT8F328P)
[...]

References

ATmega / Microchip

SRecord

Bootloaders

Programmers

Hardware

Software