How to prevent automatic initialization of variables?

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

How to prevent automatic initialization of variables?

3,927 Views
stanschultz
Contributor I

I'm using MRAM for non-volatile storage. I define a section and locate it in MRAM.  I place c variables in that section. I would like to prevent the automatic initialization of these variables.  I there a way to do that?

0 Kudos
11 Replies

1,484 Views
stanschultz
Contributor I

It turns out my code, linker file, etc. was correct and there really wan't any automatic initialization of the variables in MRAM.  I found out (with Freescale's help) that MRAM should be located in a non-cacheable page (i.e. 0xa0000000).  When I did this everything worked as expected.  I originally had MRAM located at 0x60000000 which is a cacheable page.  When my program wrote to this address the value was going into cache memory and not to the MRAM.

0 Kudos

1,484 Views
Carlos_Musich
NXP Employee
NXP Employee

Hello Stan,

MQX initialization code setup GPIOs and Flexbus for every project, you can see this in init_hw.c. After this, __copy_rom_sections_to_ram() is executed, this function copies all data from flash to RAM (or MRAM in this case) and after this it jumps to the main application.

As your flag is a variable linked in MRAM __copy_rom_sections_to_ram() is causing you to loose your data as it reloads the default value before you can read the flag status. You can avoid this by creating a new section in the linker file and placing your variable here, this way, __copy_rom_sections_to_ram() will not be aware of this variable.

Another workaround would be not to use a variable, just write to an MRAM address that you know and is not used in your application, this way you can read a known value from this address and determine if you need to initialize your data or not.

Hope this helps!

Carlos

0 Kudos

1,484 Views
stanschultz
Contributor I

Carlos,

That’s what my code does, it puts the variable initFlag in a new section labeled myNonVol. I then created the section in the link control file (see attached file).

Stan

0 Kudos

1,484 Views
carlos_neri
NXP Employee
NXP Employee

Stan,

Variable initialization process is tool chain dependent and usually is divided in 2 sections:

- BSS: variables not initialized or zero initialized. In this case, the memory is set to zeros

- Data: initialized variables.

On your toolchain startup code, you should find functions that makes the memory zero fill for BSS and the copy from Flash to RAM for Data. In the case of CW with GCC compiler, these can be found on "__arm_start.c" file.

Now, the code there will only apply to memory sections specified to store bss and data on the linker file, here an example from LCF of CW 10.4 with GCC compiler:

/* Initialized data sections goes into RAM, load LMA copy after code */

  .data : AT(___ROM_AT)

  {

    . = ALIGN(4);

    _sdata = .;        /* create a global symbol at data start */

   *(.data)           /* .data sections */

    *(.data*)          /* .data* sections */

    . = ALIGN(4);

    _edata = .;        /* define a global symbol at data end */

  } > m_data

 

  ___data_size = _edata - _sdata;

 

  /* Uninitialized data section */

  . = ALIGN(4);

  .bss :

  {

    /* This is used by the startup in order to initialize the .bss section */

    __START_BSS = .;

  PROVIDE ( __bss_start__ = __START_BSS );

    *(.bss)

    *(.bss*)

    *(COMMON)

    . = ALIGN(4);

    __END_BSS = .;

  PROVIDE ( __bss_end__ = __END_BSS );

  } > m_data

As you can see, there are two sections, .data and .bss using linker such as *(.bss) and *(.data) will make the linker to place all bss on .bss memory section and all .data on .data section. ONLY what is placed here will be take by the startup functions for zero fill and copy from flash to RAM.

If your linker file define the MRAM section to be filled by .bss or .data then you would need to manually discard those by tweaking the start up code. If your MRAM section does not request to be filled with .bss or .data then the startup code is not touching this section, which means there is no variable initialization.

Hope this helps.

Regards,

Carlos Neri

0 Kudos

1,484 Views
stanschultz
Contributor I

Thanks Carlos,

Your comments were helpful but I still haven’t come up with a solution. I’m using the Freescale toolsuite (not GCC) since I’m using MQX. I’m having a difficult time finding the routine that is equivalent to __arm_start.c. I attached my lcf file for your information.

Stan

0 Kudos

1,484 Views
thomasgrieger
Contributor III

Hi Stan,

the start-up routine used by the Freescale toolchain is located in the CodeWarrior directory (see <CW>\MCU\ARM_EABI_Support\ewl\EWL_Runtime\Runtime_ARM\Source, startup.c and ROMCopy.c). Normally your projects use the precompiled libs (ewl\lib) which are automatically included by the compiler. If you need to change to init routine you have to prevent the inclusion of the library and add the needed parts from the described CW directory.

Copying is done in ROM_copy.c using the table S_romp defined in the lcf file.

Are you sure that your variables are placed inside the MRAM section as from your lcf file it looks like only the variables placed in main_application_data will be initialized (definition of S_ROMP at end of file)?

Thomas

0 Kudos

1,484 Views
stanschultz
Contributor I

Thomas,

Thank you for your response. Yes, my variables are in the MRAM. I attached a partial listing of the map file to show you that yes there are included.

I also found the ROMCopy.c and included that file in my project. I then rebuilt my project and searched the link map file to make sure my copy was the one included. I then put breakpoints in ROMCopy and verified that nothing was being copied to MRAM. My program runs correctly but I have to explicitly initialize all my MRAM variables every run. It looks to me like something is initializing MRAM.

Stan

0 Kudos

1,484 Views
carlos_neri
NXP Employee
NXP Employee

all the variables on the map file you sent are zero initialized? or how do you expected them on the memory?

0 Kudos

1,484 Views
stanschultz
Contributor I

I have a flag variable in MRAM that indicates whether the variables have been initialized. If the flag variable is not equal to a unique fixed constant, my software calls a routine to initialize the MRAM variables and then sets the flag variable to that unique fixed constant. On subsequent resets, I expect the flag variable to still be that unique fixed constant and the rest of my MRAM variables contain the last values that were written to them.

0 Kudos

1,484 Views
carlos_neri
NXP Employee
NXP Employee

the expectation makes sense, being MRAM non-volatile, that variable shouldn't change.

I would then look for any code that does a copy on buffers on your MRAM? I'm thinking that perhaps a pointer runaway is overwriting that exact variable or the MRAM entirely?

0 Kudos

1,484 Views
stanschultz
Contributor I

Carlos,

Thank you for your suggestion.

The following is a much simpler program.  When I break at the if statement the value of initFlag and temp2 is 8.  The value of temp is INIT_VALUE and the value of temp1 is 12.  When I then break at mqx_exit, the value of initFlag is INIT_VALUE.  The other variables haven’t changed.  I then restart the program and get the exact same results.  The address of initFlag is 0x60000000.

Stan

/****************************************************************************

*

  •   This file contains MQX only stationery code.

*

****************************************************************************/

#include "main.h"

typedef volatile unsigned int VUINT32;

#define INIT_VALUE 0x5a3ca5c3

#pragma define_section myNonVol ".myNonVol" far_abs RW

#pragma section myNonVol begin

      VUINT32 initFlag;

#pragma section myNonVol end

      VUINT32 temp;

      VUINT32 temp1;

      VUINT32 temp2;

TASK_TEMPLATE_STRUCT MQX_template_list[] =

{

/*  Task number, Entry point, Stack, Pri, String, Auto? */

  {MAIN_TASK,  Main_task,  1500,  9,  "main", MQX_AUTO_START_TASK},

  {0,          0,          0,    0,  0,      0,                }

};

/TASK

void Main_task(uint_32 initial_data)
{

temp = *(VUINT32*)(0x60040000);
temp1 = *(VUINT32*)(0x60060000);
temp2 = initFlag;

if (initFlag !=INIT_VALUE)
{
  *(VUINT32*)(0x60040000) = INIT_VALUE;
  *(VUINT32*)(0x60060000) = 12;//INIT_VALUE;
  temp1 = *(VUINT32*)(0x60060000);
  initFlag = INIT_VALUE;
}
  
   _mqx_exit(0);
}

0 Kudos