Hallo,
ich finde immer wieder Quellcode für ATmegas, wo zum Beispiel die
Adresse eines Arrays in einem char (8bit) übergeben wird. Ist das auch
noch für einen Atmega1280 zulässig?
Wenn ich es richtig verstanden habe, dann ist das SRAM der AVR's 16bit
breit, so dass man mit einem char maximal 16*256, also 4k Speicher,
adressieren kann. Der Mega1280 hat aber nun 8k Speicher, die sich mit
einem char nicht mehr voll adressieren lassen.
Ralf schrieb:> ich finde immer wieder Quellcode für ATmegas, wo zum Beispiel die> Adresse eines Arrays in einem char (8bit) übergeben wird. Ist das auch> noch für einen Atmega1280 zulässig?
Das war noch nie zulässig. Beispiel?
> Wenn ich es richtig verstanden habe, dann ist das SRAM der AVR's 16bit> breit,
Nein. Das Flash-ROM ist es. Dessen Adressierung ist je nach Art der
Verwendung in 16-Bit Worten (als Code) oder in 8-Bit Bytes (als Daten).
> so dass man mit einem char maximal 16*256, also 4k Speicher,> adressieren kann.
Nein. Ausserdem fehlt die Einheit. In Bits wäre immerhin der
Gedankengang nachvollziehbar. Nur wird die Kapazität von RAM
üblicherweise in Bytes angegeben.
Ralf schrieb:> Hallo,>> ich finde immer wieder Quellcode für ATmegas, wo zum Beispiel die> Adresse eines Arrays in einem char (8bit) übergeben wird. Ist das auch> noch für einen Atmega1280 zulässig?
Eine Adresse wird nicht mit einem char übergeben, sondern mit einem
char*. Und Pointer sind 16 Bit gross.
> Wenn ich es richtig verstanden habe, dann ist das SRAM der AVR's 16bit> breit, so dass man mit einem char maximal 16*256, also 4k Speicher,> adressieren kann. Der Mega1280 hat aber nun 8k Speicher, die sich mit> einem char nicht mehr voll adressieren lassen.
Nein. Das RAM ist 8 Bit breit. Das Flash hat 16 Bit.
mfg.
Thomas Eckmann schrieb:> Eine Adresse wird nicht mit einem char übergeben, sondern mit einem> char*. Und Pointer sind 16 Bit gross.
...ach da lag mein Fehler...vielen Dank
Ralf schrieb:> ich finde immer wieder Quellcode für ATmegas, wo zum Beispiel die> Adresse eines Arrays in einem char (8bit) übergeben wird. Ist das auch> noch für einen Atmega1280 zulässig?
Der Pointer auf einen bestimmten Datentyp hat nichts mit der
Verarbeitung auf Maschinenebene zu tun.
Der Benutzer sagt ich will auf char zeigen, und der Compiler
kümmert sich darum das auf Maschinenebene richtig umzusetzen.
Dabei kommen je nach Prozessor und Speichergrösse unterschiedliche
Ergebnisse zustande.
Fritz Ganter schrieb:> u meinst die Zeile?>> val &= 0x0F;>> Das ist keine Adressübergabe sondern die Kurzschreibweise für>> val=val & 0x0f;
nein, nein, mir war in der Tat der Ausdruck char* xx nicht geläufig. Ich
dachte der Pointer wäre aufgrund dem "char" nur 8bit breit.
Ralf schrieb:> Fritz Ganter schrieb:>> u meinst die Zeile?>>>> val &= 0x0F;>>>> Das ist keine Adressübergabe sondern die Kurzschreibweise für>>>> val=val & 0x0f;>> nein, nein, mir war in der Tat der Ausdruck char* xx nicht geläufig. Ich> dachte der Pointer wäre aufgrund dem "char" nur 8bit breit.
der springende Punkt bei einem Pointer ist der Stern '*'. Die Angabe
davor bezieht sich nur darauf, worauf der Pointer zeigt.
Denn ein Pointer auf einen char ist etwas anderes als ein Pointer auf
einen long. D.h. der Pointer im Sinne einer Variablen die eine Adresse
enthält nicht, die ist immer gleich groß. Aber beim Dereferenzieren,
also beim Holen des Wertes auf das der Pointer dann tatsächlich zeigt,
muss der Compiler ja wissen, ob sich unter der so angegebenen Adresse
lediglich 1 Byte oder deren 4 Bytes verbergen, die umkopiert werden
müssen.
1
POintervariable
2
+---------+
3
| o |
4
+---|-----+ das, worauf der Pointer zeigt. zb. ein long
5
| +------------+
6
+-------------->| 5 |
7
+------------+
1
longlongVar;
2
3
long*Pointer;
4
5
Pointer=&longVar;// der Pointer zeigt jetzt auf die Variable
6
*Pointer=5;
7
8
longk;
9
k=*Pointer;// k kriegt den Wert, auf den Pointer zeigt
wichtig ist:
nur weil du einen Pointer hast, heisst das noch lange nicht, dass du
deswegen auch eine Speicherfläche hast, in der Werte gespeichert werden
können.
1
Ein
2
[c]
3
int*Ptr;
legt lediglich die Variable Ptr an. Eine Variable, die auf eine
Speicherfläche zeigen kann, es aber im Moment noch nicht tut. Im obigen
Schaubild entspricht das einem
1
Ptr
2
+------------+
3
| |
4
+------------+
Also nur die Pointervariable, die noch nicht auf irgendetwas zeigt.
Würdest du da jetzt einfach die Operation
1
*Ptr=8;
drauf anwenden, dann wäre das ein schwerer Fehler. Denn wie im Schaubild
zu sehen, gibt es keinen bestimmten von Ptr ausgehenden Pfeil, der auf
für dein Programm reservierten Speicher zeigt. Das ist aber
Grundvoraussetzung, damit du mit einem Pointer sicher arbeiten kannst:
Es muss einen derartigen Pfeil geben und am Ende des Pfeiles muss ein
für das Programm reservierter Speicher sein.
Da hätte ich noch eine Gretchenfrage, vielleicht weiss jemand
eine Antwort?
Es ist ja möglich const Variablen im Flash anzulegen, wie
würden denn diese im Falle eines AVRs mit >64K Flash per
Pointer adressierbar sein (wenn der Pointer auf Register-
Ebene nur 16 Bit gross ist)?
Eberhard F. schrieb:> Es ist ja möglich const Variablen im Flash anzulegen, wie> würden denn diese im Falle eines AVRs mit >64K Flash per> Pointer adressierbar sein (wenn der Pointer auf Register-> Ebene nur 16 Bit gross ist)?
Dazu musst du eine andere Art von Pointern verwenden. Beispielsweise
char __flash *string;
Wobei dafür ein leidlich aktueller Compiler nötig ist. Früher war das
umständlicher.
Wie es tatsächlich umgesetzt ist, weiß ich zwar nicht, aber ein Zeiger
auf Flash muss eh ein anderer Typ sein, als einer auf RAM, da ja auch
der Zugriff anders ablaufen muß. Dann könnte man solche Zeiger auch
größer machen als die auf RAM. Letztendlich gilt das gleiche auch für
Zeiger auf Funktionen.
@Eberhard F. (loocee):
Das hängt vom Typ des verwendeten AVRs ab. Manche haben ein spezielles
IO-Register (RAMPZ), mit dem eine Art Bankswitching möglich ist, bei
anderen Typen gibt es das nicht, und man muß sich darum kümmern, daß die
Konstanten / Tabellen in den unteren 64k angelegt werden. Diese
Beschränkung gilt dann auch für indirekte Sprünge über das Z-Register,
dort sind allerdings 128k erreichbar, da ja in Words gezählt wird.
Absolute Sprünge, und Calls können den ganzen Bereich erreichen,
brauchen dann auch mehr Taktzyklen, Adressen auf dem Stack belegen dann
3 Bytes statt 2. So braucht dann auch der RET einen Taktzyklus mehr.
Mit freundlichem Gruß - Martin
Bei den AVR's ist es der Z-Pointer der RAM und Flash gemeinsam nutzen
kann.
z.B für Flash
;z darf nicht mit x / y ersetzt werden da LPM sonst nicht Funktioniert
siehe DB
ldi zh,High(OUT_LCD)
ldi zl,Low (OUT_LCD) ;Stringadresse an den Pointer übergeben
start:
lpm r16,z+ ;erst Z von lesen und dann Adresse
Z+1
;Programm irgendwas
cpi r16,$FF ;Stoppbedingung
brne start
.
.
.
.db OUT_LCD "HELLO",$FF
Selber Pointer für RAM
RAMPZ = $0060
RAMPX = $0070
RAMPY = $0080 ;Adresse auf RAM als Namen deklarieren
ldi zh,High(RAMPZ) ;z kann durch x oder y ersetzt werden
ldi zl,Low (RAMPZ)
start:
ld r16,z+
st z+,r16
;Programm irgendwas
.
.
.
um eventuell einen größeren Bereich mit Pointer abzubacken kann man die
Pointer "zusammenschalten"
Ich spiele gerade ein bisschen mit const char im Flash.
Dabei zeigt sich dass der GCC (WINAVR-2010) störrisch reagiert mit
einer unklaren Fehlermeldung:
../Main_Flash_Test.c:12: warning: '__progmem__' attribute ignored
Das passiert dann wenn man einen Flash String in einer Funktion
anlegt:
1
intmain(void)
2
{
3
constchar__ATTR_PROGMEM__MyString[]="Das ist ein String im Flash";
4
........
5
}
.... nicht ganz einleuchtend .... da ja eigentlich const. Das bekommt
man ja sonst auch.
Legt man dagegen den String im globalen Scope an ist es ok .....
Eberhard F. schrieb:> Ich spiele gerade ein bisschen mit const char im Flash.>> Dabei zeigt sich dass der GCC (WINAVR-2010) störrisch reagiert mit> einer unklaren Fehlermeldung:>> ../Main_Flash_Test.c:12: warning: '__progmem__' attribute ignored>> Das passiert dann wenn man einen Flash String in einer Funktion> anlegt:>>
1
>intmain(void)
2
>{
3
>constchar__ATTR_PROGMEM__MyString[]="Das ist ein String im
4
> Flash";
5
>........
6
>}
7
>
> .... nicht ganz einleuchtend ....
na ja. eigentlich schon einleuchtend.
> da ja eigentlich const.
das hat ja damit nichts zu tun.
Das "Problem" ist nun mal, dass derartige funktionslokale Variablen,
wenn man es genau nimmt, erzeugt werden, wenn die Funktion betreten wird
und zerstört werden, wenn die Funktion verlassen wird. Und das ist nun
mal mit Variablen im Flash schwierig, egal ob const oder nicht.
Karl Heinz schrieb:> Das "Problem" ist nun mal, dass derartige funktionslokale Variablen,> wenn man es genau nimmt, erzeugt werden, wenn die Funktion betreten wird> und zerstört werden, wenn die Funktion verlassen wird.
Das hab ich eben anders in "Erinnerung": Ein const Variable wird
in einer Funktion nicht "at runtime" angelegt wie eine echte
Variable. Das wäre ja auch Zeitverschwendung ....
Aber ich kann mich täuschen, und jeder Compiler mag es anders machen.
Eberhard F. schrieb:> Karl Heinz schrieb:>> Das "Problem" ist nun mal, dass derartige funktionslokale Variablen,>> wenn man es genau nimmt, erzeugt werden, wenn die Funktion betreten wird>> und zerstört werden, wenn die Funktion verlassen wird.>> Das hab ich eben anders in "Erinnerung": Ein const Variable wird> in einer Funktion nicht "at runtime" angelegt wie eine echte> Variable. Das wäre ja auch Zeitverschwendung ....
Ob der Compiler für eine const Variable überhaupt eine Variable anlegt
oder nicht, musst du schon dem Compiler überlassen.
Konzeptionell kommt bei
1
voidfoo()
2
{
3
constinti=5;
4
}
die Variable i beim Betreten der Funktion zur Welt und wird beim
Verlassen der Funktion zerstört.
Das der Compiler die Variable komplett wegoptimiert und anstelle von i
...
1
voidfoo()
2
{
3
constinti=5;
4
k=i;
5
}
... bei der Zuweisung gleich den bekannten Wert der Variablen benutzt,
ändert am grundsätzlichen Konzept nichts. Denn Optimierungen werden in C
anhand der 'as if' Regel behandelt. Der Compiler darf nach Lust und
Laune optimieren, aber immer nur 'as if' die Optimierung nicht statt
gefunden hätte. D.h. das Endergebnis muss dasselbe sein. Aus dieser
'Muss' Klausel folgt unmittelbar, dass Optimierungen keine C Regeln
ausser Kraft setzen können. Insbesonders können Optimierungen kein
illegales Programm plötzlich legal machen.
>> Aber ich kann mich täuschen, und jeder Compiler mag es anders machen.
Immer dieses 'jeder COmpiler macht das anders'. Nein! Es gibt Dinge, die
sind in C so definiert. Entweder ein Compiler implementiert die genau
so, oder er ist kein C Compiler. Scope und die damit verknüpfte Lifetime
von Variablen fallen da zu 100% darunter.
davor, dann ist man das
> Lokale los.
Nö, lokal ist die Variable dann immer noch; hat aber eine andere
Speicherklasse: static statt auto. Damit kann die Variable dann im
Flash oder allgemeiner einem readonly-Speicher liegen.
Karl Heinz schrieb:> Immer dieses 'jeder COmpiler macht das anders'. Nein!
Nö. Nicht immer. Nur jetzt gerade, und nur heute, bei diesem Thema.
Schön cool bleiben.
> Es gibt Dinge, die> sind in C so definiert. Entweder ein Compiler implementiert die genau> so, oder er ist kein C Compiler.
Dann kann immer noch gelten:
> Aber ich kann mich täuschen, .....
Alles klar, Herr Kommissar?
> Damit kann die Variable dann im
Flash oder allgemeiner einem readonly-Speicher liegen.
Ja, falscher Begriff. Es ging mir nicht um die Sichtbarekeit, sondern um
global vs lokal als Speicherort.
Eberhard F. schrieb:> Dann kann immer noch gelten:>> Aber ich kann mich täuschen, .....>> Alles klar, Herr Kommissar?
Postings wie
"Die Sonne ist schwarz, aber ich kann mich auch täuschen"
haben genau welchen Informationsgehalt?
Genau, keinen. Der einzige Effekt ist, dass man all die anderen Leser
verwirrt und in die Irre führt. Also lass das. Dann muss da auch keiner
reingrätschen.
Karl Heinz schrieb:> Der Compiler darf nach Lust und Laune optimieren, aber immer nur 'as if'> die Optimierung nicht statt gefunden hätte. D.h. das Endergebnis muss> dasselbe sein. Aus dieser 'Muss' Klausel folgt unmittelbar, dass> Optimierungen keine C Regeln ausser Kraft setzen können. Insbesonders> können Optimierungen kein illegales Programm plötzlich legal machen.
Nun bewegen wir uns allerdings mit Zeigern auf Flash sowieso schon
außerhalb der ISO-Norm, womit der Code in der Hinsicht eh illegal ist,
egal ob mit oder ohne static. Wie also die Kombination "lokale Variable
im Flash" gehandhabt wird, ist ganz alleine Sache des Compilers. Und
dort wurde entschieden, daß in diesem Fall der Flash verliert und es zu
einer normalen lokalen Variable wird, auch wenn diese const ist und sich
am Verhalten des Programms nichts ändern würde, wenn sie im Flash
stünde.
> Immer dieses 'jeder COmpiler macht das anders'. Nein! Es gibt Dinge, die> sind in C so definiert.
Ja, aber _ATTR_PROGMEM_ ist dort gar nicht definiert.
Ich bleibe mal beim Thema: 8bit Pointer bei großen AVRs
Wie macht man denn bitte einen Char Pointer "far" sodass man
auch Strings im Bereich jenseits von 64KByte Flash erreichen
kann?
Eine Anwendung wäre, viele Strings in einem ATMega256 zu
verwenden die dann die ersten 64K sprengen würden.
Zum Handlen von Strings aus dem Flash gibt es Macros wie
strcpy_P, aber die erschlagen leider nicht die Problematik >64K.
Vermutlich ist das im neueren Versionen des GCC gelöst (ich habe
es nicht gewagt mein Absturz-schwangeres Studio 6.2 diesbezüglich
zu bemühen), nicht aber im WinAVR-2010.
Nun gut, die Frage wird sich nicht auf Char Pointer bzw Strings
im Flash beschränken .......
Eberhard F. schrieb:> Vermutlich ist das im neueren Versionen des GCC gelöst (ich habe> es nicht gewagt mein Absturz-schwangeres Studio 6.2 diesbezüglich> zu bemühen), nicht aber im WinAVR-2010.
Im WinAVR ist es gelöst, weil darin nicht der Compiler bemüht wird,
sondern der Inhalt von <avr/pgmspace.h>. Die "pointer" der "far"
Funktionen sind dort dementsprechend 32-Bit gross:
http://www.nongnu.org/avr-libc/user-manual/pgmspace_8h.html> Zum Handlen von Strings aus dem Flash gibt es Macros wie> strcpy_P, aber die erschlagen leider nicht die Problematik >64K.
Sehr wohl aber strcpy_PF.
A. K. schrieb:> Im WinAVR ist es gelöst, weil darin nicht der Compiler bemüht wird,> sondern der Inhalt von <avr/pgmspace.h>.
In WinAVR_2010 (GCC 4.3.3) sind diese *_PF Makros nicht enthalten.
Da muss man wohl den GCC mit einer neueren Lib updaten .... ?
(um in den Genuss der *_PF Makros zu kommen)
Selbst wenn mir diese Makros zur Verfügung stehen sind aber die
Pointer für Strings oberhalb von 64K immer noch nicht "far".
Denn an deren Deklaration hat sich ja nichts geändert.