Why does my local variable reserve global memory?

I am #define-ing a huge but constant 800-byte array of configuration commands for a doodad called an EZ-Radio. The goal is to keep this array in program memory then load it into local memory the exactly one time I need to. I absolutely do NOT want to reserve 1/3 of my 2560 bytes of memory for this array. I have tried many many things, here is how I am accessing the array right now:

#define MY_DEFINED_ARRAY {0x08, 0x04, 0x21 ... ~800 more bytes ... 0x13, 0x15, 0x1B}

uint8_t getIndex(int i) {
     uint8_t my_huge_array[] = MY_DEFINED_ARRAY; //the only place this huge array is mentioned or used
     return my_huge_array[i];
}

Despite reading everywhere that variables defined in functions will be local and not global, doing it this way still reserves 1/3 of my memory. Is it because I #define-ed the array? If that's the case, how can I access a #define-ed array without creating a global variable and reserving way too much memory?

Could it be your definition of "local"?

Which arduino are you using?

Then put it in PROGMEM. Your example code didn't do that.

What do you mean my definition of local?

I just want my variable to be "not global" because I do not need it to be a global variable and do not want to reserve 1/3 of my memory for it

Arduino Leonardo, sorry for not mentioning

Whether or not you leave the array in memory you still need to leave room for it or this function will overflow the stack and crash your code. The fact that it's only needed once doesn't do anything for letting you use that memory elsewhere.

It would be better to just put the array in progmem if it isn't changing. Then it lives in flash and never takes any of your 2K of ram.

Mega is 8kB - he has only 800 bytes. May be UNO (but that would be more the 1/3)

PROGMEM occurred to me, I could absolutely do it like that. Unfortunately I am importing the array from headers generated by another program, so redoing the headers every time i generate one to use PROGMEM would kind of suck. Also I believe that #define will cause the array to be essentially copy/pasted into the right spot of program memory, then loaded into dynamic memory when the time comes. If I'm wrong about that.... well, I know what the problem is.

No it means you always need at least 800 bytes on the stack for when you use the function but other functions not called at the same time could also require 800 bytes too.

If the platform is AVR - the reason is due to the way the compiler places data in RAM and not flash unless told so (would happen too for const char* text) contrary to an ESP32 for example. This has to do with the Harvard architecture.

So +1 on the idea of using PROGMEM if it’s an AVR based arduino.

It’s copy/paste at compile time in the source code

The way the compiler handled variable initialization means it needs to have the data somewhere in memory to copy it over to the stack…

You could do something like placing the array in Flash memory and access it directly:

#define MY_DEFINED_ARRAY {0x08, 0x04, 0x21, ... , 0x13, 0x15, 0x1B}

const uint8_t my_huge_array[] PROGMEM = MY_DEFINED_ARRAY;

uint8_t getIndex(int i) {
    return pgm_read_byte(&my_huge_array[i]);
}
1 Like

Still the question about which arduino this is

This makes sense. I was mistaken in believing that the #define would cause "my_huge_array[] = {0x08, 0x04, 0x21 ... ~800 more bytes ... 0x13, 0x15, 0x1B}" to be stored in program memory. It seems like that was wishful thinking. I'm now doing it like this:

#define MY_DEFINED_ARRAY {0x08, 0x04, 0x21 ... ~800 more bytes ... 0x13, 0x15, 0x1B}
const uint8_t my_huge_array[] PROGMEM = MY_DEFINED_ARRAY;

uint8_t getIndex(int i) {
     return pgm_read_byte(my_huge_array + i);
}

This works perfectly and does not permanently reserve 1/3 of my dynamic memory for no reason.

1 Like

#define is a macro.

When you compile your code it literally just copies the line of text after the define into your code

#define MY_INT 5

int newInt = MY_INT;

Will output the exact same code as

Int newInt = 5;

So the following will output the exact same thing code wise (without the define)

const uint8_t my_huge_array[] PROGMEM = {0x08, 0x04, 0x21 ... ~800 more bytes ... 0x13, 0x15, 0x1B}

1 Like

Well, since you already marked this as "resolved". I just want to point out a beautiful and powerful feature of C family programming languages.
It's called "Pointer". Tadah!

They make an inexpensive part called FRAM which is Nov-volatile that is driven by I2C, works the same as EEPROM but does not have the life or speed problems. They can be gotten in I2C or SPI, 32Kx8 is just a few $$$