27.3.4.5 CRC Initial Value
The access to the CRC shift engine is provided through the CRCWDAT registers. These registers can be loaded with a desired CRC initial value prior to the start of the calculations. The form of this initial value depends on the operating mode selected by the MOD bit (CRCCON[2]).
In Alternate mode (MOD bit = 1
, not available on all
devices), the CRC initial value must be in direct form.
In Legacy mode (MOD bit = 0
), the CRC initial value
must be in non-direct form. The non-direct initial value is a value for which the CRC
calculation gives the desired direct CRC initial value. For example, if the application
uses CRC-32 polynomial, 0x04C11DB7, and must start the calculations from the CRC direct
initial value, 0xFFFFFFFF, then the non-direct value, 0x46AF6449, must be loaded in the
CRCWDAT registers (the CRC of this non-direct value, 0x46AF6449, is 0xFFFFFFFF). When
the non-direct initial value is written into the shift engine using the CRCWDAT
registers, it will be converted by the CRC module to the direct initial value after
(PLEN[4:0] + 1) peripheral clock cycles.
Usually, the CRC calculation starts from the same initial value every time. In this case, the non-direct initial value can be found just once and then can be defined as a constant in the application code.
Software Routine to Calculate the Non-Direct Initial Value shows a possible software routine to get the non-direct initial value from the direct initial value.
The CRC module can be used to get the non-direct initial value. To do this:
- Enable the CRC module (ON =
1
) and shifts (CRCGO =1
). - Shift the polynomial value right by one.
- Reverse the bit order of the shifted polynomial value.
- Write this result in the CRCXOR registers.
- Set the data width and polynomial length (DWIDTH[4:0] and PLEN[4:0] bits) to the polynomial order (length).
- Reverse the bit order of the desired direct initial value.
- Write the reversed initial value in the CRCWDAT registers.
- Write a dummy data to the CRCDAT
registers and wait two peripheral clock cycles to move the data from the FIFO to the
shift buffer and (PLEN[4:0] + 1) peripheral clock cycles to shift out the
result.
Alternatively, clear the CRC Interrupt Selection bit (CRCISEL =
0
) to get the interrupt when shifts from the shift buffer are done, clear the CRC interrupt flag, write dummy data in the CRCDAT registers and wait for the CRC interrupt flag to set. - Read the value from the CRCWDAT registers.
- Reverse the bit order of the read result; it will give the final non-direct initial value.
Calculating the Non-Direct Initial Value (MOD bit = 0) shows one way to implement this procedure.
To continue calculations of the full data message in the applications where the intermediate CRC sums must be read in the middle of the calculations, the non-direct value must be calculated and set to the CRCWDAT registers again. In this case, the CRC direct initial value will be an intermediate CRC result read.
Software Routine to Calculate the Non-Direct Initial Value
unsigned int CalculateNonDirectSeed(
unsigned int seed, // direct CRC initial value
unsigned int polynomial, // polynomial
unsigned char polynomialOrder) // polynomial order
{
unsigned char lsb;
unsigned char i;
unsigned int msbmask;
msbmask = ((unsigned int)1)<<(polynomialOrder-1);
for (i=0; i<polynomialOrder; i++) {
lsb = seed & 1;
if (lsb) seed ^= polynomial;
seed >>= 1;
if (lsb) seed |= msbmask;
}
return seed; // return the non-direct CRC initial value}
Calculating the Non-Direct Initial
Value (MOD bit = 0
)
unsigned int CalculateNonDirectSeed(unsigned int seed, // direct CRC initial value
unsigned int polynomial, // polynomial
unsigned char polynomialOrder) // polynomial order (valid values are
// 8, 16, 32 bits)
{
CRCCON1 = 0;
CRCCON2 = 0;
CRCCON1bits.CRCEN= 1; // enable CRC
CRCCON1bits.CRCISEL= 0; // interrupt when all shifts are done
CRCCON2bits.DWIDTH= polynomialOrder-1; // data width
CRCCON2bits.PLEN= polynomialOrder-1; // polynomial length
CRCCON1bits.CRCGO= 1; // start CRC calculation
polynomial >>= 1; // shift the polynomial right
polynomial = ReverseBitOrder(polynomial, polynomialOrder); // reverse bits order of the polynomial
CRCXOR = polynomial; // set the reversed polynomial
seed = ReverseBitOrder(seed, polynomialOrder); // reverse bits order of the seed value
CRCWDAT = seed;
_CRCIF = 0; // clear interrupt flag
switch(polynomialOrder) // load dummy data to shift out the
// seed result
{
case 8:
*((unsigned char*)&CRCDAT) = 0; // load byte
while(!_CRCIF); // wait until shifts are done
seed = CRCWDAT&0x00ff; // read reversed seed
case 16: CRCDAT = 0; // load short
while(!_CRCIF); // wait until shifts are done
seed = CRCWDAT; // read reversed seed
break;
case 32:
// load long
CRCDAT = 0;
while(!_CRCIF); // wait for shifts are done
seed = CRCWDAT; // read reversed seed
break;
default:
;
}
seed = ReverseBitOrder(seed, polynomialOrder); // reverse the bit order to get the
// non-direct seed
return seed; // return the non-direct CRC initial value}
// WHERE THE FUNCTION TO REVERSE THE BIT ORDER CAN BE
unsigned int ReverseBitOrder(unsigned int data, // input data
unsigned char numberOfBits) // width of the input data,
// valid values are 8,16,32 bits
{
unsignedintmaskin = 0;
unsignedintmaskout = 0;
unsignedintresult = 0;
unsignedchari;
switch(numberOfBits)
{
case 8:
maskin = 0x80;
maskout = 0x01;
break;
case 16:
maskin = 0x8000;
maskout = 0x0001;
break;
case 32:
maskin = 0x80000000;
maskout = 0x00000001;
break;
default:
;
}
for(i=0; i<numberOfBits; i++)
{
if(data&maskin){
result |= maskout;
}
maskin >>= 1;
maskout <<= 1;
}
return result;
}