element14 Community
element14 Community
    Register Log In
  • Site
  • Search
  • Log In Register
  • Community Hub
    Community Hub
    • What's New on element14
    • Feedback and Support
    • Benefits of Membership
    • Personal Blogs
    • Members Area
    • Achievement Levels
  • Learn
    Learn
    • Ask an Expert
    • eBooks
    • element14 presents
    • Learning Center
    • Tech Spotlight
    • STEM Academy
    • Webinars, Training and Events
    • Learning Groups
  • Technologies
    Technologies
    • 3D Printing
    • FPGA
    • Industrial Automation
    • Internet of Things
    • Power & Energy
    • Sensors
    • Technology Groups
  • Challenges & Projects
    Challenges & Projects
    • Design Challenges
    • element14 presents Projects
    • Project14
    • Arduino Projects
    • Raspberry Pi Projects
    • Project Groups
  • Products
    Products
    • Arduino
    • Avnet Boards Community
    • Dev Tools
    • Manufacturers
    • Multicomp Pro
    • Product Groups
    • Raspberry Pi
    • RoadTests & Reviews
  • Store
    Store
    • Visit Your Store
    • Choose another store...
      • Europe
      •  Austria (German)
      •  Belgium (Dutch, French)
      •  Bulgaria (Bulgarian)
      •  Czech Republic (Czech)
      •  Denmark (Danish)
      •  Estonia (Estonian)
      •  Finland (Finnish)
      •  France (French)
      •  Germany (German)
      •  Hungary (Hungarian)
      •  Ireland
      •  Israel
      •  Italy (Italian)
      •  Latvia (Latvian)
      •  
      •  Lithuania (Lithuanian)
      •  Netherlands (Dutch)
      •  Norway (Norwegian)
      •  Poland (Polish)
      •  Portugal (Portuguese)
      •  Romania (Romanian)
      •  Russia (Russian)
      •  Slovakia (Slovak)
      •  Slovenia (Slovenian)
      •  Spain (Spanish)
      •  Sweden (Swedish)
      •  Switzerland(German, French)
      •  Turkey (Turkish)
      •  United Kingdom
      • Asia Pacific
      •  Australia
      •  China
      •  Hong Kong
      •  India
      •  Korea (Korean)
      •  Malaysia
      •  New Zealand
      •  Philippines
      •  Singapore
      •  Taiwan
      •  Thailand (Thai)
      • Americas
      •  Brazil (Portuguese)
      •  Canada
      •  Mexico (Spanish)
      •  United States
      Can't find the country/region you're looking for? Visit our export site or find a local distributor.
  • Translate
  • Profile
  • Settings
DreamBoard
  • Products
  • Dev Tools
  • DreamBoard
  • More
  • Cancel
DreamBoard
Documents ATmega328(P) ISP Programming Commands in SPI Mode
  • Blog
  • Forum
  • Documents
  • Files
  • Mentions
  • Sub-Groups
  • Tags
  • More
  • Cancel
  • New
Actions
  • Share
  • More
  • Cancel
Engagement
  • Author Author: iexpress
  • Date Created: 1 Dec 2014 3:19 AM Date Created
  • Last Updated Last Updated: 8 Oct 2021 8:01 AM
  • Views 2594 views
  • Likes 1 like
  • Comments 2 comments
Related
Recommended

ATmega328(P) ISP Programming Commands in SPI Mode

I've been building an 8-bit Digital Logic Processor over the past month that has two ATmega328's on-board.

Instead of purchasing an ISP programmer, I wanted to figure out how to write Flash manually using GPIO,

so I implemented SPI with GPIO pin toggling for ISP programming with an Atmel UC3A3 Xplained Evaluation Board.

 

While I couldn't find any documentation on ISP programming on this MCU model, I kept trying for about 10 hours

before writing all the code into flash successfully, so I created a tutorial on how to manually program the ATmega328(p)

manually found below.

 

Feel free to let me know what you think! Now you can write your binaries to flash out of circuit.

Here is a video I made showing my board's ATmega328P in operation: https://www.youtube.com/watch?v=KezzU8PZMIc

_________________________

 

HOW TO PROGRAM THE ATMEGA328(p) MANUALLY THROUGH SPI BY: JASON D SWEET - iexpress@live.com - November 30 2014

 

Programming the ATmega328(p) manually can easily be achieved using a standard SPI connection.

By connecting the ATmega to a host MCU through SPI, programming the target can be very easy.

 

1. ChipSelect - Enables programming mode on the target ATmega328(p)

2. Issue corresponding commands from host to the target.

3. Release ChipSelect

___________________________________________________________________________________

 

CONNECTIONS

 

HOST - TARGET

SS/CS  RESET

MOSI    MOSI

MISO    MISO

SCK     SCK

V+        V+

GND     GND

 

No external crystal connection is needed. Programming speed is determined by SPI SCK.

___________________________________________________________________________________

 

ATMEGA328(p) ISP COMMANDS

 

0xAC EXECUTABLE COMMAND PREFIX

0x20 READ LOW BYTE FROM FLASH

0x28 READ HIGH BYTE FROM FLASH

0x30 READ DEVICE ID INFORMATION

0x40 WRITE LOW BYTE TO FLASH BUFFER

0x48 WRITE HIGH BYTE TO FLASH BUFFER

0x4C TRANSFER BYTES FROM BUFFER TO FLASH AT ADDRESS LOADED INTO 0x40 AND 0x48

0xC0 WRITE BYTE TO EEPROM

0xA0 READ BYTE FROM EEPROM

___________________________________________________________________________________

 

OPCODE USAGE

 

STEP 1: Issuing the "Programming Enable" command to the target:

 

This is the only command the target will acknowledge initially when RESET goes low.

You can enter Programming Mode by sending AC 53 00 00 to the target.

 

 

STEP 2: Reading the Device ID from the target after initialization:

 

The next step is to see if init occured correctly, so we have to read the Device ID from the target.

Device ID can be read by issuing 30 00 00 to the target, and then read one byte back from the

target checking for data first then issuing clock in that order on the bit level.

 

The Device ID byte should read back as 1E signifying Atmel as the manufacturer.

If the Device ID byte reads as 0x1E, the device is set to be reprogrammed.

If the Device ID byte reads as 0xFF, the device did not initialize properly.

 

If the Device ID byte reads as 0x00, then the Lock Bit is set, and the

device has to be erased first before you can properly read the Device ID.

 

Send three bytes, then read one byte for a total of four bytes in the sequence.

 

** Note that each command in Programming Mode is ALWAYS 4 bytes long **

** You can also read flash size using 30 00 01 + read one byte **

** You can also read device family using 30 00 02 + read one byte **

 

 

STEP 3: Issuing the Chip Erase Command to Erase the entire contents of Flash and EEPROM:

 

Before programming can occur, the Flash and EEPROM must be erased at the same time.

This resets all bytes in the physical address space to 0xFF so they can be reprogrammed.

Erasing Flash and EEPROM can be accomplished by issuing AC 80 00 00 to the target.

ALL bytes in Flash and EEPROM become 0xFF.

 

** ATmega328(p) is only capable of setting individual bits to 0's from 1's during programming **

** The unit can not program bits from 0's to 1's, so the bytes default to 0xFF after format **

 

 

STEP 4: Checking to see if the device was formatted properly:

 

Checking Flash to see if it was formatted properly can be done by issuing

the "Read Byte From Flash" command. Each address location holds 2 bytes,

a High byte and a Low byte.

 

aa=SEGMENT or MSB high byte of address

bb=OFFSET or LSB low byte of address

 

Example: If the Segment=00 and the Offset=01 then the ADDRESS= 0x0001

 

To read a low byte from an address in Flash, issue: 20 aa bb then read one byte,

or issue: 20 SEGMENT OFFSET then read one byte.

 

To read a high byte from an address in Flash, issue: 28 aa bb then read one byte

or issue: 28 SEGMENT OFFSET then read one byte.

 

Send three bytes, then read one byte for a total of four bytes in the sequence.

 

If the bytes read are 0xFF, then the device has been formatted properly.

The Flash address range is 0x0000 - 0x03FFF or 0-16383 for a total of 16384 memory locations.

** Each address in Flash contains 2 bytes, a Low byte and a High byte **

 

 

STEP 5: Writing a byte to Flash after proper Format:

 

Writing bytes to flash occurs by sending a byte to a high or low location per address in flash.

 

Writing a low byte to a Flash address is accomplished by issuing 40 SEGMENT OFFSET uint8_t

for a total of four bytes sent to the target from the host.

 

Writing a high byte to a Flash address is accomplished by issuing 48 SEGMENT OFFSET uint8_t

for a total of four bytes sent to the target from the host.

 

Physically writing the low and high bytes to  the flash from the buffer is done by issuing

the "Write Program Memory Page" command which must be done per address location

after having written the low and high bytes to a single address.

 

Locking the bytes into Flash memory can be done by issuing 4C SEGMENT OFFSET 00

for a total of four bytes sent to the target MCU.

 

Simply release the RESET line of the target MCU to end programming mode.

 

Example 40 00 00 FE  48 00 00 EF  4C 00 00 00 writes EFFE to address 0x0000 in Flash.

Commands are issued one after another without releasing RESET, (which must remain low).

 

 

STEP 6: Reading a byte from EEPROM:

 

Reading a byte from EEPROM can be accomplished by issuing A0 SEGMENT OFFSET then

reading one byte form the target, data first then clock per bit in the byte.

 

Send three bytes, then read one byte for a total of four bytes in the sequence.

 

EEPROM address range is: 0x0000 - 0x03FF and contains one byte per address unlike Flash.

This is 1024 bytes or 1KB

 

 

STEP 7: Writing a byte to EEPROM:

 

Writing a byte to an EEPROM address can be accomplished by issuing C0 SEGMENT OFFSET uint8_t

for a total of four bytes sent to the target.

 

** EEPROM addresses don't have to be pre-formatted before they can be written to as the Flash requires **

** There is no Write Page command needed for the EEPROM, the bytes autoset themselves in place **

__________________________________________________________________________________________

 

INTERPRETING INTEL HEX FORMAT

 

Intel HEX format traditionally looks something like this: :107800000C94343C0C94513C0C94513C0C94513CE1

 

Understanding the bytes can be done by breaking each line of HEX code into groups like this:

 

:10 7800 00 0C94343C0C94513C0C94513C0C94513C E1

 

Each line in this bootloader example begins with a : representing the start of a new line.

 

The next two chars 0x10 from the example shows how many data bytes are in the line of text.

 

The next four bytes 0x7800 show the starting address where the code will be written to Flash

with 0x78 as MSB or SEGMENT and 0x00 as LSB or OFFSET for the address.

 

The next two chars 0x00 show that the next 16 bytes in the line are plain uint8 data.

This will be written low byte first then high byte in that order until end of file.

 

Following the data type is a group of 16 bytes beginning with 0x0C ending with 0x3C

0x0C will be written as the low byte using ISP command 0x40 at address 0x7800

0x94 will be written as the high byte using ISP command 0x48 at address 0x7800

 

Then these bytes are locked into place inside the Flash using ISP command

4C 78 00 00 reflecting the address of the bytes that were issued to the buffer.

 

0x3C will be written as the high byte using ISP command 0x48 at address 0x7807

This is because the ATmega328(p) holds two bytes per address in Flash unlike

the hex file shows.

 

The last two chars 0xE1 are the checksum digits for the entire line which can be discarded.

 

The last two lines in the hex file can be ignored as they will not be written to Flash in any shape, way or form.

The last two lines of code look something like this:

:040000030000780081

:00000001FF

 

They are not used for AVR, but used for storing instruction and stack pointer addresses in Intel x86  CPU's.

The last line marks the end of file which can be ignored completely.

 

** Write the low byte, then write the high byte and then lock the bytes into place before writing any bytes to any other address **

** The only address we are interested in is the very first address listed in the hex file, 7800 in this case for bootloader **

** No other address should ever be used as the other addresses do not line up to how the data needs to be written to MCU Flash! **

_______________________________________________________________________________________________________________________

 

BOOTLOADERS

 

ATmega328(p) has four bootloader locations inside it.

 

They are:

 

BLS1 - 0x7E00 - 0x7FFF size 0x0200 or 512 bytes

 

BLS2 - 0x7C00 - 0x7FFF size 0x0400 or 1024 bytes

 

BLS3 - 0x7800 - 0x7FFF size 0x0800 or 2048 bytes

 

BLS4 - 0x6FFF - 0x7FFF size 0x1000 or 4096 bytes

 

Per the example above, this bootloader begins at 0x7800

so we know we'll have to use Bootloader Section 3, BLS3.

This will be the start address where the bootloader code

will reside.

 

However, all Application Code should be written starting

at address 0x0000 inside the MCU Flash without entering

bootloader space unless the bootloader option is disabled.

 

Disabling the bootloader can be accomplished by setting [BOOTRST] to 0

which will set the Reset Vector address to 0x0000 during Power-Up.

 

This way, the bootloader is disabled and your Application Code will still work.

 

Disabling the bootloader will give your Application Code more space as it

can then fill up the bootloader sections since execution starts at 0x0000.

________________________________________________________________________________________________________________________

 

APPLICATION CODE

 

Application code should always be written to the ATmega328(p) MCU Flash starting with address 0x0000.

Traditional bootloaders will jump to this address after they finish setting up the ATmega328(p) MCU hardware.

** Always remember that there are two bytes per address in the ATmega328(p) MCU Flash **

________________________________________________________________________________________________________________________

 

NOTES FROM THE AUTHOR

 

SPI was implemented using GPIO pin toggling in AVR32 using an UC3A3 Xplained Evaluation Board as the ISP hardware.

 

ATmega328(p) MISO was connected to the UC3A3 XPlained ADC1 pin on J2 header.

 

Reading data was accomplished by reading the value of the ADC1 pin with the AVR32 gpio_pin_is_high() function,

and then adding a value to a uint8_t variable such that:

 

//Reading from MISO

 

uint8_t = 0x00;

 

if (gpio_pin_is_high(&AVR32_PIN_'Pin Number Here') == 1){

    uint8_t = uint8_t + 128;  //as listed below per Read, Toggle Clock Pin On and Off

    gpio_set_gpio_pin(Your Clock Pin);

    gpio_clr_gpio_pin(Your Clock Pin);

}else{

    gpio_set_gpio_pin(Your Clock Pin);

    gpio_clr_gpio_pin(Your Clock Pin);

}

 

//Add to uint8_t in this following order:

 

uint8_t = uint8_t + 128

uint8_t = uint8_t + 64

uint8_t = uint8_t + 32

uint8_t = uint8_t + 16

uint8_t = uint8_t + 8

uint8_t = uint8_t + 4

uint8_t = uint8_t + 2

uint8_t = uint8_t + 1

 

 

//Writing to MOSI

 

if (uint8_t >= 128){

    gpio_set_gpio_pin(Your MOSI data output Pin);

    gpio_set_gpio_pin(Your SCK clock output Pin);

    gpio_clr_gpio_pin(Your SCK clock output Pin);

    gpio_clr_gpio_pin(Your MOSI data output Pin);

    uint8_t = uint8_t - 128;

}else{

    gpio_set_gpio_pin(Your SCK clock output Pin);

    gpio_clr_gpio_pin(Your SCK clock output Pin);

}

 

//Subtract from uint8_t in this following order:

uint8_t = uint8_t - 128

uint8_t = uint8_t - 64

uint8_t = uint8_t - 32

uint8_t = uint8_t - 16

uint8_t = uint8_t - 8

uint8_t = uint8_t - 4

uint8_t = uint8_t - 2

uint8_t = uint8_t - 1

 

//uint8_t should always equal 0x00 after these 8 writes to target ATmega328(p)

______________________________________________________________________________________________________________

Attachments:
ATmega328CompleteProgrammingGuide.rtf
  • avr
  • avr32
  • atmel
  • Share
  • History
  • More
  • Cancel
  • Sign in to reply

Top Comments

  • clem57
    clem57 over 10 years ago +1
    Very well written guide @ Jason Sweet ! Clem
  • clem57
    clem57 over 10 years ago

    CONNECTIONS

     

    HOST - TARGET

    SS/CS  RESET

    MOSI    MOSI

    MISO    MISO

    SCK     SCK

    V+        V+

    GND     GND

     

    Shouldn't that be MOSI to MISO and MISO to MOSI???

     

    Clem

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • More
    • Cancel
  • clem57
    clem57 over 10 years ago

    Very well written guide @Jason Sweet !

     

    Clem

    • Cancel
    • Vote Up +1 Vote Down
    • Sign in to reply
    • More
    • Cancel
element14 Community

element14 is the first online community specifically for engineers. Connect with your peers and get expert answers to your questions.

  • Members
  • Learn
  • Technologies
  • Challenges & Projects
  • Products
  • Store
  • About Us
  • Feedback & Support
  • FAQs
  • Terms of Use
  • Privacy Policy
  • Legal and Copyright Notices
  • Sitemap
  • Cookies

An Avnet Company © 2025 Premier Farnell Limited. All Rights Reserved.

Premier Farnell Ltd, registered in England and Wales (no 00876412), registered office: Farnell House, Forge Lane, Leeds LS12 2NE.

ICP 备案号 10220084.

Follow element14

  • X
  • Facebook
  • linkedin
  • YouTube