Compilierfehler -PROGMEM

Hallo,

ich habe fogendes deklariert (bzw ich versuche es):

const char CALLSTART[] PROGMEM = {"Kallib. Start"};
const char CALLEND[] PROGMEM = {"Kallib. Ende"};

const PROGMEM char* startmenu2[2] = {(char*) &CALLSTART,(char*) &CALLEND};

Leider gibt es folgenden Compilierfehler und ich komme nicht drauf, was ich da falsch gemacht habe:

[schnipp]
error: variable 'startmenu2' must be const in order to be put into read-only section by means of 'attribute((progmem))'

const PROGMEM char* startmenu2[] = {(char*) &CALLSTART,(char*) &CALLEND};

[schnipp]

Es wäre schön, wenn mir jemand auf die Sprünge hilft.

Grüßle

Harry

Warum mischt du das PROGMEM?

Syntax:
const dataType variableName[] PROGMEM = {data0, data1, data3...};

sschultewolter:
Warum mischt du das PROGMEM?

Syntax:
const dataType variableName[] PROGMEM = {data0, data1, data3...};

Ich habe im ersten Schritt (um dyn. Speicher zu sparen) folgendes gemacht:

char* startmenu[10] = {(char*) &CALLSTART,(char*) &CALLEND};

Da nimmt mir das Array selbst noch dyn. Speicher weg, also wollte/will ich das Array selbst auch in den Flash bringen ...

Grüßle

Harry

Bitte poste einmal den gesamten Sketch. Mal schreibst du startmenu2[2], das andere mal nur startmenu[xy]

HarryR:
Es wäre schön, wenn mir jemand auf die Sprünge hilft.

const char CALLSTART[] PROGMEM = "Kallib. Start";
const char CALLEND[]  PROGMEM = "Kallib. Ende";

const char*  const startmenu2[2] PROGMEM  = {CALLSTART,CALLEND};

sschultewolter:
Bitte poste einmal den gesamten Sketch. Mal schreibst du startmenu2[2], das andere mal nur startmenu[xy]

Den gesamten Sketch willst du nicht sehen :frowning:

Im Ernst, ich habe eine funktionierende Variante und die eine die der Compiler nicht will.

Zuerst wurden folgende Zeichenketten definiert :

const char CALLSTART[] PROGMEM    = {"Kallib. Start"};
const char CALLEND[]   PROGMEM    = {"Kallib. Ende"};

Hier die funktioniernde Variante:

char*       startmenu[2]      = {(char*) &CALLSTART,(char*) &CALLEND};

Hier die Variante die nicht funktioniert, natürlich mit unterschiedlichem Bezeichner :

const char* startmenu2[2] PROGMEM  = {(char*) &CALLSTART,(char*) &CALLEND};

Wohin auch immer ich das PROGMEM setze, der Compiler meckert immer:

error: variable 'startmenu2' must be const in order to be put 
into read-only section by means of '__attribute__((progmem))'

Grüßle

Harry

Interessant!
Auch das Strings Beispiel auf Arduino Playground - PROGMEM tuts nicht (mehr)

jurs:

const char CALLSTART[] PROGMEM = "Kallib. Start";

const char CALLEND[]  PROGMEM = "Kallib. Ende";

const char*  const startmenu2[2] PROGMEM  = {CALLSTART,CALLEND};

Ja, das lässt sich compilieren.

Jetzt wird es richtig schwer.

Um mir das Leben einfach zu machen habe ich mir für Variante 1 folgende function geschrieben:

char* getString(const char* str) 
{
  static char Buffer[BUFSIZE];
  strncpy_P(Buffer, (char*)str,BUFSIZE-1);
  return(Buffer);
}

Funtioniert das dann auch mit Variante 2, also das Array ist im Flash und seine Elemente (also die Pointer) ebenfalls ?

Grüßle
Harry

PS.: Sorry kann es im Moment mangels Arduino nicht testen

So wie du das geschrieben hast nicht.

Wenn Pointer im PROGMEM liegen, musst du die erst von dort lesen, dann kannst du die erst benutzen. z.B. mit

pgm_read_int_near(&array[1]);

const char* const bedeutet ein const Zeiger auf const Daten. const char* ist nur ein const Zeiger auf variable Daten.

Wenn du deine getString() Funktion so hast und gleich einen char* übergibst um den String auszulesen, was machst du dann mit dem zweiten Array? Das Array aus Strings brauchst du nur wenn du per Index auf die Strings zugreifen willst. Hier habe ich das erst letztens gezeigt:
http://forum.arduino.cc/index.php?topic=352709.msg2431938#msg2431938

Das was Whandall geschrieben hat gilt auch nur für die Variante auf der PROGMEM Seite, bzw. im Link oben (und dann ist es "word" statt "int"). Das hat mich auch erst verwirrt. So wie du das heißt reichen die einzelnen Strings im PROGMEM und die übergibst dann die Adresse eines Strings direkt an die Funktion. Da fehlt eben diese Zwischenstufe.

Es gibt übrigens auch strlcpy_P(). Da kannst du BUFSIZE als Größe übergeben und es wird maximal BUFSIZE - 1 kopiert.

Sorry. Man sollte halt immer alles testen.

Ich hatte aus der Existenz von pgm_read_float_near auf die Existenz von int geschlossen.

Es gibt auch pgm_read_ptr(), was in diesem Fall semantisch etwas aussagekräftiger wäre. Das liefert einen void*. Den muss dann aber glaube ich genauso casten.

Aber wie gesagt ist dieser Schritt sowie er es hat gar nicht unbedingt nötig, wenn er direkt die Adresse des eigentlichen Strings übergibt und diese nicht erst aus dem Flash ausliest. Also man kann direkt getString(CALSTART) machen.

Wenn er allerdings getString(&startMenu[0]) machen will, dann muss man erst mal den Zeiger aus dem Flash auslesen und danach erst an strcpy_P() übergeben.

Noch eine mögliche Variante ist es das Zeiger-Array im RAM zu lassen. Also da kein PROGMEM. Dann geht die Funktionen mit beiden Aufrufen. Das verbraucht dann 2 Byte RAM pro Zeiger.

Und noch etwas komplizierter wird es, wenn man oberhalb der 64k Grenze Sachen ablegen will,
dann muss man mit den _far Varianten der Funktionen arbeiten.

Mit dem Macro von Microcontroller.net kann man einen Pointer (long) ermitteln,
das hatte ich nur mit Bordmitteln nicht hinbekommen.

// Macro to make a pointer to an objects defined in PROGMEM above 64kB

#define FAR(var)                     \
({ uint_farptr_t tmp;                \
   __asm__ __volatile__(             \
       "ldi    %A0, lo8(%1)"  "\n\t" \
       "ldi    %B0, hi8(%1)"  "\n\t" \
       "ldi    %C0, hh8(%1)"  "\n\t" \
       : "=d" (tmp)                  \
       : "p"  (&(var)));             \
   tmp;                              \
})

Wurde hier mal von jurs gezeigt:

http://forum.arduino.cc/index.php?topic=174084.msg1294539#msg1294539

Die _PF Versionen der Funktionen (deren Fehlen er da anmeckert) gibt es übrigens in neueren Compiler-Versionen

Ich habe das mal überflogen, kann aber '>64k geht nicht ohne Aufteilung', nicht bestätigen.
Wenn man nicht aufteilt, muss man mit der Grenze aufpassen.

Aber das Testprogramm macht nicht viel, druckt nur Arrays aus, benimmt sich aber normal.