27.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)

// This macro is used to swap bytes for big endian
#define			Swap(x) __extension__({ \
unsigned			int __x = (x), __v; \
__asm__ ("wsbh %0,%1;\n\t" \
"rotr %0,16" \
: "=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;
// standard CRC-SMBUS
#define			CRCSMBUS_POLYNOMIAL ((unsigned int)0x00000007)
#define			CRCSMBUS_SEED_VALUE ((unsigned int)0x00000000)		    // direct initial value
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
IFS0CLR = _IFS0_CRCIF_MASK;									   // clear the interrupt flag
CRCDAT  = data;											 // write last data into FIFO
CRCCONbits.CRCGO = 1;										  // resume CRC calculation
while(!IFS0bits.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)

// 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;
// standard CRC-16
#define			CRC16_POLYNOMIAL ((unsigned int)0x00008005)
#define			CRC16_SEED_VALUE ((unsigned int)0x00000000)			   // direct initial value
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
IFS0CLR = _IFS0_CRCIF_MASK;									     // clear the interrupt flag
*((unsigned short*)&CRCDAT) = data;								    // write last data into FIFO
CRCCONbits.CRCGO = 1;										    // resume CRC calculation
while(!IFS0bits.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)

// 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;
// standard CRC-32
#define			CRC32_POLYNOMIAL ((unsigned int)0x04C11DB7)
#define			CRC32_SEED_VALUE ((unsigned int)0xFFFFFFFF)			// direct initial value
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
IFS0CLR = _IFS0_CRCIF_MASK;									   // clear the interrupt flag
CRCDAT  = *pointer;										    // write last data into FIFO
CRCCONbits.CRCGO = 1;										  // resume CRC calculation
while(!IFS0bits.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)

// 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;
#define			CRC32_POLYNOMIAL ((unsigned int)0x04C11DB7)
#define			CRC32_SEED_VALUE ((unsigned int)0xFFFFFFFF)	// direct initial value
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
IFS0CLR = _IFS0_CRCIF_MASK;							   // clear the interrupt flag
CRCDAT  = *pointer32;								  // write last 32-bit data into FIFO
CRCCONbits.CRCGO = 1;								  // resume CRC calculation
while(!IFS0bits.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
IFS0CLR = _IFS0_CRCIF_MASK;							   // clear the interrupt flag
*((unsigned char*)&CRCDAT) = *pointer8;					     // write last 8-bit data into FIFO
CRCCONbits.CRCGO = 1; 								 // resume CRC calculation
while(!IFS0bits.CRCIF);								// wait until shifts are done
crcResultCRC32 = CRCWDAT; 							    // get the final CRC result (must be 0xE092727E)
while(1);
return 1;
}