27.4.2 Typical Operations
To use the module for a typical CRC calculation:
- Set the CRCEN bit to enable the module.
- Configure the module for the desired operation:
- Program the desired polynomial using the CRCXOR registers and the PLEN<4:0> bits.
- Configure the data width and shift direction using the DWIDTH<4:0> and LENDIAN bits.
- Set the CRCGO bit to start the calculations.
- Set the desired CRC initial value in the CRCWDAT registers as described in CRC Initial Value.
- 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).
- Wait until the data FIFO is empty (CRCMPT bit is set).
- 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;
}