CRC
Cyclic Redundancy Check


Home Page






Click here for English version




Il CRC viene usato per garantire l'integrità dei pacchetti che vengono trasferiti tra due MCU o tra un PC e una MCU collegate attraverso un'interfaccia quale UART, SPI, I2C ecc.

Alcune MCU dell'ultima generazione includono un generatore di CRC automatico nelle periferiche sopra menzionate che evitano di implementare il calcolo dello stesso.

Quello che qui faremo è implementare il CRC via software.




INTRODUZIONE

Il principio di CRC consiste nel trattare le sequenze binarie come dei polinomi binari, cioè dei polinomi i cui coefficienti corrispondono alla sequenza binaria.
Così la sequenza binaria 0110101001 può essere rappresentata con la forma polinomiale seguente:

0*X9 + 1*X8 + 1*X7 + 0*X6 + 1*X5 + 0*X4 + 1*X3 + 0*X2 + 0*X1 + 1*X0 ovvero
X8 + X7 + X5 + X3 + X0 ovvero
X8 + X7 + X5 + X3 + 1

In questa modo, il bit di peso minore della sequenza (il bit più a destra) rappresenta il grado 0 del polinomio (X0 = 1), il quarto bit partendo da destra rappresenta il grado 3 del polinomio (X3)… 

Una sequenza di n bits costituisce quindi un polinomio di grado massimo n-1
Tutte le espressioni polinomiali sono manipolate successivamente con l'aritmentica modulo 2.



Normalmente come Polinomio Generator G si sceglie un numero primo che inizi e finisca con 1, alcuni esempi sono:
1001 - 11101 - 1100000001111 (CRC12) - 11000000000000101 (CRC16)


APPLICAZIONE

Sia M il messaggio da trasmettere di valore: 1010 0011 1010 1100
Si assume che G sia 11010
Chiamiamo M' il messaggio con associato il CRC.
Il CRC saràM / G.
Il codice CRC è così uguale al resto della divisione polinomiale di M / G dove ad M sono stati concatenati n bits nulli (0) corrispondenti al grado di G.
Dato che nel nostro caso G = 11010 si dice che è di grado 4 per cui si ha che G(bit)=4 quindi si tratta di aggiungere 4 bits a 0 ad M che diventa:
M = 1010 0011 1010 1100
0000.
Qui sotto c'è l'esempio su come calcolare il CRC.

1010 0011 1010 1100 0000
1101 0||| visto che il bit più a sinistra vale 1 cominciamo subito con la sottrazione
0111 0||| questo è il resto che abbiamo dopo aver effettuato l'XOR
111 00|| portiamo giù la prossima cifra e visto che il bit più a sinistra è 1 facciamo nuovamente la sottrazione
110 10|| fracciamo la sottrazione
001 10|| questo è il resto che abbiamo dopo aver effettuato l'XOR
01 101| portiamo giù la prossima cifra e visto che il bit più a sinistra e 0 non facciamo la sottrazione e portiamo giù un'altro bit
1 1011 visto che il bit più a sinistra è 1 facciamo nuovamente la sottrazione
 1 1010
0 0001 questo è il resto che abbiamo dopo aver effettuato l'XOR
zzzzz

Ripetendo queste operazioni sino alla fine si ottiene:

1010 0011 1010 1100 0000
1101 0
0111 00
110 10
001 101
01 1011
1 1010
0 0001 1
0001 10
001 101
01 1010
1 1010
0 0000 1
0000 11
000 110
00 1100
0 1100 0
1101 0
0001 00
001 000
01 0000
1 1010
0 1010 == CRC

Per creare M' basta concatenare il CRC così ottenuto, ai bits del messaggio da trasmettere M :
M'
= 1010 0011 1010 1100 + 1010
M'
= 1010 0011 1010 1100 1010
In generale l'algoritmo usato può essere rappresentato come sotto.







0 == CRC che essendo zero è OK
Se il destinatario del messaggio effettua la divisione di M' con G e ottiene 0 (zero) significa che non ci sono stati errori durante la trasmissione.

Qui sotto c'è un esempio completo di Tx con CRC e Rx che ricalcola il CRC





Polinomi generatori

I polinomi generatori più frequentemente impiegati sono :






Implementazione su MCU (microcontrollori)

Ci sono due possibili modi per implementare il CRC via SW e sono:

Loop driven implementation lavora come mostrato in Figure.1 (per 8bit MCU).
I dati sono inseriti in shift register e spostati a sinistra in sequenze di uno per volta.
Se il primo dato più a sinistra è 1 si fa l'XOR se invece il dato fosse 0 si fa un altro shift a sinistra e si ricomincia la verifica.



Table driven implementation
Questo metodo è più veloce del precedente perchè usa una tabella precalcolata per le operazioni di calcolo del CRC.
In questo caso invece che calcolare il CRC bit per bit si fanno i calcoli byte per byte.
Il vantaggio di questa tecnica rispetto alla precedente è la velocità a scapito di una occupazione di memoria superiore a causa della tabella (look-up table) che si deve avere in memoria.

Sotto c'è una comparazione fra le due tecniche in termini di memoria occupata e di velocità di esecuzione.
I dati sono riferiti a una MCU a 8Bit.

Comparation Table for 8bit MCU



Loop driven implementation

/* bit by bit
* The width of the CRC calculation and result.
* Modify the typedef for a 16 or 32-bit CRC standard.
*/
typedef uint8_t crc;

#define WIDTH (8 * sizeof(crc))
#define TOPBIT (1 << (WIDTH - 1))

crc
crcSlow(uint8_t const message[], int nBytes)
{
crc remainder = 0;


/*
* Perform modulo-2 division, a byte at a time.
*/
for (int byte = 0; byte < nBytes; ++byte)
{
/*
* Bring the next byte into the remainder.
*/
remainder ^= (message[byte] << (WIDTH - 8));

/*
* Perform modulo-2 division, a bit at a time.
*/
for (uint8_t bit = 8; bit > 0; --bit)
{
/*
* Try to divide the current data bit.
*/
if (remainder & TOPBIT)
{
remainder = (remainder << 1) ^ POLYNOMIAL;
}
else
{
remainder = (remainder << 1);
}
}
}

/*
* The final remainder is the CRC result.
*/
return (remainder);

} /* crcSlow() */

Table driven implementation

TABLE precalculation
crc crcTable[256];

void
crcInit(void)
{
crc remainder;


/*
* Compute the remainder of each possible dividend.
*/
for (int dividend = 0; dividend < 256; ++dividend)
{
/*
* Start with the dividend followed by zeros.
*/
remainder = dividend << (WIDTH - 8);

/*
* Perform modulo-2 division, a bit at a time.
*/
for (uint8_t bit = 8; bit > 0; --bit)
{
/*
* Try to divide the current data bit.
*/
if (remainder & TOPBIT)
{
remainder = (remainder << 1) ^ POLYNOMIAL;
}
else
{
remainder = (remainder << 1);
}
}

/*
* Store the result into the table.
*/
crcTable[dividend] = remainder;
}



} /* crcInit() */

Table driven implementation
crc
crcFast(uint8_t const message[], int nBytes)
{
uint8_t data;
crc remainder = 0;


/*
* Divide the message by the polynomial, a byte at a time.
*/
for (int byte = 0; byte < nBytes; ++byte)
{
data = message[byte] ^ (remainder >> (WIDTH - 8));
remainder = crcTable[data] ^ (remainder << 8);
}

/*
* The final remainder is the CRC.
*/
return (remainder);

} /* crcFast() */

Free source code in C

Esempio Loop driven eTable driven pronto all'uso fatto per Windows sviluppato usando Dev-C++ per scaricarlo cliccate qui.
Il Dev-C++ è free ad è possibile prenderlo qui, se volete la mia versione di Dev-C++ clicate qui.

Il sito originale dell'esempio del CRC sopra menzionato è: http://www.netrino.com/code/crc.zip






Altri esempi da provare:



// Programma che calcola il CRC di una sequenza di caratteri
// immessi da tastiera, terminati con EOF


#include <stdio.h>

#define PG 0x11021 /* Polinomio generatre */

int crc(int oldcrc, unsigned char toadd); /* Aggiunge toadd al CRC calcolato */

main()
{
int resto=0; // CRC
int c; // Carattere letto
int i = 0; // Contatore dei caratteri

printf("Inserisci una sequenza di caratteri: ");
while((c=getchar())!=EOF)
{
resto=crc(resto,c); // Agginge il carattere letto al CRC dei precedenti
i++; // Conta i caratteri letti
}
resto=crc(resto,0); // Agginge al CRC i primi otto zeri
resto=crc(resto,0); // Agginge al CRC i secondi otto zeri in fondo

printf("\nLetti %d caratteri, CRC calcolato: %x\n", i, resto);
}

/* Aggiunge i bit del codice oldcrc al dividendo, per
* calcolare il nuovo CRC
*/
int crc(int oldcrc, unsigned char toadd)
{
int i; // Indice del bit

// I bit del carattere vanno trattati dal piu' significativo al meno
for(i=0;i<8;i++) // Per ogni bit del byte
{
oldcrc= (oldcrc<<1) | (toadd>>7); // Aggiunge il bit piu' significativo
// del codice in fondo al CRC,
// spostando a sinistra i bit del CRC
toadd <<= 1; // Toglie il bit gestito dal codice
if((oldcrc & 0x10000) != 0) // Se il divisore ci sta' (alla sua maniera)
{
oldcrc=oldcrc^PG; // Allora lo toglie (sottrazione senza riporti,
// quindi XOR
}
}
return oldcrc; // Restituisce il CRC ricalcolato
}



CRC16 Calculation Algorithm

Polynomial: x16 + x12 + x5 + 1
Start Value: 0xFFFF

CRC_POLYNOM = 0x8408;
CRC_PRESET = 0xFFFF;

C-Example:

unsigned internal CRC = CRC_PRESET;
for (i = 0; i < cnt; i++) /* cnt = number of protocol bytes without CRC */
{
    crc ^= DATA[i];
    for (j = 0; j < 8; j++)
    {
        if (crc & 0x0001)
            crc = (crc >> 1) ^ CRC_POLYNOM;
        else
            crc = (crc >> 1);
    }
}






References
Web page that calculates the CRC:
http://www.zorc.breitbandkatze.de/crc.html
Articles on the theory of the CRC:
http://en.wikipedia.org/wiki/Cyclic_redundancy_check(EN)
http://it.wikipedia.org/wiki/Cyclic_redundancy_check(IT)
A PAINLESS GUIDE TO CRC ERROR DETECTION ALGORITHM
http://www.geocities.com/SiliconValley/Pines/8659/crc.htm
http://www.repairfaq.org/filipg/LINK/F_crc_v3.html
A Table-Driven implementation for speed up the CRC calculation (Chaper 10)
http://www.repairfaq.org/filipg/LINK/F_crc_v33.html#CRCV_001
http://www.repairfaq.org/filipg/LINK/F_crc_v3.html
http://it.kioskea.net/contents/base/control.php3
http://www.microst.it/Progetti/CRC_2.html

EXAMPLEs
http://www.codeproject.com/KB/cs/csRedundancyChckAlgorithm.aspx
http://www.relisoft.com/science/CrcOptim.html
http://www.experts-exchange.com/Programming/Editors_IDEs/C_CPP_CS/CPP_Builder/Q_21192644.html
http://www.faqs.org/faqs/compression-faq/part1/section-26.html



Home Page