What are the generally practiced methods for the optimization program memory usage?
(nb. as per Edgar's comment I emphasise that this is about using PROGMEM more efficiently.)
If you can replace code with a table whose size is ≤ the lines of code, do it.
- Instead of using a sequence of ifs, find a way to collapse the procedure into a table
- Use tables of function pointers if it makes sense
- Sometimes you can come up with a mini-language that is much more dense than AVR instructions, for example encoding robot logic into 16 commands, and then you can pack two commands per byte. This could collapse your memory usage 50-fold.
- Use functions instead of repeated code—this may sound obvious but there are often subtle ways of rewriting code (but bear in mind that function calls have overhead)
- Use hash tables rather than tables with big gaps
- Use fixed point rather than floating point (e.g. you can take a byte and interpret its value as ranging from 0.00 to 2.55, instead of using a 4-byte float)
Is there any difference in memory usage if the variable is declared globally or locally.
Let's talk about the stack.
void A() {
byte a[600];
...
}
void B() {
byte b[400];
...
}
void loop() {
byte xxx[1000];
...
}
This program will firstly use at least 1000 bytes of RAM all the time. There is no real difference compared to declaring xxx globally. But then what is critical is which function calls which.
If loop() calls A(), and then loop() calls B(), the program will not use more than 1600 at any time. However, if A() calls B(), or vice versa, the program will use 2000. To illustrate:
loop() [1000]
└──── A() [1600]
│ [1000]
└──── B() [1400]
└──── A() [1600]
└──── B() [1400]
versus
loop() [1000]
└──── A() [1600]
└──── B() [2000]
│ [1000]
└──── A() [1600]
└──── B() [2000]
Will it matter what the control statement/selection statements are (like if, switch )
Not much difference for a small number of cases. Otherwise it depends on your code. The best way is to just try both and see which is better. But:
switch
es usually use jump tables which are quite compact if you cover nearly every case in a range (0,1,2,3,4,..,100). if
s usually use a sequence of instructions, which take up more bytes and cycles than a jump table entry, but it makes more sense if you don't have a consecutive stretch of cases.
Usage of Serial monitor. Serial.print()
I don't believe that makes a lick of difference. Serial buffers are tiny (say 64 bytes, or 128 for a bigger board) and I believe they are allocated whether or not you use Serial.
Of course "literal strings like this" and char[] buffers consume memory. You can comment them out (or use #ifdef
s) when you don't need them.