Hallo,
mein Problem ist nicht ganz einfach zu erklären, darum hole ich etwas
weiter aus:
Ich habe eine Struktur mit ganz einfachen Variablen, z.B. eine Byte,
eine Word und eine long Variable. Die werden im Speicher abgelegt.
Jetzt will ich die Struktur auf der seriellen Schnittstelle übertragen,
was auch nicht das Problem ist.
Ich lege also einen Char Zeiger auf den Anfang der Struktur und
übertrage sizeof(Struktur) Daten.
Auf der anderen Seite der Schnittstelle saß bisher eine gleiche CPU
Familie, also alles gut!
Jetzt habe ich eine PC-ähnliche CPU angeschlossen und folgendes gemacht
wie immer.
Im Datenpuffer liegen neue Daten die ich wie geschildert
herübergeschickt habe. Jetzt nehme ich wieder meine Struktur und will
die Daten auslesen.
Jetzt habe ich aber bemerkt das die Daten verutscht sind. Auch die
Ursache ist schnell(ok,hat gedauert) gefunden.
Mein Sender hat die Daten folgendermaßen angelegt. Erst 1Byte, dann ein
Dummy Byte, dann die 16Bit Variable und die 32Bit Variable. Heißt also
das der sizeof folgerichtig die Struktur 8Byte groß macht, und diese
auch sendet. Die Emfangsseite erwartet aber nach der Byte Variable die
16Bit Variable u.s.w., erwartet also 7Byte.
Natürlich kann man auf der Emfangsseite 1 Byte einfügen in deren
Struktur sofern man das weiß, aber hier ist nur das Beispiel, meine
Struktur hat zig Variablen unterschiedlicher Größe. Auch sortieren nach
Größe oder schicker jeder Variable einzeln ist nicht wirklich eine
Lösung.
Meine Frage also: Wie schickt ihr Daten aus dem Speicher der genau
gespiegelt auf der Emfangsseite ankommen muss. Ich habe DMA und würde
ungern jedes Byte einzeln überprüfen. Oder, wie macht ihr das, irgendwie
müsste man vereinbaren das er die Daten schön hintereinander ablegt.
Wenn das so nicht möglich ist und ihr schon vor lachen nicht in den
Schlaf kommt bin ich natürlich auch an einer anderen Lösung
interessiert.
>Meine Frage also: Wie schickt ihr Daten aus dem Speicher der genau>gespiegelt auf der Emfangsseite ankommen muss.
Byteweise, dann gibts kein Problem mit Alignment.
Alternativ im ASCII Code. Braucht halt etwas länger.
Wenn die Bytereihenfolge gleich ist, also immer das unterste Byte einer
Variablen vorangeht, dann musst du dafür sorgen, dass keine
automatischen Füllbytes eingefügt werden. Dass also auch ohne diese alle
Variablen an ihrer natürlichen Grenze anfangen.
Entweder du sortierst die Struktur entsprechend, so dass dies nicht
vorkommt (Elemente der Grösse nach absteigend sortieren), oder du füllst
die Füllbytes selber explizit in die Strukturdefinition ein.
Alternativ kannst du versuchen alle beteiligen Compiler dazu zu bringen,
die Struktur dicht zu packen. Kann allerdings sein, dass nicht alle das
können, und üblicherweise kostet das deutlich Performance beim Zugriff.
@holger
Byteweise schicke ich ja ohnehin, da ich aber nicht feststellen kann wo
er jetzt Füllbytes einfügt habe ich ja das Henne ei Problem.
@A.K ok, habe ich ja auch herausgefunden, ist aber echt nicht schön,
alles zu ordnen, da sich dann kein logischer zusammenhang mehr ergibt,
zumindest nicht immer.
Selber Füllbytes einfügen ist zu kritisch, finde ich, hatte so ein
bißchen auf einen Art Pflichtanweisung gehofft die es ermöglicht das
immer richtig geordnet wird.
Anton schrieb:> bißchen auf einen Art Pflichtanweisung gehofft die es ermöglicht das> immer richtig geordnet wird.
Pflicht ist dies nicht, weil nicht im C Standard vorgesehen, aber
entsprechende compilerabhängige Attribute/Pragmas/... finden sich in
etlichen Compilern.
NB: Was ist für dich "richtig"? Gepackte Strukturen sind im Zugriff oft
langsam und codeintensiv. x86 kann das zwar in HW, aber bremsen tut es
dennoch.
>@holger>Byteweise schicke ich ja ohnehin, da ich aber nicht feststellen kann wo>er jetzt Füllbytes einfügt habe ich ja das Henne ei Problem.
Nö.
uint16_t var1 = 0x1234;
Sendbyte((uint8_t) (var1)); // Lowbyte
Sendbyte((uint8_t) (var1 >> 8)); // Highbyte
uint32_t var2 = 0x12345678;
Sendbyte((uint8_t) (var2));
Sendbyte((uint8_t) (var2 >> 8));
Sendbyte((uint8_t) (var2 >> 16));
Sendbyte((uint8_t) (var2 >> 24));
Damit ist immer die Reihenfolge der Bytes klar.
Alignment ist so egal. Bigendian oder Littleendian
spielt keine Rolle mehr. Alles ist geregelt.
Kannst du so auch auf Members von Structs machen.
Wenn du ein Struct ohne Rücksicht auf Alignment
oder Endianness versendest dann hast du die Arschkarte
gezogen.
holger schrieb:> Damit ist immer die Reihenfolge der Bytes klar.> Alignment ist so egal. Bigendian oder Littleendian> spielt keine Rolle mehr. Alles ist geregelt.> Kannst du so auch auf Members von Structs machen.
Das ist zweifellos der portabelste und sicherste Weg. Ob er hier
sinnvoll ist hängt vom geforderten Durchsatz ab, nicht immer ist das
praktikabel.
WOW, wie gesagt, man kann natürlich alles einzeln übertragen, dann ist
der Weg auch nicht weiter. Aber wenn man schon DMA hat und 20K in einer
Wurst übertragen will ist dann nicht mehr so schon.
Das Fachwort ist Aligment, wenn man es kennt kann man ja auch danach
such und sieht das andere auch selbiges Problem haben.
@A.K. Habe auf der Emfängerseite ein x86 Derivat, der Byteweise keine
Probleme hat.
Überlege nun alles INTs zu nehmen statt der chars, aber bläht meine
arrays ganz schön auf.
>Das ist zweifellos der portabelste und sicherste Weg. Ob er hier>sinnvoll ist hängt vom geforderten Durchsatz ab, nicht immer ist das>praktikabel.
Klar, für GCC kann man das z.B. so machen
struct PartInfo {
} __attribute__((packed));
Visual C
#pragma pack(push)
#pragma pack(1)
struct WaveHeader {
};
#pragma pack(pop)
Die Frage ist nur: Was ist das kleinere Übel?
Anton schrieb:> @A.K. Habe auf der Emfängerseite ein x86 Derivat, der Byteweise keine> Probleme hat.
Rechne damit, dass Zugriffe auf eine gepackte Struktur auch bei x86 ein
Vielfaches langsamer sind als auf eine ungepackte, ganz besonders wenn
sehr zeitnah geschrieben und gelesen wird. Ob das für dich eine Rolle
spielt hängt davon ab, wie intensiv sie so genutzt werden.
Hallo A.K.
Das ist OK, da der Prozessor "nur" so arbeitet wie in der Doku steht.
Ich habe zum Glück genügend Zeit die Nachrichten zu verschicken. Der
eigendliche Sendevorgang läuft über einen genügend großen Puffer.
Habe auf der gcc Seite nun "__attribute__((packed))" zugefügt und alles
funktioniert. Schöne Sache wenn mans weiß.
Danke für die Antworten.