Dunfield Development Services Inc.
APPLICATION NOTE
Home
Products
Ordering & Status
Free Download Files
Links
Notices
Contact Us

 

Dunfield Development Services Inc.
Customer Support -- Application Note #0012

MICRO-C
Initialized data variables in RAM

Applies to: [Micro-C Compiler ]
Last updated: Sunday May 04, 2003 .
Application Note Index

Back ] Next ]

PROCEDURE

In it's effort to keep things small and simple on CPU's with limited resources, some versions of Micro-C automatically assigned constant data to ROM memory. Most of the time, constant global/static data does not change and this works well, as it avoids duplicating the data in ROM (for the initial value), and RAM (for the variable location)...

There are however cases where you may wish to have a large amount of data located in RAM (so that it can be changed), but have it initialized to set values at the beginning of the program.

Some Micro-C versions/memory models will automatically do this for you, be sure to check the documentation for your particular toolset before proceeding with this application note.

If you have a version of Micro-C which automatically puts constant data into ROM, it is a fairly simple matter to define your variables to be uninitialized and placed in RAM, and to define another table of initial values to be placed in ROM, and use a single memory copy function to copy the initial values into the uninitialized variables (this is the versions which support initialized data in RAM do "behind your back").

This works because variables are always defined by the compiler in exactly the order in which they are declared in your 'C' source code, this it is possible to define two series of variables (one initialized
and one uninitialized) and keep them exactly "in sync" by making sure that each variables size exactly matches the corresponding variable in the other group.

Note that some versions of the compiler will "word align" data, by placing all word accessed values first, and then all byte accessed values. This is OK, because the compiler will perform identical rearrangement on both the initialized and uninitialized data. This will keep them "in sync", even though their physical layout in memory may not exactly match the order of declaration in the C source code.

Here is a short example 'C' source which shows how to set up initialized data in RAM from a table in ROM:
------------------------------------------------------------------------
/*
* The 'copy_start' variable marks the beginning of initialized data, this
* is an UNASSIGNED array of zero length, so that it will take up no space,
* and evaluate to a RAM address when referenced.
*/
char copy_start[0];

/*
* Actual DATA variables to be used by program.
* These are UNASSIGNED, so that the compiler will allocate them in RAM
* Note that some compilers (HC16, 8096) will re-arrange the data to be
* WORD aligned... This is OK, because the constant data will also be
* rearranged in exactly the same way.
*
* If you are creating INTERNAL DATA variables on the 8051 family, these
* declarations should include the "register" keyword.
*/
unsigned a;
char b;
unsigned c[10];

/*
* The 'copy_end' variable marks the end of the initialized data. This
* is an UNASSIGNED array so that it evaluate to a RAM address when
* referenced. NOTE that the length is 1, so that it will be an ODD
* size, and therefore get put at the end of the byte aligned segment
* if the compiler "word aligns". If you know your compiler does not
* do word alignment, then you can make this 0 length and save a byte
*/
char copy_end[1];

/*
* Initial values for variables
* These are ALL ASSIGNED, so that the compiler will allocate them in
* ROM. They values must be presented in EXACTLY the order in which the
* unassigned DATA variables occur. Also note that if the compiler word
* aligns, it will separate out the WORD/BYTE aligned data in exactly
* the same way for both unassigned and assigned data.
*/
unsigned _a = 10;
char _b = 99;
unsigned _c[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };

/*
* At the beginning of the main program, use a library function to
* copy over the initial data.
*/
main()
{
/*
* For most CPU's having only a single data space, use memcpy()
*/
memcpy(copy_start, &_a, copy_end-copy_start);

/*
* The AVR puts "constant" data in ROM/FLASH, use: memcpyc()
*/
memcpyc(copy_start, &_a, copy_end-copy_start);

/*
* If you want to initialize INTERNAL DATA variables on the 8051,
* define the DATA variables with "register", and use: _move()
*/
_move(copy_start, &_a, copy_end-copy_start);

/* ... remainder of program ... */
}

 

 

Back ] Next ]

© 2008 Dunfield Development Services Inc.     View our Privacy Statement
Refunds given at the discretion of management.
 Last Updated:  Tuesday, March 18, 2008