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
00FEFF11A0030012A0050013...
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?
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.
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.
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.
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.
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?
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.
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.
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.
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.
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
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 ....
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...
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.
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.
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...
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.