Forum: Mikrocontroller und Digitale Elektronik CRC durch uC berechnen lassen - Problem bei der Umsetzung


von CRC-hilfesuchender (Gast)


Lesenswert?

Hi Leute!

Ich möchte gerne Daten, welche ich über ein 1m langes Kabel in einem 
EEPROM speichere, mit einer Prüfsummer versehen.

Die generelle Vorgehensweise zum erstellen der Prüfsumme habe ich 
verstanden und das klappt auch.

Hier mal als Beispiel:

Daten:   0x3E (0011 1110)
Polynom: 0xA7 (1010 0111) (x^7 + x^5 + x^2 + x + 1)

Prüfsummer erstellen:
1
001111100000000
2
  10100111|||||
3
  --------|||||
4
  010111110||||
5
   10100111||||
6
   --------||||
7
   00011001000|
8
      10100111|
9
      --------|
10
      011011110
11
       10100111
12
       --------
13
       01111001 Pruefsumme
Diese Prüfsumme speichere ich jetzt separat zum Datenbyte ab.

Beim Empfänger, bzw. beim Auslesen der Daten aus dem EEPROM lese ich 
dann die Daten und die zusätzlich für diese Daten gespeicherte Prüfsumme 
aus und mache das ganze erneut:
1
001111101111001
2
  10100111|||||
3
  --------|||||
4
  010111001||||
5
   10100111||||
6
   --------||||
7
   00011110100|
8
      10100111|
9
      --------|
10
      010100111
11
       10100111
12
       --------
13
              0 PASST!

Jetzt habe ich ein wenig Schwierigkeiten bei der Umsetzung des ganzen im 
uC. Pseudocode-mäßig mache ich doch folgendes beim Erstellen der CRC:

Schiebe die Daten solange nach links, bis die erste Stelle eine 1 ist.
XOR die Daten mit dem Generator-Polynom (die 1 muss hier auch ganz links 
stehen) und speichere diesen Wert an die Stelle, wo vorher die Daten 
standen. Widerhole solange, bis die erste Stelle der Daten gleich 0 ist.

Ist das soweit erstmal richtig, oder totaler Humbug?

Würde mich über Ratschläge sehr freuen. Habe auch schon im Forum gesucht 
und auch Sachen dazu gefunden, aber da ist das alles sehr knapp (was 
natürlich optimal ist), aber für mich nicht so ganz verständlich. Eine 
sehr kurze Variante von KHB habe ich gefunden. Ich verstehe sie nur 
nicht, daher würde ich auch erstmal mit einer längeren Variante 
zufrieden sein, die ich dann aber nachvollziehen kann.

Gruß

von ... (Gast)


Lesenswert?

Ein CRC sollte sich doch auch mit Gurgel finden lassen. Was war daran 
nicht brauchbar?

von CRC-hilfesuchender (Gast)


Lesenswert?

... schrieb:
> Ein CRC sollte sich doch auch mit Gurgel finden lassen. Was war daran
> nicht brauchbar?

Ich sag ja nicht, dass nichts brauchbares dabei ist, habe mich übrigens 
vertan, meinte hier das von Peda:

Beitrag "Re: CRC-16 Prüfsumme (serielle Übertragung)"

Ich sagte nur, dass ich das nicht verstehe!

von Falk B. (falk)


Lesenswert?

@  CRC-hilfesuchender (Gast)

>Schiebe die Daten solange nach links, bis die erste Stelle eine 1 ist.
>XOR die Daten mit dem Generator-Polynom

Ja.

> (die 1 muss hier auch ganz links
>stehen) und speichere diesen Wert an die Stelle, wo vorher die Daten
>standen. Widerhole solange, bis die erste Stelle der Daten gleich 0 ist.

Nö, solang wie die Daten sind.

>Würde mich über Ratschläge sehr freuen. Habe auch schon im Forum gesucht
>und auch Sachen dazu gefunden, aber da ist das alles sehr knapp (was
>natürlich optimal ist), aber für mich nicht so ganz verständlich.

Siehe CRC.

In dem bekannten CRC explaind ist es doch recht verständlich 
beschrieben.

>nicht, daher würde ich auch erstmal mit einer längeren Variante
>zufrieden sein, die ich dann aber nachvollziehen kann.

http://www.csm.ornl.gov/~dunigan/crc.html

von CRC-hilfesuchender (Gast)


Lesenswert?

Ich habe das Beispiel mal ausprobiert, aber damit bekomme ich auf jeden 
Fall nicht das richtige heraus:
1
uint8_t generate_crc_8bit( uint8_t data )
2
{
3
  uint8_t checksum;
4
  uint8_t counter;
5
6
  checksum = data;
7
  for( counter = 8; counter; counter-- )
8
  {
9
    checksum = (checksum >> 1) ^ ((checksum & 1) ? CRC_POLYNOM : 0 );
10
  }
11
  
12
  return checksum;
13
}

von Falk B. (falk)


Lesenswert?

@  CRC-hilfesuchender (Gast)

>Ich habe das Beispiel mal ausprobiert, aber damit bekomme ich auf jeden
>Fall nicht das richtige heraus:

Das Problem ist vielfälltig.
Wird deine CRC in der gleichen Richtung geschoben wie in dem Beispiel 
nach RECHTS?
CRC_Polynom richtig eingetragen?
Stimmt der Initialisierungswert der CRC?

MFG
Falk

von CRC-hilfesuchender (Gast)


Lesenswert?

Falk Brunner schrieb:
> Das Problem ist vielfälltig.

Nee, hier stimmt grad garnix bei mir. Moment, ich muss nochmal 
drübergucken.

von Alexander V. (avogra)


Lesenswert?

CRC-hilfesuchender schrieb:
> uint8_t generate_crc_8bit( uint8_t data )
> {
>   uint8_t checksum;
>   uint8_t counter;
>
>   checksum = data;

also ich kenn das eigentlich so, dass checksum auch als parameter 
übergeben wird. bei jedem neuen datenbyte wird der alte crc-wert 
übergeben, beim ersten datenbyte irgendein initialwert.

Gruß, Alex

von CRC-hilfesuchender (Gast)


Lesenswert?

Alexander v. Grafenstein schrieb:
> bei jedem neuen datenbyte wird der alte crc-wert
> übergeben

Und wieso?

von CRC-hilfesuchender (Gast)


Lesenswert?

Ich habe es jetzt so, aber da ist am Ende dann immer ein Shift zuviel:
1
uint8_t generate_crc_8bit( uint8_t data )
2
{
3
  uint8_t checksum = data;
4
  uint8_t counter;
5
6
  for( counter = 0; counter < 8; counter++ )
7
  {
8
    if( checksum & 0x80 )
9
    {
10
      checksum ^= CRC_POLYNOM;
11
    }
12
    
13
    checksum <<= 1;
14
  }
15
16
  return checksum;
17
}
Sonst isses richtig

von Falk B. (falk)


Lesenswert?

@  CRC-hilfesuchender (Gast)

>> bei jedem neuen datenbyte wird der alte crc-wert
>> übergeben

>Und wieso?

Na weil die CRC über einen Block Daten zusammenhägend berechnet wird, 
das Ergebnis eines Bytes beeinflußt die Berechnung des nächsten.

von CRC-hilfesuchender (Gast)


Lesenswert?

Falk Brunner schrieb:
> Na weil die CRC über einen Block Daten zusammenhägend berechnet wird

Aber wenn ich doch grad nur ein Byte habe

von CRC-hilfesuchender (Gast)


Lesenswert?

OK, formuliere ich es anders: Ich habe nur einzelne Daten, keine Blöcke. 
Ich schreibe z.B. zum uint8 eine Prüfsumme, oder zu einem uint16, o. ä.

Einen Datneblock habe ich nicht.

von CRC-hilfesuchender (Gast)


Lesenswert?

Ich sehe gerade, dass meine Variante da auch nur klappt, wenn das 
Polynom so aufgebaut ist, dass es am MSB des Bytes eine 1 hat.

Ach scheiße - ist bestimmt voll simpel, aber ich kriegs nicht gescheit 
hin.

von Karl H. (kbuchegg)


Lesenswert?

CRC-hilfesuchender schrieb:
> Falk Brunner schrieb:
>> Na weil die CRC über einen Block Daten zusammenhägend berechnet wird
>
> Aber wenn ich doch grad nur ein Byte habe

Was willst du dann mit einer CRC?

CRC macht nur dann wirklich Sinn, wenn du viele Bytes absichern willst. 
Das ist ja gerade der Witz an der Sache: Viele Informationen (viele 
Bytes) so auf ein paar Bytes eindampfen, dass zufällige Fehler in der 
Übertragungen möglichst auffallen.

von Falk B. (falk)


Lesenswert?

@  CRC-hilfesuchender (Gast)

>Ich habe es jetzt so, aber da ist am Ende dann immer ein Shift zuviel:

Nö, das passt. Aber das XOR passt nicht.

Eher so.
1
uint8_t generate_crc_8bit( uint8_t data )
2
{
3
  uint8_t checksum = data;
4
  uint8_t counter;
5
6
  for( counter = 0; counter < 8; counter++ )
7
  {
8
    if( checksum & 0x80 )
9
    {
10
       checksum <<= 1;
11
       checksum ^= CRC_POLYNOM;
12
    } else {
13
       checksum <<= 1;
14
    }   
15
  }
16
17
  return checksum;
18
}

Da man seltenst die Prüfsumme über einzelne Bytes berechnet, übergibt 
man der Funktion eher einen Pointer auf einen Datenblock und einen 
Bytezähler.
1
uint8_t generate_crc_block( uint8_t *data, unit8_t count )
2
{
3
  uint8_t checksum;
4
  uint8_t newdata;
5
  uint8_t bitmask;
6
7
  checksum = *data;
8
  data++;
9
  count--;
10
11
  For(; count>0; count--) {
12
    newdata = *data;
13
    data++;
14
15
    for( bitmask= 0x80; bitmask !=0; bitmask >>=1 )
16
    { 
17
      if( checksum & 0x80 )
18
      {
19
         checksum <<= 1;
20
         if (newdata & bitmask) checksum |=1;
21
         checksum ^= CRC_POLYNOM;
22
      } else {
23
         checksum <<= 1;
24
         if (newdata & bitmask) checksum |=1;
25
      }   
26
    }
27
  }
28
29
  return checksum;
30
}

MFG
Falk

von CRC-hilfesuchender (Gast)


Lesenswert?

Falk Brunner schrieb:
> Eher so.
> uint8_t generate_crc_8bit( uint8_t data )
> {
>   uint8_t checksum = data;
>   uint8_t counter;
>
>   for( counter = 0; counter < 8; counter++ )
>   {
>     if( checksum & 0x80 )
>     {
>        checksum <<= 1;
>        checksum ^= CRC_POLYNOM;
>     } else {
>        checksum <<= 1;
>     }
>   }
>
>   return checksum;
> }

Da ist doch auch der Shift zuviel drin. Ich habe gerade gesehen, dass 
ich in meinem Quelltext das Shift rausgenommen hatte, um es 
auszuprobieren und dann natürlich genau den Text ohne das Shift hier 
rein gepostet habe - jedenfalls hatte ich den Shift auch drin. Wenn das 
Shift vor dem ^= steht, geht es nicht, danach isses richtig bis auf den 
zusätzlichen Shift.

Und was meinst du mit

Falk Brunner schrieb:
> Nö, das passt. Aber das XOR passt nicht.

von Falk B. (falk)


Lesenswert?

@  CRC-hilfesuchender (Gast)

>Da ist doch auch der Shift zuviel drin.

Nein! Es wird IMMER geschoben, nur je nach 8. Bit XOR oder nicht 
gemacht.

"To perform the division perform the following:

   Load the register with zero bits.
   Augment the message by appending W zero bits to the end of it.
   While (more message bits)
      Begin
      Shift the register left by one bit, reading the next bit of the
         augmented message into register bit position 0.
      If (a 1 bit popped out of the register during step 3)
         Register = Register XOR Poly.
      End
   The register now contains the remainder.

(Note: In practice, the IF condition can be tested by testing the top
 bit of R before performing the shift.)"

> Ich habe gerade gesehen, dass
>ich in meinem Quelltext das Shift rausgenommen hatte, um es
>auszuprobieren und dann natürlich genau den Text ohne das Shift hier
>rein gepostet habe - jedenfalls hatte ich den Shift auch drin. Wenn das
>Shift vor dem ^= steht, geht es nicht, danach isses richtig bis auf den
>zusätzlichen Shift.

Dann ist villeicht deine andere CRC-Berechnung falsch.

>Und was meinst du mit
>> Nö, das passt. Aber das XOR passt nicht.

Dass VOR dem XOR ein Shift rein muss. Siehe oben.

von CRC-hilfesuchender (Gast)


Lesenswert?

Falk Brunner schrieb:
> Nein! Es wird IMMER geschoben, nur je nach 8. Bit XOR oder nicht
> gemacht.

OK!

Falk Brunner schrieb:
> Dann ist villeicht deine andere CRC-Berechnung falsch.

Das kann natürlich auch sein, habe sie halt nach dem Schema gemacht, wie 
es auch im iNet steht. Meine manuelle Berechnung ist ja ganz oben im 
Eröffnungsthread. Ist die falsch?

von CRC-hilfesuchender (Gast)


Lesenswert?

Karl Heinz Buchegger schrieb:
> CRC macht nur dann wirklich Sinn, wenn du viele Bytes absichern willst.
> Das ist ja gerade der Witz an der Sache: Viele Informationen (viele
> Bytes) so auf ein paar Bytes eindampfen, dass zufällige Fehler in der
> Übertragungen möglichst auffallen.

Das sehe ich ja auch ein. Ich habe halt nur einzelne 
Datenbytes/Worte/etc..., welche verändert und dann einzeln abgespeichert 
werden, nur halt in einem EEPROM, das auf einer extra Platine in einem 
anderen Gehäuse (steckbar) ist. Ich will vermeiden, dass hier 
Übertragungsfehler entstehen, bzw. diese zumindest erkennen können.

von Falk B. (falk)


Lesenswert?

@  CRC-hilfesuchender (Gast)

>es auch im iNet steht. Meine manuelle Berechnung ist ja ganz oben im
>Eröffnungsthread. Ist die falsch?

Ja. Du musst das XOR eine Stelle tiefer ansetzen. Jedes Polynom hat noch 
ein implizites höchstwertiges Bit, das immer 1 ist aber direkt nie 
hingeschrieben wird. Dein Polynom 0xA7 ist in Wirklichkeit 0x1A7
1
001111100000000
2
  110100111||||
3
  ---------||||
4
  00101011100||
5
    110100111||
6
    ---------||
7
    0111110110|
8
     110100111|
9
     ---------|
10
     00101000100
11
       110100111
12
       ---------
13
       011100011 Pruefsumme

Und genau das kommt incl. Zwischenschritte auch bei dem C-Code raus.

MFG
Falk

von CRC-hilfesuchender (Gast)


Lesenswert?

Jetzt komme durcheinander...nach diesem Rechner ist sie aber doch auch 
richtig, ohne das implizite Bit.

http://www.leischner.inf.fh-bonn-rhein-sieg.de/lehrmat/crc.htm

Wonach soll ich mich denn jetzt richten? So hatte ich es zumindest 
früher auch gelernt.

:-/

von CRC-hilfesuchender (Gast)


Lesenswert?

Ich muss mich nochmal melden :-\ Ich bin jetzt wirklich ratlos. Wieso 
gehen die Berechnungen für die CRC denn so auseinander?

Kann da evtl. nochmal einer drüber gucken?

@Falk: Vielen Dank für deine Mühe. Wenn das Ergebnis mit diesem 
impliziten Bit hinhaut nach dem C-Code, dann ist das ja spitze, aber 
warum wird das anders gerechnet, als von Hand?

von Falk B. (falk)


Lesenswert?

@  CRC-hilfesuchender (Gast)

>Ich muss mich nochmal melden :-\ Ich bin jetzt wirklich ratlos. Wieso
>gehen die Berechnungen für die CRC denn so auseinander?

Erstmal ist die Seite oben falsch, weil bei einer 8 Bit CRC auch acht 
Bit an die Daten angehängt werden müssen und nicht sieben.

Meiner Meinung ist die Berechung auf der Website falsch, weil eben das 
XOR eine Bit zu früh gemacht wird. Das implizite gesetzte Bit der CRC 
fehlt dort.

http://smbus.org/faq/crc8Applet.htm

Wenn man es mit dem Polynom 0x07 rechnet, stimmt es mit meiner Funktion 
überein.

http://www.lammertbies.nl/comm/software/index.html

Hier wird es auch so gemacht, erst schieben, dann XOR.

http://www.zorc.breitbandkatze.de/crc.html

Hier stimmt was nicht, ich kommen nicht auf die gleichen Zahlen.

http://ghsi.de/CRC/index.php?Polynom=1010+0111&Message=3E

Hier sind auch massive Fehler drin, nicht mal das Polynom wird korrekt 
dargestellt!

Ergo. Man darf nicht alles glauben, was im Internet steht ;-)

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.