How to define variables that share the same ram area in avr studio 7?

46 views Asked by At

I need to host a 500 byte array momentarily for a block of a large program that consists of several blocks but I don't have enough ram so I want to share an area of ram between two blocks of the program. Obviously the execution of both blocks is exclusive.

The program written in C will run on atmega16 and written in avr studio 7.

How can I define the variables of each block so that the compiler assigns them the same ram area without generating an error?

Thank you.

I tried to define my own segment but that doesn't mean they share the same ram area.

2

There are 2 answers

0
dvd280 On

By declaring the array inside a function, it tells the C compiler that the array will no longer be needed once returning from the function (so it will be stack allocated almost always, and the memory will be automatically freed once the function returned). Otherwise, the array might be statically allocated, which reserves the memory for the entire runtime.

If the array is already declared inside a function, there probably is no way to do what you want, since there is no space to store the rest of your program data for a temporary period, and trying to "trick" the compiler will only introduce potentially fatal bugs and undefined behavior.

You could always try to refactor your code so that the array's life is contained as early as possible in the call stack. Meaning that instead of creating the array after 10 function calls (without returning) you can try to create it , use it and then proceed to the rest of the calls, but this is an approach which requires some understanding of how C compilers work.

0
emacs drives me nuts On

There are many different solutions, each with its ups and downs detailed out below. For the matter of discussion, I'll assume you have two modules with headers like module1.h which typedefs module1_t, and similar for module2.h.

Approach RAM Region Complies to
Standard
Costs extra Code
for (De)Allocation
Costs
extra RAM
Must know Size
at Compile Time
A.   Local vars Stack Yes Yes (a bit) No No
B.   Union Static Storage Yes No No Yes
C.   use __heap_start No No No No
D.   malloc Heap Yes Yes Yes No
E.   COMMON Static Storage Legacy C No No Yes

A. Use local Objects

Just use local objects in respective functions like in:

#include "module1.h"

void run_module1 (void)
{
    // Enter / init module1.
    module1_t module1;

    // Execute module1.
    for (bool looping = true; looping; )
    {
        // Execute code of module1 until
        // I/O terminates its execution.
    }
    // Leave module1.
}

B. Union holding required Components

The following solution uses a union:

#include "module1.h"
#include "module2.h"

typedef union
{
    module1_t module1;
    module2_t module2;
} modules_t;

extern modules_t modules;

// Use modules.module1 in module1.c

and then use modules.module1 in module 1 etc. You have to pick a module that defines the modules object, e.g. modules_t modules; in module1.c, but not in module2.c.

The drawback of this method is that you have to expose everything needed to define the module*_t objects, which might be quite annoying when you have many modules that participate in that "coalescing".

Advantage is that no code is needed to allocate or free the data as it lives in static storage.

C. Locate the Objects by Hand in the Heap Region

The following solution uses the fact that the default avr-gcc linker script defines a symbol __heap_start which immediately follows the memory region used for static storage:

#include "module1.h"

extern module1_t module1 __asm("__heap_start");

// Use module1
// Similar code in module2 etc.

The value of the symbol points one past the last location of objects in static storage (stuff in .data, .bss, .noinit). The is no need to define objects in C/C++ code

You can have at most one group of objects "allocated" that way.

The memory starting at __heap_start is supposed used by malloc, hence this solution won't work together with malloc, which is the case for almost all AVR applicatons.

Upside is that no code is needed to allocate or free the object(s) because they all live in static storage. Moreover, there is no need to expose all of moduleN.h; all can be done in moduleN.c.

Downside is that it's avr-gcc specific and not covered by the standard (assembly names by means of asm is a GCC extension, and __heap_start is specific to GNU tools for AVR). Moreover, this bypasses tools that show memory consumption of static storage like avr-size.

D. malloc and free

I am mentioning this one for completeness only. In AVR programs you would always avoid malloc if possible (Which is the case here). It consumes code and also RAM for administration. Memory fragmentation is no issue, though, because at most one object is allocated at a time (assuming rest of the code avoids malloc).

E. Common Section

Also just for completeness:

Some binary formats (aout?) support common symbols for tentative declarations in C. In each module, declare

module1_t module;

i.e. use the same name across modules and no initializer. This requires the use of option -fcommon. GCC changed the default from -fcommon to -fno-common some time ago. This might lead to hick-ups with LTO or linters.