Forum: Mikrocontroller und Digitale Elektronik CRC16 nach CCITT auf AVR mit crc16.h probs


von Yogy (Gast)


Lesenswert?

Hallo,
Wintermonate sind SW-Spielmonate.
Ich will bei meinem Datenprotokoll die bisherige 16bit Checksum durch 
CRC16 nach CCITT erstezen. Aber das funzt nicht.

Ich will nicht nerven, habe auch fleißig rumgegoogelt und auch hier im 
Forum gesucht, aber ich stehe auf dem Schlauch.

Nehmen wir mal an, die Nachricht besteht nur aus $55, $AA,

dann müßte die CRC laut "Breitbandkatze" sowie laut 
http://www.lammertbies.nl/comm/info/crc-calculation.html übereinstimmend 
0xF8E5 ergeben.

Aber die Nutzung Funktion des AVR-libc: _crc_ccitt_update (crc16, data)
ergibt 0x57a7.
Parallel habe ich das LIBC-Beispiel auf VB-express implementiert. Die 
Funktion:

    Private Function crc_ccitt_update(ByVal crc As UInt16, ByVal idata 
As Byte) As UInt16
        Dim xdata As UInt16

        xdata = idata
        xdata = xdata Xor (crc And &HFF)
        xdata = (xdata Xor (xdata << 4)) And &HFF

        crc = (((xdata << 8) Or (crc And &HFF00)) Xor (xdata >> 4) Xor 
(xdata << 3))
        Return crc

        '        data ^= lo8 (crc);
        '       data ^= data << 4;

        '      return ((((uint16_t)data << 8) | hi8 (crc)) ^ 
(uint8_t)(data >> 4)
        '             ^ ((uint16_t)data << 3));

    End Function

ergibt den Wert: 0xFDD5  Dieser stimmt weder mit dem ergebnis der 
ASM-Implementierung der libc laut crc16.h überein noch mit 
Breitbandkatze.

Eine Implementierung aus einer anderen Quelle:
    Private Function crc_ccitt_update_5(ByVal crc As UInt16, ByVal idata 
As Byte) As UInt16

        Dim xdata As UInt16
        xdata = idata

        ' x = ((crc>>8) ^ data) & 0xff;
        xdata = ((crc >> 8) Xor xdata) And &HFF

        ' x ^= x>>4;
        xdata = xdata Xor (xdata >> 4)

        ' crc = (crc << 8) ^ (x << 12) ^ (x <<5) ^ x;
        crc = (crc << 8) Xor (xdata << 12) Xor (xdata << 5) Xor xdata

        crc = crc And &HFFFF

        Return crc

    End Function

hingegen ergab den "richtigen" Breitbandkatzewert 0xF8E5

Ist die libc bzw crc16.h falsch? Muß ich ggf. das Makefile anpassen? 
Meines ist "Standard" laut AVR Studio? Osder hat einer eine korrekte 
schnelle Implementierung in ASM?

Danke für Eure Mühen :-)

Yogy

von Oliver (Gast)


Lesenswert?

_crc_xmodem_update mit Startwert 0xffff liefert dir dein gewünschtes 
0xF8E5 (und mit Startwert 0 das auch in den Internetrechnern für 
crc_xmodem gezeigte 0xE5EA).

Ob jetzt eher die Internet-Rechner oder die avrlibc richtig liegen, 
darfst du selber rausfinden. Dem folgenden Kommentar in der avrlib-Doku 
nach tippe ich allerdings auf die avrlibc:
1
Note:
2
Although the CCITT polynomial is the same as that used by the Xmodem protocol, 
3
they are quite different. 
4
The difference is in how the bits are shifted through the alorgithm. 
5
Xmodem shifts the MSB of the CRC and the input first, 
6
while CCITT shifts the LSB of the CRC and the input first.

Oliver

von Oliver (Gast)


Lesenswert?

Nachtrag:

Vielleicht hilft das hier zu weiteren Verwirrung ;)

http://regregex.bbcmicro.net/crc-catalogue.htm#crc.cat.crc-16-ccitt-false

Oliver

von Yogy (Gast)


Lesenswert?

Oh, das ging aber fix. Danke. Oliver. Damit funzt es.

Ich vermute nal, die libc ist da fehlerhaft. Denn die ASM-Routinen 
entsprechen auch nicht dem genannten C-Beispiel, bzw. in C ist ein ODER 
anstelle eines XOR (bei return). Auch scheint mir der ASM Teil ein wenig 
verquer.

Aber Hauptsache, es geht jetzt und ich kann das in C oder VB auf dem PC 
und mittels crc26.h auf dem AVR in C nutzen. Mal sehen, vlt. setze ich 
mich nochmals dran und versuche eine ASM Implementierung (Kenne mich 
-noch- nicht mit dem Interface GNU-C und ASM für den AVR aus) der 
erwähnten C-Routine "crc_ccitt_update_5" (Bei mir als VB laufend)

Danke nochmals und schönes WE. Ich habe ja was zu tun...

Yogy

von Oliver (Gast)


Lesenswert?

Oliver schrieb:
> Nachtrag:

s.o.

Oliver

von yogy (Gast)


Lesenswert?

So, ich habe die o.a. VB-Routine nach AVR / GNU-C portiert und passend 
für das File crc16.h dargestellt:
1
static __inline__ uint16_t
2
_crc_ccitt_update (uint16_t __crc, uint8_t __data)
3
{
4
    uint16_t __ret;
5
6
    __asm__ __volatile__ (
7
8
        "eor    %B0,%1"          "\n\t"   
9
10
        "mov    __tmp_reg__,%B0" "\n\t"
11
        "swap   %B0"             "\n\t"
12
        "andi   %B0,0x0f"        "\n\t"
13
        "eor    %B0,__tmp_reg__" "\n\t" 
14
    "mov  %1,%B0"       "\n\t" 
15
16
        "mov    %B0,%A0"         "\n\t"
17
    "mov  %A0,%1"       "\n\t"    
18
        "swap   %A0"             "\n\t"
19
        "andi   %A0,0xf0"        "\n\t" 
20
        "eor    %B0,%A0"         "\n\t"
21
22
23
        "mov    %A0,%1"       "\n\t"
24
        "lsr    %A0"             "\n\t"
25
        "lsr    %A0"             "\n\t"
26
        "lsr    %A0"             "\n\t"
27
        "eor    %B0,%A0"         "\n\t"
28
29
30
        "mov    %A0,%1"       "\n\t"
31
        "swap   %A0"             "\n\t"
32
        "andi   %A0,0xf0"        "\n\t"
33
        "lsl    %A0"             "\n\t"
34
35
        "eor    %A0,%1"          "\n\t"
36
37
38
39
        : "=d" (__ret)
40
        : "r" (__data), "0" (__crc)
41
        : "r0"
42
    );
43
    return __ret;

Diese Routine ist kürzer als die dort angegebenen XMODEM-Routine. Zur 
freien Verwendung natürlich.

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.