Moin!
Ich versuche seit Freitag Vormittag die CRC Peripherie des STM32F103C8T6
ans laufen zu bekommen, wobei ans laufen zu bekommen ist nicht ganz
richtig. Laufen tut sie schon jedoch kann ich das Ergebnis welches mir
die CRC-Engine liefert nicht bestätigten.
Habe mich ein bisschen mit CRC auseinander gesetzt, aber egal was ich
versuche ich schaffe es nicht den CRC Wert zu überprüfen.
Folgendes habe ich vor: Ein Programm, welches noch in Java geschrieben
werden muss, sendet in einem bestimmten Interval(250-1000ms) immer
wieder ein Haufen an Datenpaketen an den Mikrocontroller der diese dann
verarbeitet. Um Fehler in der Übertragung zu erkennen wollte ich das
ganze mit CRC32 machen, da dieses per Hardware im STM32 implementiert
ist. Dabei würde ich dann über die Daten eine CRC32 berechnen und diese
dann nachträglich an die Daten hängen und übertragen. Der
Mikrocontroller bastelt das dann alles aus einander und rechnet selber
die CRC32 nochmal aus und wenn die passt alles gut wenn nicht wird
erneut angefordert.
Ich habe von STM32 die Application Note "AN4187" gefunden und
durchgelesen diese beschreibt wie man die CRC Einheit in den
Mikrocontroller verwendet. Ich habe euch zwei Bilder davon angehängt
einmal das "CRC Algorithm flowchart" und "CRC Peripheral Features".
So wie ich das sehe wird die CRC32 (nach dem CRC Peripheral Features
Tabelle) mit folgenden Einstellungen berechnet:
Startwert: 0xFFFFFFFF (fix im F1)
Polynom : 0x04C11DB7 (fix im F1)
Kein Reflektieren der Eingangs/Ausgangsdaten
Kein Final XOR am Ende
Ich habe für den Wert 0x1F7463AB(zufällig gewählt) die CRC32 wie folgt
berechnen lassen im STM32:
1
RCC->AHBENR |= RCC_AHBENR_CRCEN; //Enable CRC
2
CRC->CR |= CRC_CR_RESET; //Reset CRC to 0xFFFFFFFF
3
CRC->DR = 0x1F7463AB; //Input Data. Start Calc
4
uint32_t strCRC = CRC->DR; //Get CRC32
Das Ergebnis ist 0x3A56D979 als CRC32-Prüfsumme. Auf mehreren Webseiten,
Foren und auch YouTube Videos wurde immer erwähnt das man das Ergebnis
mit dem "CRC-32/MPEG-2" Standard vergleichen soll jedoch ist die CRC32
bei MPEG2: 0x4BC4C523
(https://crccalc.com/?crc=0x1F7463AB&method=crc32&datatype=hex&outtype=hex)
In der Application Note wurde ja auch ein CRC Algorithm flowchart
dargestellt. Ich vermute jetzt mal das die CRC Peripherie nach diesen
Schema die CRC32 berechnet. Also habe ich eine C-Funktion geschrieben
die nach diesem Flowchart arbeitet:
1
uint32_t crc32(uint32_t data) {
2
uint32_t crc = 0xFFFFFFFFUL; //CRC with Initial Value
3
crc ^= data; //XOR with Inital Value and Input Data
4
5
for(uint8_t i = 0; i < 32; i++) { //Go through all 32 Bits of Input Data
6
if(crc & 0x8000L) { //If MSB 1?
7
crc = (crc << 1) ^ 0x04C11DB7UL;//Shift left by one and XOR with Polynormial
8
}else{ //MSB is 0
9
crc <<= 1; //Shift left by one
10
}
11
}
12
return crc;
13
}
Jedoch liefert mir die Funktion bei einen Dateneingang von 0x1F7463AB
ein CRC Wert von 0x4E40D245. Da sollte ja eigentlich der gleiche Wert
rauskommen wie bei der STM32 Peripherie, sofern ich das richtig
umgesetzt habe mit der Funktion glaube aber wohl weil in der App Note
auch ein Binäres Beispiel drin steht.
Dort soll als CRC 0x4C rauskommen Initial ist 0xFF, Input Data ist 0xC1
und Polynom ist 0xCB. Wenn ich das dort eingebe und die Funktion auf 8
Bit abändere bekomme ich als Ergebnis 0x4C raus passt.
Ich weiß nicht mehr weiter. Egal was ich versuche ich komme nicht auf
die gleiche Prüfsumme.
Habt ihr ne Idee woran das liegen kann? Oder vllt. selbst schonmal mit
der Hardware CRC Engine im STM32 gearbeitet?
Mfg
Wenn das so im Code steht, solltest du ein __DSB(); dazwischen einfügen,
um darauf zu warten, dass die CRC-Peripherie auch wirklich an ist bevor
du darauf zugreifst. Siehe auch
Beitrag "STM32F1: Wartezyklus nach Clock-Enable im RCC" .
Programmierer schrieb:> Wenn das so im Code steht, solltest du ein __DSB(); dazwischen einfügen,> um darauf zu warten, dass die CRC-Peripherie auch wirklich an ist bevor> du darauf zugreifst. Siehe auch
Hallo, ja ist 1:1 raus kopiert. Ich habe das __DSB(); mal eingefügt.
Dieses hat kein Unterschied gemacht. Jedoch hast du mich da auf eine
Idee gebracht. Ich habe mal einfach zwischen jeder Codezeile ein
__NOP(); eingefügt und tatsächlich funktioniert es nun.
Ein __NOP(); zwischen CRC->CR |= CRC_CR_RESET; und den eigentlichen
Einfügen der Daten ins Datenregister der CRC.
Hatte dieses Problem schonmal bei einer anderen Peripherie glaube es war
I2C. Die CRC Engine läuft ja nicht auf 72 MHz wie die CPU da wird das
Datenreinschieben ins Datenregister wahrscheinlich schneller gewesen
sein als die CRC selbst das Register auf 0xFFFFFFFF zurückgesetzt hat.
Jetzt bekomme ich bei 0x1F7463AB Dateneingang ein CRC32 Wert von
0x4BC4C523. Passt.
A. B. schrieb:> Das testet Bit 15, nicht Bit 31.
Oh nein, verdammt nicht wirklich. (facepalm) Das ist das wenn man sich
das ganze erst selbst zusammenbastelt dann mit anderen Codebeispielen
vergleicht und rumexperimentiert .... Ich habe es auf 0x80000000
abgeändert. Nun liefert meine selbst geschrieben C-Funktion nach dem
Flowchart auch das richtige Ergebnis von 0x4BC4C523. Danke
Irgend W. schrieb:> Da war noch was mit big/little endian (wenn man kein byte-array nimmt):
Ja diesen Beitrag bei Stackoverflow hatte ich auch schon gelesen
gemacht. Der Code soll die CRC Berechnung in das "richtige" CRC32 Format
bringen mit Final XOR 0xFFFFFFFF und Reflektierten Eingangs und
Ausgangsdaten. Hatte ich aber noch nicht getestet.
Ja also meine Hauptfragen warum das ganze nicht funktioniert hat sind
beantwortet. Vielen dank an euch!
Hätte aber nochmal eine andere Frage. In Java gibt es eine vorerstelle
Klasse die sich "CRC32" nennt diese berechnet ein CRC32 Wert nach dem
ZIP CRC Standard. Habs ausprobiert es ist mit Startwert 0xFFFFFFFF,
Final XOR 0xFFFFFFFF und Reflektieren Daten an Ein und Ausgang.
Ich würde jetzt meine C Funktion einfach in Java implementieren dann
würden die richtigen Checksummen gebildet werden mit Java die dann auch
geprüft werden können vom Mikrocontroller ohne groß jetzt noch die Daten
der CRC-Engine nachträglich "nachzubearbeiten". Da der PC deutlich
schneller ist als der Mikrocontroller sollte es keine große Rolle
spielen wie lange die CRC Berechnung im Java Programm nachher dauert.
Hat das Reflektieren der Ein/Ausgangsdaten bzw. Final XOR irgendwelche
Vorteile der gegenüber der oben geposteten C-Funktion? Ich habe mal
gelesen das teilweise manche Peripherie Module wie SPI/USART die Daten
teils nur reflektiert ausgeben.
Mfg
Felix N. schrieb:> Ein __NOP(); zwischen CRC->CR |= CRC_CR_RESET; und den eigentlichen> Einfügen der Daten ins Datenregister der CRC.
Verwende lieber DSB, das ist genau dafür da. NOP funktioniert hier eher
zufällig, und nicht unbedingt immer konsistent.
Programmierer schrieb:> RCC->AHBENR |= RCC_AHBENR_CRCEN;> CRC->CR |= CRC_CR_RESET;> Wenn das so im Code steht, solltest du ein __DSB(); dazwischen einfügen,> um darauf zu warten, dass die CRC-Peripherie auch wirklich an ist bevor> du darauf zugreifst.
Da muss ich mal nachhaken. Ich habe bei STM32L0, F1 und F3 schon oft
ähnliche Kombinationen von Register-Zugriffen gehabt und dabei noch nie
DSB benötigt. Nun denke ich mir nach deine Info, dass ich vielleicht
einfach nur Glück hatte. Aber: Die Code-Beispiele und HAL Code von ST
machen es nicht anders. Auch da habe ich DSB noch nicht gesehen.
Mir ist auch nicht klar, was es hier nützen soll. Sowohl die RCC
Register als auch die CRC Register hängen am AHB Bus. Soweit ich
verstehe überlappen sich aufeinanderfolgende Zugriffe auf dem selben Bus
niemals. Selbst wenn die CRC Einheit an einem langsamen APB1/2 Bus
hängen würde, gäbe es kein Problem, weil der Weg dorthin durch den AHB
Bus führt.
Überlappende Zugriffe sind meiner Meinung nach nur möglich, wenn ich
direkt nacheinander auf APB1 und APB2 (oder anders herum) zugreife.
Habe ich etwas übersehen?
Felix N. schrieb:> Hallo, ja ist 1:1 raus kopiert. Ich habe das __DSB(); mal eingefügt.> Dieses hat kein Unterschied gemacht.
Wundert mich nicht, siehe mein vorheriger Beitrag.
> Ein __NOP(); zwischen CRC->CR |= CRC_CR_RESET; und den eigentlichen> Einfügen der Daten ins Datenregister der CRC.
Schauen wir mal, wie dieses Bit dokumentiert ist: "Resets the CRC
calculation unit and sets the data register to 0xFFFF FFFF.
This bit can only be set, it is automatically cleared by hardware."
Ich würde sagen, du musst warten, bis die Hardware das Bit wieder
ge-cleared hat. Das ein NOP hier Genügt, ist Glück.
Felix N. schrieb:> Hätte aber nochmal eine andere Frage. In Java gibt es eine vorerstelle> Klasse die sich "CRC32" nennt diese berechnet ein CRC32 Wert nach dem> ZIP CRC Standard.
Der wiederum auf ISO3309 (HDLC) und V.42 verweist.
> Habs ausprobiert es ist mit Startwert 0xFFFFFFFF,> Final XOR 0xFFFFFFFF und Reflektieren Daten an Ein und Ausgang.
Laut
https://reveng.sourceforge.io/crc-catalogue/all.htm#crc.cat.crc-32-iso-hdlc>> width=32 poly=0x04c11db7 init=0xffffffff refin=true refout=true>> xorout=0xffffffff check=0xcbf43926 residue=0xdebb20e3>> name="CRC-32/ISO-HDLC"
Also ja, sollte stimmen.
> Hat das Reflektieren der Ein/Ausgangsdaten bzw. Final XOR irgendwelche> Vorteile der gegenüber der oben geposteten C-Funktion? Ich habe mal> gelesen das teilweise manche Peripherie Module wie SPI/USART die Daten> teils nur reflektiert ausgeben.
Ja, das Reflektieren soll von Hardware-CRCs in UARTs stammen. UARTs
schieben das niederwertigste Bit eines Datums zuerst auf die Leitung.
Berechnet man eine CRC direkt auf diesem Bitstrom rechnet man auf
reflektierten Daten. Das Reflektieren in Software, bzw. reflektierte
Algorithmen sorgen für Kompatibilität mit direkt aus Bitströmen
berechneten CRCs.
Wenn man Sende- und Empfangsseite in Software macht braucht man das
nicht, aber es ist irgendwie hängen geblieben.
Das abschließende XOR hat einen ähnlichen Grund wie das anfängliche XOR.
Allerdings sichert es einen obskuren Fehlerfall ab. Nämlich wenn aus
irgend einem Grund den Daten und der CRC bei der Übertragung noch
Müll-Daten angefügt wurden und man das korrekte Frame-Ende nicht erkannt
hat.
Also statt einem Frame wie
<Daten> <CRC>
etwas wie
<Daten> <CRC> <Müll>
Wenn dann die Müll-Daten noch alles Null-Bytes sind, dann ergibt die
normale CRC-Berechnung ohne abschließendes XOR trotzdem eine gültige
CRC.
Programmierer schrieb:> Verwende lieber DSB, das ist genau dafür da. NOP funktioniert hier eher> zufällig, und nicht unbedingt immer konsistent.
Alles klar.
Stefan ⛄ F. schrieb:> Ich würde sagen, du musst warten, bis die Hardware das Bit wieder> ge-cleared hat. Das ein NOP hier Genügt, ist Glück.
Ich weiß nicht wie oft ich das Datenblatt im Abschnitt "CRC" gelesen
habe es ist mir nicht aufgefallen das das Bit von der Hardware gelöscht
wird und man darauf warten könnte. Habs wohl immer überflogen.
Stefan ⛄ F. schrieb:> Aber: Die Code-Beispiele und HAL Code von ST> machen es nicht anders.
Später nachdem es Freitag Vormittag + Mittag nicht geklappt hat habe ich
am Abend mir den HAL Code für CRC angeschaut und mich daran ein bisschen
gehalten. Hab auch alles gefunden außer ein Makro der die CRC
zurücksetzt. Wahrscheinlich wäre mir das warten auf das Bit dann
aufgefallen.
Noch mal eine Frage zu CRC generell:
Wenn ich jetzt doch den STM32 so laufen lassen will das er mir ein
CRC32-ZIP generiert muss ich ja noch die Daten Final XORn mit 0xFFFFFFFF
und die Eingangs und Ausgangsdaten reflektieren.
Das final XOR ist ja recht einfach mit (... ^ 0xFFFFFFFFUL) gemacht.
Aber wie genau ist das mit den Reflektieren wird da einfach nur die
Bitreihe umgekehrt? Sprich:
0000 0101 -> 0x05 (Original)
1010 0000 -> 0xA0 (Reflektiert)
? Oder wie Reflektiert man das?
//EDIT:
Hannes J. schrieb:> Das abschließende XOR hat einen ähnlichen Grund wie das anfängliche XOR.> Allerdings sichert es einen obskuren Fehlerfall ab. Nämlich wenn aus> irgend einem Grund den Daten und der CRC bei der Übertragung noch> Müll-Daten angefügt wurden und man das korrekte Frame-Ende nicht erkannt> hat.
Achso okay. Ja dann ist doch noch sinnvoll mit zu machen. Lässt sich ja
leicht umsetzten.
Hannes J. schrieb:> Ja, das Reflektieren soll von Hardware-CRCs in UARTs stammen. UARTs> schieben das niederwertigste Bit eines Datums zuerst auf die Leitung.
Ja genauso oder in etwa hatte ich das in irgendein Blog über CRC
Berechnungen und umsetzten und C-Code gelesen gehabt.
Hannes J. schrieb:> Also ja, sollte stimmen.
Gut
Mfg
Hannes J. schrieb:> Das abschließende XOR hat einen ähnlichen Grund wie das anfängliche XOR.> Allerdings sichert es einen obskuren Fehlerfall ab.
Daß das im STM32 nicht drin ist, dürfte wohl im Hinblick auf
Bufferlängen sein, die nicht durch 4 teilbar sind. Das
CRC-Eingangsregister ist ja immer 32 Bit weit, und so kann man die
"überflüssigen" letzten 1-3 Byte als Nullbytes reinhängen. Ein
abschließendes XOR muß man dann manuell machen.
Felix N. schrieb:> Aber wie genau ist das mit den Reflektieren wird da einfach nur die> Bitreihe umgekehrt?
Ja genau, siehe hier (reverse):
https://en.wikipedia.org/wiki/Mathematics_of_cyclic_redundancy_checks
Bei "normal" ist links im Bit 16 der höchste Koeffizient, der bei der
Hex-Darstellung implizit ist und weggelassen wird. Bei "reverse" wird
dasselbe Bit weggelassen, es ist immer noch Bit 16, nur steht es
gespiegelterweise jetzt ganz rechts.
Der Unterschied zum reziproken Polynom ist der, daß dabei das volle
Polynom (also mit 17 Bit dargestellt) ebenfalls gespiegelt wird, aber
anders als bei reverse beim reziproken nicht das neue rechteste Bit,
sondern das linkeste weggelassen wird, d.h. das niederwertigste aus der
normalen Form und nicht das alte (und implizite) höchstwertige.
Du hast bei der STM32 CRC ein paar implementationsprobleme, die daher
rühren, dass die CRC 32bit-Wortweise arbeitet.
Der STM schiebt quasi Bit 31 zuerst in die CRC und als letztes bit 0 des
Datenworts. Wenn du jetzt 4 Bytes aus dem Speicher nimmst, sind die aber
wegen dem little endian layout so angeordnet: [7...0] [15...8] [23...16]
[31.. 24]
Da muss man aufpassen, wenn man den Datenstream auf einem Rechner bspw.
byteweise verrechnet. Während du bspw. in Python o.ä.
Byte0 Byte1 Byte2 Byte3 Byte4 Byte5 Byte6 Byte7...
in die CRC nacheinander schieben kannst, muss du darauf achten, dass der
STM, wenn du die obige Folge hast, jedes 32 bit Wort gespiegelt
ausließt. Es würde somit folgendes in die CRC wandern:
1
Byte3 Byte2 Byte1 Byte0 Byte7 Byte6 Byte5 Byte4
2
|---- Wort 1 ----------|--------Wort 2---------|
In Python nutze ich für die STM32F4 CRC folgenden Code:
be_data = bytearray([0 for k in range(0, len(data))])
9
# Rearrange data, because the STM controller sees it as 32 bit little endian words
10
for i in range(0, int(len(data)/4)):
11
be_data[i*4+0] = data[i*4+3]
12
be_data[i*4+1] = data[i*4+2]
13
be_data[i*4+2] = data[i*4+1]
14
be_data[i*4+3] = data[i*4+0]
15
16
return crc_calc(be_data)
Hier, wie gesagt auf das byte ordering aufpassen. Meine Funktion oben
dreht, bevor sie die Daten in die CRC schiebt alle 32 bit Worte um.
Wenn du einen C Code brauchst, der das wortweise mal testet: Der hier
funktioniert und nimmt wie der STM auch 32bit Worte:
Einfach die Funktion calculate_stm_crc() mit deinen Daten füttern.
EDIT:
Ich habe das jetzt mal mit deinem Testwert 0x1F7463AB gemacht. Ich komme
mit meinem C Progrämmchen auf den Wert: 0x4bc4c523.
Woher dien Wert kommt, kann ich nicht nachvollziehen. Mein Code
funktioniert bei mir für einen STM32F407. Der sollte gemäß Tabelle ja
dieselbe CRC-Einheit haben... Komisch.
EDIT2: Habe den Wert mal auf meinem STM32F407 durch die CRC unit laufen
lassen. Ergebnis: 0x4bc4c523.
Ist es sichergestellt, dass du die richtigen Werte in das Modul
schreibst und auch wieder richtig liest?
Oder das CRC Modul bei deinem F1 ist doch anders als meins...
Hallo,
Nop schrieb:> Ein> abschließendes XOR muß man dann manuell machen.
Das ist ja schnell gemacht.
Nop schrieb:> Bei "normal" ist links im Bit 16 der höchste Koeffizient, der bei der> Hex-Darstellung implizit ist und weggelassen wird. Bei "reverse" wird> dasselbe Bit weggelassen, es ist immer noch Bit 16, nur steht es> gespiegelterweise jetzt ganz rechts.
Ah okay. Ja ich muss sagen ich habe mich zwar Freitag und den ganzen
Samstag mit CRC beschäftig und habe auch ein zwei Berechnungen auf dem
Papier bei einer CRC-8 durchgeführt. Aber so tief bin ich da jetzt nicht
eingestiegen.
Aber um mal auf das reflektieren zurück zukommen würde man das dann so
machen?
1
uint32_t reflectBits(uint32_t data) {
2
uint32_t reflected = 0; //Holds the Reflect Value
3
4
for(uint8_t i = 0; i < 32; i++) { //Go through all Bits
5
if(data & (1<<(31-i))) { //Check if Last Bit - i is a 1
6
reflected |= (1<<i); //Put a 1 at i (reserved to input data)
7
}else{
8
reflected &= ~(1<<i); //Same for 0
9
}
10
}
11
12
return reflected; //Return Reflected Data
13
}
Also funktionieren tut diese Funktion so wie ich mir das vorgestellt
habe. Wenn ich das in Visual Studio Code ausführe und als Input 0xAA
oder 0x0000FFFF reingebe dann kommt für 0xAA 0x55 raus und bei FF
0xFFFF0000. Nur ist das jetzt richtig? Wenn ich das aus deinem Text
richtig verstanden habe wird das um das 16 Bit gespiegelt?
Nop schrieb:> reziproken Polynom
Also muss ich wenn ich die Daten reflektiere 0xDB710641 als Generator
Polynom nehmen anstatt 0x04C11DB7?
M. H. schrieb:> Wenn du jetzt 4 Bytes aus dem Speicher nimmst, sind die aber> wegen dem little endian layout so angeordnet: [7...0] [15...8] [23...16]> [31.. 24]
Woher weiß ich eigentlich ob die Daten jetzt nach little oder big endian
angeordnet sind? Ist das standardmäßig immer little endian?
M. H. schrieb:> In Python nutze ich für die STM32F4 CRC folgenden Code:
Ich habe jetzt von Python keine Ahnung, da später die PC Software von
mir in Java geschrieben wird habe ich meine CRC32 Berechnungsfunktion
mal in Java erstellt. In Java sind ein paar mehr Schritte nötig da es
kein "unsigned int" gibt der 32-Bit breit ist. int hat zwar 32-Bit breit
jedoch signed reicht also nicht. long ist mindestens 64-Bit breit jedoch
auch signed reicht für die CRC32. Meine sogar mal gelesen zu haben das
ein long ob Java SE 8 128-bit breit ist.
Falls es für jemanden relevant ist hier der Code für Java um eine CRC-32
zu berechnen die vom STM32 CRC Engine gleich berechnet wird:
1
public long crc32_stm32(long data) {
2
long crc = 0xFFFFFFFFL;
3
crc ^= data;
4
for(int i = 0; i < 32; i++) {
5
if((crc & 0x80000000L) != 0) {
6
crc = (crc << 1) ^ 0xDB710641L;
7
}else{
8
crc <<= 1;
9
}
10
}
11
crc ^= 0xFFFFFFFFL;
12
return crc & 0xFFFFFFFFL;
13
}
Hier ist jetzt noch ein final XOR mit eingebaut von 0xFFFFFFFF welches
ich bei dem STM32 auch eingebaut habe nach der eigentlichen Berechnung
der CRC von der Engine vom STM.
Wichtig ist hierbei zu beachten das & 0xFFFFFFFF bei dem return sonst
bekommt man ein 64-Bit langen Integer zurück wovon aber nur die ersten 8
Ziffern die CRC sind. Alternativ kann man auch (crc << 32) >> 32 machen.
Und das "L" Suffix an den Zahlen nicht vergessen sonst werden die wie
Integer behandelt und nicht wie longs. Hat mich gestern fast zwei
Stunden gekostet bis ich das gecheckt hatte.
Felix N. schrieb:> Jetzt bekomme ich bei 0x1F7463AB Dateneingang ein CRC32 Wert von> 0x4BC4C523. Passt.Felix N. schrieb:> Nun liefert meine selbst geschrieben C-Funktion nach dem> Flowchart auch das richtige Ergebnis von 0x4BC4C523.M. H. schrieb:> Woher dien Wert kommt, kann ich nicht nachvollziehen.
Was genau meinst du? Mittlerweile bekomme ich auch den richtigen Wert
von 0x4BC4C523 bei dem STM32 und meiner C-Funktion. Die Java Funktion
liefert auch den gleichen Wert wenn man das Final XOR weg lässt.
Oder reden wir da irgendwo aneinander vorbei?
M. H. schrieb:> Ist es sichergestellt, dass du die richtigen Werte in das Modul> schreibst und auch wieder richtig liest?
Denke schon. Zurücksetzten der CRC. Mit dem Bit in einer while Schleife
warten (Danke @stefanus) dann daten reinschieben und danach wieder
abholen.
Wüsste nicht was man da jetzt noch falsch machen könnte. Abgesehen von
der vorher gefehlten while Schleife.
M. H. schrieb:> Oder das CRC Modul bei deinem F1 ist doch anders als meins...
Also streng genommen habe ich kein STM32F103C8T6 sondern ein
CKS32F103C8T6 der auf ein Blue-Pill Board verbaut ist. Er ist zwar als
STM32 gelabelt hat aber eine andere ID und 128K an Flash anstatt 64K.
Aber bis jetzt hatte ich noch keine Sachen gefunden die damit nicht
gehen(oder anders funktionieren) im Gegensatz zum Original STM32.
Ich habe oben im Eröffnungsbeitrag ein Bild verlinkt wo die CRC
Peripherien in unterschiedlichsten STM Controllern aufgeführt sind für
den L1, F1, F2, F4 sind alle CRC Engines gleich nur der F0 und F3 sind
dort "leistungsstärker" weil man mehr einstellen kann wie Polynom,
Startwert ...
Mfg
Felix N. schrieb:> Woher weiß ich eigentlich ob die Daten jetzt nach little oder big endian> angeordnet sind? Ist das standardmäßig immer little endian?
Du schaust in das Datenblatt deines Controllers. Die meisten Systeme
sind little-endian. Dein Rechner (x86_64) ist auch little-endian.
Theoretisch kannst du die Cortex-Kerne von ARM auch alle als big-endian
synthetisieren. Mir ist aber bisher keiner untergekommen, der das so
macht.
In deinem Compiler aufruf für GCC müsste dementsprechend auch irgendwo
die Option "-mlittle-endian" auftauchen (sofern du GCC nutzt).
Felix N. schrieb:> Aber um mal auf das reflektieren zurück zukommen würde man das dann so> machen?
Wenn man's von Hand machen will, wäre das eine portable Möglichkeit. Das
Setzen der 0 in der Schleife ist aber unnötig, weil "reflected" ja schon
mit 0 vorinitialisiert ist. Normalerweise würde man das aber nicht
berechnen, sondern direkt als Konstante im Quelltext nutzen.
Wobei, eigentlich würde man auch die Polynom-Konstante so nicht im
Quelltext nutzen, sondern sich eine Lookup-Tabelle machen, d.h. wenn man
keine CRC in Hardware hat oder die HW-CRC nicht das gewünschte Polynom
kann. Entweder Byte-weise, das kostet 1kB ROM für CRC32, oder
Nibble-weise, das kostet 64 Bytes.
> Nur ist das jetzt richtig? Wenn ich das aus deinem Text> richtig verstanden habe wird das um das 16 Bit gespiegelt?
Das kommt nur, weil in dem Link beispielhaft mit einer CRC16 gearbeitet
wird. Für CRC32 wäre das also entsprechend um 32 Bit gespiegelt, und das
"implizite" weggelassene Bit, das immer 1 ist, ist dann Bit 32
(beginnend bei Bit 0 gezählt).
>> reziproken Polynom>> Also muss ich wenn ich die Daten reflektiere 0xDB710641 als Generator> Polynom nehmen anstatt 0x04C11DB7?
Reflektiert und reziprok sind was anderes. Bei reflektiert geht es um
dasselbe Polynom, nur daß man bei der Berechnung andersrum reinschiebt
und daher auch das Polynom bitweise andersrum hinschreibt. Das reziproke
Polynom ist ein tatsächlich anderes, das aber dieselben Eigenschaften
bezüglich Fehlererkennung hat.
> Woher weiß ich eigentlich ob die Daten jetzt nach little oder big endian> angeordnet sind? Ist das standardmäßig immer little endian?
Meistens ja, aber das liegt daran, auf welcher CPU Dein Code läuft.
Solange Deine Daten in Deiner Hardware bleiben, ist das auch meistens
egal - aber wenn Du welche nach außerhalb schickst oder von außerhalb
bekommst, muß man im Protkoll nachsehen, wie die Byte-order auf dem
Draht ist. Oft big endian ("network order").
Portablen Code rüstet man daher mit Funktionen Host_To_Network und
Network_To-Host (oder so) aus, die man immer aufruft, die aber auf einem
System, das dieselbe endianess wie das Protokoll auf dem Draht hat,
einfach nichts tun.
Hallo bambel2,
VIELEN DANK für den Tipp mit der Umwandlung ins Big-Endian-Format!!!
Damit klappt es natürlich.
Ich hätte mir beinahe die Zähne daran ausgebisse..
Gruß Gahlen