5

Does anybody know how to deal with the following problem:
I have an IAR Embedded workbench. The project is using the SDRAM for running it's code and Flash ROM too. The code for SDRAM is loaded from SD Card. However, in SDRAM there are also some data stored, like global or static variables. Some of them have to be initialized. The initialization step, the iar_data_init3 function call, goes after the low_level_init function. So the problem is that for initialization of some of the variables in SDRAM, the initializer function is called from iar_data_init3, the code of which is inside of the SDRAM itself. Which is wrong because the loading of SDRAM code from SD Card is not yet done.

I have tried manual initialization as described in the C/C++ development guide, but this didn't help.

The function which is called is __sti__routine, which provides initialization of variables. All of these functions are generated by IAR. Is there any way to tell the linker to put the initializer functions to Flash ROM?

EDIT 1: Here is information from IAR manual for C/C++. It is an example of how to use manual initialization.

In the linker config file:

initialize manually { section MYSECTION };

Then IAR documentation says:

you can use this source code example to initialize the section:

#pragma section = "MYSECTION"
#pragma section = "MYSECTION_init"
void DoInit()
{
char * from = __section_begin("MYSECTION_init");
char * to = __section_begin("MYSECTION");
memcpy(to, from, __section_size("MYSECTION"));
}

I can't understand however, first of all, what is the difference between MYSECTION_init and MYSECTION. Aslo, if I have a global variable:

SomeClass myclass;

And it should be placed in SDRAM, then how does the initialization is done for it? I want to manually initialize the variable, and place that initializing functions to flash ROM. (the problem is that by placing variable to SDRAM it's initializing function also is placed to SDRAM).

maximus
  • 4,201
  • 15
  • 64
  • 117

1 Answers1

5

You can specify the location of variables and functions through the use of pragma preprocessor directives. You will need to use either one of the predefined sections or define your own.

You don't mention the specific flavor of IAR you're using. The following is from the Renesas IAR Compiler Reference Guide but you should check the proper reference guide to make sure that the syntax is exactly the same and to learn what the predefined sections are.

Use the @ operator or the #pragma location directive to place groups of functions or global and static variables in named segments, without having explicit control of each object. The variables must be declared either __no_init or const. The segments can, for example, be placed in specific areas of memory, or initialized or copied in controlled ways using the segment begin and end operators. This is also useful if you want an interface between separately linked units, for example an application project and a boot loader project. Use named segments when absolute control over the placement of individual variables is not needed, or not useful.

Examples of placing functions in named segments

void f(void) @ "FUNCTIONS";

void g(void) @ "FUNCTIONS"
{
}

#pragma location="FUNCTIONS"
void h(void);

To override the default segment allocation, you can explicitly specify a memory attribute other than the default:

__code32 void f(void) @ "FUNCTIONS";

Edit

Based on your comments you should have a linker file named generic_cortex.icf that defines your memory regions. In it should be instructions somewhat similar to the following:

/* Define the addressable memory */
define memory Mem with size = 4G;

/* Define a region named SDCARD with start address 0xA0000000 and to be 256 Mbytes large */
define region SDCARD = Mem:[from 0xA0000000 size 0xFFFFFFF ];

/* Define a region named SDRAM with start address 0xB0000000 and to be 256 Mbytes large */
define region SDRAM = Mem:[from 0xB0000000 size 0xFFFFFFF ];

/* Place sections named MyCardStuff in the SDCARD region */
place in SDCARD {section MyCardStuff };

/* Place sections named MyRAMStuff in the SDRAM region */
place in SDRAM {section MyRAMStuff };

/* Override default copy initialization for named section */
initialize manually { section MyRAMStuff };

The actual names, addresses and sizes will be different but should look similar. I'm just using the full size of the first two dynamic memory areas from the datasheet. What's happening here is you are assigning names to address space for the different types of memory (i.e. your SD Card and SDRAM) so that sections named during the compile will be placed in the correct locations by the linker.

So first you must define the address space with define memory:

The maximum size of possible addressable memories

The define memory directive defines a memory space with a given size, which is the maximum possible amount of addressable memory, not necessarily physically available.

Then tell it which chips go where with define region:

Available physical memory

The define region directive defines a region in the available memories in which specific sections of application code and sections of application data can be placed.

Next the linker needs to know in what region to place the named section with place in:

Placing sections in regions

The place at and place into directives place sets of sections with similar attributes into previously defined regions.

And tell the linker you want to override part of it's initialization with initialize manually:

Initializing the application

The directives initialize and do not initialize control how the application should be started. With these directives, the application can initialize global symbols at startup, and copy pieces of code.

Finally, in your C file, tell the compiler what goes into what sections and how to initialize sections declared manually.

SomeClass myClass @ "MyCardStuff";

#pragma section = "MyCardStuff"
#pragma section = "MySDRAMStuff"
void DoInit()
{
    /* Copy your code and variables from your SD Card into SDRAM */
    char * from = __section_begin("MyCardStuff");
    char * to = __section_begin("MySDRAMStuff");
    memcpy(to, from, __section_size("MySDRAMStuff"));

    /* Initialize your variables */
    myClass.init();
}

In order to customize startup initialization among multiple different memory devices, you will need to study the IAR Development Guide for ARM very carefully. Also try turning on the --log initialization option and studying the logs and the map files to make sure you are getting what you want.

embedded.kyle
  • 10,976
  • 5
  • 37
  • 56
  • In the example above you are dealing with functions, but what if there are variables which need to be initialized at the begining, the method above will be usefuk to place variables to some place, but how about the functions that initialize those variables? I want to control where to put initializing functions. – maximus Dec 10 '12 at 01:12
  • @maximus The example I cited is specifically for functions because that's what you asked about in your question. But the same method applies to both functions and variables. Have a look at teh section entitled "Controlling data and function placement in memory" in the linked reference guide or in the reference guide that is applicable to your particular chip. – embedded.kyle Dec 10 '12 at 14:53
  • I have read the manual. And I have updated the question. Can you please refer to it again? – maximus Dec 12 '12 at 03:14
  • @maximus In that example, `MYSECTION_init` would be your SD Card and `MYSECTION` would be your SDRAM. `DoInit` copies the variables and functions that were placed in `MYSECTION_init` through the use of `pragma` into `MYSECTION`. After that is done, you can call any initialization functions or constructors. – embedded.kyle Dec 12 '12 at 13:17
  • @maximus Different architectures have different idiosyncrasies. There are different flavors of IAR for different chips and they are not all the same. If you link to the documentation you are reading or mention the board and/or chip you are using, I could be more specific. – embedded.kyle Dec 12 '12 at 13:19
  • I am using the embedded artists lpc1788 board. – maximus Dec 12 '12 at 14:46
  • I want to place the MYSECTION, which contains data, to SDRAM, but the initializing functions, which are inside the MYSECTION_init I suppose, to FLASH_ROM. Do you mean that I have to place in linker file section MYSECTION to SDRAM, and MYSECTION_init to FLASH ROM? And then call DoInit, and then call init functions? (how do I call them?) – maximus Dec 12 '12 at 14:56
  • Thank you very much! Now I understood. It seems I have to find every global variable of the certain sections in order to init them manually using described procedure.. – maximus Dec 12 '12 at 18:14
  • Little more questions, 1. initialization of class objects can not be done by calling the init like myClass.init(); What should be done to myClass to initialize it? 2. What if I have to initialize the array, which was declared as: int array[2][2] = {1,1 2,2} ? – maximus Dec 13 '12 at 01:55
  • I did as you said, but unfortunately, in my test project, the initializing is for class object is done from iar_data_init3 which calls iar_cstart_call_ctors then call_ctors and finally at sti_routine function, however the initializing functions are inside of flash rom, and the variables themselves are in sdram. I think linker just ignoring what I am telling it regarding the initializing functions. – maximus Dec 13 '12 at 05:29
  • Also the log file for initialization (--log initialization) is empty. – maximus Dec 13 '12 at 06:22
  • @maximus This discussion is getting a bit long. Let's either move this to chat or ask another question. Your choice. But let's make sure you have some info from the log to help out. `--log initialization` sends to `stdout`. That was my mistake. Add `--log_file` to specify a filename. Hopefully that will have a clue. – embedded.kyle Dec 13 '12 at 13:28
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/21085/discussion-between-maximus-and-embedded-kyle) – maximus Dec 13 '12 at 14:07