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


von Fabian G. (kjion) Benutzerseite


Angehängte Dateien:

Lesenswert?

Hallo,

ich habe ein Problem mit C++ und PROGMEM:
1
#include <avr/pgmspace.h>
2
3
const char bar[] PROGMEM = "Blub";  // Flash
4
5
const prog_char bar2[] = "Bla";    // RAM
6
7
typedef char PROGMEM test_char_t;
8
const test_char_t bar3[] = "Hello World";  // RAM
9
10
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:
1
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
1
  71                 .LBE2:
2
  72                 .LFE2:
3
  74                   .section  .progmem.data,"a",@progbits
4
  77                 _ZL3bar:
5
  78 0000 426C 7562     .string  "Blub"
6
  78      00
7
  79                   .data
8
  82                 _ZL4bar2:
9
  83 0000 426C 6100     .string  "Bla"
10
  86                 _ZL4bar3:
11
  87 0004 4865 6C6C     .string  "Hello World"
12
  87      6F20 576F 
13
  87      726C 6400 
14
  88                   .section  .progmem.data
15
  91                 _ZL4bar4:
16
  92 0005 4861 6C6C     .string  "Hallo Welt"
17
  92      6F20 5765 
18
  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

von A. N. (netbandit)


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:
1
extern PROGMEM const char sEthernetLink1[];

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

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

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Fabian G. schrieb:
> Hallo,
>
> ich habe ein Problem mit C++ und PROGMEM:
>
>
1
#include <avr/pgmspace.h>
2
> 
3
> const char bar[] PROGMEM = "Blub";  // Flash
4
> 
5
> const prog_char bar2[] = "Bla";    // RAM
6
> 
7
> typedef char PROGMEM test_char_t;
8
> const test_char_t bar3[] = "Hello World";  // RAM
9
> 
10
> 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:
>
>
1
warning: only initialized variables can be placed into program memory
2
> 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/avr.c?revision=148689

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

von Fabian G. (kjion) Benutzerseite


Lesenswert?

@A. N.
In der Tat, wenn ich die ganzen Definitionen nach diesem Schema umforme 
funktioniert es ohne Warnung:
1
extern const char bar[] PROGMEM;
2
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&file=viewtopic&t=57011

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

von Johann L. (gjlayde) Benutzerseite


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:
1
#include <stdint.h>
2
3
typedef struct
4
{
5
    uint8_t a, b;
6
} data_t;
7
8
extern const char string1[];
9
extern const data_t data;
10
11
// end of header
12
13
#include <avr/pgmspace.h>
14
15
const char string1[] PROGMEM = "abc";
16
static const char string2[] PROGMEM = "def";
17
18
const data_t data  PROGMEM = { 1, 2 };
19
static const data_t data0 PROGMEM = { 3, 4 };
20
21
const char * foo (void)
22
{
23
    return string2 + pgm_read_byte (& data0.b);
24
}

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

von Fabian G. (kjion) Benutzerseite


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:
1
#include <avr/pgmspace.h>
2
3
extern const char string1[] PROGMEM;
4
const char string1[] = "Blub";
5
6
int
7
main(void)
8
{
9
  char foo[20];
10
  
11
  memcpy_P(foo, string1, sizeof(bar));
12
  
13
  {
14
    static const char string2[] PROGMEM = "Bla";
15
16
    memcpy_P(foo, string2, sizeof(bar));
17
  }
18
}

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


Johann L. schrieb:
1
> #include <avr/pgmspace.h>
2
> 
3
> typedef struct
4
> {
5
>     uint8_t a, b;
6
> } data_t;
7
> 
8
> extern const char string1[];
9
> extern const data_t data;
10
> 
11
> const char string1[] PROGMEM = "abc";
12
> 
13
> static const char string2[] PROGMEM = "def";
14
> 
15
> const data_t data  PROGMEM = { 1, 2 };
16
> static const data_t data0 PROGMEM = { 3, 4 };
17
> 
18
> const char * foo (void)
19
> {
20
>     return string2 + pgm_read_byte (& data0.b);
21
> }

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

Grüße
Fabian

von A. N. (netbandit)


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. :)

von Johann L. (gjlayde) Benutzerseite


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:
>
>
1
#include <avr/pgmspace.h>
2
> 
3
> extern const char string1[] PROGMEM;
4
> const char string1[] = "Blub";
5
> 
6
> int
7
> main(void)
8
> {
9
>   char foo[20];
10
> 
11
>   memcpy_P(foo, string1, sizeof(bar));
12
> 
13
>   {
14
>     static const char string2[] PROGMEM = "Bla";
15
> 
16
>     memcpy_P(foo, string2, sizeof(bar));
17
>   }
18
> }
>
> 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:
1
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.
>
>
1
Compiling C++: main.cpp
2
> main.cpp:11: warning: only initialized variables can be placed into
3
> program memory area
4
> ...

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

Johann

von Fabian G. (kjion) Benutzerseite


Lesenswert?

Johann L. schrieb:
> Ich bekomme da einen Fehler:
>
1
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

von Johann L. (gjlayde) Benutzerseite


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

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.