Forum: Mikrocontroller und Digitale Elektronik 1-Wire CRC Probleme


von Bastian W. (jackfrost)


Lesenswert?

Hallo,

ich versuche gerade die CRC vom Scratchpad von einem DS18S20 zu 
berechnen. Laut der Appnote 27 von Maxxim wird mit dem LSB vom Byte 0 
angefangen.

Ich hab von 
http://werner.dichler.at/sites/default/files/attachment/prj21_CRC%20Einfuehrung.pdf 
die Vorwärts Berechnung so geändert, das mit dem LSB begonnen.
Leider stimmt die CRC in Byte 8 nicht mit dem berechneten aus den ersten 
8 Bytes überein. Wo liegt hier mein Fehler ?
1
uint8_t calc_forward_CRC8_LFSR(char *data, uint8_t length)
2
{
3
   reg         = 0x0;
4
   poly        = 0x31;
5
   currentByte = 0x00;
6
   helper =0x00;
7
  for(int i=0; i<length*8; i++)
8
  {
9
    if (i%8 == 0)
10
    {
11
      currentByte = *(data + i/8);
12
    }
13
     inputBit = currentByte & 0x01;
14
    currentByte = currentByte >> 1;
15
    helper = ((reg & 0x01)^(inputBit))<<7;
16
    if ((reg & 0x01)^(inputBit))
17
    {
18
      reg = (reg>>1)^(poly);
19
      reg += helper;
20
    }
21
    else
22
    {
23
      reg = (reg >> 1);
24
    }
25
     
26
  }
27
  return reg;
28
}

Ich hab die Appnote so verstanden das die beiden LSB über xor verrechnet 
werden. Der Inhalt des Schieberegisters wird denn um eins nach rechts ( 
zum LSB ) verschoben und denn mit dem Ergebnis aus den beiden LSBs über 
xor verrechnet. Das Ergebnis der beiden LSBs kommt "ins" MSB.

Hab ich die Appnote so richtig verstanden ?

Gruß JackFrost

von Falk B. (falk)


Lesenswert?

Beitrag "Onewire + DS18x20 Library"

Das funktioniert. Deine Routine sieht komisch aus, ein Modulo ist in 
einer CRC nie drin.

Es gibt auch noch die rein serielle Variante. Hab ich aber damals 
verworfen, wei die Nibbleversion deutlich schneller ist. Finde sie auch 
nicht mehr. Ohne Gewähr, so könnte es stimmen.
1
uint8_t onewire_crc(const uint8_t *data, uint8_t cnt) {
2
    uint8_t crc, i, tmp, poly=0x8C;
3
4
    // serial CRC calculation,
5
6
    // first byte is not changed, since CRC is initialized with 0
7
    crc = *data++;        
8
    cnt--;
9
10
    for(; cnt>0; cnt--) {
11
        tmp = *data++;                        // next byte
12
        for(i=0; i<8; i++) {
13
            if (crc & 0x01) {
14
                crc >>= 1;
15
                if (tmp & 1) crc |= 0x80;
16
                crc ^= poly;
17
            } else {
18
                crc >>= 1;
19
                if (tmp & 1) crc |= 0x80;
20
            }
21
            tmp >>= 1;
22
        }
23
    }
24
    return crc;
25
}

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Was für ein Controller?

In der avr-libc gibt's fertigen Code dafür.

von Falk B. (falk)


Lesenswert?

@Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite

>In der avr-libc gibt's fertigen Code dafür.

In allen Varianten? CRC ist vielfältig, mal links, mal recht schieben, 
vorher die CRC auf Null oder FF setzen, am Ende invertieren oder nicht . 
. .

http://www.ross.net/crc/download/crc_v3.txt

Der Klassiker!

von (prx) A. K. (prx)


Lesenswert?

Falk B. schrieb:
>>In der avr-libc gibt's fertigen Code dafür.
>
> In allen Varianten?

Es geht hier um eine ganz bestimmte CRC.

: Bearbeitet durch User
von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Falk B. schrieb:
>> In der avr-libc gibt's fertigen Code dafür.
>
> In allen Varianten?

In vielen Varianten, und insbesondere in der, die Dallas, ähem,
Maxim für 1-wire benutzt.

von Bastian W. (jackfrost)


Angehängte Dateien:

Lesenswert?

Hallo,

danke für eure Hilfe.

@Falk danke für die Funktion. Mit dieser ist das Ergebnis über alle 9 
Bytes 0. Auch mit deiner Variante mit den Nibbels. Was mich etwas 
verwundert hat, das wenn ich es nur auf den ersten 8 Bytes anwende, dann 
kommt eine andere CRC als die im 9. Byte vom Scratchpad raus. Ich hab 
meine Funktion geändet und die Variante direkt vom Wiki für die CRC32 
genommen. Mit dieser kommt bei den 9 Bytes auch 0 raus und bei 8 Bytes 
der Wert der CRC im 9. Byte.

Ich hab einen Screenshot vom Inhalt des Arrays gemacht. Die Bytes 0 - 8 
sind die vom Scratchpad.
Die Bytes 9 und 10 wurde mit folgender Funktion berechnet :
1
uint8_t calc_forward_CRC8_LFSR(const char *data, uint8_t length)
2
{
3
   reg         = 0x0;
4
   poly        = 0x8c;
5
   currentByte = 0x00;
6
   helper =0x00;
7
   for(;length>0;length--)
8
   {
9
     currentByte = *data++;
10
     for(int i=0; i<8; i++)
11
     {
12
       inputBit = currentByte & 0x01;
13
       currentByte = currentByte >> 1;
14
       //helper = ((reg & 0x01)^(inputBit))<<7;
15
       if ((reg & 0x01) != (inputBit))
16
       {
17
         reg = (reg>>1)^poly;
18
         
19
       }
20
       else
21
       {
22
         reg = reg >> 1;
23
         
24
       }
25
       
26
     }
27
   }
28
  
29
  return reg;
30
}
Der Rest mit der von dir geschriebenen.

Mit deinenen Funktionen kann ich die CRC beliebiger Daten bestimmen und 
prüfen , oder ? Die Variante mit den Nibbels sollte ja schneller gehen 
als das Byteweise verarbeiten der Daten.

@ Jörg, ich verwende einen xMega128A1. Wo finde ich die Libc beim der 
Toolchain wenn ich das Atmel Studio installiert habe ?

Gruß JackFrost

von Falk B. (falk)


Lesenswert?

@ Bastian Werner (jackfrost)

>@Falk danke für die Funktion. Mit dieser ist das Ergebnis über alle 9
>Bytes 0.

Ist das nicht der Sinn einer CRC? Mal die Kommentare im Quelltexte 
gelesen?

> Auch mit deiner Variante mit den Nibbels. Was mich etwas
>verwundert hat, das wenn ich es nur auf den ersten 8 Bytes anwende, dann
>kommt eine andere CRC als die im 9. Byte vom Scratchpad raus.

Auch das ist normal. Die echte CRC erhälst du nur, wenn du die 
empfangene CRC zwischenspeicherst, im Array auf 0 setzt und über 9 Byte 
berechnest. Siehe Quelltext!!!

> Ich hab
>meine Funktion geändet und die Variante direkt vom Wiki für die CRC32
>genommen. Mit dieser kommt bei den 9 Bytes auch 0 raus und bei 8 Bytes
>der Wert der CRC im 9. Byte.

Das ist eher Zufall.

>uint8_t calc_forward_CRC8_LFSR(const char *data, uint8_t length)

Sieht immer noch komisch aus.

>   for(;length>0;length--)
>   {
>     currentByte = *data++;
>     for(int i=0; i<8; i++)
>     {
>       inputBit = currentByte & 0x01;

OK.

>       currentByte = currentByte >> 1;
>       //helper = ((reg & 0x01)^(inputBit))<<7;
>       if ((reg & 0x01) != (inputBit))

DAS ist vollkommen komisch. Ich glaube nicht, dass damit die CRC stimmt.

>Mit deinenen Funktionen kann ich die CRC beliebiger Daten bestimmen und
>prüfen , oder ?

Ja sicher!

> Die Variante mit den Nibbels sollte ja schneller gehen
>als das Byteweise verarbeiten der Daten.

Logisch, steht ja auch im Quelltext.

von Bastian W. (jackfrost)


Lesenswert?

Falk B. schrieb:
> Auch das ist normal. Die echte CRC erhälst du nur, wenn du die
> empfangene CRC zwischenspeicherst, im Array auf 0 setzt und über 9 Byte
> berechnest. Siehe Quelltext!!!

Wer lesen kann ist klar im Vorteil. Macht man es so wie im Quelltext 
steht gehts :)

Falk B. schrieb:
>>@Falk danke für die Funktion. Mit dieser ist das Ergebnis über alle 9
>>Bytes 0.
>
> Ist das nicht der Sinn einer CRC? Mal die Kommentare im Quelltexte
> gelesen?

Das war mir bewusst das hier eine Null stehen muss wenn die Daten 
richtig übertragen wurden.

Falk B. schrieb:
>> Ich hab
>>meine Funktion geändet und die Variante direkt vom Wiki für die CRC32
>>genommen. Mit dieser kommt bei den 9 Bytes auch 0 raus und bei 8 Bytes
>>der Wert der CRC im 9. Byte.
>
> Das ist eher Zufall.

Ich habs bei 10 verschiedenen Werten ( Temperaturen ) Scratchpad 
probiert und immer hat die Berechnete CRC aus den ersten 8 Bytes mit dem 
9. Byte bzw. mit den Werten aus deiner Funktion übereingestimmt. Wobei 
es egal ist, da die Nibbelvariante Vorteile hat.

Gruß JackFrost

: Bearbeitet durch User
von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Bastian W. schrieb:
> @ Jörg, ich verwende einen xMega128A1. Wo finde ich die Libc beim der
> Toolchain wenn ich das Atmel Studio installiert habe ?

Die hängt implizit hinten am Compiler mit dran …

Doku (für den CRC-Teil) ist hier:

http://www.nongnu.org/avr-libc/user-manual/group__util__crc.html

_crc_ibutton_update() ist der 1-wire-Algorithmus.

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.