Hallo Leute, wo finde ich Informationen darüber, ob der atmega64 (bzw. die Familie) Little oder Big Endian verwendet? Das Gleiche für den H8S/2367 von Hitachi...? Grüße Christian
@ Christian (Gast) >wo finde ich Informationen darüber, ob der atmega64 (bzw. die Familie) >Little oder Big Endian verwendet? AFAIK Little Endian. Sieht man an den merkwürdigen HEX-Dumps. http://www.mikrocontroller.net/articles/Digitaltechnik#Endianness Spielt aber kaum eine Rolle. In ASM machst du das sowieso alles "per Hand", in C macht es der Compiler. MFG Falk
Es gibt nicht viele Stellen, wo man das beim AVR überhaupt mitkriegt: - Anordnung der Bytes im Flash bei Zugriff per LPM, - Reihenfolge der Return-Adresse auf dem Stack, - 16bit-Werten in benachbarten Registern. Wenn man das zusammenrechnet, ist AVR zu zwei Dritteln little-endian, zu einem Drittel big-endian.
Naja, ich arbeite viel auf der Bitebene. Und da muss ich schon wissen, ob ich Little oder Big-Endian verwende, wenn ich mit meinen Masken arbeite... Ich habe nämlich die gleichen Masken auf einem PC genutzt um die vom µC generierten Daten auszuwerten, und bin da ganz schön auf die Sch*** gestürtzt, bis ich mein Problem fand: mein damaliger µC verwendete Big Endian... (MSB first), und im PC war dann leider das LSB first... Dumm, dass die Maske nicht automatisch mit gedreht wurde ;) Worum es mir eigentlich geht: Ich muss doch irgendwo auf den Herstellerseiten eine Info darüber finden... Sowas kann doch nicht mit Try & Error herausgefunden werden, oder? Grüße Christian
Klar findet man das. Die Doku zum LPM Befehl klärt 2 der 3 erwähnten Fragen, nur die Return-Adresse ist undokumentiert.
Das hängt vom C compiler ab, nicht vom Mikrocontroller, auch wenn die Registerstructur eines Micros da sehrwohl einen Einfluß hat, LSB mit niederer oder höherer Addresse bei 16bit Timern usw.
Warum du keine klare Antwort " ... ist little-endian" von Atmel erwarten darfst: Das Problem stellt sich überwiegend nicht, weil es bei AVRs keinen einzigen Befehl gibt, der im SRAM mit Werten grösser als 8 Bit arbeitet, wenn man von der erwähnten Return-Adresse mal absieht. In diesem Sinne sind AVRs also ist-mir-egal-mach-es-wie-du-willst-endian.
@ Christian (Gast) >Naja, ich arbeite viel auf der Bitebene. Und da muss ich schon wissen, >ob ich Little oder Big-Endian verwende, wenn ich mit meinen Masken >arbeite... Nööö. Man muss nur bei Daten mit mehr als ein Byte RICHTIG drauf zugreifen. Ein Compiler macht das automatisch, in ASM muss man halt aupassen. >mein damaliger µC verwendete Big Endian... (MSB first), und im PC war >dann leider das LSB first... Dumm, dass die Maske nicht automatisch mit >gedreht wurde ;) Hat dennoch nix mit den Masken zu tun, sondern mit dem Datenzugriff. 0xABCD ist immer 0xABCD, egal ob Little oder Big Endian. >Worum es mir eigentlich geht: Ich muss doch irgendwo auf den >Herstellerseiten eine Info darüber finden... Sowas kann doch nicht mit >Try & Error herausgefunden werden, oder? Der AVR ist ein 8-Bitter, da stellt sich die Frage so gut wie gar nicht. Aussnahmen wurden genannt. MFG Falk
"ist-mir-egal-mach-es-wie-du-willst-endian" Das ist ja nett formuliert. Na mal schauen. Ich muss es irgendwie in der Doku begründen, warum ich die Bitmasken auf dem PC drehen musste. Ich wollte halt vorher nur sicher gehen, dass der µC auch Big Endian hat, damit ich in der Doku keinen Mist zusammen-begründe ;) Grüße Christian
Für Daten hat er aber gerade kein Big Endian von Haus aus, sondern nur für die Returnadressen auf dem Stack.
Christian wrote: > Worum es mir eigentlich geht: Ich muss doch irgendwo auf den > Herstellerseiten eine Info darüber finden... Nein. Der AVR ist ein 8-Bitter und damit ein No-endian. Wie nun ein C-Compiler aus 2 Bytes einen 16Bit-Wert zusammenbastelt, ist seine persönliche Freiheit. Der AVR-Hersteller kann das also garnicht festlegen. In der Regel ist eine Datenübertragung (UART, CAN) auch 8Bittig und damit No-Endian. Man muß also im Protokoll festlegen, in welcher Reihenfolge die Bytes übertragen werden. Auf PC- und AVR-Seite verwende ich zur Übertragung Code, der endian unabhängig ist und schon gibts nie Probleme:
1 | int8_t hi; |
2 | int8_t lo; |
3 | int16_t word; |
4 | ...
|
5 | hi = word>>8; |
6 | lo = word; |
7 | ...
|
8 | word = lo | (hi>>8); |
Peter
Ok, weil die Frage mit den Masken aufkam: so sieht meine Maske im Mikrocontroller aus:
1 | typedef struct |
2 | {
|
3 | union /* Status des Telegramms */ |
4 | {
|
5 | unsigned char Byte; /* Byte-Zugriff */ |
6 | struct /* Bit-Zugriff */ |
7 | {
|
8 | unsigned char BELEGT: 1; /* 1: Speicher ist belegt */ |
9 | /* 0: Speicher ist nicht belegt */
|
10 | unsigned char SENDEN: 1; /* 1: Telegramm kann gesendet werden */ |
11 | /* 0: Telegramm kann noch nicht gesendet werden */
|
12 | unsigned char RESERVIERT5: 1; |
13 | unsigned char RESERVIERT4: 1; |
14 | unsigned char RESERVIERT3: 1; |
15 | unsigned char FILTERBEREIT: 1; /* 1: Telegramm vollständig */ |
16 | /* 0: Telegramm unvollständig */
|
17 | unsigned char RICHTUNG: 1; /* 0: Telegramm vom BC */ |
18 | /* 1: Telegramm vom FM */
|
19 | unsigned char KANAL: 1; /* 0: Telegramm vom FM_A */ |
20 | /* 1: Telegramm vom FM_B */
|
21 | }Bit; |
22 | }Status; |
23 | }maske_uC; |
und so muss die Maske für den PC aussehen:
1 | typedef struct |
2 | {
|
3 | bool inUse; |
4 | union
|
5 | {
|
6 | unsigned char BYTE; // Byte-Zugriff |
7 | struct
|
8 | {
|
9 | unsigned char KANAL: 1; // 0 == Kanal A, 1 == Kanal B |
10 | unsigned char RICHTUNG: 1; // 0 == Master, 1 == Slave |
11 | unsigned char RESERVIERT2: 1; |
12 | unsigned char RESERVIERT3: 1; |
13 | unsigned char RESERVIERT4: 1; |
14 | unsigned char RESERVIERT5: 1; |
15 | unsigned char SENDEN: 1; // 0 == nicht Senden, 1 == Senden (in der PC-Software ohne Bedeutung) |
16 | unsigned char RESERVIERT7: 1; |
17 | }Bit; // Bit-Zugriff |
18 | }Status; |
19 | }maske_PC; |
Ich musste die Reihenfolge der Bits der Maske ändern, da die Maske sonst bei dem gleichen Byte-Wert andere Ergebnisse ausgespuckt hat... Beide Codeabschnitte werden vom Gcc kompiliert... Jedoch einmal für den x86 und einmal für den µC. Vielleicht ist nun meine Frage nachvollziehbar ;) Grüße Christian
Peter Dannegger wrote: > Der AVR ist ein 8-Bitter und damit ein No-endian. Er ist ziemlich no-endian, ja, aber viele 8-Bitter sind das nicht und fast alle haben irgendwo 16bit Werte verbuddelt, meist im Code. 8051 kennst du selber, 65xx/68xx,8080/Z80,Z8 haben das querdurch in Code und Daten. Völlig frei von jeder hardwareseitigen Vorgabe war m.W. nur SC/MP.
@Christian: Und genau solche Mätzchen vermeidet man elegant mit der Danegger'schen Methode, indem man die Daten in einer definierten Reihenfolge überträgt, unabhängig von der maschinell bevorzugten Reihenfolge. Das mag etwas aufwendiger sein, erspart aber einigen Ärger. Und bei Bitfeldern begiebt man sich voll in Abhängigkeit vom Compiler. Das darf der nämlich in weiten Grenzen machen wie er will.
Berichtigung: Das High-Byte muß natürlich nach links geschoben werden:
1 | int8_t hi; |
2 | int8_t lo; |
3 | int16_t word; |
4 | ...
|
5 | hi = word>>8; |
6 | lo = word; |
7 | ...
|
8 | word = lo | (hi<<8); |
Peter
Andreas Kaiser wrote: >> Der AVR ist ein 8-Bitter und damit ein No-endian. > > Er ist ziemlich no-endian, ja, ... ...und die Stellen, an denen er selbst eine Endianess vorgibt, hast du ja bereits im dritten Posting ganz oben genannt. Will wohl bloß keiner wahr haben.
Kann man, da es hier ja um Bitfelder geht, das beim GCC evtl. einstellen? beim IAR habe ich eine Pragma-Direktive, die mir das Bitfeld "umdreht". MW
Michael Wilhelm wrote: > Kann man, da es hier ja um Bitfelder geht, das beim GCC evtl. > einstellen? Gewissermassen. Da der GCC quelloffen ist, bleibt es dir unbenommen, eine eigene Version zu erstellen, die deinen Wünschen entspricht. ;-)
@ Christian (Gast) >Ok, weil die Frage mit den Masken aufkam: >so sieht meine Maske im Mikrocontroller aus: Also innerhalb eines BYTES wird gar nichts gedreht, weder bei Big noch Little Endian. ABER, da nicht festgelegt ist, WO im Byte der Compiler die Bits hinlegen soll, kann er das ad libidum machen. Was zwei verschiedene Compiler auch tun. -> Solche Unions und Bitfummelein manch man anders. Über #defines und Bitmasken. >Beide Codeabschnitte werden vom Gcc kompiliert... Jedoch einmal für den >x86 und einmal für den µC. Naja, die haben zwar den gleichen Namen aber unter der Haube verschiedene Back ends. MFG Falk
Jörg Wunsch wrote: > ...und die Stellen, an denen er selbst eine Endianess vorgibt, hast > du ja bereits im dritten Posting ganz oben genannt. Will wohl bloß > keiner wahr haben. Es gibt Stellen, z.B. in den 4 Registerpaaren oder wie ein Call Adressen pusht, die indirekt nen Endian haben. Es kostet aber kein einziges Byte mehr, wenn der Compiler für SRAM-Variablen den Endian andersrum festlegt, da die immer nur byteweise gelesen werden können. Daher bin ich der Meinung, der Endian des AVR ist nirgends in Stein gemeißelt, sondern der Compiler kann ihn nach belieben festlegen. Peter
Christian wrote: > Ich musste die Reihenfolge der Bits der Maske ändern, da die Maske sonst > bei dem gleichen Byte-Wert andere Ergebnisse ausgespuckt hat... Ja, das ist die persönliche Freiheit des Compilers. Aber auch dafür gibt es eine Lösung. Man definiert die Variablen nicht direkt in einer Union, sondern als Elemente einer vorher definierten struct. Dann muß man nur für jeden Compiler einmal die Elemente in dieser struct umdefinieren, fertig. Ein Beispiel (in sbit.h) findest Du hier: Beitrag "LCD Treiber Routine 4*40" Wenn mans ganz sauber machen will, definiert man diese Struct in Abhängigkeit vom Compilernamen. Peter
Gibt noch ein paar 16-Bit-Befehle, bei denen das Endianesisch zumindest für die Assemblerprogrammierung meiner Meinung nach relevant ist: Bei der Multiplikation gilt: R0 = Product Low R1 = Product High [R1:R0] also Little Endian Bei ADIW und SBIW gilt ebenfalls: Rd+1:Rd := Rd+1:Rd +- K ist Little Endian Und die Doppelregister X = [R27:R26] Y = [R29:R28] Z = [R31:R30] auch Little Endian Da die Register auch im globalen Adressraum eingeblendet werden, kann hier meiner Meinung nach schon von einer little endian-Architektur gesprochen werden. Ob man die Stackreihenfolge dann big endian nennt sei mal dahingestellt. Gruß Kai
@ Peter Dannegger (peda) >Wenn mans ganz sauber machen will, definiert man diese Struct in >Abhängigkeit vom Compilernamen. Wäre es nicht sinnvoller, mit #defines und Bitmasken zu arbeiten? MFG Falk MFG Falk
Sorry, dass ich das jetzt grad noch nicht ganz gerallt Aber vielleich stehe ich zum Nachmittag auch auf meiner Leitung... Ich kann doch nicht dem Compiler überlassen, wie rum er meine Bits im Speicher hinterlegt?!? Grüße Christian
Christian wrote: > Ich kann doch nicht dem Compiler überlassen, wie rum er meine Bits im > Speicher hinterlegt?!? Gegenfrage: Warum nicht? Solange du dich immr nur auf ein und derselben Maschine tummelst und immer denselben Compiler verwendest, ist es doch (weitgehend) egal. C enthält viele solche Dinge, die im Ermessen des Compilers bzw. des Compilerbauers liegen. Das hat sein Gutes denn dadurch bleibt die Sprache von Besonderheiten einer bestimmten Architektur frei und der Compilerbauer kann sich für eine bestimmte Architektur eine optimale Strategie überlegen. Das hat aber auch sein weniger Gutes, indem man einen Teil der Kontrolle als Programmierer abgeben muss. In dem Moment, in dem Datenübertragung auf eine andere Maschine ansteht, und man die unbedingt binär machen will, hat man dann meist sowieso das eine oder andere kleine Problem.
>>persönliche Freiheit des Compilers.
Aha!
Schützt die Compiler!
Gebt ihnen Wahlrecht ab 18!
Gleichheit für alle!!
;-)
[duck & wech]
-stef
Stefan B. wrote: >>>persönliche Freiheit des Compilers. > > > Aha! > > Schützt die Compiler! > Gebt ihnen Wahlrecht ab 18! > Gleichheit für alle!! Weils gerade in einem anderen Fred angesprcohen wurde (und ich der Übeltäter war). Es muss CompilerInnen heissen :-) > [duck & wech] [noch mehr duck aber dafür nicht mehr ganz so schnell wech]
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.