Forum: Compiler & IDEs Progmem zuweisungen


von mem (Gast)


Lesenswert?

Guten Tag,

eine Frage meinerseits zum Einsparen von RAM.  Ich arbeite mit dem 
ATmega32.

Gibt es noch andere Möglichkeiten ausser:

1)
PrintString(PSTR("Hallo"));

oder

2)
#define PrintString(__pstr,x)   PrintString_P((PSTR(__pstr)),x)

PrintString("Hallo");




Danke für alle Hilfe. :)

: Verschoben durch User
von Karl H. (kbuchegg)


Lesenswert?

mem schrieb:
> Guten Tag,
>
> eine Frage meinerseits zum Einsparen von RAM.  Ich arbeite mit dem
> ATmega32.
>
> Gibt es noch andere Möglichkeiten ausser:

Was gefällt dir an den beiden Möglichkeiten nicht?
Sind doch perfekt!

Das einzige was man bekritteln könnte ist, dass aus dem Funktionsnamen 
'PrintString' nicht unmittelbar ersichtlich ist, dass es sich dabei um 
eine Spezialversion handelt, die den String im Flash erwartet (das ist 
doch so programmiert, oder nicht?). Aus dem Grund gibt es eine 
Konvention, dass derartige Funktionen hinten im Funktionsnamen ein _p 
oder ein _P haben. Aber das ist nur eine Konvention.

: Bearbeitet durch User
von mem (Gast)


Lesenswert?

Karl Heinz schrieb:
> Was gefällt dir an den beiden Möglichkeiten nicht?
> Sind doch perfekt!


Bei der ersten Möglichkeit muss man ständig das "PSTR()" mitschleifen, 
was unschön ist. Bei der zweiten Möglichkeit gefällt mir nicht, dass ich 
dem user ein Makro nach außen liefere anstatt einer Funktion.

Hinweis:  Ich schreibe eine Bibliothek, welche dann vom user in seine 
Projekte einfefügt werden soll. Da würde ich ihm gerne im Header-File 
als Schnittstelle liefern: void PrintString (uint8_t *String);
anstatt: #define PrintString(__pstr,x)   PrintString_P((PSTR(__pstr)),x)

Ist das irgendwie hinzubekommen? :)

von Marc (gierig) Benutzerseite


Lesenswert?

Wenn dein C Compiler GCC und >= 4.7 ist dann darfst du dir das leben 
auch
ein ganz klein wenig einfacher machen.

http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial#flash_und_Embedded-C

von Karl H. (kbuchegg)


Lesenswert?

mem schrieb:

> Bei der ersten Möglichkeit muss man ständig das "PSTR()" mitschleifen,
> was unschön ist. Bei der zweiten Möglichkeit gefällt mir nicht, dass ich
> dem user ein Makro nach außen liefere anstatt einer Funktion.

So schlimm ist das auch wieder nicht.

flash Pointer, wie von Marc angeführt, vereinfachen zwar einiges, lösen 
aber nicht das Problem, dass im Aufruf
1
  PrintString_P( PSTR("Hallo") )
für den Compiler klar gemacht werden muss, dass dieser String im Flash 
residieren soll. Um den Teil kommt man meines Wissens nicht herum. Auch 
nicht durch flash Pointer. Dann muss man eben, unter Zuhilfe nahme des 
im Tutorial angebenen Makros FSTR schreiben
1
  PrintString_F( FSTR("Hallo") );
ok. Einen Vorteil hat letztere Lösung. Da das "flash_" Teil des 
Datentyps ist, ist es für den Compiler prüfbar, ob man hier einen Fehler 
gemacht hat. Ein
1
  PrintSring_F( "Hallo" );
müsste zu einem Fehler führen, was in der alten Systematik nicht so ist.

: Bearbeitet durch User
von Oliver (Gast)


Lesenswert?

mem schrieb:
> Hinweis:  Ich schreibe eine Bibliothek, welche dann vom user in seine
> Projekte einfefügt werden soll. Da würde ich ihm gerne im Header-File
> als Schnittstelle liefern: void PrintString (uint8_t *String);

Das kannst auch einfach so machen. Der gcc unterscheidet keinen Ram- und 
Flash-Pointer, für den ist das alles das gleiche. Damit muß die Funktion 
selber wissen, wo sie das Arguemnt herholen muß.
Deshalb gibt es z.B. in der avrlibc die Stringfunktionen doppelt, einmal 
normal mir Argument im RAM, und einemal mit _p hintendrann, die erwartet 
das Argument im Flash.

Das Makro in PSTR("Hallo") braucht es ja nicht für den Aufruf der 
Funktion, sondern um die Konstante "Hallo" in den Flash zu befördern. 
Das geht halt bei der Verwednung einer Konstaneten als Argument nicht 
anders.

Oliver

von Marc (gierig) Benutzerseite


Lesenswert?

@Karl Heinz
Ebnend ist für den Abruf nichts besonders nötig, nur zum Ablegen ist
das __flash nötig. Zu lesen dann nicht mehr.
1
static const __flash uint8 TEMP = 0x44;

und schon ist Temp eine Flash Konstante, und kann so verwendet werden 
ohne
nochmal explizit auf einen anderen Speicherort hinweisen zu müssen.
(gilt analog für natürlich auch für Pointer oder andere Strukturen).

dazu ggf.
http://gcc.gnu.org/onlinedocs/gcc/Named-Address-Spaces.html

Bei der Verwendung der Krücke PROGMEN ist das so das man den Compiler
jedes mal sagen musste das das benötigte DATUM im Flash residiert.

Kennen sollte man beides, ich bin persönlich weg von PROGMEN bei neuen 
Code.

von mem (Gast)


Lesenswert?

Marc D. schrieb:
> Wenn dein C Compiler GCC und >= 4.7 ist dann darfst du dir das leben
> auch
> ein ganz klein wenig einfacher machen.

Ich benutze Atmel Studio 6. Da hab ich grad folgendes rausgelesen:
Installed Packages: AVRGCC - 3.4.1.95
AVR Toolchain 32Bit (3.4.1.348 - GCC 4.4.3)
Kann ich in Atmel Studio den Compiler auf einfache Weise erneuern?

Karl Heinz schrieb:
> Einen Vorteil hat letztere Lösung. Da das "flash_" Teil des
> Datentyps ist, ist es für den Compiler prüfbar, ob man hier einen Fehler
> gemacht hat.

Danke für den Tipp! Stimmt.

Karl Heinz schrieb:
> Um den Teil kommt man meines Wissens nicht herum.

Hmm Ok.

Oliver schrieb:
> Deshalb gibt es z.B. in der avrlibc die Stringfunktionen doppelt, einmal
> normal mir Argument im RAM, und einemal mit _p hintendrann, die erwartet
> das Argument im Flash.

Hmm, ja so mache ich das wahrscheinlich auch. Gebe dem user dann als 
Schnittstelle vor:
void PrintString (uint8_t *String);
void PrintString_P (uint8_t *String);
oder
void PrintString_F (....);  <-- Welche Übergabeparameter hier?

von Stefan E. (sternst)


Lesenswert?

mem schrieb:
> Hmm, ja so mache ich das wahrscheinlich auch. Gebe dem user dann als
> Schnittstelle vor:
> void PrintString (uint8_t *String);
> void PrintString_P (uint8_t *String);
> oder
> void PrintString_F (....);  <-- Welche Übergabeparameter hier?

An deiner Stelle würde ich dann ja gleich __memx nehmen:
1
void PrintString (uint8_t __memx *String);
Dann kann der Benutzer mit der selben Funktion sowohl Strings aus dem 
Flash, als auch welche aus dem RAM ausgeben.

von A. W. (uracolix)


Lesenswert?

>Installed Packages: AVRGCC - 3.4.1.95

Ich denke mal die 3.4.1 bezieht sich nicht auf die gcc version
sondern auf die Atmel Build Nummer. da muesste sich ein gcc 4.7.2
dahinter verstecken. Juengst kam eine Version mit dem gcc 4.8.1
heraus.

Man kann die Atmel Toolchain auch seperat installieren.

Wenn man die neue TTC dem AS unterschieben will, dann muss  man
sicher nur das entsprechende Verzeichnis innerhalb des AS Baumes finden
und umbenennen und die neue TC dort hin kopieren.

von mem (Gast)


Lesenswert?

Hallo, ich bin wieder da.

Also mein compiler kennt kein __flash:

static const __flash uint8 x = 0x44;

Error  1 : unknown type name '__flash'


Muss ich noch irgendeine Bibliothek miteinbinden?


Das "__memx"  kennt er auch nicht.

von Peter II (Gast)


Lesenswert?

mem schrieb:
> mein compiler

und was ist dein Compiler? Name? Version?

von Karl H. (kbuchegg)


Lesenswert?

mem schrieb:
> Hallo, ich bin wieder da.
>
> Also mein compiler kennt kein __flash:

Dann ist dein Compiler zu alt.

Edit:
Den Teil aus dem Tutorial
1
Daher müssen C-Module, die Address-Spaces verwenden, mit -std=gnu99 compiliert werden.
hast du beachtet?

: Bearbeitet durch User
von mem (Gast)


Lesenswert?

Wie und wo komme ich an einen aktuellen compiler? Einfach das neuste 
Atmel studio 6 installieren?

Karl Heinz schrieb:
> Den Teil aus dem TutorialDaher müssen C-Module, die Address-Spaces
> verwenden, mit -std=gnu99 compiliert werden.
> hast du beachtet?

Ich habe unter Toolchain > AVR/GNU C Compiler > Other flags: -std=gnu99

per Hand eingefügt. Sehe auch das flag im output Fenster beim erstellen.

von mem (Gast)


Lesenswert?

Peter II schrieb:
> und was ist dein Compiler? Name? Version?

Ich verwende Atmel Studio 6.  Unter Help > About Atmel Studio
lese ich:
ARM Toolchain
Version: 4.7.0.59 - GCC 4.7.0

von mem (Gast)


Lesenswert?

Wobei... stop!

Unter Help > About Atmel Studio > AVRGCC  lese ich:

AVR Toolchain 32 Bit
Version: 3.4.1.348 - GCC 4.4.3



Ich arbeite mit dem ATmega32 und brauche also eine AVR Toolchain.
GCC 4.4.3 ist veraltet oder?  Wie bekomme ich eine neue her?

von mem (Gast)


Lesenswert?

Das einzige was ich finde ist:
http://sourceforge.net/projects/winavr/files/


Das Ding ist aber von 2010!

von Peter II (Gast)


Lesenswert?

mem schrieb:
> Das einzige was ich finde ist:
> http://sourceforge.net/projects/winavr/files/

dann suchst du falsch

http://www.atmel.com/tools/atmelavrtoolchainforwindows.aspx

keine Ahnung welcher GCC darin ist.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

__flash ist hier aber keine Lösung, denn das Stringliteral muß immer 
noch irgendwie in den Flash gelegt werden.  Nur eine Funktion aufzurufen 
wie
1
extern void f (const __flash char*);
2
3
void g (void)
4
{
5
    f ("Hallo");
6
}
Reicht dauzu nicht aus: "Hallo" wird im RAM (aka. Generic Address Space) 
abgelegt.

von Walter T. (nicolas)


Lesenswert?

Johann L. schrieb:
> extern void f (const __flash char*);
>
> void g (void)
> {
>     f ("Hallo");
> }


Und auf die übliche Art:
1
f (PSTR("Hallo"));
geht's.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Walter Tarpan schrieb:
> Johann L. schrieb:
>> extern void f (const __flash char*);
>>
>> void g (void)
>> {
>>     f ("Hallo");
>> }
>
>
> Und auf die übliche Art:
>
1
> f (PSTR("Hallo"));
2
>
> geht's.

...womit der OP dann wieder genau an der Stelle ist, an der er 
angefangen hat!

von mem (Gast)


Lesenswert?

Guten Tag!

Also meine Toolchain habe ich nun endlich erneuert bekommen und alles 
funktioniert jetzt.

Hier die Zusammenfassung meiner Erkenntnisse:

1. String wird im RAM abgelegt
1
Func("Hallo");
2
void Func (uint8_t *pstring)
3
{}

2. String wird im FLASH abgelegt
1
Func_P(PSTR("Hallo"));
2
void Func_P ()
3
{}

3. String wird im FLASH abgelegt
1
static const __flash uint8_t FLASH[10] = {'B'};
2
Func_F(FLASH);
3
void Func_F (const __flash char* pstring)
4
{}


Folgende Fragen sind noch offen:

1. Oben wurde gepostet, dass das funktionieren sollte:
1
Func_M("Hallo");
2
void Func_M (const __memx char* pstring)
3
{
Das funktioniert aber nicht. Oder mach ich was falsch?

2. Weiter wurde gesagt, dass der Compiler einen Fehler meldet bei:
1
static uint8_t RAM[10] = {'B'};
2
Func_F(RAM);
3
void Func_F (const __flash char* pstring)
4
{}
Tut er aber nicht.

Bin für alle weiteren Tipps dankbar! :)

von mem (Gast)


Lesenswert?

Noch eine weitere Frage ist aufgetaucht:

Wieso funktioniert das nicht?:

1
#define FSTR(X) ((const __flash char[]) { X } )
2
3
Func_F(FSTR("Hallo"));
4
Func_F(const __flash char *String)
5
{}


Wie schreibt man das richtig?

von Stefan E. (sternst)


Lesenswert?

Was genau bedeutet "funktioniert nicht"?

: Bearbeitet durch User
von mem (Gast)


Lesenswert?

Der Compiler gibt die Fehlermeldung aus:

compound literal qualified by address-space qualifier.

von mem (Gast)


Lesenswert?

Hier nochmals der gesamte Code. Ich habe den Fehler nicht finden können.
1
#include <avr/io.h>
2
#include <avr/pgmspace.h>
3
4
5
#define FSTR(X) ((const __flash char[]) { X } )
6
7
8
Func_F(const __flash char *String);
9
10
 
11
int main(void)
12
{
13
    
14
    Func_F(FSTR("Hallo"));
15
    
16
    while(1)
17
    {
18
        //TODO:: Please write your application code 
19
    }
20
}
21
22
23
Func_F (const __flash char *String)
24
{
25
    
26
}

Fehlermeldung: compound literal qualified by address-space qualifier

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

M.E. rührt das von einer (ziemlich dämliche und kurzsichtige) 
Einschränkung von Embedded C her.  Funktionslokale Objekte können z.B. 
nicht in einen Address Space gelegt werden.  Hier ist ein ähnlicher 
Fall, der zudem von GCC durch eine wenig hilfreiche Fehlermeldung 
abgehandelt wird.

von mem (Gast)


Lesenswert?

Hmm Ok. Das natürlich recht blöd. Dann werde ich wohl vom dem __flash 
absehen müssen.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Di kannst ja immer noch PSTR für diese wenigen Fälle benutzen, 
allerdings functioniert PSTR nur für lokale Variablen, nicht für 
(modul-)globale Variablen...

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.