What I am trying to do is define an array of strings but with a minimum memory footprint.
What I need is a list of color names which matches a color RGB value. I know I can get it to work by defining two arrays, one with color names and one matching one with color values like:
Than if someone asks for a color (on a webpage) I can look it up in the colorNames array and take the matching index of colorValues. But if I have more colors (which I plan to do) I am afraid it will eat into my memory to much.
What I am looking for is a suggestion on how to get this working.
Use char arrays in flash. There is lots of info about PROGMEM on this forum, and the learning section.
Then almost all of the RAM is freed.
In RAM a String has a small overhead for each string (length, buffer length, pointer to data).
Strings can be handy, but are not a great choice when you are trying to keep a "minimum memory footprint".
A String is useful for text that needs to change, definitely not static stuff.
Hint: Color values like "255000000" should be stored as an integer (3/4 bytes vs 10 chars).
Thanks for the tips so far. I am trying to code using PROGMEM and after some unsuccessful attempts I tried just copying the sample code:
/*
PROGMEM string demo
How to store a table of strings in program memory (flash),
and retrieve them.
Information summarized from:
http://www.nongnu.org/avr-libc/user-manual/pgmspace.html
Setting up a table (array) of strings in program memory is slightly complicated, but
here is a good template to follow.
Setting up the strings is a two-step process. First define the strings.
*/
#include <pgmspace.h>
const char string_0[] PROGMEM = "String 0"; // "String 0" etc are strings to store - change to suit.
const char string_1[] PROGMEM = "String 1";
const char string_2[] PROGMEM = "String 2";
const char string_3[] PROGMEM = "String 3";
const char string_4[] PROGMEM = "String 4";
const char string_5[] PROGMEM = "String 5";
// Then set up a table to refer to your strings.
const char* const string_table[] PROGMEM = {string_0, string_1, string_2, string_3, string_4, string_5};
char buffer[30]; // make sure this is large enough for the largest string it must hold
void setup()
{
Serial.begin(9600);
while(!Serial);
Serial.println("OK");
}
void loop()
{
/* Using the string table in program memory requires the use of special functions to retrieve the data.
The strcpy_P function copies a string from program space to a string in RAM ("buffer").
Make sure your receiving string in RAM is large enough to hold whatever
you are retrieving from program space. */
for (int i = 0; i < 6; i++)
{
strcpy_P(buffer, (char*)pgm_read_word(&(string_table[i]))); // Necessary casts and dereferencing, just copy.
Serial.println(buffer);
delay( 500 );
}
}
Unfortunately all it does is give me an exception (28) and a reboot. I did not mention I am programming this on an ESP8266 because I hoped/thought it did not matter. Looks like it does.
The ESP core does have PROGMEM like functionality added to it. People are using my PGMWrap library fine on an ESP.
I think your issue is related to pointer sizes on an ESP.
You are using pgm_read_word() for a two byte pointer (which is correct in AVR), but an ESP has a 32 bit/4byte pointer. Your pointer accesses may need to use pgm_read_dword(), but its would be even safer to use pgm_read_ptr()
PaulMurrayCbr:
Not related to storage, but if you have two corresponding arrays then it can make sense to store them as structs.
I'm not 100% sure about how to get everything in progmem, but without that factor, it's like:
char *name will need to be an array otherwise the string will still reside in RAM, only its pointer is copied to flash. This is similar to storing a String in PROGMEM, the actual string data is located elsewhere.
For common length text this is perfect, however if one option is 100 chars, and the rest 3 or 4 then there can be a bit of waste (bit flash has always been less precious to me anyway).
Another option which was popular in Windows programming years ago was multistrings. A single PROGMEM array could hold all strings (each typically separated by null and the array terminated with a double null). Then the struct pointers can simply reference the start of the string.
As far as I know (AVR anyway) F() does not work on global declarations, it needs to be used within a function.