www.mikrocontroller.net

Forum: Compiler & IDEs avr-gcc, C++ und PROGMEM


Autor: Fabian G. (kjion) Benutzerseite
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

ich habe ein Problem mit C++ und PROGMEM:
#include <avr/pgmspace.h>

const char bar[] PROGMEM = "Blub";  // Flash

const prog_char bar2[] = "Bla";    // RAM

typedef char PROGMEM test_char_t;
const test_char_t bar3[] = "Hello World";  // RAM

const test_char_t PROGMEM bar4[] = "Hallo Welt";  // Flash

Compiliert man das Ganze als C-Code werden sämtliche Strings wie 
erwartet im Flash abgelegt, als C++ Code hingegen nur die markierten. 
Zudem gibt es dabei für bar und bar4 folgende Warnung:
warning: only initialized variables can be placed into program memory area

Ein Blick ins Listing zeigt auch das nur bar und bar4 in .progmem.data 
verschoben wurden, bar2 und 3 liegen noch in .data
  71                 .LBE2:
  72                 .LFE2:
  74                   .section  .progmem.data,"a",@progbits
  77                 _ZL3bar:
  78 0000 426C 7562     .string  "Blub"
  78      00
  79                   .data
  82                 _ZL4bar2:
  83 0000 426C 6100     .string  "Bla"
  86                 _ZL4bar3:
  87 0004 4865 6C6C     .string  "Hello World"
  87      6F20 576F 
  87      726C 6400 
  88                   .section  .progmem.data
  91                 _ZL4bar4:
  92 0005 4861 6C6C     .string  "Hallo Welt"
  92      6F20 5765 
  92      6C74 00

Hat jemand eine Idee was genau dort falsch läuft bzw. wo man ansetzen 
muss um das zu beheben?

Getestet ist das mit einem GCC 4.3.3 unter Ubuntu aus dem Build-Script 
von avrfreaks.net. Im Anhang ist das vollständige Test-Projekt.

Grüße
Fabian

Autor: A. N. (netbandit)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ja der C++ Compiler hat da wohl einen Bug. Ich mache das so und dann 
kommen keine Warnungen und das ganze landet auch im Progmem:

In der Header Datei:
extern PROGMEM const char sEthernetLink1[];

In der CPP datei:
const char sEthernetLink1[] = "Ethernet-link was detected:\n";

Die Lösung dafür stand irgendwo mal bei den Freaks.

Autor: Johann L. (gjlayde) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Fabian G. schrieb:
> Hallo,
>
> ich habe ein Problem mit C++ und PROGMEM:
>
>
#include <avr/pgmspace.h>
> 
> const char bar[] PROGMEM = "Blub";  // Flash
> 
> const prog_char bar2[] = "Bla";    // RAM
> 
> typedef char PROGMEM test_char_t;
> const test_char_t bar3[] = "Hello World";  // RAM
> 
> const test_char_t PROGMEM bar4[] = "Hallo Welt";  // Flash
>
> Compiliert man das Ganze als C-Code werden sämtliche Strings wie
> erwartet im Flash abgelegt, als C++ Code hingegen nur die markierten.
> Zudem gibt es dabei für bar und bar4 folgende Warnung:
>
>
warning: only initialized variables can be placed into program memory
> area

> Hat jemand eine Idee was genau dort falsch läuft bzw. wo man ansetzen
> muss um das zu beheben?

Es werden in
  ./gcc/config/avr/avr.c:avr_handle_progmem_attribute()
ein paar Fälle nicht behandelt. Von dort kommt auch die Warnung.
   http://gcc.gnu.org/viewcvs/trunk/gcc/config/avr/av...

Was das DECL_EXTERNAL da soll seh ich jetzt auch nicht...

Lösung:
avr-gcc debuggen und rausfinden, wie der tree genau aussieht. Den Fall 
behandlen, ein Patch machen und in einer passenden gcc- oder 
avr-libc-Maillingliste posten.

Johann

Autor: Fabian G. (kjion) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@A. N.
In der Tat, wenn ich die ganzen Definitionen nach diesem Schema umforme 
funktioniert es ohne Warnung:
extern const char bar[] PROGMEM;
const char bar[] = "Blub";

So richtig schön ist die Lösung aber leider auch nicht, vor allem weil 
alle Variablen damit global angelegt werden müssen.

> Die Lösung dafür stand irgendwo mal bei den Freaks.

Du meinst vermutlich diesen Thread hier:
http://www.avrfreaks.net/index.php?name=PNphpBB2&f...

Johann L. schrieb:
> Lösung:
> avr-gcc debuggen und rausfinden, wie der tree genau aussieht. Den Fall
> behandlen, ein Patch machen und in einer passenden gcc- oder
> avr-libc-Maillingliste posten.

Hmm, ich habe gerade mal in die avr.c rein geschaut, befürchte aber das 
ich da nicht so schnell durchsteige was dort genau passiert. Dazu fehlt 
mir einfach das komplette Wissen über die Interna des GCC.

Grüße
Fabian

Autor: Johann L. (gjlayde) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Fabian G. schrieb:

> Johann L. schrieb:
>> Lösung:
>> avr-gcc debuggen und rausfinden, wie der tree genau aussieht. Den Fall
>> behandlen, ein Patch machen und in einer passenden gcc- oder
>> avr-libc-Maillingliste posten.
>
> Hmm, ich habe gerade mal in die avr.c rein geschaut, befürchte aber das
> ich da nicht so schnell durchsteige was dort genau passiert. Dazu fehlt
> mir einfach das komplette Wissen über die Interna des GCC.

In dem Falle macht man einen aussagekräftigen Bug-Report nachdem man 
sich versichert hat, daß nicht bereits einer gemacht wurde. Da das 
Problem bei den Freaks wohlbekannt ist, ist letzteres nicht 
unwahrscheinlich.

Im übrigen brauch's das ganze prog_-Typ-Gerüffel garnicht. Die Lösung 
mit PROGMEM funktioniert doch sowohl für extern als auch für static:
#include <stdint.h>

typedef struct
{
    uint8_t a, b;
} data_t;

extern const char string1[];
extern const data_t data;

// end of header

#include <avr/pgmspace.h>

const char string1[] PROGMEM = "abc";
static const char string2[] PROGMEM = "def";

const data_t data  PROGMEM = { 1, 2 };
static const data_t data0 PROGMEM = { 3, 4 };

const char * foo (void)
{
    return string2 + pgm_read_byte (& data0.b);
}

Ausserdem will man eh nicht für jede Struktur/Union eigene Typen 
definieren mit Ausprägungen für EEPROM, RAM und Flash.

> non sunt multiplicanda entia sine necessitate

oder wie die Angelsachsen sagen würden: avoid name space pollution ;-)

Johann

Autor: Fabian G. (kjion) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Johann L. schrieb:
> In dem Falle macht man einen aussagekräftigen Bug-Report nachdem man
> sich versichert hat, daß nicht bereits einer gemacht wurde. Da das
> Problem bei den Freaks wohlbekannt ist, ist letzteres nicht
> unwahrscheinlich.

Es gibt zum Beispiel schon die folgenden:
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=34734
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=40112

> Im übrigen brauch's das ganze prog_-Typ-Gerüffel garnicht.

Das ist richtig, waren jetzt hier auch nur zum Testen drinnen.

> Die Lösung mit PROGMEM funktioniert doch sowohl für extern als auch für static:

Der vorgeschlagene Workaround aber leider nicht:
#include <avr/pgmspace.h>

extern const char string1[] PROGMEM;
const char string1[] = "Blub";

int
main(void)
{
  char foo[20];
  
  memcpy_P(foo, string1, sizeof(bar));
  
  {
    static const char string2[] PROGMEM = "Bla";

    memcpy_P(foo, string2, sizeof(bar));
  }
}

Erzeugt für string2 die Warnung, für string1 aber nicht. Und man kann 
string2 ja schlecht als "extern static" deklarieren.


Johann L. schrieb:
> #include <avr/pgmspace.h>
> 
> typedef struct
> {
>     uint8_t a, b;
> } data_t;
> 
> extern const char string1[];
> extern const data_t data;
> 
> const char string1[] PROGMEM = "abc";
> 
> static const char string2[] PROGMEM = "def";
> 
> const data_t data  PROGMEM = { 1, 2 };
> static const data_t data0 PROGMEM = { 3, 4 };
> 
> const char * foo (void)
> {
>     return string2 + pgm_read_byte (& data0.b);
> }

Wenn man dies durch den avr-g++ schickt spuckt er halt die Warnung aus, 
obwohl aber korrekter Code erzeugt wird.
Compiling C++: main.cpp
main.cpp:11: warning: only initialized variables can be placed into program memory area
main.cpp:13: warning: only initialized variables can be placed into program memory area
main.cpp:15: warning: only initialized variables can be placed into program memory area
main.cpp:16: warning: only initialized variables can be placed into program memory area

Grüße
Fabian

Autor: A. N. (netbandit)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Fabian:

Ich sammel alle Strings die thematisch zusammen passen in einer CPP 
Datei + Header. Den Header includiere ich dann nur in der CPP Datei in 
der die Strings gebraucht werden. Damit sind sie nicht wirklich global, 
da man ja von anderen CPP Dateien nicht darauf zugreifen kann.

Aber du hast schon recht, schöner wäre es schon, wenn es auch so klappen 
würde wie in C. :)

Autor: Johann L. (gjlayde) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Fabian G. schrieb:
> Johann L. schrieb:
>> Die Lösung mit PROGMEM funktioniert doch sowohl für extern als auch für static:
>
> Der vorgeschlagene Workaround aber leider nicht:
>
>
#include <avr/pgmspace.h>
> 
> extern const char string1[] PROGMEM;
> const char string1[] = "Blub";
> 
> int
> main(void)
> {
>   char foo[20];
> 
>   memcpy_P(foo, string1, sizeof(bar));
> 
>   {
>     static const char string2[] PROGMEM = "Bla";
> 
>     memcpy_P(foo, string2, sizeof(bar));
>   }
> }
>
> Erzeugt für string2 die Warnung, für string1 aber nicht. Und man kann
> string2 ja schlecht als "extern static" deklarieren.

Ich bekomme da einen Fehler:
error: `bar' was not declared in this scope

Wenn ich das behebe, dann wird das ohne Warnung übersetzt und der Code 
ist korrekt. Sowohl für avr-g++ 3.4.6 als auch avr-g++ 4.3.2 und 
zusammen mit -W -Wall.

> Johann L. schrieb: [c]
>> #include <avr/pgmspace.h>
>>
>> [snip weil Foren-Software meckert]
> Wenn man dies durch den avr-g++ schickt spuckt er halt die Warnung aus,
> obwohl aber korrekter Code erzeugt wird.
>
>
Compiling C++: main.cpp
> main.cpp:11: warning: only initialized variables can be placed into
> program memory area
> ...

Auch diese Warnungen bekomme ich mit den genannten g++-Version nicht.

Johann

Autor: Fabian G. (kjion) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Johann L. schrieb:
> Ich bekomme da einen Fehler:
>
error: `bar' was not declared in this scope

Ähm, ja, klassischer Copy-Paste und noch was geändert Fehler.

> Wenn ich das behebe, dann wird das ohne Warnung übersetzt und der Code
> ist korrekt. Sowohl für avr-g++ 3.4.6 als auch avr-g++ 4.3.2 und
> zusammen mit -W -Wall.

Hmm, ein avr-g++ 4.3.3 erzeugt bei mir die Warnungen. Könntest du mal 
versuchen das Ganze mit dem Makefile aus dem ersten Beitrag zu 
compilieren?

Grüße
Fabian

Autor: Johann L. (gjlayde) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Fabian G. schrieb:

> Hmm, ein avr-g++ 4.3.3 erzeugt bei mir die Warnungen. Könntest du mal
> versuchen das Ganze mit dem Makefile aus dem ersten Beitrag zu
> compilieren?

Das compiliert mit 4.3.2 ohne Warnung, für 3.4.6 gibt es unbekannte 
Optionen.
Die Warnungen kommen erst wenn .dep/main.o.d existiert

Johann

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.