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.

Note: The write to the CRCWDAT registers clears/resets the shift buffer.

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.

Note: The CRC non-direct initial value of zero is zero.

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:

  1. Enable the CRC module (ON = 1) and shifts (CRCGO = 1).
  2. Shift the polynomial value right by one.
  3. Reverse the bit order of the shifted polynomial value.
  4. Write this result in the CRCXOR registers.
  5. Set the data width and polynomial length (DWIDTH[4:0] and PLEN[4:0] bits) to the polynomial order (length).
  6. Reverse the bit order of the desired direct initial value.
  7. Write the reversed initial value in the CRCWDAT registers.
  8. 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.

  9. Read the value from the CRCWDAT registers.
  10. 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;
}