I am running up against the size limit of 30720 byte code size limitation on the AVR328. I've made an attempt to keep the code size as small as possible (using 8 byte integers where appropriate, moving common code to functions). I'm posting my code here in case I've missed anything.
I never tried that train of words that is static const bla bla bla, I always use defines, so I know that I'm not using extra ram, and to put something in ram it would need to be located in flash as well, so maybe it does, maybe the gcc is smarter than I think.
Graynomad:
I've always used #defines partly because I was certain they didn't use any memory and we had a discussion about this a while back.
Anyway I thought I'd do a quick test
//const int x = 9600;
#define x 9600
void setup() {
Serial.begin(x);
}
void loop() {
}
This produces exactly the same code size either way.______
Rob
Yes, same code size, but less memory in RAM.
Think about it, for the GCC to decrease the size in code you'd have to skip instructions. Defining a const variable or a define doesn't make the Serial.begin() instruction go away, does it? And that's what is taking up space in the code memory.
How big is your font table? You might be able to save some space by going to all upper case and deleting some symbols, but if it's a reasonable implementation that ought to be only about 5 bytes per glyph...
PS: upgrade to a recent version of optiboot and gain back an additional 1.5k of code memory.
Yes the vast majority of that size is library and setup code, but if an extra variable was being created I would expect a difference of 1 or 2. Remember we are looking at the difference between #define and const, the existence or otherwise of Serial shouldn't matter.
AFAIK the value reported by the IDE shows the text + data sections so any normal constants that get created (say a string) will go into the data section and show in the total.
This code
const int x = 9600;
//#define x 9600
int y = 12;
void setup() {
Serial.begin(x);
//pinMode (y, OUTPUT);
}
void loop() {
}
Produces
text data bss dec hex filename
1844 18 160 2022 7e6 output/test.elf
Regardless of whether #define or const is used.
"Serial.begin (9600)" produces the same values as well, so I think it's fair to say that no matter what method you employ the memory used (of any kind) is the same. Whether or not something is created in RAM or flash cannot be determined from this, but the two methods are the same. (Note that "y" has been optimized out.)
If I uncomment the pinMode() line we get
text data bss dec hex filename
2020 20 160 2200 898 output/test.elf
Text has increased as expected because we've brought in another library function, but data has risen by 2, ie the size of the int y.
Therefore I submit that "#define", "const" and a literal number all create nothing in RAM (and presumably all create 2 bytes in flash as part of an LDI instruction somewhere) and are essentially the same in this respect.
I may be wrong, but I think the define is a compiler directive and not something that gets passed on to the microcontroller... that being said, if you #define something, when you compile, the compiler changes the #define'd for the value used by us. In other words, a define exists merely to allow us to give meaning to values in code. Using const int, would create an actual variable. I know that in the end, it doesn't matter, because both work... but that's what I learned.
One thing that may be happening is the compiler optimization settings equaling a define and a const int to the same. This is after all a memory constrained device and I don't know what optimization options the microcontroller allows or is set to.
Here's a few more discussions on the subject that point out some differences:
The reason why the Serial.begin(9600) takes up the same space is because it still needs to load a value (this time from Flash) into memory to pass it on to the register.
But either of them won't solve your memory program shortage. It would be nice though, to create a tutorial or a sticky post explaining this in the forum...
I may be wrong, but I think the define is a compiler directive and not something that gets passed on to the microcontroller...
Pretty much, actually it's a preprocessor thing, it doesn't even get to the compiler.
Using const int, would create an actual variable.
It seems that's not the case.
I confess I put forward almost the same argument as you did not that long ago, I can only assume that the compiler (or optimizer) is clever enough to realize what's going on and it inserts a literal. So effectively the #define and const do the same thing, just in different places.
I'd feel better if they were "static const int xxx = a;"
Without the "static", the compiler will (probably) produce variables as well as use constants, and it is only in the link phase that anything discovers that no other modules access the variables and they therefore can be "garbage collected."
You should be able to see the difference by disassembling the .o files as well as the .elf files.
const int x = 9600;
int *ptr;
//#define x 9600
void setup() {
ptr = &x;
Serial.begin(*ptr);
}
void loop() {
}
What I'm trying to prove is that this will create the actual "const int" variable. Of course that the code will be bigger, but the memory footprint will include the const int variable because now there is pointer to it. (Yes, I'm assuming the compiler is not that smart)
Just looks like a very long program to me, around 2,000 lines.
I had a program (several files compared with your one file), that grew to 2,700 lines and took 27K FLASH. It had lots of strings for LCD but I bet the difference between mine and your program is includes. I didn't have that many includes.
Two suggestions I can think off:
USE a 24LC512 EEPROM to store your English letters. Hope this won't slow you down too much. You'll have to try.
See if you're overloading any functions. Try not to overload. Say you have a constructor chips(int) and another one chips(long). If you used both, just because you didn't bother to convert long into int, the compiler stores both constructors in FLASH.
This can get significant with Serial.print(). Say you're already using the awesome sprintf, you should NOT use serial.print(int or float or long), only use serial.print(string). Use sprintf to construct a string and print with serial.print(string). Try serial.print(string) and serial.print(float) in one program and get rid of serial.print(float)
USE a 24LC512 EEPROM to store your English letters. Hope this won't slow you down too much. You'll have to try.
I don't see what you mean by English letters... do you mean strings?
Another possibility is to have commands (a couple of bytes) sent to the PC instead of a describing string. And multiply your floating points to 10 or 100 (depending on the size) and use those on the communication to the PC instead of floating point.
liudr:
2) See if you're overloading any functions. Try not to overload. Say you have a constructor chips(int) and another one chips(long). If you used both, just because you didn't bother to convert long into int, the compiler stores both constructors in FLASH.
What's english.h? It's not in your code. I suppose if it's a bunch of letter matrix for your persistent (?) display, you will need these matrix letters.
Thank you everyone for looking over the code. I can verify that replacing all of the
const uint8_t bla = xx;
with
#define bla xx
retained the exact code size.
@westwf The font is pretty large, 8 bytes / char. Most symbols use only 7x7 pixels so I could save 128 bytes there. I had a quick look at the optiboot. Looks like the way to go.