31.4.2 Typical Operations

To use the module for a typical CRC calculation:

  1. Set the CRCEN bit to enable the module.
  2. Configure the module for the desired operation:
    1. Program the desired polynomial using the CRCXOR registers and the PLEN[4:0] bits.
    2. Configure the data width and shift direction using the DWIDTH[4:0] and LENDIAN bits.
  3. Set the CRCGO bit to start the calculations.
  4. Set the desired CRC initial value in the CRCWDAT registers as described in CRC Initial Value.
  5. Load all data into the FIFO by writing to the CRCDAT registers as space becomes available (the CRCFUL bit must be zero before the next data loading).
  6. Wait until the data FIFO is empty (CRCMPT bit is set).
  7. Read the CRC result as described in CRC Result.

CRC-SMBus (8-Bit Polynomial with 32-Bit Data, Big-Endian, MOD bit = 1) through Data Width Switching (32-Bit Polynomial, Little-Endian, MOD bit = 1) show typical code for different combinations of polynomial length, data width, shift direction and CRC Engine modes.

CRC-SMBus (8-Bit Polynomial with 32-Bit Data, Big-Endian, MOD bit = 1)

// standard CRC-SMBUS
#define CRCSMBUS_POLYNOMIAL ((unsigned int)0x00000007)
#define CRCSMBUS_SEED_VALUE ((unsigned int)0x00000000) // direct initial value

// This macro is used to swap bytes for big endian, using the SWAP instruction
#define Swap(x) __extension__({ \
unsigned int __x = (x), __v; \
__asm__ ("swap.l %0;\n\t" \
: "=d" (__v) \
: "d" (__x)); \
__v; \
})

// ASCII bytes "12345678"
volatile unsigned char __attribute__((aligned(4))) message[] = 
{'1','2','3','4','5','6','7','8'};

volatile unsigned char crcResultCRCSMBUS = 0;

int main (void)
{
    unsigned int* pointer;
    unsigned short length;
    unsigned int data;

    CRCCON = 0;
    CRCCONbits.MOD = 1;     				// alternate mode
    CRCCONbits.ON = 1;      				// enable CRC
    CRCCONbits.LENDIAN = 0; 				// big endian
    CRCCONbits.CRCISEL = 0; 				// interrupt when all shifts are done
    CRCCONbits.DWIDTH = 32-1; 			    // 32-bit data width
    CRCCONbits.PLEN = 8-1; 				 // 8-bit polynomial order

    CRCXOR = CRCSMBUS_POLYNOMIAL; // set polynomial
    CRCWDAT = CRCSMBUS_SEED_VALUE; // set initial value

    CRCCONbits.CRCGO = 1; // start CRC calculation
    pointer = (unsigned int*)message;
    length = sizeof(message)/sizeof(unsigned int);

    while(1)
    {
        while(CRCCONbits.CRCFUL); 			// wait if FIFO is full
        data = *pointer++; 				// load from little endian
        data = Swap(data); 				// swap bytes for big endian
        length--;
        if(length == 0)
        {
            break;
        }
        CRCDAT = data; 				   // 32-bit word access to FIFO
    }

    CRCCONbits.CRCGO = 0; 				// suspend CRC calculation
    _CRCIF = 0; 					   // clear the interrupt flag
    CRCDAT = data; 					// write last data into FIFO
    CRCCONbits.CRCGO = 1; 			     // resume CRC calculation
    while(!_CRCIF); 				     // wait until shifts are done

    crcResultCRCSMBUS = (unsigned char)CRCWDAT&0x00ff; // get CRC result (must be 0xC7)

    while(1);

    return 1;
}

CRC-16 (16-Bit Data with 16-Bit Polynomial, Little-Endian, MOD bit = 1)

#include <xc.h>

// standard CRC-16
#define            CRC16_POLYNOMIAL ((unsigned int)0x00008005)
#define            CRC16_SEED_VALUE ((unsigned int)0x00000000)               // direct initial value

// ASCII bytes "87654321"
volatile            unsigned        short message[] = {0x3738,0x3536,0x3334,0x3132};
volatile            unsigned        short crcResultCRC16 = 0;
int main(void)
{
    unsigned short* pointer;
    unsigned short  length;
    unsigned short  data;

    CRCCON = 0;
    CRCCONbits.MOD = 1;             		// alternate mode
    CRCCONbits.ON  = 1;             		// enable CRC
    CRCCONbits.CRCISEL = 0;         		// interrupt when all shifts are done
    CRCCONbits.LENDIAN = 1;         		// little endian
    CRCCONbits.DWIDTH  = 16-1;     		 // 16-bit data width
    CRCCONbits.PLEN    = 16-1;      		// 16-bit polynomial order
    CRCXOR  = CRC16_POLYNOMIAL;     		// set polynomial
    CRCWDAT = CRC16_SEED_VALUE;     		// set initial value
    CRCCONbits.CRCGO = 1;           		// start CRC calculation
    
    pointer = (unsigned short*)message;
    length = sizeof(message)/sizeof(unsigned short);

    while (1)
    {
        while (CRCCONbits.CRCFUL);          	// wait if FIFO is full
        data = *pointer++;                  	// load data
        length--;
        if(length == 0) {
            break;
        }
        *((unsigned short*)&CRCDAT) = data;       // 16-bit word access to FIFO
    }
    CRCCONbits.CRCGO = 0;                         // suspend CRC calculation
    IFS4bits.CRCIF = 0;                           // clear the interrupt flag
    *((unsigned short*)&CRCDAT) = data;           // write last data into FIFO
    CRCCONbits.CRCGO = 1;                         // resume CRC calculation
    while (!IFS4bits.CRCIF);                      // wait until shifts are done
    crcResultCRC16 = (unsigned short)CRCWDAT;     // get CRC result (must be 0xE716)
    
    while (1);
    return 1;
}

CRC-32 (32-Bit Polynomial with 32-Bit Data, Little-Endian, MOD bit = 1)

#include <xc.h>

// standard CRC-32
#define CRC32_POLYNOMIAL ((unsigned int)0x04C11DB7)
#define CRC32_SEED_VALUE ((unsigned int)0xFFFFFFFF)            // direct initial value

// ASCII bytes "12345678"
volatile            unsigned        char __attribute__((aligned(4))) message[] =
{'1','2','3','4','5','6','7','8'};
// function to reverse the bit order (OPTIONAL)
unsigned int ReverseBitOrder(unsigned int data);
volatile unsigned int crcResultCRC32 = 0;

int main(void)
{
    unsigned int*  pointer;
    unsigned short length;

    CRCCON = 0;
    CRCCONbits.MOD = 1;             				// alternate mode
    CRCCONbits.ON  = 1;             				// enable CRC
    CRCCONbits.CRCISEL = 0;         				// interrupt when all shifts are done
    CRCCONbits.LENDIAN = 1;         				// little endian
    CRCCONbits.DWIDTH  = 32-1;     				 // 32-bit data width
    CRCCONbits.PLEN    = 32-1;     				 // 32-bit polynomial order
    CRCXOR  = CRC32_POLYNOMIAL;     				// set polynomial
    CRCWDAT = CRC32_SEED_VALUE;    				 // set initial value
    CRCCONbits.CRCGO = 1;          				 // start CRC calculation
    
    pointer = (unsigned int*)message;
    length  = sizeof(message)/sizeof(unsigned int);

    while(1)
    {
        while(CRCCONbits.CRCFUL);   				// wait if FIFO is full
        length--;
        if (length == 0) {
            break;
        }
        CRCDAT = *pointer++;        				// 32-bit word access to FIFO
    }
    CRCCONbits.CRCGO = 0;           				// suspend CRC calculation
    IFS4bits.CRCIF = 0;             				// clear the interrupt flag
    CRCDAT  = *pointer;             				// write last data into FIFO
    CRCCONbits.CRCGO = 1;           				// resume CRC calculation
    while(!IFS4bits.CRCIF);         				// wait until shifts are done
    crcResultCRC32 = CRCWDAT;       				// get the final CRC result
    
    // OPTIONAL reverse CRC value bit order and invert (must be 0x9AE0DAAF)
    crcResultCRC32 = ~ReverseBitOrder(crcResultCRC32);
    
    while(1);
    return 1;
}

unsigned int ReverseBitOrder(unsigned int data)
{
    unsigned int  maskin;
    unsigned int  maskout;
    unsigned int  result = 0;
    unsigned char i;

    maskin  = 0x80000000;
    maskout = 0x00000001;
    for(i=0; i<32; i++)
    {
        if (data & maskin) {
            result |= maskout;
        }
        maskin >>= 1;
        maskout <<= 1;
    }

    return result;
}

Data Width Switching (32-Bit Polynomial, Little-Endian, MOD bit = 1)

#include <xc.h>

#define CRC32_POLYNOMIAL ((unsigned int)0x04C11DB7)
#define CRC32_SEED_VALUE ((unsigned int)0xFFFFFFFF)    // direct initial value

// ASCII bytes "12345678"
volatile unsigned int message1[] = {0x34333231,0x38373635};

// ASCII bytes "123"
volatile unsigned char message2[] = {'1','2','3'};
volatile unsigned int crcResultCRC32 = 0;
int main(void)
{
    unsigned char* pointer8;
    unsigned int*  pointer32;
    unsigned short length;

    CRCCON = 0;
    CRCCONbits.MOD = 1;                 // alternate mode
    CRCCONbits.ON  = 1;                 // enable CRC
    CRCCONbits.CRCISEL = 0;             // interrupt when all shifts are done
    CRCCONbits.LENDIAN = 1;             // little endian
    CRCCONbits.DWIDTH  = 32-1;          // 32-bit data width
    CRCCONbits.PLEN    = 32-1;          // 32-bit polynomial order
    CRCXOR  = CRC32_POLYNOMIAL;         // set polynomial
    CRCWDAT = CRC32_SEED_VALUE;         // set initial value
    CRCCONbits.CRCGO = 1;               // start CRC calculation
    pointer32 = (unsigned int*)message1;
    length    = sizeof(message1)/sizeof(unsigned int);
    while(1)
    {
        while(CRCCONbits.CRCFUL);       // wait if FIFO is full
        length--;
        if(length == 0)
        {
        break;
        }
        CRCDAT = *pointer32++;          // 32-bit word access to FIFO
    }

    CRCCONbits.CRCGO = 0;               // suspend CRC calculation
    IFS4bits.CRCIF = 0;                 // clear the interrupt flag
    CRCDAT  = *pointer32;               // write last 32-bit data into FIFO
    CRCCONbits.CRCGO = 1;               // resume CRC calculation
    while(!IFS4bits.CRCIF);             // wait until shifts are done
    
    CRCCONbits.DWIDTH = 8-1;              // switch the data width to 8-bit
    pointer8 = (unsigned char*)message2;  // calculate CRC
    length   = sizeof(message2)/sizeof(unsigned char);
    
    while(length--)
    {
        while(CRCCONbits.CRCFUL);         // wait if FIFO is full
        length--;
        if(length == 0)
        {
        break;
        }
        *((unsigned char*)&CRCDAT) = *pointer8++;   // byte access to FIFO
    }

    CRCCONbits.CRCGO = 0;                       // suspend CRC calculation
    IFS4bits.CRCIF = 0;                         // clear the interrupt flag
    *((unsigned char*)&CRCDAT) = *pointer8;     // write last 8-bit data into FIFO
    CRCCONbits.CRCGO = 1;                       // resume CRC calculation
    while(!IFS4bits.CRCIF);                     // wait until shifts are done
    crcResultCRC32 = CRCWDAT;                   // get the final CRC result (must be 0xE092727E)
    
    while (1);
    return 1;
}