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
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
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? :)
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
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
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
@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.
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?
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.
>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.
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.
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
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.
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
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?
Das einzige was ich finde ist: http://sourceforge.net/projects/winavr/files/ Das Ding ist aber von 2010!
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.
__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.
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.
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!
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! :)
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?
Der Compiler gibt die Fehlermeldung aus: compound literal qualified by address-space qualifier.
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
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.
Hmm Ok. Das natürlich recht blöd. Dann werde ich wohl vom dem __flash absehen müssen.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.