SAM3S4C: global variables initialized to 0

Discussion around product based on ARM Cortex M3 core.

Moderators: nferre, ncollot

entik
Posts: 17
Joined: Tue Mar 13, 2012 5:19 pm

SAM3S4C: global variables initialized to 0

Thu Jan 26, 2017 10:22 am

Hi all,
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)
  }
}
Bootloader is loaded to the chip using JTAG, then it writes fw itself (fw image is received from USART).
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"
};
The situation when the variables are not initialized is right after the firmware image is written and a jump is made to start its execution. Since the global variables are not initialized and contain zeroes, the first call of any globally initialized function ptr causes Hard Fault. The code execution in this case should be following

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();
}
The Reset Handler of the firmware program is generic

Code: Select all

; Reset Handler
Reset_Handler   PROC
                EXPORT  Reset_Handler             [WEAK]
                IMPORT  __main
                LDR     R0, =__main
                BX      R0
                ENDP
I do not understand why the initialization of the variables is fine in the second case and fails in the first one. The control is passed to the fw image the very same way in both cases.

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

Return to “SAM3 Cortex-M3 MCU”

Who is online

Users browsing this forum: No registered users and 1 guest