Access Bootloader variable from program

Hello,
For my project, I created a process that create and burn a bootloader that contains variable like UID, board type,... this bootloader also read i2c eeprom from shields at the reset of the atmega.
All these variables are writed in Serial at each reboot. It allows computer to know wich board is connected, if a shield is connected,...
All this process works verry well (bootloader creation from a program, reading an i2c eeprom, write it to the Serial at 115200 baud rate,...)
The last problem is that I would like that the arduino program started after this bootloader can be retreive these variable from the bootloader (UID, board type, i2c eeprom whitout re-reading it,...)

I also would like to not use EEPROM to store these variables.
Is there a way to get access to variables declared in the bootloader with pgm_read or something like this?

Anyone can help me?

(sorry for my french english ;D but I will have no problem to understand you ;D)

PS : maybe it's better to put this topic in the bootloader section?

Tibus:
Hello,
For my project, I created a process that create and burn a bootloader that contains variable like UID, board type,... this bootloader also read i2c eeprom from shields at the reset of the atmega.
All these variables are writed in Serial at each reboot. It allows computer to know wich board is connected, if a shield is connected,...
All this process works verry well (bootloader creation from a program, reading an i2c eeprom, write it to the Serial at 115200 baud rate,...)
The last problem is that I would like that the arduino program started after this bootloader can be retreive these variable from the bootloader (UID, board type, i2c eeprom whitout re-reading it,...)

I also would like to not use EEPROM to store these variables.
Is there a way to get access to variables declared in the bootloader with pgm_read or something like this?

Anyone can help me?

(sorry for my french english ;D but I will have no problem to understand you ;D)

PS : maybe it's better to put this topic in the bootloader section?

How are these version ID's stored? post a snippet of your bootloader code.

I would start by printing a LST of your BootLoader HEX file. You should be able to identify the memory address at which your version code is burned into the FLASH, then use
This code assumes you are using a UNO, if your are using a MEGA you will need to use the pgm_read_XXX_far variants.

#define VERSIONADDR 0x1234  // memory address for version from HEX->LST 

//if version is a zero terminated char string
uint16_t ofs=0;
do{
 char myChar =  pgm_read_byte_near(VERSIONADDR+ofs);
 if(myChar) Serial.print(myChar);
 ofs++;
 }while(myChar);

Chuck.

  1. Yes, it should be possible.
  2. Make sure the Lock bits are set appropriately; the Arduino default of 0x0F does not allow the application to read the boot section, but 0x2F will.
  3. The application will not be able to access "symbols" from the bootloader; you'll have to put the variables you want to share in "known locations" (typically using the "section" attribute and section-start linker command. See Optiboot and how it handles its "version") or by providing a function in a known location that the application code can call with some sort of intermediate value identifier ("bootloaderReadVariable(BOOTLOADER_UID);")

Ok, it's working well with a section that represent an array of functions.

These functions are some getter to return values.
When the variable to return is a constant (with a Define or dirrectly the value), it's working well but when the variable is a dynamic, the return value is not good. here is the code :

static uint16_t SHIELD_ID = 15;

#define SIKWI_TYPE 3
#define SIKWI_VERSION 2
#define SIKWI_UID 108

#define hasShield 0
#define shieldVersion 0
#define shieldAlternative 0

uint16_t functable[7] __attribute__((section(".functable"))) =
{
    (uint16_t) 12,
    (uint16_t) &__bl_SikwiType,
    (uint16_t) &__bl_SikwiVersion,
    (uint16_t) &__bl_SikwiUID,
    (uint16_t) &__bl_SikwiShieldId,
    (uint16_t) &__bl_SikwiShieldVersion,
    (uint16_t) &__bl_SikwiShieldAlternative
};

uint16_t __bl_SikwiType(){
	return SIKWI_TYPE;
}
uint8_t __bl_SikwiVersion(){
	return SIKWI_VERSION;
}
uint32_t __bl_SikwiUID(){
	return SIKWI_UID;
}
uint8_t __bl_SikwihasShield(){
	return hasShield;
}
uint16_t __bl_SikwiShieldId(){
	return SHIELD_ID;
}
uint8_t __bl_SikwiShieldVersion(){
	return 0; //shieldVersion;
}
uint8_t __bl_SikwiShieldAlternative(){
	return 0; //shieldAlternative;
}

Everything works good if I call these functions from program but if I do in the appStart function :

SHIELD_ID = 0

When I call the function "__bl_SikwiShieldId" from the program, it doesn't return 0 or even 15 but "29545"?
I think it's because the SHIELD_ID variable must be in SRAM to modify them inside the appStart (when I read the i2c eeprom by exemple) but how to do that?

Tibus:
Ok, it's working well with a section that represent an array of functions.

These functions are some getter to return values.
When the variable to return is a constant (with a Define or dirrectly the value), it's working well but when the variable is a dynamic, the return value is not good. here is the code :

When I call the function "__bl_SikwiShieldId" from the program, it doesn't return 0 or even 15 but "29545"?
I think it's because the SHIELD_ID variable must be in SRAM to modify them inside the appStart (when I read the i2c eeprom by exemple) but how to do that?

westfw:
3) The application will not be able to access "symbols" from the bootloader; you'll have to put the variables you want to share in "known locations" (typically using the "section" attribute and section-start linker command. See Optiboot and how it handles its "version") or by providing a function in a known location that the application code can call with some sort of intermediate value identifier ("bootloaderReadVariable(BOOTLOADER_UID);")

Change your bootloader code to what @westfw suggested:

unsigned const int __attribute__((section(".version"))) SHIELD_ID         =15;
unsigned const int __attribute__((section(".version"))) SIKWI_TYPE       =3;
unsigned const int __attribute__((section(".version"))) SIKWI_VERSION = 2;

in your application code:

uint16_t SHIELD_ID;
uint16_t SIKWI_TYPE;
uint16_t SIKWI_VERSION;

void load_versions_consts(){
uint16_t p=0x7FFA;  // the .section(".version") places these constants at the end of FLASH
// They actually might be in reverse order?

SHIELD_ID = pgm_read_word_near(p);
p=p+2;
SIKWI_TYPE = pgm_read_word_near(p);
p=p+2;
SIKWI_VERSION = pgm_read_word_near(p);
}

chuck

Thanks for The respons but can i modify the Shield id in The appStart before running the program with this way? Because I have some i2c reading in the appStart function in the boot loader before jumping to program and I would like to modify these variable a this moment just before running the program. So how to change these .version variable in the bootloader appStart function?

when the variable is a dynamic, the return value is not good.

If you need dynamic variables from the bootloader, it's going to be MUCH more complicated, because anything dynamic will be in RAM. Normally, there is no way to tell an application to avoid taking ALL of RAM, so the app will quickly overwrite any RAM that the bootloader has used.

Yeah, I need dynamic variables because variables are set in the appStart before running the program. It's set only once per reboot but it's so dynamic...

So no way to modify a variable in the appStart and retreive it later in a getter in the .section?