Merge EEPROM from bootloader and application

Go To Last Post
9 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I have an EEPROM variable in my bootloader that signals whether the bootloader should run the application or should listen for data on a communication channel. The idea is taken from here: https://www.avrfreaks.net/sites/d.... The variable is called APP_RUN and the inital value is set to 1 since the app should normally run. I need access to this variable in both the application and the bootloader. What is the best way to implement this? Should I simply define the variable as 

 

uint8_t EEMEM APP_RUN = 1;

 

in both the bootloader and my application? I could then generate an EEPROM file from my application hex file and flash it onto the microcontroller. (If I use the EEPROM file generated from the bootloader I lose the non-bootloader-related EEPROM variables in my application). I'm not sure whether this is the way to go though, is there maybe a way to somehow merge the EEPROM files from both the bootloader and application hex files (similar to how the .hex files themselves get merged into one hex file that can be flashed onto the mcu)?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Nimyz wrote:
Should I simply define the variable as

Personally I wouldn't. I would move it to a fixed place away from any "real" EEPROM variables the app may want to use. The obvious place (to me at least) then is the END of the EEPROM. So say your device has 1K of EEPROM that would be location 0x03FF for example.

 

To position a variable there do this:

uint8_t __attribute__((section(".myee"))) APP_RUN;

then to set it's position use:

-Wl,-section-start=.myee=0x8103FF

as an option passed to the linker. Notice how to place something in EEPROM you add 0x810000 to the required address in the .section-start. So if you had 512 bytes and the last one was 0x1FF instead it would be:

-Wl,-section-start=.myee=0x8101FF

etc.

 

The section attribute replaces the "EEMEM". In fact when you look into "EEMEM" you will actually find that it is simply:

#define EEMEM __attribute__((section(".eeprom")))

(and by default .eeprom is placed at 0x810000). So your original variable definition was:

uint8_t __attribute__((section(".eeprom"))) APP_RUN = 1;

The one thing in doing this is that it will not be part of the .eep line and your "= 1" won't work as it stands.

 

The way that bit works for "EEMEM" and the creation of project.eep is that the build rules have:

%.eep: %.elf
        @echo
        @echo $(MSG_EEPROM) $@
        -$(OBJCOPY) -j .eeprom --set-section-flags=.eeprom="alloc,load" \
        --change-section-lma .eeprom=0 --no-change-warnings -O $(FORMAT) $< $@ || exit 0

That uses avr-objcopy to extract the section called ".eeprom" and write it to the .eep file. In doing so the -change-section-lma option rebases the data to 0 in the Intel Hex file. I could envisage a rule where you said something like:

%.eep: %.elf
        @echo
        @echo $(MSG_EEPROM) $@
        -$(OBJCOPY) -j .myee --set-section-flags=.myee="alloc,load" \
        --change-section-lma .myee=0x1FF \
        -j .eeprom --set-section-flags=.eeprom="alloc,load" \
        --change-section-lma .eeprom=0 --no-change-warnings -O $(FORMAT) $< $@ || exit 0

That would extract both ".eeprom" and ".myee" and place one at 0x1FF and one at 0x0000 (I hope!) and write both to the .eep file.

 

HOWEVER if you can live without pre-initialisation using .eep (the default will then be the erased EEPROM value of 0xFF) then it would be a LOT simpler!!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Clawson, thanks for your very detailed answer. This cleared a lot of things up for me, I didn't realise the implementation of EEMEM was this simple!

 

It seems that for my purposes I don't really need to have the intializiation set to 1. I could definitely live with a value of 0xFF, I would simply check whether the variable is 0xFF instead of 0x01. Say that I went this way (without initialization) then I would define 

 

uint8_t __attribute__((section(".myee"))) APP_RUN

 

in both my bootloader and application code and add the linker flag for .myee and that's all, right?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Nimyz wrote:
in both my bootloader and application code and add the linker flag for .myee and that's all, right?

That should be all there is to it. Which AVR? How much EEPROM memory? I would suggest you target the very last byte in the EEPROM (which is the last one that would get used if the app starts to use lots of EEPROM).

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Which AVR? How much EEPROM memory? I would suggest you target the very last byte in the EEPROM (which is the last one that would get used if the app starts to use lots of EEPROM).

It's an Atmega328p with 1kB of EEPROM so the 0x03FF address you mentioned should work. I'm having trouble reading and writing to the APP_RUN variable now though. Can I still use the eeprom_read_byte and eeprom_write_byte to read and write the APP_RUN variable that is now in the .myee section? 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Just access it by name in the usual way. At the end of the day the linker will simply have given it the address 0x3FF so &APP_RUN = 0x3FF. That means it would give you the same result whether you used:

val = eeprom_read_byte(&RUN_APP);

or

val = eeprom_read_byte((uint8_t *) 0x3FF);

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks, it is working now. I was trying to figure out why avrdude was giving me an address out of range exception. The reason was that I forgot to remove the .myee section from the .elf file when generating my .hex file. Is there any particular reason why it is bad practice to just put the APP_RUN variable at the start of EEPROM together with the other values?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Nimyz wrote:
Is there any particular reason why it is bad practice to just put the APP_RUN variable at the start of EEPROM together with the other values?

Yes. Think about it. The whole reason to use a bootloader is that you cannot know what application program might later get programmed into the device. It could be that some later program you put in there via the bootloader uses the first 15 locations of the EEPROM. That is going to "bump into" the location the bootloader itself uses.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Yes of course that makes a lot of sense, thanks!