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.

TMS320F28375D: About calculation result of CRC32

Part Number: TMS320F28375D
Other Parts Discussed in Thread: CONTROLSUITE, LAUNCHXL-F28379D

We want to calculate CRC32 that confirms to IEEE802.3 using VCU-II.
CRC polynomial is equal to Poly1 type.
We use examples of "controlSUITE\libs\dsp\VCU\v2_10_00_00\examples\crc\2837x_vcu2_crc_32".
But  both CRC_run32BitPoly1 and CRC_run32BitPoly1Reflected do not match the expected value.
Is there a way to match the expected value?

  • Hello, I’ll look into this and get back to you by tomorrow.

    Thanks
    Sira
  • Hello, I have fallen sick and will be out of the office for 2 days. I will try to get back to you on this by Monday.

    Hope that's OK.

    Sira
  • Hello, Sira.

    I understand. I'm waiting for your answer.

    Kento

  • Hello,

    Can you please provide some additional details? Do the CRC_run32BitPoly1 and CRC_run32BitPoly1Reflected results match each other? When you say they don't match the expected value, where are you getting the "Expected value" from?

    In my experience, the byte order is usually the first thing to check in these situations.

    Thanks,
    Sira
  • Hello,

    I got the expected value from WireShark.

    WireShark calculate the CRC as Frame Check Sequence. We executed Wireshark on Linux.

    (Wireshark says FCS is incorrect, but it is in spec.

      https://www.wireshark.org/faq.html#q10.1)

     

     

    We calculated CRC of the data byte sequence (real ethernet packet) by three programs.

    [A] "controlSUITE\libs\dsp\VCU\v2_10_00_00\examples\crc\2837x_vcu2_crc_32" on TI Reference Board

    [B] The C program calcrc.c from

    http://kozos.jp/fpga/spartan3a_ether_tx.html

    (Sorry, Japanese Page) on Linux

    [C] The C program from

    https://blog.goo.ne.jp/masaki_goo_2006/e/69c68a18c872338e8c2751d662706f46

    (Sorry, Japanese Page) on Linux

     

    The CRC value is [A] = [C] and [B] = Wireshark.

    That's why I think it is an algorithm difference.

    Kento

  • Hello Kento,

    Thanks for the info. So you are basically compare TI generated CRC against multiple other CRC generation mechanisms. It's good that atleast one other external method matches TI's CRC. I am not sure why the Wireshark value is different. As of now, I can only hypothesize, and as I said before, often it is the order of the bytes that makes the difference. Can you try that and let me know what you find?

    Thanks,
    Sira
  • Hello Sira,

    For example, I input these byte data below.

    The CRC-32 value which WireShark calculated is as the expected value.

    The program [C] for TI Reference Board is attached.

    //#############################################################################
    //! \file /2837x_vcu2_crc_32/main.c
    //!
    //! \brief  Demo code for the 32-bit CRC routine(VCU and C)
    //!
    //! \date   May 21, 2013
    //! 
    //! This example shows how to
    //! -# use the vcu2 supported 32-bit CRC routines from the library
    //! -# use a C based table lookup routine to run a 32-bit CRC check using
    //!    any 32-bit polynomial
    //! -# demonstrate the link time CRC generation(using the
    //!    polynomials 0x04C11DB7 and 0x1EDC6F41) on a specified section of memory
    //
    //  Group:             C2000
    //  Target Family:     F2837x
    //
    // Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com/ 
    // ALL RIGHTS RESERVED 
    //#############################################################################
    //$TI Release: C28x VCU Library Version v2.10.00.00 $
    //$Release Date: Mar 3, 2015 $
    //#############################################################################
    
    //*****************************************************************************
    // includes
    //*****************************************************************************
    #include "crc_tbl.h"
    #include "vcu2_types.h"
    #include "vcu2_crc.h"
    #include "CrcTable0x04C11DB7.h"
    #include "CrcTable0x04C11DB7Reflected.h"
    #include "CrcTable0x1EDC6F41.h"
    #include "CrcTable0x1EDC6F41Reflected.h"
    #include "examples_setup.h"
    
    //!
    //! \defgroup CRC32_EXAMPLES Cyclic Redundancy Check 32-bit Example
    
    //!
    //! \ingroup CRC32_EXAMPLES
    // @{
    
    //*****************************************************************************
    // defines
    //*****************************************************************************
    #define     NBYTES        (94)
    #define     NWORDS        (NBYTES/2)
    
    #define SWAP_TYPE_0 (0)
    #define SWAP_TYPE_1 (1)
    #define SWAP_TYPE_2 (2)
    #define SWAP_TYPE_3 (3)
    
    #define SWAP_TYPE SWAP_TYPE_0
    //*****************************************************************************
    // 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 uint16_t testInput[NWORDS + 1] = {
    		  0xffff,
    		  0xffff,
    		  0xffff,
    		  0x0800,
    		  0x277f,
    		  0x07af,
    		  0x0800,
    		  0x4500,
    		  0x0054,
    		  0x0000,
    		  0x4000,
    		  0x4001,
    		  0x219c,
    		  0x0a00,
    		  0x020f,
    		  0x0a00,
    		  0x02ff,
    		  0x0800,
    		  0xf9a7,
    		  0x1dcf,
    		  0x0001,
    		  0xd9ce,
    		  0x035c,
    		  0x0000,
    		  0x0000,
    		  0x3b8a,
    		  0x0900,
    		  0x0000,
    		  0x0000,
    		  0x1011,
    		  0x1213,
    		  0x1415,
    		  0x1617,
    		  0x1819,
    		  0x1a1b,
    		  0x1c1d,
    		  0x1e1f,
    		  0x2021,
    		  0x2223,
    		  0x2425,
    		  0x2627,
    		  0x2829,
    		  0x2a2b,
    		  0x2c2d,
    		  0x2e2f,
    		  0x3031,
    		  0x3233,
    		  0x0000 /* dummy */
    };
    
    // \brief linker generated object(CRC table)
    //
    extern CRC_TABLE linkerCrcTable;
    // \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 32-bit CRC example
    //! \return returns a 1
    //!
    //! This example shows how to
    //! -# use the vcu2 supported 32-bit CRC routines from the library
    //! -# use a C based table lookup routine to run a 32-bit CRC check using
    //!    any 32-bit polynomial
    //! -# demonstrate the link time CRC generation(using the
    //!    polynomials 0x04C11DB7 and 0x1EDC6F41) 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.
    //!
    int main( void )
    {
        // Locals
        int16_t i;
        uint32_t crcResultC_1, crcResultC_2 ;
        uint32_t crcResultVcu_1, crcResultVcu_2;
        uint32_t crcResultLnk;
    
    #ifdef FLASH
    	EALLOW;
    	Flash0EccRegs.ECC_ENABLE.bit.ENABLE = 0;
    	memcpy((uint32_t *)&RamfuncsRunStart, (uint32_t *)&RamfuncsLoadStart,
    			(uint32_t)&RamfuncsLoadSize );
    	VCU2_initFlash();
    #endif //FLASH
    	
    #if SWAP_TYPE == SWAP_TYPE_1 || SWAP_TYPE == SWAP_TYPE_3
    	for (i = 0; i < (NWORDS + 1); i+=2) {
    		 uint16_t temp_swap;
    		 temp_swap = testInput[i];
    		 testInput[i] = testInput[i+1];
    		 testInput[i+1] = temp_swap;
    
    	}
    
    #endif
    #if SWAP_TYPE == SWAP_TYPE_2 || SWAP_TYPE == SWAP_TYPE_3
    	for (i = 0; i < NWORDS; i++) {
    		 uint16_t temp_swap;
    		 temp_swap = testInput[i];
    		 testInput[i] = (temp_swap & 0xFF00) >> 8;
    		 testInput[i] |= (temp_swap & 0xFF);
    	}
    #endif
    
    	VCU2_initSystemClocks();
    	
    	VCU2_initEpie();
    
        //*************************************************************************
        // 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 "CrcTable0x04C11DB7.h" and
        //! "CrcTable0x1EDC6F41.h"respectively and the entries were generated from the
        //! polynomials \f$ x^{32}+x^{26}+x^{23}+x^{22}+x^{16}+x^{12}+x^{11}+x^{10}+x^{8}+x^{7}+x^{5}+x^{4}+x^{2}+x^{1}+1 \f$(CCITT-32, 0x04C11DB7) and
        //! \f$ x^{32}+x^{28}+x^{27}+x^{26}+x^{25}+x^{23}+x^{22}+x^{20}+x^{19}+x^{18}+x^{14}+x^{13}+x^{11}+x^{10}+x^{9}+x^{8}+x^{6}+1 \f$(0x1EDC6F41) respectively.
        //! 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    = 0xffffffff;//INIT_CRC32;
        CRC.nMsgBytes    = NBYTES;
        CRC.parity       = CRC_parity_even;
        CRC.crcResult    = 0;
        CRC.pMsgBuffer   = (uint16_t *)&testInput[0];
        CRC.pCrcTable    = (uint16_t *)&crc32P1Table[0];
        CRC.init         = (void (*)(void *))CRC_init32Bit;
        CRC.run          = (void (*)(void *))CRC_run32BitTableLookupC;
    
        // Step 3: Initialize the handle
        handleCRC = &CRC;
    
        // Step 4: Run the 32-bit table look-up CRC routine and save the first result
        CRC.init(handleCRC);
        CRC.run(handleCRC);
        crcResultC_1 = CRC.crcResult;
    
        // Step 5: Load the second lookup table and run the C routine
        CRC.pCrcTable    = (uint16_t *)&crc32P2Table[0];
        CRC.crcResult    = 0;
        CRC.run(handleCRC);
        crcResultC_2 = CRC.crcResult;
    
        //*************************************************************************
        //! \endcode
        //!
        //! \b Example \b #1, \b Part \b 2
        //! Now we run the VCU routine on the vector testInput. The two
        //! polynomials employed by the VCU are  fixed i.e.
        //! \f$ x^{32}+x^{26}+x^{23}+x^{22}+x^{16}+x^{12}+x^{11}+x^{10}+x^{8}+x^{7}+x^{5}+x^{4}+x^{2}+x^{1}+1 \f$(CCITT-32, 0x04C11DB7) and
        //! \f$ x^{32}+x^{28}+x^{27}+x^{26}+x^{25}+x^{23}+x^{22}+x^{20}+x^{19}+x^{18}+x^{14}+x^{13}+x^{11}+x^{10}+x^{9}+x^{8}+x^{6}+1 \f$(0x1EDC6F41) respectively
        //! The parity chosen was CRC_parity_even indicating that the CRC will start
        //! from the low byte of the first word.
        //!
        //! Most of the object elements remain unchanged from the initial setup
        //!
        //! \note The VCU routine does not require a lookup table; pCrcTable can be
        //! reset to NULL or left as-is
        //! \code
        //*************************************************************************
        // Step 1: Reset a few elements of the CRC object
        CRC.crcResult    = 0;
        CRC.run          = (void (*)(void *))CRC_run32BitPoly1;
    
        // Step 2: Run the VCU 32-bit CRC routine and save the result
        CRC.run(handleCRC);
        crcResultVcu_1   = CRC.crcResult;
    
        // Step 3: Now for the other polynomial
        CRC.crcResult    = 0;
        CRC.run          = (void (*)(void *))CRC_run32BitPoly2;
    
        // Step 4: Run the VCU 32-bit CRC routine and save the result
        CRC.run(handleCRC);
        crcResultVcu_2   = CRC.crcResult;
        //*************************************************************************
        //! \endcode
        //!
        //! \b Example \b #1, \b Part \b 3
        //! The linker will compute the CRC(s) of the section \c testInput
        //! and keep the result as a record in a CRC_TABLE structure
        //! \c linkerCrcTable.
        //!
        //! Each record from this table is an object of type CRC_RECORD. The
        //! elements of this structure are described in detail, at the time of
        //! writing, in SPRU513D, section 7.9
        //!
        //! \note
        //! -# In the event the linker is configured to run multiple algorithms
        //!    on a section of memory, the result of those computations are placed in
        //!    the records in an unspecified order. The user must poll the crc_alg_ID
        //!    field of the record to determine which algorithm was run
        //! -# Note the use of the \b UNION keyword in the linker command file around
        //!    the \b testInput section to allow the linker to calculate two different
        //!    32-bit CRCs for the same memory block
        //!
        //*************************************************************************
        // Step 1: Initialize the CRC table pointer.
    
        pLinkerCrcTable  = &linkerCrcTable;
    
        // Step 2: Get the CRC results from the linker CRC table
        for(i = 0; i < pLinkerCrcTable->num_recs; i++){
            // Get the current CRC record
            linkerCrcRecord = pLinkerCrcTable->recs[i];
            // Get the linker generated CRC
            crcResultLnk    = linkerCrcRecord.crc_value;
            if(linkerCrcRecord.crc_alg_ID == CRC32_PRIME){ //0x04C11DB7
                (crcResultLnk == crcResultVcu_1)? pass++ : fail++;
                (crcResultVcu_1 == crcResultC_1)? pass++ : fail++;
            }else if(linkerCrcRecord.crc_alg_ID == CRC32_C){ //0x1EDC6F41
                (crcResultLnk == crcResultVcu_2)? pass++ : fail++;
                (crcResultVcu_2 == crcResultC_2)? pass++ : fail++;
            }else{
                fail++;
            }
        }
        //*************************************************************************
        //! \endcode
        //!
        //! \b Example \b #2
        //! We now run the reflected algorithm using both a table lookup method and
        //! compare it against its equivalent VCU routine. The reflected CRC
        //! table is specified in the header files "CrcTable0x04C11DB7Reflected.h" and
        //! "CrcTable0x1EDC6F41Reflected.h"; the entries were generated from the table
        //! indices 0,1,...255 by shifting out the LSB of the index and XOR'ing the
        //! remainder with the polynomial if the LSB was a 1
        //! The parity chosen was CRC_parity_even indicating that the CRC will start
        //! from the low byte of the first word.
        //! \code
        //*************************************************************************
        // Step 1: For the C routine, assign the correct look-up table and function
        // to the object and reset the CRC result
        CRC.crcResult    = 0;
        CRC.pCrcTable    = (uint16_t *)&crc32P1TableReflected[0];
        CRC.run          = (void (*)(void *))CRC_run32BitReflectedTableLookupC;
    
        // Step 2: Run the C routine, reflect and save the result
        CRC.run(handleCRC);
        crcResultC_1     = (uint32_t)(CRC_bitReflect((uint32_t)CRC.crcResult, 32));
    
        // Step 3: Replace the lookup table with that of the second polynomial
        CRC.crcResult    = 0;
        CRC.pCrcTable    = (uint16_t *)&crc32P2TableReflected[0];
        CRC.run(handleCRC);
        crcResultC_2     = (uint32_t)(CRC_bitReflect((uint32_t)CRC.crcResult, 32));
    
        // Step 4: Assign the VCU routine to the object and run it
        CRC.crcResult    = 0;
        CRC.run          = (void (*)(void *))CRC_run32BitPoly1Reflected;
        CRC.run(handleCRC);
        crcResultVcu_1   = CRC.crcResult;
    
        // Step 5: Assign the VCU routine(2nd polynomial) to the object and run it
        CRC.crcResult    = 0;
        CRC.run          = (void (*)(void *))CRC_run32BitPoly2Reflected;
        CRC.run(handleCRC);
        crcResultVcu_2   = CRC.crcResult;
    
        // Step 6: Compare the results of steps 2/3 with 4/5
        (crcResultC_1 == crcResultVcu_1)? pass++ : fail++ ;
        (crcResultC_2 == crcResultVcu_2)? pass++ : fail++ ;
    
        //*************************************************************************
        //!
        //! \endcode
        //!
        //*************************************************************************
        // End of test
        done();
        // Execution never reaches this point
        return 1;
    }
    // End of main
    
    // @} //addtogroup
    
    // End of file
    

    This program is a little changed from

    "controlSUITE\libs\dsp\VCU\v2_10_00_00\examples\crc\2837x_vcu2_crc_32".

     

    [Input Data Byte] (length: 0x5E octet) (ICMP packet)

    0000   ff ff ff ff ff ff 08 00 27 7f 07 af 08 00 45 00

    0010   00 54 00 00 40 00 40 01 21 9c 0a 00 02 0f 0a 00

    0020   02 ff 08 00 f9 a7 1d cf 00 01 d9 ce 03 5c 00 00

    0030   00 00 3b 8a 09 00 00 00 00 00 10 11 12 13 14 15

    0040   16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25

    0050   26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33

     

    [Expected Value]

    0xf63b3068

     

     

    [B] The C program calcrc.c on Linux

    0xf63b3068

    ->matched the expected value!!!

     

    [A] The C program on Linux

    0x70df6905

    ->unmatch the expected value

     

    Endian Swaps (3patterns below)

    →also unmatch the expected value

     

    [A'-1] Input data endian swap 1 of A (0xAABBCCDD → 0xDDCCBBAA)

    0x3568f093

     

    [A'-2] Input data endian swap 2 of A (0xAABBCCDD → 0xCCDDAABB)

    0xd7b2bd7d

     

    [A'-3] Input data endian swap 3 of A (0xAABBCCDD → 0xBBAADDCC)

    0xce394a9a

     

    [C]

    (As an assumption, since the initial value of CRC should be 0xffffffff in IEEE802.3,

    it is changed from the sample source.)

    #define SWAP_TYPE SWAP_TYPE_0

    <CRC_run32BitPoly1>

    crcResultVcu_1: 0xD7B2BD7D

    crcResultC_1:   0xD7B2BD7D

    <CRC_run32BitPoly1Reflected>

    crcResultVcu_1: 0xEAE0CA5C

    crcResultC_1:   0xEAE0CA5C

     

    [C'-1] Input data endian swap 1 of C (0xAABB, 0xCCDD → 0xCCDD, 0xAABB)

    #define SWAP_TYPE SWAP_TYPE_1

    <CRC_run32BitPoly1>

    crcResultVcu_1: 0x3568F093

    crcResultC_1:   0x3568F093

    →Same as [A'-1]!!

     

    <CRC_run32BitPoly1Reflected>

    crcResultVcu_1: 0xFAF09106

    crcResultC_1:   0xFAF09106

     

    [C'-2] Input data endian swap 2 of C (0xAABB, 0xCCDD → 0xBBAA, 0xDDCC)

    #define SWAP_TYPE SWAP_TYPE_2

    <CRC_run32BitPoly1>

    crcResultVcu_1: 0x0DBA7B59

    crcResultC_1:   0x0DBA7B59

    <CRC_run32BitPoly1Reflected>

    crcResultVcu_1: 0xD66F973A

    crcResultC_1:   0xD66F973A

     

    [C'-3] Input data endian swap 3 of C (0xAABB, 0xCCDD → 0xDDCC, 0xBBAA)

    #define SWAP_TYPE SWAP_TYPE_3

    <CRC_run32BitPoly1>

    crcResultVcu_1: 0x6D69A3D1

    crcResultC_1:   0x6D69A3D1

    <CRC_run32BitPoly1Reflected>

    crcResultVcu_1: 0xF9C6F089

    crcResultC_1:   0xF9C6F089

    I’m looking forward to your reply.

    Kento

  • Kento,

    Thanks for your reply. I do recognize that there are many different methods and programs available on CRC computation, and it is difficult for us to track and maintain all those methods.

    However, what we do provide with the TI CRC library is the ability to be flexible and compute the CRC the way you want it to be computed. To this end, we have the following options:
    1. Parity i.e. Endianness. This setting allows you to determine whether the first byte of your CRC computation is the LSB (Even parity) of the 16-bit word of your data buffer, or the MSB (Odd parity).
    2. Bit order i.e. using the "Reflected" option. This setting allows you to determine whether the bytes of data used for CRC computation are taken normally i.e. byte = bits(7:0) (CRCMSGFLIP = 0) or flipped i.e. byte = bits(0:7) (CRCMSGFLIP = 1).

    I would encourage you to become aware of how exactly the expected CRC is being generated i.e. which configuration values above are used. If that is known, you can set the same settings in the TI CRC library and generate the CRC. Otherwise, it becomes a guessing game, and you have to try various things.

    A few comments on your code:
    1. I see a #if SWAP_TYPE == SWAP_TYPE_1 || SWAP_TYPE == SWAP_TYPE_3 section, and also a #if SWAP_TYPE == SWAP_TYPE_2 || SWAP_TYPE == SWAP_TYPE_3 section. So it seems like SWAP_TYPE_3 is appearing in both places. Not sure what the intent is there.
    2. With the first set, it looks like you are swapping 16-bit words in memory. Not sure why you are doing this.
    3. With the second set, it looks like a bug - you are copying the 16-bit value to a temporary variable, then assigning the memory value to the MSB, and then ORing it with the LSB. So it looks like you are corrupting the values.

    Thanks,
    Sira
  • Hello, Sira.

    Thanks for your reply.
    As you say, there are many different methods to calculate CRC.
    And the biggest problem to me is that there is no unified term or notation in such variation,
    It is because we cannot uniquely identify what kind of method it is.

    Of course we do not want "a guessing game",
    The fact that the algorithm required by IEEE 802.3 is I know.

    [IEEE-802.3 CRC32 Ethernet Standard]
    Generator polynomial 0x04C11DB7(*1)
    Initial value 0xFFFFFFFF(*2)
    Final XOR value 0xFFFFFFFF(*3)
    bit order LSB First(*4)
    Output bit order LSB First(*5)

    How should I set up (*1)-(*5)?
    I think below.
    (*1) I understood clearly. I have to call CRC_run32BitPoly1() or CRC_run32BitPoly1Reflected();
    (*2) I understood too. I have to call CRC_run32bitXXX() with seedValue = 0xFFFFFFFF.
    (*3) I think that TI library is not support Final XOR. But I can calculate XOR of crcResult, can't I?.
    (* 4) (* 5) You can change by calling either CRC_run32BitPoly1 () or CRC_run32BitPoly1Reflected ().
    I think that CRC_run32BitPoly1Reflected () matches.

    My ultimate desire is that I only want the VCU-II sample program conforming to IEEE 802.3.
    I think that IEEE802.3 is one of the most widely used examples of CRC-32bit, so I think it will be useful for other TI users.

    Thanks,
    Kento

  • Kento,

    3. Yes, you can calculate the XOR on the TI CRC result.

    I would suggest you to compute 4 TI CRCs:
    1. Even parity and CRC_run32BitPoly1 ()
    2. Odd parity and CRC_run32BitPoly1 ()
    3. Even parity and CRC_run32BitPoly1Reflected()
    4. Odd parity and CRC_run32BitPoly1Reflected()

    In each case, log both the result CRC as well as the XOR of the result CRC.

    Also, are you sure that Wireshark and the other method that matches Wireshark use ALL the data bytes for the CRC computation?

    One more thing I would suggest is removing the dummy data word at the end of your data buffer i.e. let your data buffer be static uint16_t testInput[NWORDS] not static uint16_t testInput[NWORDS + 1]

    Thanks,
    Sira
  • Hello, Sira.
    Thanks for your advice.

    I got a little time and did an experiment.
    Unfortunately none of the results matched.

    First, to simplify the problem, I made the input data a multiple of 4 octets.
    As a result, "NWORDS + 1" become "NWORDS"

    [Input Data] (Add 0x0000, total 96 octets)
    ffffffff ffff0800 277f07af 08004500
    00540000 40004001 219c0a00 020f0a00
    02ff0800 f9a71dcf 0001d9ce 035c0000
    00003b8a 09000000 00001011 12131415
    16171819 1a1b1c1d 1e1f2021 22232425
    26272829 2a2b2c2d 2e2f3031 32330000

    [Expect Value] (Calculated by calcrc.c [B])
    d0d534b2

    1. Even parity and CRC_run32BitPoly1 ()

    Result:         0xED95E7AD
    ResultXOR: 0x126A1852

    2. Odd parity and CRC_run32BitPoly1 ()

    Result:         0x5F63D2EE
    ResultXOR: 0xA09C2D11

    3. Even parity and CRC_run32BitPoly1Reflected()

    Result:         0xC62679D6
    ResultXOR: 0x39D98629

    4. Odd parity and CRC_run32BitPoly1Reflected()

    Result:         0x358CE2A7
    ResultXOR: 0xCA731D58

    I think that VCU - II can not support IEEE 802.11. There is not much basis, but I imagine that the reason is probably bit order or endian relation.

    TI 's example program is comparing VCU - II and table method, and the algorithm is difficult to understand. Can you supply if there is a simple C language implementation that is not a table method?

    Thanks,
    Kento

  • Hi Kento,

    Thanks for trying out my suggestions, and it's unfortunate that the results still don't tally with the expected results.

    There's one C reference implementation that's not Table based, but I am not sure it fits your needs. I have attached it.

    I think our reference assembly routines definitely have some gaps in that they don't meet all customer use-cases, which is why our approach going forward (likely at the end of 3Quarter 2019) will be to provide intrinsics to customers using which they can write custom CRC algorithms easily in C. It is unfortunate that the CRC you are trying to generate doesn't match with the TI CRC even though the polynomial is the same, but this is not very surprising - since other users in the past have faced similar issues (with non-matching CRCs). This is why we are modifying our approach.

    For now, can you mark this issue as Resolved?

    Thanks,

    SiraF28335_Modbus_CRC_140905.zip

  • Hello Sira.

    Thank you for replying to us many times and providing the code.
    Unfortunately the code implements table method.

    main()@main.c
        result = CRC16_calc(accum, nBytes, parity, (uint16_t *)&crcTable[0], (uint16_t *)&msg[0]);
      ↓
    CRC16_calc()@CRC16.asm
    ;; \param tablePtr    XAR4   pointer to the CRC lookup table

      Argument "crcTable" is CRC lookup Table.

    VCU-II is very fast and attractive, so regrettable that we can not use it, and I want to clarify why it can not be used.
    We will consider a little more, but if possible, could you provide a code representing the algorithm of CRC 32 of VCU - II which is not table method?

    Thanks,
    Kento

  • Hi Kento,

    Happy to hear you want to use the VCU-II. I'll contact another expert and see if there's reference models for our assembly algorithms (there should be).

    In the meantime, I'd like a clarification and some extra information - in your first message, you mentioned IEEE 802.3, and in your previous message, you mention IEEE 802.11. Can you clarify? Also, can you provide some links on the CRCs associated with the IEEE standard you are looking to compute?

    Thanks,
    Sira
  • Hello, Sira.

    Thank you for your quick reply and great help.

    Sorry  It is mistake that I wrote 802.11. What I really want is 802.3.

    I provide a little  links.

    [1] ieeexplore.ieee.org/.../mostRecentIssue.jsp
      (open PDF and see 3.2.8)
    [2] www.xilinx.com/.../xapp209.pdf
    [3] kozos.jp/.../calcrc.c
      (Since it is a Japanese page, please refer only as code example.
        I have confirmed that this code is consistent with CRC of Wireshark.)

    Thanks,
    Kento

  • Hi Kento,

    The expert I talked to told me that there is no C or MATLAB models for the assembly CRC routines. There are C/MATLAB models for the Table based routines, and the assembly routines are verified by comparing results against the Table based routines.

    On the CRC mismatch issue, why don't we simplify and try to make the CRC match with a single data word or byte? For example, use 0x01 (or if you want to use a 16-bit word, 0x0001) and generate the CRC with Wireshark, and with TI CRC (if necessary, using various combinations of TI configuration settings that we discussed and maybe also the data e.g. 0x1000 etc.) and see if we can get a match. 

    Thanks,

    Sira

  • Kento,

    I would like to leave you with my suggestions above and mark the issue as resolved. If you have any further questions, please open a new forum question and it will get assigned to me.

    Also, I would appreciate if you could indicate "Answer Verified" against my reply.

    Thanks,
    Sira
  • Hi Kento,

    I am having similar problems finding appropriate VCU parameters to match a given CRC32 implementation.

    This is as close as I have gotten:

    Given data bytes {0x12, 0x34, 0x56, 0x78, ...} store them as uint16_t array {0x3412, 0x7856, ...}

    Using

    uint32_t VCU_CRC32reflected(uint16_t *data,  uint32_t len, uint32_t init, uint32_t final_xor) {
        CRC.seedValue    = init;
        CRC.nMsgBytes    = len;
        CRC.parity       = CRC_parity_even;
        CRC.crcResult    = 0;
        CRC.pMsgBuffer   = data;
        CRC.pCrcTable    = NULL;
        CRC.init         = (void (*)(void *))CRC_init32Bit;
        CRC.run          = (void (*)(void *))CRC_run32BitPoly1Reflected;

        CRC.init(&CRC);
        CRC.run(&CRC);
        return CRC.crcResult^final_xor;
    }

    with init = final_xor = 0xffffffff to calcualte the checksum for the data you have posted, I am getting 0x6FDC0C16 as the result of the function above.

    This is the bit reverse of 0x68303bf6 which is the byte reverse of what you expect.

    Please let me know If you have found a better solution in the meantime.

    Regards,

    Johannes

     

  • Hi Johannes,

    I appreciate you taking the time to share your findings. It is good to know there is correlation (albeit a complex one!) Can you please share your uint16_t data array and the value of "len" that you used to arrive at the above result?

    Thanks,
    Sira
  • Hi Sira,

    here is the code I used for testing:

    const uint16_t test_data2[47] = {
    0xffff, 0xffff, 0xffff, 0x0008, 0x7f27, 0xaf07, 0x0008, 0x0045,
    0x5400, 0x0000, 0x0040, 0x0140, 0x9c21, 0x000a, 0x0f02, 0x000a,
    0xff02, 0x0008, 0xa7f9, 0xcf1d, 0x0100, 0xced9, 0x5c03, 0x0000,
    0x0000, 0x8a3b, 0x0009, 0x0000, 0x0000, 0x1110, 0x1312, 0x1514,
    0x1716, 0x1918, 0x1b1a, 0x1d1c, 0x1f1e, 0x2120, 0x2322, 0x2524,
    0x2726, 0x2928, 0x2b2a, 0x2d2c, 0x2f2e, 0x3130, 0x3332}; 
    
    
    const uint16_t test_data3[48] = {
    0xffff, 0xffff, 0xffff, 0x0008, 0x7f27, 0xaf07, 0x0008, 0x0045,
    0x5400, 0x0000, 0x0040, 0x0140, 0x9c21, 0x000a, 0x0f02, 0x000a,
    0xff02, 0x0008, 0xa7f9, 0xcf1d, 0x0100, 0xced9, 0x5c03, 0x0000,
    0x0000, 0x8a3b, 0x0009, 0x0000, 0x0000, 0x1110, 0x1312, 0x1514,
    0x1716, 0x1918, 0x1b1a, 0x1d1c, 0x1f1e, 0x2120, 0x2322, 0x2524,
    0x2726, 0x2928, 0x2b2a, 0x2d2c, 0x2f2e, 0x3130, 0x3332, 0x0000};
    
    
    uint32_t VCU_CRC32_test(uint16_t *data,  uint32_t len, uint32_t init, uint32_t final_xor) {
        CRC_Obj    CRC;
        CRC.seedValue    = init;
        CRC.nMsgBytes    = len;
        CRC.parity       = CRC_parity_even;
        CRC.crcResult    = 0;
        CRC.pMsgBuffer   = data;
        CRC.pCrcTable    = NULL;
    
        CRC_init32Bit(&CRC);
        CRC_run32BitPoly1Reflected(&CRC);
        return CRC_bitReflect(CRC.crcResult^final_xor, 32);
    }
    
    
    uint32_t crc32_vcu;
    
    void crc_test(void) {
       crc32_vcu = VCU_CRC32_test((uint16_t *)test_data2, 2*sizeof(test_data2), 0xffffffff, 0xffffffff);
       crc32_vcu = VCU_CRC32_test((uint16_t *)test_data3, 2*sizeof(test_data3), 0xffffffff, 0xffffffff);
       return;
    }

    With test_data2 I'm getting crc32_value = 0x68303bf6, which is the result I was referring to in my response post.

    With test_data3 I'm getting crc32_value = 0xB234D5D0, which is the byte reverse of the expected value 0xd0d534b2.

    Regards, Johannes

  • Johannes,

    Yes, I did ask Kento to append a 0x0000 midway through our discussions.

    I repeated your tests, and was able to reproduce 0x6FDC0C16 with test_data2, however with test_data3, the result I am getting is 0x0BAB2C4D.

    Can you please check?

    Thanks,
    Sira
  • Johannes,

    The test result 0x6FDC0C16, when bit-reversed byte-by-byte, results in 0xF63B3068 (as you pointed out) which matches what Kento's reference expected value. Without an understanding of what that website reference is doing, it is difficult to know why the results don't exactly match straightaway. Have you used any other reference websites to compare against?

    Thanks,
    Sira
  • Sira Rao80 said:
    I repeated your tests, and was able to reproduce 0x6FDC0C16 with test_data2, however with test_data3, the result I am getting is 0x0BAB2C4D.

    Can you please check?

    I checked, and the result for test_data3 remains 0xB234D5D0. 

    I'm testing on a LAUNCHXL-F28379D but I wouldn't expect that to make any difference...

    Regards, Johannes

  • I was trying to match CRCs computed by ZIP. I tested using the Perl script:

    #!/usr/bin/perl
    use strict;
    use warnings;
    use Archive::Zip;
    my $data = pack('S*', 0xc0ff, 0xc01a, 0x1122, 0x3344, 0x5566, 0x7788);
    printf "%08X\n", Archive::Zip::computeCRC32($data);
    

    which prints 259D4336. In order to get the same result using VCU I had to do the following:

    const uint16_t test_data4[] = { 0xc0ff, 0xc01a, 0x1122, 0x3344, 0x5566, 0x7788 };
    
    uint32_t VCU_CRC32_test(uint16_t *data,  uint32_t len, uint32_t init, uint32_t final_xor) {
        CRC_Obj    CRC;
        CRC.seedValue    = init;
        CRC.nMsgBytes    = len;
        CRC.parity       = CRC_parity_even;
        CRC.crcResult    = 0;
        CRC.pMsgBuffer   = data;
        CRC.pCrcTable    = NULL;
    
        CRC_init32Bit(&CRC);
        CRC_run32BitPoly1Reflected(&CRC);
        return CRC_bitReflect(CRC.crcResult^final_xor, 32);
    }
    
    crc32_vcu4 = VCU_CRC32_test((uint16_t *)test_data4, 2*sizeof(test_data4), 0xffffffff, 0xffffffff);
    

    I hope this helps. Unfortunately, I have no explanation why that works.

    Regards, Johannes

  • Johannes,

    Thanks for checking and for the updates.

    It's interesting that you had to run CRC_bitReflect on the CRC result to get it to match the ZIP CRC.

    But with the earlier CRCs we were trying to match up, we got the CRC result = 0x6FDC0C16, and if we ran CRC_bitReflect() on it, it would result in 0x68303bf6, AND we would still need to Byte Reverse these to get 0xf63b3068 which Kento was referring to as the Wireshark result?

    Thanks,
    Sira
  • Johannes,

    I would like to learn more about your specific application of the CRC. What exactly are you using the CRC for? And the details i.e. is your application fine with computing CRC on a block of data? What polynomials are required? Would user-configurable polynomials be preferable, or standard polynomials suffice? Please let me know.

    Thanks,
    Sira
  • Sira Rao80 said:
    What exactly are you using the CRC for?

    We use it as part of our communication protocols to detect transmission errors. Because the communication protocol is used by many of our devices, I had to find matching CRC parameters by an unsatisfying trial-and-error procedure. In the communication protocol the checksum is often calculated over some 10 words. In this case, the requirement to bit reverse the output of CRCrun32BitPoly1 eats some of the performance advantages (compared to a table based implementation).

    Another use could be to check data integrity in external memory (e.g. serial flash). Here, the CRC parameters are not so important. Since serial flash is slow, the performance advantage of VCU based CRC calculation is less important.

    Sira Rao80 said:
    What polynomials are required? Would user-configurable polynomials be preferable, or standard polynomials suffice?

    I'm fine with the standard polynomials. Having more choice would make it even more difficult to find something that matches a given implementation (IMHO).

    Regards, Johannes

  • Johannes,

    Apologies for a delayed response from my side. Thanks for your use case description!

    So basically there is an embedded CRC in the message that you are trying to matchup against by having the VCU compute the CRC? (assuming the embedded CRC didn't get corrupted itself).

    What about in the memory case? Where is the CRC to match up against?

    Indeed, the BitReflect() performance hit is unfortunate. Spru514 user guide has an intrinsic __flip32() that does the same thing I believe. Can you please check and see if you can use that to reduce the performance hit?

    Thanks,

    Sira

  • Sira Rao80 said:
    So basically there is an embedded CRC in the message that you are trying to matchup against by having the VCU compute the CRC? (assuming the embedded CRC didn't get corrupted itself).

    Yes.

    Sira Rao80 said:
    What about in the memory case? Where is the CRC to match up against?

    Mostly against CRCs computed on the same device, so in this case the CRC parameter values are not really important. They only have to be the same.

    Sira Rao80 said:
    __flip32() that does the same thing I believe. Can you please check and see if you can use that to reduce the performance hit?

    Thank you for pointing me to the intrinsic. Actually, there are other bottlenecks in our software, so that the CRC computation performance isn't the only thing that matters.

    Regards, Johannes