Managing configurations via EEPROM by writing it with the hex file I've been looking into I2C bootloaders for an ATTINY coprocessor on a board I'm developing, and I ran into a bit of a snag. I have the need to detect what board the main processor's code is running on, since there are a number of write-only peripherals I can't probe for presence or configuration (WS2812-series LEDs and a SSD1306 screen, among a few others), and I was going to manage that via a configuration blob stored on the ATTINY.

Unfortunately, this was coded into the firmware, and pushing out any sort of update for the coprocessor would then require that I build, label, and provide each version, and then have the user choose the correct one.

So, the solution would seemingly be EEPROM, since that can be set to persist over programming attempts (there's even a fuse setting to keep it, although in the other case how the AVR knows if it's been programmed [in the era of bootloaders] I'm not sure).

The issue is now that I need a way to set the EEPROM configuration when I create the original program, and then have future updates not touch it. The existing way is that I add a stub to my code that checks if there's a config and sets it (unfortunately per-unique-board-design, so I'd need lots of different copies again) and then never touches it again. Future firmwares could then just not include any stub at all.

However, this annoys me, especially since if something goes wrong it could mess up the EEPROM.

Does anyone know of a way to use a ICSP programmer to set EEPROM, ideally as part of the firmware upload?

I am using a usbasp with PlatformIO to do the chip programming, so I should have enough access on the first burning to change the EEPROM. Does anyone know how I could add in an EEPROM configuration to go with the flash one?

Some thoughts I have had:


Somehow modify/append the hex file to include data that goes to EEPROM and then burn it
Add a script to PlatformIO that lets me edit/compile/upload/whatever to EEPROM (I do not speak Python, so I'd need help)
Use an existing feature of PlatformIO/the build process/the AVR toolchain to set an EEPROM configuration (I have to suspect there is one, but Googling does not seem to have pointed one out)
Somehow do this with AVRDude
AVRDUDE can program EEPROM. I usually do this as part of the firmware burn - the operator can pick which config block should go into the board while running the programming cycle. In some cases the EEPROM info is even generated programmatically during the cycle to contain dynamic info like unit serial number and commision date.

Here is an example command line that will program the file filename.hex into EEPROM...

avrdude -c stk500v2 -P COM6 -p atmega328p -U eeprom:w:filename.hex:i


The AVRDUDE write command (U) has many options to do almost anything you want...

-U memtype:op:filename[:format]
Perform a memory operation. Multiple ‘-U’ options can be specified in order to operate on multiple memories on the same command-line invocation. The memtype field specifies the memory type to operate on. Use the ‘-v’ option on the command line or the part command from terminal mode to display all the memory types supported by a particular device. Typically, a device’s memory configuration at least contains the memory types flash and eeprom. All memory types currently known are:
(...)
MEMTYPE:
eeprom
The EEPROM of the device.
(...)

OP:
w
read the specified file and write it to the specified device memory

(...)

FILENAME:
The filename field indicates the name of the file to read or write. The format field is optional and contains the format of the file to read or write. Possible values are:

i
Intel Hex

s
Motorola S-record

r
raw binary; little-endian byte order, in the case of the flash ROM data

e
ELF (Executable and Linkable Format), the final output file from the linker; currently only accepted as an input file

m
immediate mode; actual byte values specified on the command line, separated by commas or spaces in place of the filename field of the ‘-U’ option. This is useful for programming fuse bytes without having to create a single-byte file or enter terminal mode. If the number specified begins with 0x, it is treated as a hex value. If the number otherwise begins with a leading zero (0) it is treated as octal. Otherwise, the value is treated as decimal.

a
auto detect; valid for input only, and only if the input is not provided at stdin.

d
decimal; this and the following formats are only valid on output. They generate one line of output for the respective memory section, forming a comma-separated list of the values. This can be particularly useful for subsequent processing, like for fuse bit settings.

h
hexadecimal; each value will get the string 0x prepended.

o
octal; each value will get a 0 prepended unless it is less than 8 in which case it gets no prefix.

b
binary; each value will get the string 0b prepended.

The default is to use auto detection for input files, and raw binary format for output files.

Note that if filename contains a colon, the format field is no longer optional since the filename part following the colon would otherwise be misinterpreted as format.

As an abbreviation, the form -U filename is equivalent to specifying -U flash:w:filename:a. This will only work if filename does not have a colon in it.


Any of these files types can be used depending on what kind of data you are writing to the EEPROM and how it is being generated. 

More info here...
https://www.pololu.com/docs/0J67/5.8