use linker to reinitialize data again

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

use linker to reinitialize data again

Jump to solution
3,951 Views
fireas
Contributor I

Hello,

 

I really need your help.

I want to reinit all global initialized variables in my C-Sourcecode again after start of the S12P microcontroller (like "int example = 8").

I thought I would know how to do this, but I have lots of problems.

The only thing I need to know is the adress in ROM where the initial values are stored, right?

After I know that, I would be able to write a function to get these values again and reinitialize the variables any time I want to... thats my plan, if you have better suggestions tell me please.

 

I read the linker manual today and thought the adress of my global initialized data is representated by .copy, so the ELF name is COPY.

Problem: I always get a linker warning that there is no information about the segment COPY !?

 

My prm-file looks like:

 

PLACEMENT /* here all predefined and user segments are placed into the SEGMENTS defined above. */
      _PRESTART,              /* Used in HIWARE format: jump to _Startup at the code start */
      STARTUP,                /* startup data structures */
      ROM_VAR,                /* constant variables */
      STRINGS,                /* string literals */
      VIRTUAL_TABLE_SEGMENT,  /* C++ virtual table segment */
    //.ostext,                /* OSEK */
      NON_BANKED,             /* runtime routines which must not be banked */
      COPY                    /* copy down information: how to initialize variables */
                              /* in case you want to use ROM_4000 here as well, make sure
                                 that all files (incl. library files) are compiled with the
                                 option: -OnB=b */
                        INTO  ROM_C000/*, ROM_1400, ROM_4000*/;

      DEFAULT_ROM       INTO  PAGE_08, PAGE_09, PAGE_0A, PAGE_0B, PAGE_0C, PAGE_0C_A800, PAGE_0E                  ;

    //.stackstart,            /* eventually used for OSEK kernel awareness: Main-Stack Start */
      SSTACK,                 /* allocate stack first to avoid overwriting variables on overflow */
    //.stackend,              /* eventually used for OSEK kernel awareness: Main-Stack End */
    DEFAULT_RAM         INTO  RAM;

  //.vectors            INTO  OSVECTORS; /* OSEK */
END

 

 

What I do in the Sourcecode (like the example in the linker manual):

 

char *test;

#define __SEG_START_REF(a) __SEG_START_ ## a
#define __SEG_START_DEF(a) extern char __SEG_START_REF(a) []
__SEG_START_DEF(COPY);

 

test= (char*)__SEG_START_REF(COPY);  /* this should be the startaddress of the segment COPY! */

 

If I try to do the same with SSTACK instead of COPY, everythings ok and I DO get the begin of the stack at the address 0x2800!

 

Where's the failure???

Thanks for any hints!

fireas

Labels (1)
Tags (1)
0 Kudos
Reply
1 Solution
2,276 Views
CompilerGuru
NXP Employee
NXP Employee

I would recommend to export the Init method from start12.c and not to use the C implementation.

Having 2 implementations of the startup code just wastes memory. Also the start12.c version is optimized and the provided C version lacks to initialized zero initialized areas, that would need to be added.

 

 

About the warning, the struct has a different size depending on some macros.

In Start12.c I see:

 

> #define __NO_FLAGS_OFFSET       /* we do not need the flags field in the startup data descriptor */
> #define __NO_MAIN_OFFSET        /* we do not need the main field in the startup data descriptor */
> #define __NO_STACKOFFSET_OFFSET /* we do not need the stackOffset field in the startup data descriptor */

 

If those macros have to be consitently defined before start12.h is included as that file conditionally adds some fields. Make sure the _startupData is only defined once (keep the definition in start12.c). It is probably not the best idea to define those macros in a C file (start12.c) but I guess this was done to share the start12.h definition while allowing to define those fields per project. If you want to include start12.h from multiple files I would move those defines into a common header which then includes start12.h.

 

 

Daniel

 

 

View solution in original post

0 Kudos
Reply
13 Replies
2,276 Views
kef
Specialist I

Isn't it simplier and better to reset CPU (using COP reset or if available, illegal address access reset)? I'm not sure it is safe to reinitialize only variables.

0 Kudos
Reply
2,276 Views
fireas
Contributor I

Hi again,

 

thanks for all the posts, very good ideas! 

The following days I will try what's the best solution for me and give you a feedback next week.

 

@ kef: It's simpler, but in my case the worst I could do...

0 Kudos
Reply
2,276 Views
Lundin
Senior Contributor IV
"Isn't it simplier and better to reset CPU (using COP reset or if available, illegal address access reset)? I'm not sure it is safe to reinitialize only variables."

"It's simpler, but in my case the worst I could do..."

Why? That is how you do it no matter application. You reset the CPU. If the CPU for some reason can't be reseted, then the design is seriously flawed. Because any program can get a reset at any time: watchdog, low-power/powerloss, illegal instruction, clock failure, user reset, external reset signal, external noise etc etc.

You can't design with the assumption "my processor will never be reseted".
0 Kudos
Reply
2,276 Views
fireas
Contributor I

"Why? That is how you do it no matter application. You reset the CPU. If the CPU for some reason can't be reseted, then the design is seriously flawed. Because any program can get a reset at any time: watchdog, low-power/powerloss, illegal instruction, clock failure, user reset, external reset signal, external noise etc etc.

You can't design with the assumption "my processor will never be reseted"."

 

 

Based on my description you can't  assume that my processor will never be reseted.

It will be reseted in lots of cases (and if faults appear)!

To give you a simple example in which case variables have to be reinitialized again:

Think about various tests for example at startup. After some of them you can't ensure that the variables needed for the following application haven't been modified. So the only way to fix this is to get the values of the rom and initialize these variables again (if they are global and in different files it's not very practicable and also not safe to do this manually).

 

Further Questions or hints?

0 Kudos
Reply
2,276 Views
Lundin
Senior Contributor IV
Ok I misunderstood you :smileyhappy:

But regarding your concerns about startup problems: the safest way is to avoid static initialization entirely, and instead initalize all variables is in runtime before they are used, and not at startup. Common practice in safety-critical systems is to re-initialize the variables with ROM values continuously in the main loop of the program. This is because RAM is regarded as untrustworthy, especially after long periods of runtime.

Regarding startup tests, what are these? Hardware tests? Memory diagnostics ie CRC checks, static RAM tests and such? No matter what tests they are, it sounds like you are assuming these tests will always contain bugs... wouldn't it be better to deal with the actual culprit than build a work-around?

If you persist in the re-initialization despite all of the above, here is some simple code I found. Something I once wrote to replace the startup file in CW for HCS12:


#include "start12.h"

#pragma CODE_SEG CODE_ROM

void copyDown (void)
{
  _Copy* ptr = _startupData.toCopyDownBeg;
 
  while(ptr->size > 0)
  {
    unsigned char* dest   = ptr->dest;
    unsigned char* source = (unsigned char*)(ptr+1);
    unsigned int i;
       
    for(i=0; isize; i++)
    {
      dest[i] = source[i];
    }
     
    ((unsigned char*)ptr) = source + i;
  }
}

#pragma CODE_SEG DEFAULT
0 Kudos
Reply
2,276 Views
fireas
Contributor I

I tried all suggestions today, but the only working way is to misuse the Init() function from "start12.c" again before the application is running.

Thats not my preferred solution....

 

@ lundin: I also tried to do it like in your source-code. Something like this I also have found in the "build tools utilities manual", chapter 7 "program startup". But I have only problems:

 

Warning : C3801: Segment already used with different attributes
Warning : C4200: Other segment than in previous declaration
L1827: Symbol _startupData has different size in Start12.c.o (6 bytes) and main.c.o (12 bytes)

 

So, the struct has different bytes in the Init() function and if I use it in the main. Can someone explain whats wrong? Of course I could only use the first 6 byte (which have the same data but in another structure) but thats not the normal way, cause something seems to be wrong!?

 

Do I need other pragmas perhaps? I tried CODE_ROM and also NEAR_SEG STARTUP_DATA without improvement or other behaviour.

 

Thanks in advance

Message Edited by fireas on 2009-12-01 04:38 PM
0 Kudos
Reply
2,276 Views
Lundin
Senior Contributor IV
Warning : C3801: Segment already used with different attributes
Warning : C4200: Other segment than in previous declaration

You must use the correct #pragma CODE_SEG to place the code in (same for function declaration and function definition). If you don't care where your code ends up, don't use the #pragma at all.

L1827: Symbol _startupData has different size in Start12.c.o (6 bytes) and main.c.o (12 bytes)

This seems weird.. there should be no object allocated in that code, but apparently the linker thinks so. A wild trial & error guess is to toss in the extern keyword there and see if it shuts the linker up:

extern _Copy* ptr = _startupData.toCopyDownBeg;

Message Edited by Lundin on 2009-12-01 05:42 PM
0 Kudos
Reply
2,276 Views
fireas
Contributor I

I only use the

#pragma CODE_SEG NON_BANKED

for ISRs, of course after them

#pragma CODE_SEG DEFAULT

 

I never had these warnings until trying to reinitialize the variables. So I thought perhaps the fault has to to with this fact.

 

 

The

extern _Copy* ptr = _startupData.toCopyDownBeg;

ends with errors.

 

struct _tagStartup _startupData; is enclosed in "startup12.c", I'd like to think that this is enough and I don't have to declare this again in my main.c? I already tried to to this (also with "extern") without improvement in behaviour.

 

bedevilled.

0 Kudos
Reply
2,277 Views
CompilerGuru
NXP Employee
NXP Employee

I would recommend to export the Init method from start12.c and not to use the C implementation.

Having 2 implementations of the startup code just wastes memory. Also the start12.c version is optimized and the provided C version lacks to initialized zero initialized areas, that would need to be added.

 

 

About the warning, the struct has a different size depending on some macros.

In Start12.c I see:

 

> #define __NO_FLAGS_OFFSET       /* we do not need the flags field in the startup data descriptor */
> #define __NO_MAIN_OFFSET        /* we do not need the main field in the startup data descriptor */
> #define __NO_STACKOFFSET_OFFSET /* we do not need the stackOffset field in the startup data descriptor */

 

If those macros have to be consitently defined before start12.h is included as that file conditionally adds some fields. Make sure the _startupData is only defined once (keep the definition in start12.c). It is probably not the best idea to define those macros in a C file (start12.c) but I guess this was done to share the start12.h definition while allowing to define those fields per project. If you want to include start12.h from multiple files I would move those defines into a common header which then includes start12.h.

 

 

Daniel

 

 

0 Kudos
Reply
2,276 Views
Lundin
Senior Contributor IV
Again, my reasoning is based upon the well-recognized fact that static initialization, and particulary static "zero-out" as required by the C standard, shouldn't be relied upon. Except that it possibly leads to bugs, porting-troubles, there is also the problems with reliance on RAM values over long periods of time. It also guarantees slower startup of the system.

So to sum it up, it is best no neither use the code I posted nor the start12 files. Good programming practice is to never use initialization at all in the code, while still following the standard. This will make the code safe, fast and portable to very common (non-standard C) microcontroller applications.
Message Edited by Lundin on 2009-12-02 11:52 AM
0 Kudos
Reply
2,276 Views
fireas
Contributor I

I think to use only a part of the start12.c file is in my case the happy medium :smileywink:

 

Thanks for the busy participation!

0 Kudos
Reply
2,276 Views
stanish
NXP Employee
NXP Employee

Hello fireas,

 

You can refer to startup structure  "_startupData" in your code. It's initialized by the linker. See the "Build Tools Utilities" manual, section "Program Startup" for more information about this struct.

You have to import it form "start08.h"

 

Or you can call the startup function that inits variables "Init()" from Start08.c

In fact this function does: 

1) zero out RAM-areas where data is allocated

2) init run-time data

3) copy initialization data from ROM to RAM 

You have to change the function modifier  (remove static) to use it in your module.

 

Stanish 

 

0 Kudos
Reply
2,276 Views
ipa
Contributor III

Hi,

Take a look at the file Start12.c, there is a function inside 

static void Init(void); 

maybe this will help - this function already init your variables

at startup.

Regards,

IPA

0 Kudos
Reply