Messing with PROGMEM - TABLE with differents data types (string, int, ...)

Hi all,

I actually coded a LCD menu (for KS0108 library : 128x64 pixels LCD display) with dynamic items which are stored inside a TABLE based on String data type.
The string table is like this :

String LCD_MENU_TREE [30] [5] = {
  // each entry defined as {<MENU LEVEL>, <MENU #>, <SUBMENU LEVEL>, <MENU TEXT>, <FUNCTION TO EXECUTE>}
  // MAIN MENU TEXT
  {0, 1, 1, "Main Menu", 0},
  // 1st LEVEL MENUs
  {1, 1, 11, "Status", 0},
  {1, 2, 12, "Configuration", 0},
...

Everything runs smooth except the fact that i would like to free th RAM from this TABLE.
I made some search and found that there is a function called PROGMEM which can be used thru the “pgmspace.h” library.
My problem is that when i just add PROGMEM on my string (like this “String LCD_MENU_TREE [30] [5] PROGMEM = { …”), it seems that the compiler doesn’t like it …

Like the compiler seems to be intelligent enough to store this table in RAM without bothering me, why can’t it be kind enough to do so on the same string but instead of storing it in RAM, storing it in FLASH ?

The error message i’m facing looks like this one :

...<PATH TO THE LIBRARY>\ks0108v3RC2/fonts/SystemFont5x7.h:48: error: System5x7 causes a section type conflict

Does someone already faced this kind of problem //AND//OR// can advise me of any workaround ?

Thanks !

You could use a struct instead of the String class.

AWOL:
You could use a struct instead of the String class.

Thanks for your answer !

I tried to consult the page dedicated to the STRUCT data type here : http://www.arduino.cc/playground/Code/Struct
Well … It seems that it can allow me to free some RAM by specifying the data types on my data instead of storing every values as string data type.

But, i couldn’t find any example of someone using PROGMEM and storing data inside the struct.

Could you please give me an example ?

Thanks !

http://www.arduino.cc/en/Reference/PROGMEM

I still can't get struct to work like i need ...

I'm trying to initialize a struct like this :

struct MENU_TABLE{
  byte a;
  byte b;
  byte c;
  String d;
  byte e;
  int f;
}

But then, when i want to use it on a 2D array table like this :

MENU_TABLE LCD_MENU_TREE [LCD_MENU_TREE_LENGHT] [6] = { ...

It always keeps telling me when on compile-time "error: expected initializer before 'LCD_MENU_TREE'"

I just don't get why it errors with this ?

My bad ... i forgot to add some ";" at the end of my struct "}" ...

But now, i have another question : how can i use my struct like a 2D ARRAY ? Like using it on this basis : STRUCT MY_2D_ARRAY [50] [6] { blablabla ... }

Then using it like this : "if (MY_2D_ARRAY[4][2] == something){ "do something" }"

The compiler cries a lot of errors "error: no match for 'operator=='" on my if statements ... don't know why ?!

Ok, i got it working !

I had to read a little more and understood that there is no need to delimit the lenght of values on a struct previously defined because its lenght is automatically defined by the data types defined in it.

So i had to simply replace my old MY_TABLE[x][y] by the new struct type MY_TABLE[x].y

Everything is now working, i could free 2KB of RAM which is very good !
But, as i’m perfectionist with my code, i would liek to store this table in FLASH instead of RAM.

Now i’m facing some kind of conflict problem with a FONT being part of the GLCD KS0108 V3 RC2 (systemfont5x7) which i describe in this post : http://arduino.cc/forum/index.php/topic,77405.0.html

Thanks to you guys, you lead me on the way ! BIG THANKS !

Hi

Is your solution working? I mean, ok you placed your structure array into PROGMEM, but are you able to access the member variables?

The problem is, that (to my knowledge) you can not use "->" or "." to access the member variables of objects in PROGMEM. Let me give you an example:

struct s {
 uint8_t a;
 uint8_t b;
};
struct s obj = { 22, 33 };

void setup(void)
{
  uint8_t x = obj.a;  // assigns the value 22 from member a of obj to x
}

However if obj is placed into PROGMEM, then this does not work:

struct s {
 uint8_t a;
 uint8_t b;
};
struct s obj PROGMEM = { 22, 33 };

void setup(void)
{
  uint8_t x = obj.a;  // does not work
}

Reason is, that you must use pgm_read_byte() to access data in PROGMEM area. Correct solution is:

struct s {
 uint8_t a;
 uint8_t b;
};
struct s obj PROGMEM = { 22, 33 };

void setup(void)
{
  uint8_t x = pgm_read_byte( ((char *)&obj) + offsetof(struct s, a));  // assign value 22 from PROGMEM to x
}

ok, just wrote this without testing, but with my own code in mind.

Oliver

olikraus:
you can not use “->” or “.” to access the member variables of objects in PROGMEM.

Well, you must ensure the special AVR instructions for accessing program memory are used, and they aren’t
called into play with bare → or * operators. There are lots of utility functions that understand about
PROGMEM – eg: memcpy_P().

struct s {
 uint8_t a;
 uint8_t b;
};
struct s obj[] PROGMEM = { { 22, 33 },  { 2, 43 }, { 12, 43 }, ... }

void setup(void)
{
 struct s temp_s;
  uint8_t x;

 memcpy_P((void*) &temp_s, (void *) &obj[1], sizeof(struct s)); // the one that has  { 2, 43 }
 x = temp_s.a; // 2
}

Here, I’m copying the whole struct locally, then accessing a member. This may be simpler than individually accessing struct members, if the struct is complex and you do a lot of messing with the contents. To access things individually, this approach should be okay:

x = pgm_read_byte( (void *) &(obj[1].a) );  // go straight for the one byte

…but either approach should serve.