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. :)
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.
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? :)
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.
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
voidPrintString(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.
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?
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
voidFunc(uint8_t*pstring)
3
{}
2. String wird im FLASH abgelegt
1
Func_P(PSTR("Hallo"));
2
voidFunc_P()
3
{}
3. String wird im FLASH abgelegt
1
staticconst__flashuint8_tFLASH[10]={'B'};
2
Func_F(FLASH);
3
voidFunc_F(const__flashchar*pstring)
4
{}
Folgende Fragen sind noch offen:
1. Oben wurde gepostet, dass das funktionieren sollte:
1
Func_M("Hallo");
2
voidFunc_M(const__memxchar*pstring)
3
{
Das funktioniert aber nicht. Oder mach ich was falsch?
2. Weiter wurde gesagt, dass der Compiler einen Fehler meldet bei:
1
staticuint8_tRAM[10]={'B'};
2
Func_F(RAM);
3
voidFunc_F(const__flashchar*pstring)
4
{}
Tut er aber nicht.
Bin für alle weiteren Tipps dankbar! :)
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.
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...