In the snippet below the variable customchr_qty used to be the condition in the for loop. Reasoning that the variable is just a stand-in for the result of the calculation I substituted the calculation directly in the for and it works as expected. Now, is this considered good practice or not? I figure it saves a byte of RAM so that's good.
//byte customchr_qty = sizeof (theChrdata) / sizeof (customChrdef);
void setup() {
Serial.begin(9600); // for debug only
lcd.begin(16, 2);// open comms. with 1602 display unit
/*
Initialize custom graphic characters for LCD from PROGMEM
*/
uint8_t * ccpoint;
ccpoint = lcdbuffer;
for (byte i = 0; i < sizeof (theChrdata) / sizeof (customChrdef); i++) {
memcpy_P (&lcdbuffer, &theChrdata[i], sizeof (customChrdef));// this works, as proven by k loop below
lcd.createChar(i, ccpoint);
}
Note that the compiler doesn't need to put 'const' values in RAM. It knows the value at compile time so it can just inserts the value into the code as immediate data. The should be smaller and faster than fetching the variable into a register and using the register.
This is the style I would have used.
const byte BytesPerCustomCharacter = 8;
const byte CustomChraracterData[][BytesPerCustomCharacter] PROGMEM = {
// Data Here!
};
const byte CustomChraracterCount = sizeof CustomChraracterData / BytesPerCustomCharacter;
void setup() {
byte buf[BytesPerCustomCharacter];
Serial.begin(9600); // for debug only
lcd.begin(16, 2);// open comms. with 1602 display unit
// Initialize custom graphic characters for LCD from PROGMEM
for (byte i = 0; i < CustomChraracterCount; i++) {
memcpy_P (buf, &CustomChraracterData[i], BytesPerCustomCharacter);
lcd.createChar(i, buf);
}
Using a ‘local’ temporary variable this way is no big deal.
The memory used by the value will go out of scope at the end of the function, and be available/re-used elsewhere.
So many possibilities! It's like taking an eight ounce glass to Niagara Falls for a drink. After testing several suggestions and getting the same number for RAM usage it appears it all comes down to personal preference.
it’s also worth mentioning this is the reason even though the compiler/linker shows - say 80% memory utilisation, that number doesn’t account for transient use of memory by passed values, heap and stack usage.
it’s very common that even 10% free ‘memory’ is not enough. It all depends on how you toss the memory around within your code. e.g. globals and statics are convenient, but use permanent memory allocation.
If your sketch crashes or behaves oddly... apart from coding bugs, go looking for RAM optimisation to get that utilisation down as much as practical.