I am getting back into Atmel AVR programming after nearly a decade off. To this end, I am trying to get the usual blinken lights demo working. Unfortunately this does not function, though avrdude reports that it flashed the hex file successfully.

Digging into this a bit more, I find that reading the freshly written flash back yields a different result. The original hex file is:


While the read-back hex file comes out as:


The key items of note here are the programming addresses at the beginning of each line. In the original, the addresses start at 0x10000000 and increment by 0x1000. In the read hex file the base address is 0x20000000, incrementing by 0x2000. Now, the read hex file's lines are twice as long, which should account for the difference in increment magnitude.

What would account for the difference in base address between these two hex files?

I found this question on SO which seems to indicate that the AVR is 16-bit word-addressable instead of 8-bit byte-addressable as is expected by the Intel hex format. That being said, I would have expected avrdude to handle this already since programming hex files to AVR devices is kind of its whole purpose in life.

Additionally, I dumped the symbols from the elf file. As I would have expected, most of the symbols are referenced to base address 0x00000000 (truncated for brevity):

0000004e T main
00000070 T _exit
00000070 W exit
00000072 t __stop_program
00000074 A __data_load_end
00000074 A __data_load_start
00000074 T _etext
000001ff W __stack

I would have expected one of the records in the hex file to write to 0x00000000 to set the reset jump offset in the IVT.

What is the correct initial offset for program start?

Since neither of these hex files specify a reset vector address there must be an additional mechanism which I am not aware of.

Finally, I have verified that the programmer is actually writing to the chip by erasing the flash and performing a read; I do see the chip return essentially blank. A subsequent program returns the above incorrect hex.

General Information

I am working on Linux using an original STK500v2. Everything is build using a heavily customized makefile based on this post. All the same, the relevant sections are below (please excuse the convoluted variables; this is part of a much larger build system):

AVRDUDE=@avrdude -c stk500v2 -p t441 -P /dev/ttyUSB1

%.hex: $(APP_TARGETS)
    $(ECHO) " MKHEX  $*"
    $(AVR_OBJCOPY) -j .text -j .data -O ihex $(BUILD_DIR)/$(ARCH)/$*$(BINARY_SUFFIX) $(BUILD_DIR)/$(ARCH)/$*.flash.hex
    $(AVR_OBJCOPY) -j .eeprom --set-section-flags=.eeprom="alloc,load" --change-section-lma .eeprom=0 -O ihex $(BUILD_DIR)/$(ARCH)/$*$(BINARY_SUFFIX) $(BUILD_DIR)/$(ARCH)/$*.eeprom.hex
    $(AVR_OBJCOPY) -j .fuse -O ihex $(BUILD_DIR)/$(ARCH)/$*$(BINARY_SUFFIX) $(BUILD_DIR)/$(ARCH)/$*.fuses.hex --change-section-lma .fuse=0
    $(SREC_CAT) $(BUILD_DIR)/$(ARCH)/$*.fuses.hex -Intel -crop 0x00 0x01 -offset  0x00 -O $(BUILD_DIR)/$(ARCH)/$*.lfuse.hex -Intel
    $(SREC_CAT) $(BUILD_DIR)/$(ARCH)/$*.fuses.hex -Intel -crop 0x01 0x02 -offset -0x01 -O $(BUILD_DIR)/$(ARCH)/$*.hfuse.hex -Intel
    $(SREC_CAT) $(BUILD_DIR)/$(ARCH)/$*.fuses.hex -Intel -crop 0x02 0x03 -offset -0x02 -O $(BUILD_DIR)/$(ARCH)/$*.efuse.hex -Intel
    avr-nm -n $(BUILD_DIR)/$(ARCH)/$*$(BINARY_SUFFIX) > $(BUILD_DIR)/$(ARCH)/$*.sym

    $(AVRDUDE) 2>&1 | grep "Fuses OK" | sed 's:.*(\(.*\)).*:\n\1\n:'

    $(AVRDUDE) -U flash:w:$(BUILD_DIR)/$(ARCH)/firmware.flash.hex

I know the STK500 is functional because, infuriatingly, this was working before on this very chunk of silicon.


By request: the source for my test program.

#include <avr/io.h>
#include <util/delay.h>

int main(){

    DDRA = 0x0F;
    PORTA = 0x00;

    while (1)
        PORTA ^= PORTA;

Also, for good measure, current fuse settings:

avrdude: safemode: Fuses OK (E:FF, H:DF, L:82)

Edit 2:

For any who see this later, the issue with the program was an XOR fail. PORTA ^= PORTA; should have been PORTA ^= 0x0F;. This post just about sums it up. Remember kids, don't try to be too clever.

  • 1
    \$\begingroup\$ here is the hexfile format description, for anyone doing research ... en.m.wikipedia.org/wiki/Intel_HEX \$\endgroup\$
    – jsotola
    Feb 3, 2020 at 4:18
  • \$\begingroup\$ "I am trying to get the usual blinken lights demo working. Unfortunately this does not function" - which AVR? Show us your code for blinking lights. \$\endgroup\$ Feb 3, 2020 at 4:44

1 Answer 1


The read back file is likely completely fine (I did not compare the actual bytes). The first two hex digits is the record size, and the address is in the next 4 hex digits (2 bytes). Avrdude chooses a different record length (32 bytes) as it does not know what the original one was!

Addresses like 0x10000000 are a bit of a stretch for an 8-bit AVR.

  • \$\begingroup\$ /facepalm, that makes sense. I was wondering about such a large address; I figured it was mapping into some virtual memory space. Still too big, though. \$\endgroup\$ Feb 3, 2020 at 3:51
  • \$\begingroup\$ @MysteryMoose, were you expecting less than 0x74 bytes? \$\endgroup\$
    – jsotola
    Feb 3, 2020 at 4:16
  • \$\begingroup\$ The data in the two hex files is identical \$\endgroup\$ Feb 3, 2020 at 4:18
  • \$\begingroup\$ The size of 0x74 of both hex files matches exactly the dump's result. \$\endgroup\$ Feb 3, 2020 at 7:46
  • \$\begingroup\$ Yeah, was a silly mistake born of staring at the same problem for too long. Was thinking the contents were correct but loaded at the wrong offset. This is clearly not the case. I must admit, I have been spoiled by the address space of 32-bit SOCs. \$\endgroup\$ Feb 4, 2020 at 5:23

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.