Wednesday, January 13, 2010

Atmel production file

Atmel has implemented a so called 'production file' in its programmer software. It's a simple ELF file containing sections for Flash, EEprom and fuses. You can create these sections from your C code too.
The board I developed for contains an Atmega128 attached to an ethernet controller. Also, it contains a bootloader that can program and dump the flash and eeprom memory.
What I wanted is a complete snapshot of a working board for production use (special bootloader/firmware version without final encryption keys). It will also have the default MAC and IP address and checksum information in EEprom.

So, first I prepare a complete working board and start dumping the program memory in encrypted format by using a special bootloader function. The tool automatically writes out a special format complete with checksums etc.
bootload -m 00-01-23-45-67-89 -d -i dump.img -b 172.16.0.0
Then I call the encryption/decryption tool to turn it into a plain binary.
imgtool -d -b dump.bin -i dump.img

I do the same with the bootloader that is located at 0x1E000.
bootload -m 00-01-23-45-67-89 -d -i bldump.img -s 0x1E000 -b 172.16.0.0
And decrypt that as well:
imgtool -d -b bldump.bin -i bldump.img -s 0x1E000

Then comes the EEprom dump which is already in plain binary form:
bootload -m 00-01-23-45-67-89 -e -b 172.16.0.0
You might want to crop it down to a reasonable working size since programming the EEprom is terribly slow.
srec_cat eeprom.bin -binary -crop 0x0 0x80 -o eeprom.bin -binary

We also need small files containing the (lock-)fuses and the CPU signature that needs to match before programming. The order of bytes need to be reversed.
You could also compile this data with your project.
signature.bin (3 bytes): 02 97 1E for atmega128.
fuse.bin (3 bytes): BF D8 FF
lock.bin (1 byte): DC blocks programming cable and user-mode reads of bootloader area. The lock is written last and will activate the bootloader boot process.

There are various ways to combine it all together. I chose to combined the flash sections first:
srec_cat dump.bin -binary bldump.bin -binary -offset 0x1E000 -o combined_dump.hex -intel
and then add the extra sections:
avr-objcopy -O elf32-avr -I ihex combined_dump.hex --gap-fill 0xFF --add-section .eeprom=eeprom.bin --add-section .fuse=fuse.bin --add-section .lock=lock.bin --add-section .signature=signature.bin --rename-section .sec1=.text --rename-section .sec2=.text --set-section-flags=.eeprom="alloc,load" --set-section-flags=.fuse="alloc,load" --set-section-flags=.lock="alloc,load" --set-section-flags=.signature="alloc,load" temp.elf
The final step is assigning the section addresses and turning the file into executable ELF format.
avr-ld -s -mavr5 -o ProductionFile.elf temp.elf --section-start .eeprom=0x810000 --section-start .fuse=0x820000 --section-start .lock=0x830000 --section-start .signature=0x840000
The section offsets don't mean very much but the programming tool might check for them.
After this, you can delete all other intermediate files.

Ready to test to production file...
Stk500 -cUSB -datmega128 -ipProductionFile.elf -e -pafeb
And there you have it.
I hope you stumbled upon this post and found it useful.

1 comment:

DarkFader said...

Another method without extra files:

/*
Add to [Linker options]:
-Wl,-section-start=.fuse=0x820000
-Wl,-section-start=.lock=0x830000
-Wl,-section-start=.signature=0x840000
*/

typedef struct {unsigned char B2;unsigned char B1;unsigned char B0;} __signature_t;
#define SIGNATURE __signature_t __signature __attribute__((section (".signature")))
SIGNATURE = {
.B2 = 0x02, .B1 = 0x97, .B0 = 0x1E,
};

typedef struct {unsigned char low;unsigned char high;unsigned char extended;} __fuse_t;
#define FUSE __fuse_t __fuse __attribute__((section (".fuse")))
FUSE = {
.low = 0x7F, .high = 0xC9, .extended = 0xFF,
};

__attribute__((section (".lock"))) const unsigned char __lock =
0xFF;