This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

global variables initialized to 0 instead of declared values

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

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 is received from USART).

There is whole bunch of global variables, I am pasting just an example

typedef uint8_t (*TGetCurrentPower)(uint8_t);
typedef void (*TGetItemName)(uint8_t,char*);

typedef struct TDataLogItem
{
        uint16_t mActSecOn;
        uint32_t mActPowerSecs;
        uint8_t mCbkParam;
        TGetCurrentPower fPower;
        TGetItemName fGetName;
} TDataLogItem;

TDataLogItem mDataLogger[8] =
{
        {0,0,0,&GetLightIntensity,&GetLightName},
        {0,0,1,&GetLightIntensity,&GetLightName},
        {0,0,2,&GetLightIntensity,&GetLightName},
        {0,0,3,&GetLightIntensity,&GetLightName},
        {0,0,4,&GetLightIntensity,&GetLightName},
        {0,0,5,&GetLightIntensity,&GetLightName},
        {0,0,6,&GetLightIntensity,&GetLightName},
        {0,0,7,&GetLightIntensity,&GetLightName},
};

The situation when the variables are not initialized is right after the firmware program 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 the function ptr above causes Hard Fault. The code execution in this case should be following

power on - run bootloader - write fw code 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, everything suddenly work 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

#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

; 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 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 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 send good one and bad one to email if necessary.
Simple TotalCommander compare of the .map files shows just expected shift of the location of the influenced code.

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