Memory questions

Hi I have R4 Minima and the spec says:

256 kB Flash Memory
32 kB SRAM
8 kB Data Memory (EEPROM)

The flash is for my Sketch, and the SRAM is for my variables, right? What's the EEPROM for?

My variables consist of about 10 INTs and this:
bool outputArray[3000][4];

When I compile it I get:

Global variables use 15992 bytes (48%) of dynamic memory, leaving 16776 bytes for local variables. Maximum is 32768 bytes.

So, I figure I should be able to increase my array to nearly 6,000 elements, but at 5,000 I get

c:/users/xxxx/appdata/local/arduino15/packages/arduino/tools/arm-none-eabi-gcc/7-2017q4/bin/../lib/gcc/arm-none-eabi/7.2.1/../../../../arm-none-eabi/bin/ld.exe: section .stack_dummy VMA [20007b00,20007eff] overlaps section .heap VMA [20005dd0,20007dcf]
collect2.exe: error: ld returned 1 exit status

4,000 reports 19992 bytes (61%) of dynamic memory - what is going on here?

Thanks!

1 Like

try to connect to the internet, and use search field of any search engine, even on this site appliable.

1 Like

It's for any data you want to preserve if you power the Arduino off and on again. I like to use it to save High Scores on little Arduino games.

Careful though, it has a limited number of write cycles so be sure your sketch isn't writing to the EEPROM on every pass of the main loop though, or it won't take long to get there.
https://docs.arduino.cc/tutorials/uno-r4-minima/eeprom/

the EEPROM has also a limit of 100,000 write cycles per single location, therefore avoiding rewriting the same value in any location will increase the EEPROM overall life.

source:
https://docs.arduino.cc/learn/programming/eeprom-guide/

1 Like

Thanks for the info. I don't need it for this project but might come in handy some time.

1 Like

Did you figure out why the memory limit is reached faster than you would expect? I have the same problem.

Hi, no I never did, surprised there was no answer here.

... if you do not show the full code, it is unlikely that anyone will be able to reply. :roll_eyes:

Guglielmo

I suspect that it requires a deep understanding on "how it all works". I do not have that deep understanding but I found that the verify process in the IDE generates a map file and I had a look at the generated map files for respectively 4800x4 and 4900x4 bool arrays.

You can find the map files in the temp directory if you enable verbose output during compilation in the IDE. Compile your sketch, copy the output to a text editor and search for .ino.map; you will find something like below

C:\\Users\\bugge\\AppData\\Local\\arduino\\sketches\\0EA6C06691C8B2E890772E27FCB4DF85/sketch_dec14a.ino.map

You can open that file with a normal text editor.

The test sketch

#define SIZE 4900
bool outputArray[SIZE][4];

void setup()
{
  Serial.begin(115200);
}

void loop()
{
  for (uint16_t cnt1 = 0; cnt1 < SIZE; cnt1++)
  {
    for (uint16_t cnt2 = 0; cnt2 < 4; cnt2++)
    {
      outputArray[cnt1][cnt2] = digitalRead(cnt2);
    }
  }
}

It doesn't do anything useful but serves it's purpose. Below a table with the relevant data.

variable etc start address size end address
.bss.outputArray 0x20000104/0x20000104 0x4c90/0x4b00 0x20004D93/0x20004C04
.heap 0x20005c10/0x20005a80 0x2000/0x2000 0x20007C0F/20005A7F
.stack 0x20007b00/0x20007b00 0x400/0x400 not relevant

The second, third and fourth column contain the info for 4900x4 and 4800x4 respectively separated by a '/'.

As far as I can see (and I'm absolutely no specialist)

  1. The heap always uses 0x2000 bytes and the start address moves based on size of the outputArray variable.
  2. The stack is at a fixed position (start address).

Doing the calculations you can see that the end address of the heap for 4900x4 bytes ends up in the space allocated for the stack. And that's exactly what the error tells you.

I did have a quick look around to see how this can be solved be reducing the size of the heap or changing other stuff but I did not find an obvious a way.

Hi @sterretje ...
... I don't know exactly why (it probably uses a different area of memory), but adding the keyword 'static' to the array seems to solve the problem ... :roll_eyes:

#define SIZE 4900
static bool outputArray[SIZE][4];

void setup()
{
  Serial.begin(115200);
}

void loop()
{
  for (uint16_t cnt1 = 0; cnt1 < SIZE; cnt1++)
  {
    for (uint16_t cnt2 = 0; cnt2 < 4; cnt2++)
    {
      outputArray[cnt1][cnt2] = digitalRead(cnt2);
    }
  }
}
Linking everything together...
"/Users/gpb01/Desktop/Arduino Portable 1.3.1.app/Contents/Java/portable/packages/arduino/tools/arm-none-eabi-gcc/7-2017q4/bin/arm-none-eabi-g++" -Wl,--gc-sections --specs=nosys.specs -Wall -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16 -o /var/folders/q6/1r2cyccx60d9ckl35pk_nb980000gn/T/arduino_build_437474/sketch_dec14a.ino.elf -L/var/folders/q6/1r2cyccx60d9ckl35pk_nb980000gn/T/arduino_build_437474 "-L/Users/gpb01/Desktop/Arduino Portable 1.3.1.app/Contents/Java/portable/packages/arduino/hardware/renesas_uno/1.3.1/variants/UNOWIFIR4" "-T/Users/gpb01/Desktop/Arduino Portable 1.3.1.app/Contents/Java/portable/packages/arduino/hardware/renesas_uno/1.3.1/variants/UNOWIFIR4/fsp.ld" /var/folders/q6/1r2cyccx60d9ckl35pk_nb980000gn/T/arduino_build_437474/sketch/sketch_dec14a.ino.cpp.o /var/folders/q6/1r2cyccx60d9ckl35pk_nb980000gn/T/arduino_build_437474/core/tmp_gen_c_files/common_data.c.o /var/folders/q6/1r2cyccx60d9ckl35pk_nb980000gn/T/arduino_build_437474/core/tmp_gen_c_files/main.c.o /var/folders/q6/1r2cyccx60d9ckl35pk_nb980000gn/T/arduino_build_437474/core/tmp_gen_c_files/pin_data.c.o /var/folders/q6/1r2cyccx60d9ckl35pk_nb980000gn/T/arduino_build_437474/core/variant.cpp.o -Wl,--whole-archive -Wl,--start-group "/Users/gpb01/Desktop/Arduino Portable 1.3.1.app/Contents/Java/portable/packages/arduino/hardware/renesas_uno/1.3.1/variants/UNOWIFIR4/libs/libfsp.a" /var/folders/q6/1r2cyccx60d9ckl35pk_nb980000gn/T/arduino_build_437474/../arduino_cache_871070/core/core_arduino_renesas_uno_unor4wifi_ebcacfb70b526fdd84fab5a2531cbd71.a -Wl,--no-whole-archive --specs=nano.specs -lstdc++ -lsupc++ -lm -lc -lgcc -lnosys -Wl,--end-group -Wl,-Map,/var/folders/q6/1r2cyccx60d9ckl35pk_nb980000gn/T/arduino_build_437474/sketch_dec14a.ino.map
"/Users/gpb01/Desktop/Arduino Portable 1.3.1.app/Contents/Java/portable/packages/arduino/tools/arm-none-eabi-gcc/7-2017q4/bin/arm-none-eabi-objcopy" -O binary -j .text -j .data /var/folders/q6/1r2cyccx60d9ckl35pk_nb980000gn/T/arduino_build_437474/sketch_dec14a.ino.elf /var/folders/q6/1r2cyccx60d9ckl35pk_nb980000gn/T/arduino_build_437474/sketch_dec14a.ino.bin
"/Users/gpb01/Desktop/Arduino Portable 1.3.1.app/Contents/Java/portable/packages/arduino/tools/arm-none-eabi-gcc/7-2017q4/bin/arm-none-eabi-objcopy" -O ihex -j .text -j .data /var/folders/q6/1r2cyccx60d9ckl35pk_nb980000gn/T/arduino_build_437474/sketch_dec14a.ino.elf /var/folders/q6/1r2cyccx60d9ckl35pk_nb980000gn/T/arduino_build_437474/sketch_dec14a.ino.hex
"/Users/gpb01/Desktop/Arduino Portable 1.3.1.app/Contents/Java/portable/packages/arduino/tools/arm-none-eabi-gcc/7-2017q4/bin/arm-none-eabi-size" -A /var/folders/q6/1r2cyccx60d9ckl35pk_nb980000gn/T/arduino_build_437474/sketch_dec14a.ino.elf
Sketch uses 52328 bytes (19%) of program storage space. Maximum is 262144 bytes.
Global variables use 6744 bytes (20%) of dynamic memory, leaving 26024 bytes for local variables. Maximum is 32768 bytes.

Guglielmo

1 Like

@gpb01

Hmm, It seems to throw the array away in the modified code. So now we indeed need the real code to test.

Mmm ... yes ... variables use 6744 bytes (20%) ... :roll_eyes:

Compiler optimisations ...

Guglielmo

#define SIZE 4900
static bool outputArray[SIZE][4];

void setup()
{
  Serial.begin(115200);
}

void loop()
{
  for (uint16_t cnt1 = 0; cnt1 < SIZE; cnt1++)
  {
    for (uint16_t cnt2 = 0; cnt2 < 4; cnt2++)
    {
      outputArray[cnt1][cnt2] = digitalRead(cnt2);
    }
  }
  for (uint16_t cnt1 = 0; cnt1 < SIZE; cnt1++)
  {
    for (uint16_t cnt2 = 0; cnt2 < 4; cnt2++)
    {
      Serial.println(outputArray[cnt1][cnt2]);
    }
  }
}

... produces the same linker error. :frowning_face:

Guglielmo

If you really have a bunch of bool, they aren't stored efficiently. sizeof(bool) is the same as sizeof(byte): one byte, which of course has eight bits. Each bit is either on ("set") or off ("clear"), just like a bool is either true or false. So

byte b[1000];

is effectively equivalent to

bit b[1000][8];  // `bit` is not a real type

You don't have to use all eight. Built-ins like bitWrite and bitRead (implemented as macros or functions) do the extra work to use them.

#define SIZE 1000
bool outputArray[SIZE][4];
byte outputBits[SIZE];
uint16_t cnt1 = 0, cnt2 = 0;

// these two are equivalent
outputArray[cnt1][cnt2] = digitalRead(cnt2);
bitWrite(outputBits[cnt1], cnt2, digitalRead(cnt2));
// and these two
Serial.println(outputArray[cnt1][cnt2]);
Serial.println(bitRead(outputBits[cnt1], cnt2));

Of course @kenb4 , but ... that doesn't solve the problem that on an MCU with 32 KB SRAM I can't allocate a 19660 byte variable without getting a linker error :confused:... and that's what we need to understand, not how to use the 8 bits in a byte... :wink:

Guglielmo

2 Likes

So ... I have seen that, on my R4 WiFi, the limit for this #define is 4131, which is equivalent to a variable of 16524 bytes. With this value I get:

Sketch uses 52472 bytes (20%) of program storage space. Maximum is 262144 bytes.
Global variables use 23268 bytes (71%) of dynamic memory, leaving 9500 bytes for local variables. Maximum is 32768 bytes.

Beyond that you have linker error:

Linking everything together...
"/Users/gpb01/Desktop/Arduino Portable 1.3.1.app/Contents/Java/portable/packages/arduino/tools/arm-none-eabi-gcc/7-2017q4/bin/arm-none-eabi-g++" -Wl,--gc-sections --specs=nosys.specs -Wall -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16 -o /var/folders/q6/1r2cyccx60d9ckl35pk_nb980000gn/T/arduino_build_317319/sketch_dec14a.ino.elf -L/var/folders/q6/1r2cyccx60d9ckl35pk_nb980000gn/T/arduino_build_317319 "-L/Users/gpb01/Desktop/Arduino Portable 1.3.1.app/Contents/Java/portable/packages/arduino/hardware/renesas_uno/1.3.1/variants/UNOWIFIR4" "-T/Users/gpb01/Desktop/Arduino Portable 1.3.1.app/Contents/Java/portable/packages/arduino/hardware/renesas_uno/1.3.1/variants/UNOWIFIR4/fsp.ld" /var/folders/q6/1r2cyccx60d9ckl35pk_nb980000gn/T/arduino_build_317319/sketch/sketch_dec14a.ino.cpp.o /var/folders/q6/1r2cyccx60d9ckl35pk_nb980000gn/T/arduino_build_317319/core/tmp_gen_c_files/common_data.c.o /var/folders/q6/1r2cyccx60d9ckl35pk_nb980000gn/T/arduino_build_317319/core/tmp_gen_c_files/main.c.o /var/folders/q6/1r2cyccx60d9ckl35pk_nb980000gn/T/arduino_build_317319/core/tmp_gen_c_files/pin_data.c.o /var/folders/q6/1r2cyccx60d9ckl35pk_nb980000gn/T/arduino_build_317319/core/variant.cpp.o -Wl,--whole-archive -Wl,--start-group "/Users/gpb01/Desktop/Arduino Portable 1.3.1.app/Contents/Java/portable/packages/arduino/hardware/renesas_uno/1.3.1/variants/UNOWIFIR4/libs/libfsp.a" /var/folders/q6/1r2cyccx60d9ckl35pk_nb980000gn/T/arduino_build_317319/../arduino_cache_443486/core/core_arduino_renesas_uno_unor4wifi_ebcacfb70b526fdd84fab5a2531cbd71.a -Wl,--no-whole-archive --specs=nano.specs -lstdc++ -lsupc++ -lm -lc -lgcc -lnosys -Wl,--end-group -Wl,-Map,/var/folders/q6/1r2cyccx60d9ckl35pk_nb980000gn/T/arduino_build_317319/sketch_dec14a.ino.map
/Users/gpb01/Desktop/Arduino Portable 1.3.1.app/Contents/Java/portable/packages/arduino/tools/arm-none-eabi-gcc/7-2017q4/bin/../lib/gcc/arm-none-eabi/7.2.1/../../../../arm-none-eabi/bin/ld: section .stack_dummy VMA [0000000020007b00,0000000020007eff] overlaps section .heap VMA [0000000020005b08,0000000020007b07]
collect2: error: ld returned 1 exit status
exit status 1
Error compiling for board Arduino UNO R4 WiFi.

Guglielmo

I'm reasonably sure that that has to do with some additional stuff for the WiFi, even if not used.

You will have to look at the map file. With 4900x4 bytes, the heap starts at 0x20006708 and with 8k (0x2000) heap size it will go over the stack.

I tried on the MINIMA, the problem appears when the #define is 4834 and this is understandable ...

... the 'Arduino core' on the MINIMA occupies, for an empty program, 3940 bytes of SRAM, while on the WiFi is 6744 bytes ... 2804 bytes more, so, on MINIMA, you have free SRAM for 701 array elements (4 bytes each) more.

It seems that a memory occupancy greater than 23272 (71%) causes the problem ... :roll_eyes:

Guglielmo

Based on the map file with the 8K for the heap and the 1k for the stack, it brings the usable maximum down to 32k - 9k = 23k. Probably some overhead somewhere and you get at your number.

1 Like

Your array is a 2d with a second dimention of 4 so for every byte you add to the first dimention of your array it will use 4 bytes