Forum: Mikrocontroller und Digitale Elektronik FatFs Daten falsch herum


von Paul G. (paul_g210) Benutzerseite


Lesenswert?

Hallo

Ich habe ein vermutlich dusseliges Problem beim Schreiben von Binärdaten 
auf eine MicroSD via FatFs (STMF469DISCO).

Problem:

Die Daten auf der SD Karte sind alle falsch herum, also als LSB 
sozusagen.
1
// Daten im sortarray (MSB)
2
11FFFE00
3
120003A0
4
130005A0
5
...
6
// Daten auf der SD Karte
7
00 FE FF 11 A0 03 00 12 A0 05 00 13 ...


Ich lese die Daten von einem IC (ADAS1000) via SPI-DMA in einen Double 
Buffer, also zwei uint16_t rx_arrays[43000] die ich dann abwechselnd 
auswerte (sortiere) während ich den anderen neu befülle.

Beim sortieren verwerfe ich unwichtige Bytes und setze immer zwei 
uin16_t's zusammen zu einem uint32_t weil die Daten an sich 32bit sind.

Die sortieren Daten fülle ich dann in ein uint32_t sortarray[16384] und 
sobald dieses voll ist schreibe ich es komplett per
1
f_write(&fil, sortarray, 16384, &bw);
auf die SD Karte. Das funktioniert auch alles bis auf das Problem das 
die Daten falsch herum sind.

Kann es sein das es keine gute Idee ist f_write mit einem uint32_t 
buffer zu füttern?

von Falk B. (falk)


Lesenswert?

Paul G. schrieb:
> Kann es sein das es keine gute Idee ist f_write mit einem uint32_t
> buffer zu füttern?

Doch, aber man sollte schon mal über das Thema little/big endian 
nachdenken. f_write betrachtet die Daten als Bytearray. Aber da f_read 
das genau so macht, liegt der Fehler mit 99% bei dir, du machst beim 
Zusammensetzen vermutlich einen Fehler. Generiere normale 32 Bit Daten, 
gib sie per UART etc. aus, schreib sie auf SD-Card, lies zurück und zeig 
sie noch mal an.

von Paul G. (paul_g210) Benutzerseite


Lesenswert?

Falk B. schrieb:
> du machst beim
> Zusammensetzen vermutlich einen Fehler.

Okay, dann folgender Test: Ein einfaches Array
1
uint32_t testarray[3];
2
...
3
testarray[0] = 0x11223344;
4
testarray[1] = 0x12223344;
5
testarray[2] = 0x13223344;
6
7
f_write(&fil, testarray, sizeof(testarray), &bw);

Auch hier sind die Daten verdreht auf der Karte, ohne das ich irgendwas 
sortiert oder geändert habe...
1
44 33 22 11  44 33 22 12  44 33 22 13

: Bearbeitet durch User
von N. M. (mani)


Lesenswert?

Ich weiß nicht was du hast, aber die sind doch nicht verdreht.
Die 0x44 liegt bei testarray[0] auf der niedrigsten Adresse. Also wird 
dies auch zuerst geschrieben. Passt doch.

Wenn du das anders rum haben möchtest brauchst du es ja nur umzudrehen.

von AVerr (Gast)


Lesenswert?

Paul G. schrieb:
> Auch hier sind die Daten verdreht auf der Karte, ohne das ich irgendwas
> sortiert oder geändert habe...

Die Antwort dazu hat Falk schon gegeben:
Falk B. schrieb:
> Doch, aber man sollte schon mal über das Thema little/big endian
> nachdenken. f_write betrachtet die Daten als Bytearray.

Deine uint32_t werden in little endian gespeichert, f_write will jedoch 
ein bytearray. Damit liest f_write die Daten einfach byteweise ohne auf 
Endianness zu achten.

von Falk B. (falk)


Lesenswert?

Paul G. schrieb:
> Auch hier sind die Daten verdreht auf der Karte, ohne das ich irgendwas
> sortiert oder geändert habe...
> 144 33 22 11  44 33 22 12  44 33 22 13

Nein, dein STM ist halt eine little endian machine (wie die meisten 
CPUs), sprich das niederwertigste Byte steht an der niedrigsten Adresse. 
Damit ist das Ergebnis vollkommen OK.

von Paul G. (paul_g210) Benutzerseite


Lesenswert?

AVerr schrieb:
> Deine uint32_t werden in little endian gespeichert, f_write will jedoch
> ein bytearray. Damit liest f_write die Daten einfach byteweise ohne auf
> Endianness zu achten.

Okay, also dann kann ich meine Daten gleich in ein Bytearray (uint8_t) 
einsortieren und mache es nur entsprechend größer? Oder ich passe beim 
sortieren in ein uint32_t gleich die Endianess an?

Gibt es dann eigentlich einen Unterschied ob ich f_write mit einem 
uint8_t array oder mit einem uint32_t array füttere?

: Bearbeitet durch User
von AVerr (Gast)


Lesenswert?

Paul G. schrieb:
> Okay, also dann kann ich meine Daten gleich in ein Bytearray (uint8_t)
> einsortieren und mache es nur entsprechend größer? Oder ich passe beim
> sortieren in ein uint32_t gleich die Endianess an?

Beides geht, aber ist eigentlich nicht nötig: Wenn du die Daten wieder 
von der Karte liest und in ein uint32_t verwandelst kriegst du wieder 
deine Ausgangszahl. Du musst also eigentlich nichts großartiges tun, nur 
akzeptieren dass für deinen ARM Zahlen halt anders rum aussehen als du 
denkst :)

Paul G. schrieb:
> Gibt es dann eigentlich einen Unterschied ob ich f_write mit einem
> uint8_t array oder mit einem uint32_t array füttere?

Je nach Endianness der Maschine: ja, wie du gerade gesehen hast.

von Paul G. (paul_g210) Benutzerseite


Lesenswert?

Okay vielen dank. Dann lasse ich die Daten so und kümmere mich wirklich 
erst darum wenn ich die Daten von der SD Karte auf dem PC auswerte.

Was mich irgendwie verwirrt hat ist wenn ich im Debug Mode ein 
Breakpoint gesetzt habe nach dem das uint32_t Array gefüllt war und mir 
das Array angeschaut habe (CubeIDE) waren die Werte alle in Big Endian 
angezeigt.

von Falk B. (falk)


Lesenswert?

Paul G. schrieb:

> Okay, also dann kann ich meine Daten gleich in ein Bytearray (uint8_t)
> einsortieren und mache es nur entsprechend größer?

Kann man machen.

> Oder ich passe beim
> sortieren in ein uint32_t gleich die Endianess an?

Das ist nur dann sinnvoll und nötig, wenn das Datenformat, welches du 
schreiben willst mit big endian vorgegeben ist. Wenn es das nicht ist, 
und nur du selber deine Daten wieder lesen willst, ist das nicht nötig. 
Ein PC arbeitet auch mit Little endian. Big endian ist eher selten, bei 
68k, PowerPC etc. Einzige Ausnahme. Network order, wie z.B. bei Ethernet 
oder TCP/IP, dort herrscht big endian.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Paul G. schrieb:
> Okay, also dann kann ich meine Daten gleich in ein Bytearray (uint8_t)
> einsortieren und mache es nur entsprechend größer?

Ja.

> Oder ich passe beim
> sortieren in ein uint32_t gleich die Endianess an?

Ja.

> Gibt es dann eigentlich einen Unterschied ob ich f_write mit einem
> uint8_t array oder mit einem uint32_t array füttere?

Du solltest einfach bedenken: f_write fasst das Argument immer als 
Pointer auf ein Byte-Array auf - egal, was Du ihm übergibst.

P.S.

Du solltest auch beachten, welches Target-System diese Datei dann wieder 
liest. Wenn es ein System mit little Endianess (z.B. PC) ist, wäre das 
Speichern mit LSB first auf der SD-Karte gar nicht so verkehrt. Ob LSB 
first oder MSB first auf der SD-Karte "richtig" ist, entscheidest Du 
selbst.

MSB first empfindest Du als Mensch vielleicht "richtiger". Aber das 
solltest Du dabei ausblenden, das hat nur damit zu tun, wie Du im 
Dezimalsystem gelernt hast, die Ziffern zu Zahlen aneinanderzureihen.

: Bearbeitet durch Moderator
von Georg (Gast)


Lesenswert?

Paul G. schrieb:
> wenn ich im Debug Mode ein
> Breakpoint gesetzt habe nach dem das uint32_t Array gefüllt war und mir
> das Array angeschaut habe

Wenn du im Debug Mode einen hex Editor benutzt musst du auf jeden Fall 
in der Big/Little-Endian-Frage firm sein und auch in der 
Speicherbelegung aller möglichen Datentypen, das ist halt hard core 
binär. Sonst kannst du da keine Daten "lesen". Gleitkommavariable sind 
noch viel komplizierter.

Georg

von jo mei (Gast)


Lesenswert?

Paul G. schrieb:
> Okay vielen dank. Dann lasse ich die Daten so und kümmere mich wirklich
> erst darum wenn ich die Daten von der SD Karte auf dem PC auswerte.

Man könnte die Endianess Problematik auch dadurch umgehen dass
man seine Zahlenwerte in ASCII auf Textdatei oder ähnliches
schreibt. Minimaler Geschwindigkeitsnachteil ....

von c-hater (Gast)


Lesenswert?

jo mei schrieb:

> Man könnte die Endianess Problematik auch dadurch umgehen dass
> man seine Zahlenwerte in ASCII auf Textdatei oder ähnliches
> schreibt. Minimaler Geschwindigkeitsnachteil ....

So "minimal" ist der garnicht. Einerseits brauchen Zahlen in ASCII 
wesentlich mehr Platz, bei 32Bit-Werten grob über den Daumen das 2,5 
fache (bei dezimaler Darstellung). Die Speicherung selber ist damit 
schonmal um eben diesen Faktor langsamer.

Dazu kommt aber auch noch, dass die Zahlen, die im Rechner meistens in 
binärer Form vorliegen, erstmal vor der Speicherung noch gewandelt 
werden müssen. Das kostet auch Rechenzeit. Hier kann nichtmal ein Faktor 
angegeben werden, denn mit Null verglichen, bekommt man immer unendlich 
raus...

von Christian J. (Gast)


Lesenswert?

c-hater schrieb:
> Dazu kommt aber auch noch, dass die Zahlen, die im Rechner meistens in
> binärer Form vorliegen, erstmal vor der Speicherung noch gewandelt
> werden müssen.

Ich mache das tausendfach auf meiner SD Karte vom STM32 aus. Wo ist das 
Problem? Man sichert ganze Structs einfach ab mit f_write(&struct...., 
sizeof struct(....)); Und liest das Ganze auch komplett wieder zurück 
als Struct direkt in die Struktur ein. Da steht alles wo es soll. Wie 
die Maschine das macht spielt für den Programmierer normalerweise 
überhaupt kein Rolle, wenn er nicht auf Bitebene rumspielt.

von jo mei (Gast)


Lesenswert?

Christian J. schrieb:
> Wie
> die Maschine das macht spielt für den Programmierer normalerweise
> überhaupt kein Rolle, wenn er nicht auf Bitebene rumspielt.

Käse.

Die Endianess Problematik bleibt durch Anlegen einer Struct
genau so erhalten.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

jo mei schrieb:
> Die Endianess Problematik bleibt durch Anlegen einer Struct
> genau so erhalten.

Das Alignment spielt da auch noch eine Rolle.

von Wolfgang (Gast)


Lesenswert?

Für C++ Nutzer könnte Boost Endian interessant sein:

https://www.boost.org/doc/libs/1_76_0/libs/endian/doc/html/endian.html

von c-hater (Gast)


Lesenswert?

Christian J. schrieb:

> c-hater schrieb:
>> Dazu kommt aber auch noch, dass die Zahlen, die im Rechner meistens in
>> binärer Form vorliegen, erstmal vor der Speicherung noch gewandelt
>> werden müssen.
>
> Ich mache das tausendfach auf meiner SD Karte vom STM32 aus. Wo ist das
> Problem? Man sichert ganze Structs einfach ab mit f_write(&struct....,
> sizeof struct(....)); Und liest das Ganze auch komplett wieder zurück
> als Struct direkt in die Struktur ein. Da steht alles wo es soll. Wie
> die Maschine das macht spielt für den Programmierer normalerweise
> überhaupt kein Rolle, wenn er nicht auf Bitebene rumspielt.

Du hast offensichtlich nicht begriffen, worum es ging. Das war der 
Vorschlag, den Kram für die Speicherung als ASCII-Text aufzubereiten, 
statt es binär zu speichern. Und mein einwand zeigte auf, dass das nicht 
so billig ist, wie der Vorschlagende behauptet hat.

Naja, wer lesen kann, ist irgendwie klar im Vorteil...

von Wolfgang (Gast)


Lesenswert?

Frank M. schrieb:
> MSB first empfindest Du als Mensch vielleicht "richtiger".

Gutes Beispiel ist das in Deutschland meist verwendete Datumsformat
<TT.MM.JJJJ>. Least significant Value first für Tag, Monat Jahr, most 
significant digit first innerhalb der Zahlen.

Der Mensch empfindet unlogisch.

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
Noch kein Account? Hier anmelden.