This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

TMS320F28377D: VCU2 CRC vs manual calculation

Part Number: TMS320F28377D

Hello.

I've calculated CRC-16 for test array "0xAF41" by VCU2 functions from example project.

For "INIT_CRC16 = 0x0000" "Calculated_CRC = 0x1C73", for "INIT_CRC16 = 0xFFFF" "Calculated_CRC = 0x9C7E".

If I calculate CRC-16 for this test array manually, I'll get the same result for init value "0" but another for init "0xFFFF" ("Calculated_CRC = 0x1C57", see pictures below).

If I want calculated CRC by VCU equals manually calculated CRC I have to set "INIT_CRC16 = 0x0000" and real init value (0xFFFF) write in front of the test array (test array in this case will be "0xFFFFAF41"). Then "Calculated_CRC = 0x1C57" too.

Is it a normal behavior of CRC VCU calculation? Do I need to write init value in front of array before call CRC VCU functions for proper results?

I know that online-CRC-calculators issues results like CRC VCU functions but I can not understand why they do so and what I have to do. Maybe it is worldwide practice to calculate CRC so?

My CRC parameters:

Name: CRC-16
Width: 16
Poly: 0x8005
Init: 0xFFFF
RefIn: FALSE
RefOut: FALSE
XorOut: 0xFFFF

  • Hi Aleksey,

    In the case of 0xFFFF, what specific function in the VCU library are you calling, and how are you setting it up?

    The seed (init) is XOR'd with the first value 0xAF41 before doing the CRC calculation. Now i noticed that the answer is actually the bit flipped output you get at the end.

  • Vishal_Coelho said:

    In the case of 0xFFFF, what specific function in the VCU library are you calling, and how are you setting it up?

    I use function "Calculate_CRC16" from file "CRC16.c" (I have attached it). After CRC-calculation from example project "2837x_vcu2_crc_16" I've only added XOR for result value with 0xFFFF. I don't reflect any values.

    CRC16.c
    /*
     * CRC16.c
     *
     *  Created on: 22 ���. 2018 �.
     *      Author: Griffin
     */
    
    
    //*****************************************************************************
    // includes
    //*****************************************************************************
    #include "crc_tbl.h"
    #include "vcu2_types.h"
    #include "vcu2_crc.h"
    #include "crctable0x8005.h"
    
    //!
    //! \defgroup CRC16_EXAMPLES Cyclic Redundancy Check 16-bit Example
    
    //!
    //! \ingroup CRC16_EXAMPLES
    // @{
    
    //*****************************************************************************
    // defines
    //*****************************************************************************
    //#define     NBYTES        (9)
    //#define     NWORDS        (5)
    #define     NBYTES        (2)
    #define     NWORDS        (1)
    //*****************************************************************************
    // globals
    //*****************************************************************************
    #ifdef __cplusplus
    #pragma DATA_SECTION("testInput")
    #else
    #pragma DATA_SECTION(testInput,"testInput")
    #endif //__cplusplus
    
    //\brief test input
    //
    // This vector is declared as a static const in order for the linker to
    // be able to run the CRC algorithm on it. It needn't be either static
    // or const for the C and VCU routines
    //
    static const uint16_t testInput[NWORDS] =
    {
        0x41AF,
        //0x3231, 0x3433, 0x3635, 0x3837, 0x0039,
    };
    
    // \brief linker generated object(CRC table)
    //
    extern CRC_TABLE linkerCrcTable;
    // \brief linker generated "run" location for the CRC table object
    //
    extern uint16_t crcTableRun;
    // \brief linker generated "load" location for the CRC table object
    //
    extern uint16_t crcTableLoad;
    // \brief linker generated "size" label indicating the size of the CRC table
    // object
    //
    extern uint16_t crcTableSize;
    // \brief object of the structure CRC_Obj
    //
    CRC_Obj    CRC;
    // \brief handle(pointer) to the CRC object
    //
    CRC_Handle handleCRC;
    // \brief A single record(element) from the CRC table object
    //
    CRC_RECORD linkerCrcRecord;
    // \brief pointer to the CRC table object
    //
    CRC_TABLE *pLinkerCrcTable;
    // \brief linker generated variables defining the load and run placements
    // of the testInput vector
    //
    extern uint32_t testInputLoadStart, testInputLoadSize, testInputRunStart;
    
    
    uint16_t pass = 0;
    uint16_t fail = 0;
    //*****************************************************************************
    // Function Prototypes
    //*****************************************************************************
    
    //*****************************************************************************
    // function definitions
    //*****************************************************************************
    
    //!
    //! \brief main routine for the 16-bit CRC example
    //! \return returns a 1
    //!
    //! This example shows how to
    //! -# use the vcu2 supported 16-bit CRC routines from the library
    //! -# use a C based table lookup routine to run a 16-bit CRC check using
    //!    any 16-bit polynomial
    //! -# demonstrate the link time CRC generation(using the
    //!    polynomials 0x8005) on a specified section of memory
    //!
    //! \note The variables used in the example are the same used in the CRC-8
    //! example and are not documented here again.
    //!
    void Calculate_CRC16(void)
    {
        // Locals
        uint32_t crcResultC_1;
    
        //*************************************************************************
        // Example #1: 128 bytes(x8, even), parity: low byte first
        //*************************************************************************
        //! \b Example \b #1, \b Part \b 1
        //! In this section we run a table lookup CRC on the vector testInput. The
        //! table is specified in the header files "CrcTable0x8005.h"
        //! The parity chosen was CRC_parity_even indicating that the CRC will start
        //! from the low byte of the first word.
        //! \code
        //************************************************************************
        // Step 1: Copy the test input vector from its load location to the run location.
        // This is necessary since the section was declared within a UNION in the linker
        // command file
        memcpy((uint32_t *)&testInputRunStart, (uint32_t *)&testInputLoadStart,
                (uint32_t)&testInputLoadSize );
    
        // Step 2: Initialize the CRC object
        CRC.seedValue    = 0xFFFF;//INIT_CRC16;
        CRC.nMsgBytes    = NBYTES;
        CRC.parity       = CRC_parity_even;
        CRC.crcResult    = 0;
        CRC.pMsgBuffer   = (uint16_t *)&testInput[0];
        CRC.pCrcTable    = (uint16_t *)&crc16P1Table[0];
        CRC.init         = (void (*)(void *))CRC_init16Bit;
        CRC.run          = (void (*)(void *))CRC_run16BitTableLookupC;
    
        // Step 3: Initialize the handle
        handleCRC = &CRC;
    
        // Step 4: Run the 16-bit table look-up CRC routine and save the first result
        CRC.init(handleCRC);
        CRC.run(handleCRC);
        crcResultC_1 = CRC.crcResult;
    
        crcResultC_1 = crcResultC_1 ^ 0xFFFF;
    }
    

    Have you seen my manual calculation? Why did you XOR init value with first word of data? I think we have to put init value to a shift register and do XOR with POLY when the highest bit is "1" like with other data bytes. Am I wrong?

  • Aleksey Nevz said:
    Have you seen my manual calculation? Why did you XOR init value with first word of data? I think we have to put init value to a shift register and do XOR with POLY when the highest bit is "1" like with other data bytes. Am I wrong?

    You can think of the seed or init value as the result of a previous CRC calculation, and that you are continuing the calculation from that point. If you think of it that way then you ought to xor the low byte of 0xFFFF with low byte of 0x41AF (your C code has it as 0x41AF and not 0xAF41), perform the CRC, shift the result and then xor it with high byte of 0x41AF, and do the whole process over. I have worked it out in the following two images. 

    This table driven implementation was inspired by 

    Its a long read, but the best literature on the subject in all my searches.

  • Ok. Thank's. I'm glad to know that we've read the same literature.

    I have the data, for example, 0x313233343536373839... and I want to calculate CRC for it. If I use VCU2 from example I have to write array

    static const uint16_t testInput[NWORDS] =
    {
    0x3231, 0x3433, 0x3635, 0x3837, 0x0039,
    };

    and use the Member 

    CRC.parity = CRC_parity_even;

    That means we calculate 0x31 first, then 0x32, 0x33 and others. Right? That's why I wrote 0x41AF in array in "CRC16.c" instead of 0xAF41 (0xAF41 - real data). If I calculate CRC with init = 0x0000 for this data (0xAF41) manually (pictures in first post), by using VCU2 (but there I have to write 0x41AF), by using CRC C-code function (we'll speak about it later) or by using one of the online-CRC-calculators (for example, this on picture below) I'll get the same result - 0x1C73.

    If I calculate CRC for 0xAF41 with init = 0xFFFF the result will be:

    - for manual calculation - 0x1C57;

    - for VCU2, online calculator and CRC C-code function - 0x9C7E.

    I've written about this in first post.

    Now let's speak about CRC C-code function and document that explains CRCs and was written by Ross N. Williams.

    On the Internet I found a CRC C-code functions (see the file "CRC_functions.c").

    CRC_functions.c
    unsigned int sciaOut[2] =
    {
         0x00AF, 0x0041,
    };
    
    void MakeCRC16Table(void)
    {
        unsigned int r;
        unsigned int i;
        unsigned int j;
    
        for(i = 0; i < 256; i++)
        {
            r = ((unsigned int) i) << 8;
            for(j = 0; j < 8; j++)
            {
                if(r & (1u << 15)) r= (r << 1) ^ 0x8005;
                else r = r << 1;
            }
            crc16Table[i] = r;
       }
    }
    
    unsigned int GetCRC16(unsigned int *buf, unsigned int len)
    {
        unsigned int crc;
    
        crc = 0xFFFF;
    
        while(len--)
        {
            crc = crc16Table[((crc >> 8) ^ *buf++) & 0xFF] ^ (crc << 8);
        }
        crc ^= 0xFFFF;
        return crc;
    }
    
    unsigned int GetCRC16_P(unsigned int *buf, unsigned int len)
    {
        unsigned int crc;
        crc = 0xFFFF;
    
        while(len--)
        {
            crc = crc16Table[(crc >> 8) & 0xFF] ^ ((crc << 8) | *buf++);
        }
    
        crc = crc16Table[(crc >> 8) & 0xFF] ^ (crc << 8);
        crc = crc16Table[(crc >> 8) & 0xFF] ^ (crc << 8);
    
        crc ^= 0xFFFF;
        return crc;
    }

    There are function "MakeCRC16Table" and function "GetCRC16" in "CRC_functions.c". If you thoroughly inspect them you'll find that 

    "crc = crc16Table[((crc >> 8) ^ *buf++) & 0xFF] ^ (crc << 8);"

    is the same to

    "while (len--) r = (r<<8) ^ t[(r >> 24) ^ *p++];"

    in document by Williams but there they do calculation for 32-bits blocks of data instead of 16-bits blocks of data in "GetCRC16". That's why we have ">> 24" instead of ">> 8".

    And near to this line in document by Williams is next note:

    Williams writes that we can not use algorithm in this way for "init" not 0x0000 but CRC C-code function "GetCRC16", that online CRC calculator and (I think) VCU2 do this! (by the way, for online CRC calculator there is an explanation for this situation - "8.6 When using an initial value other than zero in the shift register, the result is incorrect." - )

    If we inspect document by Williams above the "while (len--) r = (r<<8) ^ t[(r >> 24) ^ *p++];" we'll find the algorithm for proper calculation with any init value:

    I've changed "GetCRC16" function to this algorithm (see "GetCRC16_P"  in "CRC_functions.c") and used it for calculation CRC for my 0xAF41 and result was 0x1C57. This is the same value as manual CRC calculation!

  • Sorry for the delayed response, I had to read William's document again since its been a while. But under section 10, right after the snippet you posted he says

    "HEAD: If the initial value of the register is zero, the first four iterations of the loop will have the sole effect of shifting in the first four bytes of the message from the right. This is because the first 32 control bits are all zero and so nothing is XORed into the register. Even if the initial value is not zero, the first 4 byte iterations of the algorithm will have the sole effect of shifting the first 4 bytes of the message into the register and then XORing them with some constant value (that is a function of the initial value of the register).

    These facts, combined with the XOR property

    (A xor B) xor C = A xor (B xor C)

    mean that message bytes need not actually travel through the W/4 bytes of the register. Instead, they can be XORed into the top byte just before it is used to index the lookup table. This leads to the following modified version of the algorithm.

     

    
             +-----<Message (non augmented)
             |
             v         3    2    1    0   Bytes
             |      +----+----+----+----+
            XOR----<|    |    |    |    |
             |      +----+----+----+----+
             |                ^
             |                |
             |               XOR
             |                |
             |     0+----+----+----+----+       Algorithm
             v      +----+----+----+----+       ---------
             |      +----+----+----+----+       1. Shift the register left by
             |      +----+----+----+----+          one byte, reading in a new
             |      +----+----+----+----+          message byte.
             |      +----+----+----+----+       2. XOR the top byte just rotated
             |      +----+----+----+----+          out of the register with the
             +----->+----+----+----+----+          next message byte to yield an
                    +----+----+----+----+          index into the table ([0,255]).
                    +----+----+----+----+       3. XOR the table value into the
                    +----+----+----+----+          register.
                    +----+----+----+----+       4. Goto 1 iff more augmented
                 255+----+----+----+----+          message bytes.


    ....

    This is an IDENTICAL algorithm and will yield IDENTICAL results. The C code looks something like this:

    r=0; while (len--) r = (r<<8) ^ t[(r >> 24) ^ *p++];

    and THIS is the code that you are likely to find inside current table-driven CRC implementations. Some FF masks might have to be ANDed in here and there for portability's sake, but basically, the above loop is IT. We will call this the DIRECT TABLE ALGORITHM."

    Also, from the link you posted: http://www.sunshine2k.de/articles/coding/crc/understanding_crc.html#ch86

    "What does that mean for the initial value of the shift register when performing the CRC calculation bit by bit, like the pen and paper approach at the top? Answer: The register must be initialized with the initial value 'xored' with the first input bytes. For CRC-16 the initial value must be xored with the first two input bytes, for CRC-32 with the first four input bytes, and so on."

     

    meaning you are actually computing the CRC of 0xFFFF ^ 0x41AF = 0xBE50

       crc(0xBE50) = 0x6381

       final result = 0x6381 ^ 0xFFFF = 0x97CE

    and not the CRC of 0x41AFFFFF with zero initial value. From what I've read the whole point of the (non-zero) initial CRC register value is to catch leading zeros in the message, i.e. give a non zero CRC for leading message zeros.

  • Ok. Thanks a lot for your explanations.

  • Aleksey,

    If the issue is resolved, pls close this thread.