I found the following puzzle in 1.6.11 with an Uno.
If you have a single call to a function with up to about 250 bytes of local storage, the memory can be lost on the stack.
Here is a test program. fcn() is not special, just complicated enough so the compiler does not optimize it away.
#define DIM_A 128
// function with local array
void fcn() {
int a[DIM_A];
for (int i = 0; i < DIM_A; i++) {
a[i] = i;
}
int s = 0;
for (int i = 0; i < DIM_A; i++) {
s += a[i];
}
if (s < 10000) return;
Serial.println(s);
}
void setup() {
fcn();
// fcn();
Serial.begin(9600);
Serial.print(F("SP setup "));
Serial.println(SP);
Serial.print(F("RAMEND "));
Serial.println(RAMEND);
}
bool done = false;
void loop() {
if (done) return;
done = true;
Serial.print(F("SP loop "));
Serial.println(SP);
}
If you run this program the output is:
SP setup 2043
RAMEND 2303
SP loop 2043
So the stack pointer in loop() is more than 250 byte from RAMEND.
If you remove the // from the second fcn() call in setup the output is:
SP setup 2301
RAMEND 2303
SP loop 2301
So now the stack pointer in loop() is only two bytes different than RAMEND.
If you increase DIM_A to 200 with a single fcn() call you get this result.
SP setup 2301
RAMEND 2303
SP loop 2301
This must be some sort of optimization problem. It’s really ugly.
This bug is causing some programs that use SdFat to crash. rename() in SdFat has about 200 bytes of local storage.
Many Uno programs that use an SD are close to the edge with RAM so programs that were working are crashing.
pert
August 18, 2016, 9:20pm
#2
I get the same results as you from your test program with Arduino IDE 1.6.11/Arduino AVR Boards 1.6.13.
Using Arduino IDE 1.6.11, if you do Tools > Board > Boards Manager > Arduino AVR Boards > 1.6.11 > Install > Close the output changes to:
SP setup 2299
RAMEND 2303
SP loop 2299
So, as you'd expect, it's not an IDE version specific phenomenon. The avr-gcc version was updated in Arduino AVR Boards 1.6.12 from 4.8.1-arduino5 to 4.9.2-atmel3.5.3-arduino2. The same version is used in the Arduino AVR Boards 1.6.13 included with Arduino IDE 1.6.11. The new compiler version supports LTO, which they have enabled.
If you reinstall Arduino AVR Boards 1.6.13 but remove the LTO flags from platform.txt by changing:
compiler.c.flags=-c -g -Os {compiler.warning_flags} -std=gnu11 -ffunction-sections -fdata-sections -MMD -flto -fno-fat-lto-objects
compiler.c.elf.flags={compiler.warning_flags} -Os -flto -fuse-linker-plugin -Wl,--gc-sections
compiler.c.elf.cmd=avr-gcc
compiler.S.flags=-c -g -x assembler-with-cpp -flto
compiler.cpp.cmd=avr-g++
compiler.cpp.flags=-c -g -Os {compiler.warning_flags} -std=gnu++11 -fpermissive -fno-exceptions -ffunction-sections -fdata-sections -fno-threadsafe-statics -MMD -flto
to:
compiler.c.flags=-c -g -Os {compiler.warning_flags} -std=gnu11 -ffunction-sections -fdata-sections -MMD
compiler.c.elf.flags={compiler.warning_flags} -Os -Wl,--gc-sections
compiler.c.elf.cmd=avr-gcc
compiler.S.flags=-c -g -x assembler-with-cpp
compiler.cpp.cmd=avr-g++
compiler.cpp.flags=-c -g -Os {compiler.warning_flags} -std=gnu++11 -fpermissive -fno-exceptions -ffunction-sections -fdata-sections -fno-threadsafe-statics -MMD
You get the same output as with Arduino AVR Boards 1.6.11:
SP setup 2299
RAMEND 2303
SP loop 2299
So that tells me the difference is caused, not by the new compiler version, but the LTO.
I suspected something like LTO.
I just used exactly the setup that was giving a user trouble.
It's hard pin down because if you comment out some code to isolate the problem, some other function that had multiple calls pops up when there is only one call to it.
The linker has smashed main , setup , and loop into one function. The array is not purged when loop is called because it is still essentially in scope.