Forum: Mikrocontroller und Digitale Elektronik CRC auf XMEGA32A4U berechnen


von Sebastian (Gast)


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?

von Sebastian (Gast)


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
}

von Sebastian (Gast)


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?

von Sauger (Gast)


Lesenswert?

Nabend,

nur über die Daten. Wie soll ein noch zu berechnender und damit 
unbekannter Wert (die CRC16) mit einfließen?

MfG

von Sebastian (Gast)


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?

von Sebastian (Gast)


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);

von Sebastian (Gast)


Lesenswert?

Scheint wohl keiner den CRC-Core von XMEGA zu benutzen :-) Da muss ich 
wohl selber das Problem lösen :-))))

von Horst (Gast)


Lesenswert?

Schonmal ins ASF reingeschaut? Dort müsste m.W. ein Treiber für das 
CRC-Modul rumliegen, vielleicht bringt das etwas Licht ins Dunkel?

von Gizmo2 (Gast)


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.

von Johann (Gast)


Lesenswert?

@ Gizmo2

Du hast recht damit würde ich auch die anderen überschreiben.

von Sebastian (Gast)


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
    }

von Sebastian (Gast)


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.

von Sebastian (Gast)


Lesenswert?

Als nächstes werde ich mal die Zeit messen, die ich für die Berechnung 
der Checksummer benötige :-)

von Horst (Gast)


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.

von Sebastian (Gast)


Lesenswert?

Ich benutze den aktuellen Codevision Compiler und da ist die Struktur 
leider falsch. Ich werde morgen mal Codevision anschreiben, so das dies 
mal geändert wird.

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.