util/crc16.h, CRC-Berechnung unterschiedlich µC<->PC

OP #3750302
Lesenswert?

Hi,

ich nutze zur Absicherung der Kommunikation zwischen Master und Slave 
die _crc16_update() Funktion aus der AVR Libc: 
http://www.nongnu.org/avr-libc/user-manual/group__util__crc.html .
Aktuell bin ich noch dran, Slave und Master getrennt zu entwickeln. Ich 
kopiere mir also einfach den vom Master erzeugen String inklusive 
Checksumme (zum beispiel #DO,001,02,12345,01,01556,29610,63191\n), pack 
das ganze in ein Terminalprogramm und schick es dem Slave. Das 
funktioniert. Änder ich die Checksumme (der Letzte Abschnitt) oder die 
Daten, akzeptiert der Slave die Übertragung nicht. Das funktioniert 
also.
Der vollständigkeithalber, hier der Code vom Master:
1
void UART_SendDataToSlave(char* data)
2
{
3
  uint8_t len = strlen(data);
4
  uint16_t CRC = 0xffff;
5
  char buffer[7];
6
  
7
   for (uint8_t i = 1; i < len; i++)      //CRC berechnen
8
   {
9
     CRC = _crc16_update(CRC, data[i]);
10
  }
11
  
12
  strcat(data, ",");
13
  utoa(CRC, buffer, 10);        //CRC anhängen
14
  strcat(data, buffer);  //CRC anhängen
15
  strcat(data, "\n");    //Kommando-Ende
16
  
17
  strcpy(UART_LastTransmit, data);      //Letzte Übertragung sichern
18
  
19
  uart_puts(data);
20
  UARTWaitForACKSet;
21
}

Der Slave (UART_Data ist der komplette String, inkl \n)
1
//CRC Kontrolle:
2
        uint8_t CRClen = strlen(UART_Data);
3
        CRClen -= 6;
4
        char cCRC[6];
5
        strncpy(cCRC, UART_Data+CRClen, 5);
6
        
7
        uint16_t CRC = 0xffff;        
8
        for (uint8_t i = 1; i < CRClen-1; i++)      //CRC berechnen
9
        {
10
          CRC = _crc16_update(CRC, UART_Data[i]);
11
        }
12
        if (atol(cCRC) == CRC)
13
          ReturnVal = 1;      //CRC Ok
14
        else
15
          ReturnVal = 4;      //CRC Falsch


Da aber auch der PC mit dem Master kommunizieren soll und es mir vor 
allem das Debuging einfacher macht, wollte ich mir einen kleinen 
CRC-Calculator am PC bauen. Allerdings komm ich weder mit den Online-CRC 
Rechnern auf das Ergebnis wie der Controller, noch mit einem kleinen 
Visual C# Programm, das auf dem Code aus der <util/crc16.h> beruht.
Die CRC16 mit dem Programm von unten lautet: 20274.

PC-Programm:
1
static int crc16_update(int crc, int a)
2
        {
3
            int i;
4

5
            crc ^= a;
6
            for (i = 0; i < 8; ++i)
7
            {
8
                if ((crc & 1) == 1)
9
                    crc = (crc >> 1) ^ 0xA001;
10
                else
11
                    crc = (crc >> 1);
12
            }
13

14
            return crc;
15
        }
16

17
        private void b_calculate_Click(object sender, EventArgs e)
18
        {
19
            string CRCString = tb_string.ToString();
20
            int len = CRCString.Length;
21
            int CRC = 0xffff;
22

23
            for (int i = 1; i < len; i++)      //CRC berechnen
24
            {
25
                CRC = crc16_update(CRC, CRCString[i]);
26
            }
27

28
            tb_crc16.Text = CRC.ToString();
29
        }


Weiß jemand Rat? Was überseh ich? Oder ein Prinzipfehler?


Controller: AVR-Familie (Mega32L auf dem Testboard, später dann 328p-au)
Compiler: GCC 4.7.2 (AVR Studio 6.1)
PC: .NET4 (Visual Studio C# 2010 Express)
OP #3750354
Lesenswert?

Hi, ich habe das Programm entsprechend geändert
1
static UInt16 crc16_update(UInt16 crc, char a)
2
        {
3
            UInt16 i;
4

5
            crc ^= a;
6
            for (i = 0; i < 8; ++i)
7
            {
8
                if ((crc & 1) == 1)
9
                    crc = (UInt16)((crc >> 1) ^ 0xA001);
10
                else
11
                    crc = (UInt16)(crc >> 1);
12
            }
13

14
            return crc;
15
        }
16

17
        private void b_calculate_Click(object sender, EventArgs e)
18
        {
19
            string CRCString = tb_string.ToString();
20
            int len = CRCString.Length;
21
            UInt16 CRC = 0xffff;
22

23
            for (int i = 1; i < len; i++)      //CRC berechnen
24
            {
25
                CRC = crc16_update(CRC, CRCString[i]);
26
            }
27

28
            tb_crc16.Text = CRC.ToString();
29
        }

Ergebnis bleibt 20274.
#3750482
Lesenswert?

In C würde der gezeigte Code auf jeden Fall in die Hose gehen. Ob auch 
in C# hängt von diversen Fragen ab, wie z.B.:
Wie groß ist char in C#?
Welche Signedness hat char in C#?
Hat C# die selben Promotion-Rules wie C?
Ich kenne die Antworten nicht, denn ich kann kein C#.
Ich vermute aber mal, dass es in C# wegen der gleichen (oder ähnlicher) 
Gründe in die Hose geht.

Mache a unsigned.
#3750539
Lesenswert?

Im MikroController ist
1
uint16_t
2
    crc16_update(uint16_t crc, uint8_t a)
3
    {
4
        int i;
5

6
        crc ^= a;
7
        for (i = 0; i < 8; ++i)
8
        {
9
            if (crc & 1)
10
                crc = (crc >> 1) ^ 0xA001;
11
            else
12
                crc = (crc >> 1);
13
        }
14

15
        return crc;
16
    }

"a" unsigned. Wenn es für die 16 Bit Operation "crc ^= a;" erweitert 
wird ("crc" hat ja 16bit), wird oben 0 ergänzt.

Bei Deiner
1
 
2
static UInt16 crc16_update(UInt16 crc, char a)
3
        {
4
            UInt16 i;
5

6
            crc ^= a;
7
            for (i = 0; i < 8; ++i)
8
            {
9
                if ((crc & 1) == 1)
10
                    crc = (UInt16)((crc >> 1) ^ 0xA001);
11
                else
12
                    crc = (UInt16)(crc >> 1);
13
            }
14

15
            return crc;
16
        }

ist nicht ganz klar, ob "a" signed oder unsigned ist und wie viele Bit 
es hat. Wenn man 8 Bit signed annimmt, dann würde die Erweiterung auf 16 
Bit nicht nur 0 sondern bei Werten mit gesetztem höchsten Bit 0xff oben 
ergänzen. Damit würde sich dann das abweichende Ergebnis erklären.
OP #3750578
Lesenswert?

Stefan Ernst schrieb:
> In C würde der gezeigte Code auf jeden Fall in die Hose gehen.
Warum?

> Wie groß ist char in C#?
16-Bit Unsigned

> Mache a unsigned.
Auch mit byte (8-Bit Unsigned) kommt das selbe raus.


Ich hab mir das wohl zu einfach vorgestellt mit Copy&Paste.
Was mich aber wundert, warum in den Online-CRC-Rechnern auch überall 
meist vollständig andere Ergebnisse bei raus kommen?
Zum beispiel:
http://www.zorc.breitbandkatze.de/crc.html
Gast #3750583
Lesenswert?

Martin K. schrieb:
> Ich hab mir das wohl zu einfach vorgestellt mit Copy&Paste.

Mit der Erkenntnis stehst du nicht alleine.

Cx sind Programmiersprachen, bei denen man genau wissen muss, was man 
tut, insbesondere wenn das ganze Konstrukt hinterher auch noch auf 
verschiedenen Systemen ohne Änderungen funktionieren soll.
#3750614
Lesenswert?

Martin K. schrieb:
> Stefan Ernst schrieb:
>> In C würde der gezeigte Code auf jeden Fall in die Hose gehen.
> Warum?

Das "auf jeden Fall" war etwas übertrieben. Wenn man dem Compiler sagt, 
dass char per Default unsigned zu sein hat, dann nicht (wäre dann aber 
immer noch sehr schlechter Stil). Was ansonsten passiert, hat Achim doch 
schon erklärt.

Martin K. schrieb:
>> Wie groß ist char in C#?
> 16-Bit Unsigned

Aha. Und welchen Datentyp hat string[x]? Und was steht in diesem char 
dann konkret drin? Sind das wirklich ASCII-Codes?

Hast du überhaupt mal ganz grundsätzlich überprüft, ob auch in beiden 
Fällen wirklich identische Inputdaten an die CRC-Routinen verfüttert 
werden? Und damit meine ich jetzt nicht, was du irgendwo als Text 
eingibst, sondern, was als binäre Daten in der CRC-Routine ankommt.

Martin K. schrieb:
> Was mich aber wundert, warum in den Online-CRC-Rechnern auch überall
> meist vollständig andere Ergebnisse bei raus kommen?

Was sollen wir dazu sagen? Hier wissen wir ja noch weniger darüber, was 
genau du da eingestellt/eingegeben hast.
OP #3750634
Lesenswert?

Stefan Ernst schrieb:
> Was sollen wir dazu sagen? Hier wissen wir ja noch weniger darüber, was
> genau du da eingestellt/eingegeben hast.

CRC-CCITT
CRC order 16
CRC polynom A001
Initial value ffff (direct)
Final XOR value 0

Result: 0x6133


Ich hab noch ein wenig mit Visual C# gespielt, komm aber auf kein 
Ergebnis. Hier und da gibt es Routinen im Netz für CRC16-CCITT, auch mit 
dem Polynom A001. Mit einer Variante war ich seltsamerweise immer exakt 
91 UNTER den vom µC berechneten werden. Sehr frustrierend grade. Vllt. 
seh ich auch den Wald vor lauter bäumen nicht mehr.
#3750720
Lesenswert?

Martin K. schrieb:
> Sorry, natürlich den String von oben:
>
> #DO,001,02,12345,01,01556,29610
>
> Erwartete Checksumme: 63191 (0xF6D7)

Warum das '#'? Deine eigenen Routinen ignorieren doch das erste Zeichen, 
der Online-Rechner aber natürlich nicht.

Der Online-Rechner scheint in die andere Richtung zu shiften. Wenn du 
das Polynom umdrehst (A001->8005) und die beiden Reverse-Häkchen setzt, 
kommt bei "DO,001,02,12345,01,01556,29610" genau das raus:
> Erwartete Checksumme: 63191 (0xF6D7)
Gast #3751449
Lesenswert?

Hallo,

Ich hatte ähnliche Probleme mit der (bzw. einer) CCITT-CRC und wollte 
übereinstimmende Ergebnisse zwischen srec_cat, der avr-libc und der 
Breitbandkatze erhalten.

Hab es erst kürzlich hinbekommen und die screenshots (breitbandkatze), 
den Example-Code und das script-file f. srec_cat in ein File 
zusammengepackt (am Ende des Threads). Wie erwähnt: ist halt eine CCITT 
und nicht CRC16.

Vielleicht hilft es mal jemandem weiter:
TitelBeitrag "CRC generierung mittels srec_cat"

Gruß,
Andreas
OP #3771640
Lesenswert?

Ich hab mich noch mal dran gesetzt, aber kam nicht weiter. Mit diversen 
Routinen aus dem Netz hab ich es versucht, aber ich kam nicht auf mein 
Ergebnis.
Nach mehreren Stunden ohne weiter zu kommen hab ich das jetzt erst mal 
aufgegeben und bin grad an einer anderen Stelle vom Projekt.
Vielleicht hab ich beim nächsten Versuch ja eine Eingebung :)

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren