CRC auf XMEGA32A4U berechnen

Gast #2711917
Lesenswert?

Hallo Leute,

ich übertragen Daten über eine RS232 Verbindung zwischen 2 XMEGA µC. 
Beide µC besitzen einen Hardware CRC-Core.

Bis vor einigen Stunden wollte ich eine Software CRC8 Checksumme mit 
Hilfe einer Tabelle berechnen. Nun habe ich jedoch gesehen das der XMEGA 
einen Hardware-Kern für die Berechnung der Checksumme besitzt.

Allerdings besitzt der XMGEA nur eine CRC 16 und CRC32 Checksumme. Da 
ich aber nur wenige Bytes (so zwischen 3 und 6 Bytes) zwischen den 
beiden µC übertrage halte ich eine CRC 16 Checksummer schon für zu viel. 
Daher wollte ich auch die CRC8 Checksummer in Software umsetzen.

1. Hat es Nachteile wenn ich so wenige Bytes mit einer CRC16 Checksumme 
schütze? (außer das ich als Checksumme 1 Bytes mehr übertragen muss)

2. Oder kann ich mit dem XMEGA auf CRC8 Checksummen berechnen?
Gast #2712051
Lesenswert?

Dies ist mein 1. Code um die CRC Checksumme auf dem XMEGA zu berechnen.

Allerdings habe ich den Code noch nicht getestet.

ICH BIN MIR NICHT SICHER OB ICH DEN RESET WIEDER ZURCÜKNEHEMEN MUSS, 
DAMIT DER KERN STARTET

1
unsigned short calculate_crc16_checksum(unsigned char *data, unsigned char count)
2
{
3
    unsigned char i = 0;
4
    unsigned short crc16_checksum = 0;
5
        
6
    // Die 4 Checksum Register auf 0x00 zurücksetzen  
7
    CRC.CTRL = (CRC.CTRL & (~CRC_RESET_gm)) | CRC_RESET_RESET0_gc;
8
    
9
    // Den CRC-Kern anhalten, indem keine Quellec angegeben wird
10
    CRC.CTRL = (CRC.CTRL & (~CRC_SOURCE_gm)) | CRC_SOURCE_DISABLE_gc;
11
    
12
    // Den CRC-Kern auf CRC16 konfigurieren
13
    CRC.CTRL &= ~CRC_CRC32_bm;  
14

15
    // IO als Quelle für den CRC-Kern auswhählen
16
    CRC.CTRL = (CRC.CTRL & (~CRC_SOURCE_gm)) | CRC_SOURCE_IO_gc;
17
    
18
    //ACHTUNG IST RESET IMMER NOCH 1?
19
    
20
    for(i=0; i<count; i++)
21
    {
22
        CRC.DATAIN = data[i];        
23
    }
24

25
    // Das Busy Flag muss im CRC IO-Modus gelöscht werden, indem eine 1 in das Register geschrieben wird     
26
    CRC.STATUS |= CRC_BUSY_bm;
27
    
28
    while((CRC.STATUS & CRC_BUSY_bm) == CRC_BUSY_bm)
29
    {
30
        // Nichts machen solange der CRC-Kern noch beschäftigt ist
31
    }
32
    
33
    crc16_checksum = ((unsigned short) CRC.CHECKSUM0 & 0x00FF);
34
    crc16_checksum |= (((unsigned short) CRC.CHECKSUM1 << 8) & 0xFF00);
35
    
36
    // Den CRC-Kern anhalten, indem keine Quellec angegeben wird
37
    CRC.CTRL = (CRC.CTRL & (~CRC_SOURCE_gm)) | CRC_SOURCE_DISABLE_gc;
38
    
39
    return crc16_checksum;
40
}
Gast #2712062
Lesenswert?

Wenn ich jetzt die Checksummer von z.B. 3 Bytes berechne, dann hänge ich 
die CRC16 Checksummer an die Bytes ran bevor ich diese über die RS232 an 
meinen anderen µC sende.

Nun zu meiner Frage muss ich ich Checksummer nur über die Daten 
berechnen oder muss ich die Checksummer in der Checksummenberechnung mit 
einbeziehen?
Gast #2712188
Lesenswert?

Hat denn schon jemand diesen CRC Kern von ATMEL benutzt?


Wie ist denn das mit der Reset Leitung die setze ich ja zu Beginn auf 
'10'

Danach disable ich ja die Quelle. Danach muss konfiguriere ich den Kern 
auf auf CRC16.


Muss ich dach wieder die Reset Leitung auf '00' setzen



Wie ist es denn mit der BUSY Signal im IO Modus. Muss ich dort eine '1' 
reinschreiben, damit der Kern angehalten wird oder benötige ich die busy 
Leitung nicht im IO-Modus?
Gast #2712313
Lesenswert?

So ich habe mal den Atmel Hardware CRC Kern ausprobiert. Leider 
funktioniert dieser nicht.

Hier nocht mal mein Quellcode vielleicht sieht ja jemand sofort den 
Fehler:
1
// CRC-16(CRC-CCITT) Polynom x^16 + x^12 + x^5 + 1 --> 0x1021
2

3
unsigned short calculate_crc16_checksum(unsigned char *data, unsigned char count)
4
{
5
    unsigned char i = 0;
6
    unsigned short crc16_checksum = 0;
7
        
8
    // Die 4 Checksum Register auf 0x00 zurücksetzen  
9
    CRC.CTRL = (CRC.CTRL & (~CRC_RESET_gm)) | CRC_RESET_RESET0_gc;
10
    
11
    // Den CRC-Kern anhalten, indem keine Quellec angegeben wird
12
    CRC.CTRL = (CRC.CTRL & (~CRC_SOURCE_gm)) | CRC_SOURCE_DISABLE_gc;
13
    
14
    // Den CRC-Kern auf CRC16 konfigurieren
15
    CRC.CTRL &= ~CRC_CRC32_bm;  
16

17
    // IO als Quelle für den CRC-Kern auswhählen
18
    CRC.CTRL = (CRC.CTRL & (~CRC_SOURCE_gm)) | CRC_SOURCE_IO_gc;
19
    
20
    //ACHTUNG IST RESET IMMER NOCH 1?
21
    CRC.CTRL &= ~CRC_RESET_gm;
22
    
23
    for(i=0; i<count; i++)
24
    {
25
        CRC.DATAIN = data[i];        
26
    }
27

28
    // Das Busy Flag muss im CRC IO-Modus gelöscht werden, indem eine 1 in das Register geschrieben wird     
29
    CRC.STATUS |= CRC_BUSY_bm;
30
    
31
    while((CRC.STATUS & CRC_BUSY_bm) == CRC_BUSY_bm)
32
    {
33
        // Nichts machen solange der CRC-Kern noch beschäftigt ist
34
    }
35
    
36
    crc16_checksum = ((unsigned short) CRC.CHECKSUM0 & 0x00FF);
37
    crc16_checksum |= (((unsigned short) CRC.CHECKSUM1 << 8) & 0xFF00);
38
    
39
    // Den CRC-Kern anhalten, indem keine Quellec angegeben wird
40
    CRC.CTRL = (CRC.CTRL & (~CRC_SOURCE_gm)) | CRC_SOURCE_DISABLE_gc;
41
    
42
    return crc16_checksum;
43
}
44

45
//Im Hauptprogramm erzeuge ich ein Array mit 8 Bytes (vorbelegt)
46

47
/*Dann rufe ich die Funktion auf und übertrage die Checksumme an den PC über eine RS232 Leitung. Jedoch kommt immer als Checksumme 0 raus. HIIILFE*/
48

49
unsigned char crc_testdata[8] = {0x43, 0x23, 0x83, 0x10, 0x82, 0x44, 0x92, 0x31};
50
unsigned short crc16_checksum = 0;
51

52
crc16_checksum = calculate_crc16_checksum(&crc_testdata[0], 8);
53

54
printf("Die Checksumme lautet: %d", crc16_checksum);
Gast #2712868
Lesenswert?

Sebastian schrieb:
> // Das Busy Flag muss im CRC IO-Modus gelöscht werden, indem eine 1 in das
Register geschrieben wird
>     CRC.STATUS |= CRC_BUSY_bm;

Ich kenne den XMEGA nicht, aber wenn flags gelöscht werden sollen durch
schreiben einer 1 macht man das normalerweise so:

CRC.STATUS = CRC_BUSY_bm;

Denn deine |= Anweisung liest erst den Wert und überschreibt alle
weiteren gesetzen Bits ebenfalls mit 1 und setzt diese zurück.
Gast #2713012
Lesenswert?

So ich habe mir meinen Quellcode mal mit dem Debugger angeschaut. Immer 
wenn ich CRC.DATAIN = 0xAA; ausführe wird nichts in das DATAIN Register 
des µC übernommen. Dadurch ändert sich auch nie die Checksummer und 
bleibt immer 0. Wenn ich mit dem Debugger ins DATAIN Register manuell 
einen Wert reinschreibe, dann ändern sich sofort die Checksum Register 
so wie es sein soll.

Ist vielleicht die Adresse von dem DATAIN Register falsch?
1
for(i=0; i<count; i++)
2
    {
3
        //CRC.DATAIN = data[i];
4
        //CRC.DATAIN = testdata[i];
5
        CRC.DATAIN = 0xAA;
6
    }
Gast #2713218
Lesenswert?

Ich habe den Fehler gefunden. Das H-File vom Compiler war fehlerhaft, so 
das die Adresse von dem DATAIN und den danach folgenden Registern falsch 
war. Nachdem ich das behoben hatt funktioniert die 
Checksummenberechnung.

hier der alter Code aus dem H-File:
1
typedef struct CRC_struct
2
             {
3
             unsigned char CTRL;        // CRC Control Register 
4
             unsigned char STATUS;      // CRC Status Register
5
             unsigned char DATAIN;      // CRC Data Input 
6
             unsigned char CHECKSUM0;   // CRC Checksum byte 0 
7
             unsigned char CHECKSUM1;   // CRC Checksum byte 1 
8
             unsigned char CHECKSUM2;   // CRC Checksum byte 2 
9
             unsigned char CHECKSUM3;   // CRC Checksum byte 3 
10
             } CRC_t;

1
typedef struct CRC_struct
2
             {
3
             unsigned char CTRL;        // CRC Control Register 
4
             unsigned char STATUS;      // CRC Status Register
5
             unsigned char reserved_0x02; 
6
             unsigned char DATAIN;      // CRC Data Input 
7
             unsigned char CHECKSUM0;   // CRC Checksum byte 0 
8
             unsigned char CHECKSUM1;   // CRC Checksum byte 1 
9
             unsigned char CHECKSUM2;   // CRC Checksum byte 2 
10
             unsigned char CHECKSUM3;   // CRC Checksum byte 3 
11
             } CRC_t;

Durch die Korrektur befindet sich das DATAIN Register nun auf der 
Adresse D3. Zuvor war die Adresse vom DATAIN Register D2 und diese 
Adresse ist reserviert.
Gast #2713576
Lesenswert?

Sebastian schrieb:
> Ich habe den Fehler gefunden. Das H-File vom Compiler war fehlerhaft, so
> das die Adresse von dem DATAIN und den danach folgenden Registern falsch
> war. Nachdem ich das behoben hatt funktioniert die
> Checksummenberechnung.

Ärgerlicher Fehler. Welche Toolchain-Version? In der aktuellen Version 
(Atmel Studio 6) ist die Struktur korrekt.

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