I’m guessing that the compiler is squirreling something away in a stack or heap or whatever, something to do with the analog reads ???
The steps that the compilers does from the code until the .bin are many, including optimizations.
I often use (in the directory, where the compiler puts program.elf) this command
avr-objdump --disassemble --source --line-numbers --demangle -z --section=.text --section=.data --section=.bss --section=.rodata program.elf > program.dis
to get disassembled version of compiled code to see exactly, what was compiled to what.
Also it is possible to save those disassembled versions somewhere else and later compare them to see, what was changed, when I made some change in the source.
Also here is disassembler/emulator, which I use to step through the code, to see, how it is actually executed Disassembler for ATmega2560 (Arduino Mega R3)
If that if statement was the only code using analogRead() then yes, the compiler would have to include the code for analogRead() and that would increase the program storage space used a little and maybe also a little of the dynamic memory.
But not the huge increase you saw. That must be because the compiler figured out there was a large piece of code that could be ignored, and that code also needed a large amount of dynamic memory. Like lots of strings (unless you use the F() macro).
The compiler is very clever at figuring out which parts of your code, and the Arduino Core functions and any libraries you include, can or can't actually get called, and ignores them if they can't. It's a good thing that it is clever, or only very very small sketches would fit into so little memory!
Others here may find that useful but it’s way above my head ![]()
Still you may save it for later and eventually start playing with really simple script (say Blink - like) just to see, what it does. An maybe you will soon this somehow usefull too ![]()
Or others, who will read this thread. (I read more forums, many times I find answers to my problems in old posts. Sometime in tens of years old posts :)
(I have saved lot of things over my head for later and I already used some part of it, when the right time come
)
These 2 code lines:
lcd.setCursor(0,1);
lcd.print("Are you sure you");
are repeated a large number of times in your code, with different values & strings. You could make a function like:
void lcdPrint(int r, int c, char* s) {
lcd.setCursor(r,c);
lcd.print(s);
}
and then call it like this:
lcdPrint(0,1,"Are you sure you");
that would reduce the size of your code significantly.
But you would still need to use the F() macro to save dynamic memory. Problem is, that function above won't work with "Flash Strings". But there is a way to do it. I can't remember right now. Maybe someone else can remember how to do that?
Edit: found it!
void lcdPrint(char c, char r, const __FlashStringHelper* s ) {
lcd.setCursor(r,c);
lcd.print(s);
}
then you can call it with
lcdPrint(0,1,F("Are you sure you"));
Make two functions like this
void lcdPrint(int r, int c, const __FlashStringHelper* s) {
lcd.setCursor(r,c);
lcd.print(s);
}
and compiler will chose the right one automatically based on arguments.
Note, that the s variable is of different type in those two functions, so the lcd.print will be also different functions there, carefully chosen by compiler on the same base of type of arguments.
(Yes, they also use the same trick)
Is there any advantage in using the other function you gave? It seems to make sense to use this one to reduce both program and dynamic memory, yes?
I had no idea you could use the same function name when using different parameter definitions and let the compiler choose the right one to use!
Learning, learning, every day a schoolday :D
I converted all the lcd.print strings to use your suggested:
…and the weird thing is that the dynamic memory usage no longer jumps nearly as much when using the if statement with the analog reads. So with:
if ( (analogRead(pushButtonSA) == 0) && (analogRead(pushButtonUp) == 0) && (analogRead(pushButtonDown) == 0) ) {
enterDeleteMode();
};
I get:
Sketch uses 14386 bytes (46%) of program storage space. Maximum is 30720 bytes.
Global variables use 484 bytes (23%) of dynamic memory, leaving 1564 bytes for local variables. Maximum is 2048 bytes.
If I comment out the if statement:
// if ( (analogRead(pushButtonSA) == 0) && (analogRead(pushButtonUp) == 0) && (analogRead(pushButtonDown) == 0) ) {
enterDeleteMode();
// };
I get:
Sketch uses 7454 bytes (24%) of program storage space. Maximum is 30720 bytes.
Global variables use 440 bytes (21%) of dynamic memory, leaving 1608 bytes for local variables. Maximum is 2048 bytes.
That’s a difference of only 44 bytes - nowhere near the approx 900 bytes that I mentioned in my opening post.
So thanks everyone, we got there in the end - not sure how but I’m a happy bunny ![]()
I was just about to post the same result using the F() macro, although I have not looked at the sketch in detail enough to determine why the difference.
Something else that is rather odd, commenting out the call to enterDeleteMode(); actually increased the memory usage of the original sketch. As long as you called it unconditionally, the memory usage stayed low, making it conditional on the values from analogRead() gave the possibility of it not being called and increased the memory usage.
Something that may be causing problems, there appears to be some way to reach the call to manageBlink() that does not set the value of myButton.
/home/user/Arduino/bumping_memory_limits/bumping_memory_limits.ino: In function 'exerciseSetup':
/home/user/Arduino/bumping_memory_limits/bumping_memory_limits.ino:657:20: warning: 'myButton' may be used uninitialized in this function [-Wmaybe-uninitialized]
manageBlink(myCol, 3, mySetSettingsNew.restDurn, myAction, myButton);
^
/home/user/Arduino/bumping_memory_limits/bumping_memory_limits.ino:460:7: note: 'myButton' was declared here
int myButton; // used to let manageBlink know what button was pushed, if one actually was
^
Yes, if you need to print a string that isn't or can't use F(). But if you don't use it, guess what?
Not weird. Just like I said in post 27.
Also if the compiler decides it can ignore enterDeleteMode(), it's no longer using so much dynamic memory because you are now using the F() macro to stop all those strings using up dynamic memory.
I’m trying to think of a use case for that - maybe concatination of strings or conversion to strings of an int ready for printing? Is that the intention for that first function?
Here’s the relevant part from post 27:
The thing is, in all of the code tests I carried out there was always the possibility that the enterDeleteMode() function would be used (ie if the analogReads worked out) and therefore it wasn’t the compiler leaving it out which saved the memory. I’m confused.
But I can let it pass ;)
Thanks again for your help, PaulRB ![]()
Exactly. Any string that isn't a constant.