I have a bootloader-fw setup on SAM3S4C. It is working fine except a certain conditions, then the global variables of the fw part are not initialized (are zeroed instead), like if the __main() was not called.
Bootloader occupies the first 16kB of the flash, fw the rest. The scatter files for both bootloader and fw are Keil-generated, from the memory layout dialog
Code: Select all
LR_IROM1 0x00404000 0x0003C000 { ; load region size_region
ER_IROM1 0x00404000 0x0003C000 { ; load address = execution address
*.o (RESET, +First)
*(InRoot$$Sections)
.ANY (+RO)
}
RW_IRAM1 0x20000000 0x0000C000 { ; RW data
.ANY (+RW +ZI)
}
}
LR_IROM1 0x00400000 0x00004000 { ; load region size_region
ER_IROM1 0x00400000 0x00004000 { ; load address = execution address
*.o (RESET, +First)
*(InRoot$$Sections)
.ANY (+RO)
}
RW_IRAM1 0x20000000 0x0000C000 { ; RW data
.ANY (+RW +ZI)
}
}
There is whole bunch of global variables, I am pasting just an example
Code: Select all
char* pLightColors[] =
{
"Not Set",
"Warm White",
"Cool White",
"Red",
"Green",
"Blue"
};
power on - run bootloader - write fw image to flash - jump to fw main - run fw main
When I turn the device off and on again using the main power button, not programming anything, just executing the previously written fw image, everything suddenly works fine, the variables are initialized as they should be. The code execution in this case should be following
power on - run bootloader - jump to fw main - run fw main
The same jump to main function is used to pass the code execution to the fw. It is the following code
Code: Select all
#define MAIN_ADDRESS 0x00404000
void _jumpToMain(void)
{
register func main_entry;
int stackPointerAddress = MAIN_ADDRESS;
int resetPointerAddress = MAIN_ADDRESS + 4;
//zakazu interrupty, smazu pending
//program si to musi povolit
NVIC_DisableAllIRQ();
NVIC->ICPR[0] = 0xFFFFFFFF;
NVIC->ICPR[1] = 0xFFFFFFFF;
__disable_irq();
// Set stack pointer with the first word of the run mode program
// just for remainder: Vector table's first entry is the stack pointer value
__set_MSP((*(int*)stackPointerAddress));
//vector table offset
*(int volatile*)0xE000ED08 = MAIN_ADDRESS;
// Set the program counter to the application start address
// just for remainder: Vector table's second entry is the system reset value
main_entry = * ((func *)resetPointerAddress);
main_entry();
}
Code: Select all
; Reset Handler
Reset_Handler PROC
EXPORT Reset_Handler [WEAK]
IMPORT __main
LDR R0, =__main
BX R0
ENDP
To make it even more peculiar, total code size (?probably?) of the fw does somehow influence the variables initialization too. The compiled code size of the project is 17816 bytes. With this size, variables are not initialized. But when I remove some code to reach 17788 bytes (dummy code I added for testing purposes), initialization works just fine, even right after the fw upload. I was not able to trace any location dependency, I have tried to place/remove extra code to several different code units/objects, but it appears the only thing that matters is the total code size. But I am no expert at this, someone might see something from the .map files - I can post them here if requested.
Simple TotalCommander compare of the .map files shows just expected shift of the location of the influenced code.
I have double checked the image write procedure and it does write the full image to the flash. I also checked the image itself and the static data which should be copied to the global variables are present there as well.
I would be grateful for any comments. I know there is a workaround, to initialize the variables myself from the code, but I would like to understand the problem, not just to make the code work.
Thanks
Petr