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.

TMS570LC4357: CRC Algorithm

Part Number: TMS570LC4357

Hello,

I'm trying to find a SW algorithm which calculates the same CRC as the CRC unit in the TMS570LC4357 (see this thread: http://e2e.ti.com/support/microcontrollers/hercules/f/312/p/716945/2749159#2749159).

I tried an implementation of Richard Burke from this forum and also a table-based routine generated by pycrc, a tool that was recommended by Sunil Oak in the other thread.

What I see: The implementation of Richard Burk and the pycrc routine return exactly the same value, but they differ from the CRC generated by the HW CRC unit in the processor.

Here is my test code, including the pycrc parameters:

#define CRC_CTRL0     (*(volatile uint32 *)0xFE000000U)
#define CRC_CTRL2     (*(volatile uint32 *)0xFE000010U)
#define CRC_SIGREG    (*(volatile uint64 *)0xFE000060U)

/* Function from SafeTI Diagnostic Library (sl_misc.c) */
/*SAFETYMCUSW 61 D MR: 8.10,8.11 <APPROVED> Comment_1*/
uint64 SL_CRC_Calculate (uint64* startAddr, const uint32 count64)
{
  volatile uint32 count = 0u; /* volatile in order to prevent from being optimised */

  CRC_CTRL0 |= 0x00000001U; /* Reset the CRC Module */
  CRC_CTRL0 &= 0xFFFFFFFEU;
  CRC_CTRL2 |= 0x00000003U; /* Configure to Full CPU Mode */

  /*SAFETYMCUSW 134 S MR: 12.2 <APPROVED> Comment_5*/
  /*SAFETYMCUSW 134 S MR: 12.2 <APPROVED> Comment_5*/
  for (count=0u; count < count64; count++) {
    /*SAFETYMCUSW 45 D MR:21.1 <APPROVED> Comment_2*/
    /*SAFETYMCUSW 93 S MR: 6.1,6.2,10.1,10.2,10.3,10.4 <APPROVED> "LDRA Tool issue" */
    CRC_SIGREG = (uint64)(*startAddr);
    /*SAFETYMCUSW 45 D MR:21.1 <APPROVED> Comment_2*/
    /*SAFETYMCUSW 567 S MR:17.1,17.4 <APPROVED> "Pointer increment needed" */
    startAddr++;
  }
    return(CRC_SIGREG);
}

/* Example for manual implementation by Richard Burke */
crc_t crc_update_word(crc_t crc, crc_t data)
{
    int i, j;
    crc_t nextCrc = 0;
    // for i in 63 to 0 loop
    for(i = 63; i >= 0; i--)
    {
        // NEXT_CRC_VAL(0) := CRC_VAL(63) xor DATA(i);
        nextCrc = (nextCrc & (crc_t)0xfffffffffffffffe) | ((crc >> 63) ^ (data >> i));
        // for j in 1 to 63 loop
        for(j = 1; j < 64; j++)
        {
            //case j is
            // when 1|3|4 =>
            if(j == 1 || j == 3 || j == 4)
            {
                // NEXT_CRC_VAL(j) := CRC_VAL(j - 1) xor CRC_VAL(63) xor DATA(i);
                nextCrc = (nextCrc & ~((crc_t)1 << j)) | ((((crc >> (j-1)) ^ (crc >> 63) ^ (data >> i)) & 1) << j);
            }
            else
            { // when others =>
                // NEXT_CRC_VAL(j) := CRC_VAL(j - 1);
                nextCrc = (nextCrc & ~((crc_t)1 << j)) | (((crc >> (j-1)) & 1) << j);
            }
            // end case;
        } // end loop;
        crc = nextCrc;
    } // end loop

    return crc;
}

void crc_test(void)
{
  uint64 crc_test_value = 0x8DF8A32C74B91F3E;

  uint8 crc_test_array1[8] = {0x8D, 0xF8, 0xA3, 0x2C, 0x74, 0xB9, 0x1F, 0x3E};


  uint64 result_crc_safe_ti_lib = 0U;
  uint64 result_crc_burke = 0U;
  uint64 result_crc_pycrc = 0U;

  result_crc_safe_ti_lib = SL_CRC_Calculate(&crc_test_value, 1U);

  crcInit();  /* Sets everything to zero and enables Full CPU Mode */
  result_crc_burke = crc_update_word(0U, crc_test_value);

  /*
   * Generated on Wed Dec 12 12:46:55 2018
   * by pycrc v0.9.1, https://pycrc.org
   * using the configuration:
   *  - Width         = 64
   *  - Poly          = 0x000000000000001b
   *  - XorIn         = 0x0000000000000000
   *  - ReflectIn     = False
   *  - XorOut        = 0x0000000000000000
   *  - ReflectOut    = False
   *  - Algorithm     = table-driven
   *  */
  result_crc_pycrc = crc_init();
  result_crc_pycrc = crc_update(result_crc_pycrc, (unsigned char *)&crc_test_value, 8);
  result_crc_pycrc = crc_finalize(result_crc_pycrc);

  while(1);
}

Results:

result_crc_safe_ti_lib = 0x2646CEB873922B5F

result_crc_burke = 0x2646CED073922BFD

result_crc_pycrc = 0x2646CED073922BFD

The primitive polynomial is the same as mentioned in the reference manual of the processor and I disabled all additional reflections and XOR values.

What could be wrong?

Best regards,

Jens

  • Hi Jens,

    I have not run the pycrc routine in a while. I remember that it generated the correct signature per the CRC module on TMS570, as stated in this post from several years back:
    e2e.ti.com/.../672434

    I will run it again and let you know.

    Regards,
    Sunil
  • Hi Sunil,

    this is the command I used to generate the routines:

    python pycrc.py --model crc-64 --algorithm table-driven --reflect-in False --reflect-out False --generate h -o crc.h
    python pycrc.py --model crc-64 --algorithm table-driven --reflect-in False --reflect-out False --generate c -o crc.c

    crc.h:

    /**
     * \file
     * Functions and types for CRC checks.
     *
     * Generated on Thu Dec 13 13:29:54 2018
     * by pycrc v0.9.1, https://pycrc.org
     * using the configuration:
     *  - Width         = 64
     *  - Poly          = 0x000000000000001b
     *  - XorIn         = 0x0000000000000000
     *  - ReflectIn     = False
     *  - XorOut        = 0x0000000000000000
     *  - ReflectOut    = False
     *  - Algorithm     = table-driven
     *
     * This file defines the functions crc_init(), crc_update() and crc_finalize().
     *
     * The crc_init() function returns the inital \c crc value and must be called
     * before the first call to crc_update().
     * Similarly, the crc_finalize() function must be called after the last call
     * to crc_update(), before the \c crc is being used.
     * is being used.
     *
     * The crc_update() function can be called any number of times (including zero
     * times) in between the crc_init() and crc_finalize() calls.
     *
     * This pseudo-code shows an example usage of the API:
     * \code{.c}
     * crc_t crc;
     * unsigned char data[MAX_DATA_LEN];
     * size_t data_len;
     *
     * crc = crc_init();
     * while ((data_len = read_data(data, MAX_DATA_LEN)) > 0) {
     *     crc = crc_update(crc, data, data_len);
     * }
     * crc = crc_finalize(crc);
     * \endcode
     */
    #ifndef CRC_H
    #define CRC_H
    
    #include <stdlib.h>
    #include <stdint.h>
    
    #ifdef __cplusplus
    extern "C" {
    #endif
    
    
    /**
     * The definition of the used algorithm.
     *
     * This is not used anywhere in the generated code, but it may be used by the
     * application code to call algorithm-specific code, if desired.
     */
    #define CRC_ALGO_TABLE_DRIVEN 1
    
    
    /**
     * The type of the CRC values.
     *
     * This type must be big enough to contain at least 64 bits.
     */
    typedef uint_fast64_t crc_t;
    
    
    /**
     * Calculate the initial crc value.
     *
     * \return     The initial crc value.
     */
    static inline crc_t crc_init(void)
    {
        return 0x0000000000000000;
    }
    
    
    /**
     * Update the crc value with new data.
     *
     * \param[in] crc      The current crc value.
     * \param[in] data     Pointer to a buffer of \a data_len bytes.
     * \param[in] data_len Number of bytes in the \a data buffer.
     * \return             The updated crc value.
     */
    crc_t crc_update(crc_t crc, const void *data, size_t data_len);
    
    
    /**
     * Calculate the final crc value.
     *
     * \param[in] crc  The current crc value.
     * \return     The final crc value.
     */
    static inline crc_t crc_finalize(crc_t crc)
    {
        return crc;
    }
    
    
    #ifdef __cplusplus
    }           /* closing brace for extern "C" */
    #endif
    
    #endif      /* CRC_H */
    

    crc.c:

    /**
     * \file
     * Functions and types for CRC checks.
     *
     * Generated on Thu Dec 13 13:29:54 2018
     * by pycrc v0.9.1, https://pycrc.org
     * using the configuration:
     *  - Width         = 64
     *  - Poly          = 0x000000000000001b
     *  - XorIn         = 0x0000000000000000
     *  - ReflectIn     = False
     *  - XorOut        = 0x0000000000000000
     *  - ReflectOut    = False
     *  - Algorithm     = table-driven
     */
    #include "crc.h"     /* include the header file generated with pycrc */
    #include <stdlib.h>
    #include <stdint.h>
    
    
    
    /**
     * Static table used for the table_driven implementation.
     */
    static const crc_t crc_table[256] = {
        0x0000000000000000, 0x000000000000001b, 0x0000000000000036, 0x000000000000002d,
        0x000000000000006c, 0x0000000000000077, 0x000000000000005a, 0x0000000000000041,
        0x00000000000000d8, 0x00000000000000c3, 0x00000000000000ee, 0x00000000000000f5,
        0x00000000000000b4, 0x00000000000000af, 0x0000000000000082, 0x0000000000000099,
        0x00000000000001b0, 0x00000000000001ab, 0x0000000000000186, 0x000000000000019d,
        0x00000000000001dc, 0x00000000000001c7, 0x00000000000001ea, 0x00000000000001f1,
        0x0000000000000168, 0x0000000000000173, 0x000000000000015e, 0x0000000000000145,
        0x0000000000000104, 0x000000000000011f, 0x0000000000000132, 0x0000000000000129,
        0x0000000000000360, 0x000000000000037b, 0x0000000000000356, 0x000000000000034d,
        0x000000000000030c, 0x0000000000000317, 0x000000000000033a, 0x0000000000000321,
        0x00000000000003b8, 0x00000000000003a3, 0x000000000000038e, 0x0000000000000395,
        0x00000000000003d4, 0x00000000000003cf, 0x00000000000003e2, 0x00000000000003f9,
        0x00000000000002d0, 0x00000000000002cb, 0x00000000000002e6, 0x00000000000002fd,
        0x00000000000002bc, 0x00000000000002a7, 0x000000000000028a, 0x0000000000000291,
        0x0000000000000208, 0x0000000000000213, 0x000000000000023e, 0x0000000000000225,
        0x0000000000000264, 0x000000000000027f, 0x0000000000000252, 0x0000000000000249,
        0x00000000000006c0, 0x00000000000006db, 0x00000000000006f6, 0x00000000000006ed,
        0x00000000000006ac, 0x00000000000006b7, 0x000000000000069a, 0x0000000000000681,
        0x0000000000000618, 0x0000000000000603, 0x000000000000062e, 0x0000000000000635,
        0x0000000000000674, 0x000000000000066f, 0x0000000000000642, 0x0000000000000659,
        0x0000000000000770, 0x000000000000076b, 0x0000000000000746, 0x000000000000075d,
        0x000000000000071c, 0x0000000000000707, 0x000000000000072a, 0x0000000000000731,
        0x00000000000007a8, 0x00000000000007b3, 0x000000000000079e, 0x0000000000000785,
        0x00000000000007c4, 0x00000000000007df, 0x00000000000007f2, 0x00000000000007e9,
        0x00000000000005a0, 0x00000000000005bb, 0x0000000000000596, 0x000000000000058d,
        0x00000000000005cc, 0x00000000000005d7, 0x00000000000005fa, 0x00000000000005e1,
        0x0000000000000578, 0x0000000000000563, 0x000000000000054e, 0x0000000000000555,
        0x0000000000000514, 0x000000000000050f, 0x0000000000000522, 0x0000000000000539,
        0x0000000000000410, 0x000000000000040b, 0x0000000000000426, 0x000000000000043d,
        0x000000000000047c, 0x0000000000000467, 0x000000000000044a, 0x0000000000000451,
        0x00000000000004c8, 0x00000000000004d3, 0x00000000000004fe, 0x00000000000004e5,
        0x00000000000004a4, 0x00000000000004bf, 0x0000000000000492, 0x0000000000000489,
        0x0000000000000d80, 0x0000000000000d9b, 0x0000000000000db6, 0x0000000000000dad,
        0x0000000000000dec, 0x0000000000000df7, 0x0000000000000dda, 0x0000000000000dc1,
        0x0000000000000d58, 0x0000000000000d43, 0x0000000000000d6e, 0x0000000000000d75,
        0x0000000000000d34, 0x0000000000000d2f, 0x0000000000000d02, 0x0000000000000d19,
        0x0000000000000c30, 0x0000000000000c2b, 0x0000000000000c06, 0x0000000000000c1d,
        0x0000000000000c5c, 0x0000000000000c47, 0x0000000000000c6a, 0x0000000000000c71,
        0x0000000000000ce8, 0x0000000000000cf3, 0x0000000000000cde, 0x0000000000000cc5,
        0x0000000000000c84, 0x0000000000000c9f, 0x0000000000000cb2, 0x0000000000000ca9,
        0x0000000000000ee0, 0x0000000000000efb, 0x0000000000000ed6, 0x0000000000000ecd,
        0x0000000000000e8c, 0x0000000000000e97, 0x0000000000000eba, 0x0000000000000ea1,
        0x0000000000000e38, 0x0000000000000e23, 0x0000000000000e0e, 0x0000000000000e15,
        0x0000000000000e54, 0x0000000000000e4f, 0x0000000000000e62, 0x0000000000000e79,
        0x0000000000000f50, 0x0000000000000f4b, 0x0000000000000f66, 0x0000000000000f7d,
        0x0000000000000f3c, 0x0000000000000f27, 0x0000000000000f0a, 0x0000000000000f11,
        0x0000000000000f88, 0x0000000000000f93, 0x0000000000000fbe, 0x0000000000000fa5,
        0x0000000000000fe4, 0x0000000000000fff, 0x0000000000000fd2, 0x0000000000000fc9,
        0x0000000000000b40, 0x0000000000000b5b, 0x0000000000000b76, 0x0000000000000b6d,
        0x0000000000000b2c, 0x0000000000000b37, 0x0000000000000b1a, 0x0000000000000b01,
        0x0000000000000b98, 0x0000000000000b83, 0x0000000000000bae, 0x0000000000000bb5,
        0x0000000000000bf4, 0x0000000000000bef, 0x0000000000000bc2, 0x0000000000000bd9,
        0x0000000000000af0, 0x0000000000000aeb, 0x0000000000000ac6, 0x0000000000000add,
        0x0000000000000a9c, 0x0000000000000a87, 0x0000000000000aaa, 0x0000000000000ab1,
        0x0000000000000a28, 0x0000000000000a33, 0x0000000000000a1e, 0x0000000000000a05,
        0x0000000000000a44, 0x0000000000000a5f, 0x0000000000000a72, 0x0000000000000a69,
        0x0000000000000820, 0x000000000000083b, 0x0000000000000816, 0x000000000000080d,
        0x000000000000084c, 0x0000000000000857, 0x000000000000087a, 0x0000000000000861,
        0x00000000000008f8, 0x00000000000008e3, 0x00000000000008ce, 0x00000000000008d5,
        0x0000000000000894, 0x000000000000088f, 0x00000000000008a2, 0x00000000000008b9,
        0x0000000000000990, 0x000000000000098b, 0x00000000000009a6, 0x00000000000009bd,
        0x00000000000009fc, 0x00000000000009e7, 0x00000000000009ca, 0x00000000000009d1,
        0x0000000000000948, 0x0000000000000953, 0x000000000000097e, 0x0000000000000965,
        0x0000000000000924, 0x000000000000093f, 0x0000000000000912, 0x0000000000000909
    };
    
    
    crc_t crc_update(crc_t crc, const void *data, size_t data_len)
    {
        const unsigned char *d = (const unsigned char *)data;
        unsigned int tbl_idx;
    
        while (data_len--) {
            tbl_idx = ((crc >> 56) ^ *d) & 0xff;
            crc = (crc_table[tbl_idx] ^ (crc << 8)) & 0xffffffffffffffff;
            d++;
        }
        return crc & 0xffffffffffffffff;
    }

    Regards,

    Jens

  • Hi Jens,

    The TI CodeGen tools include an ability to generate CRC tables for initialized sections. Please refer to the ARM assembly tools user guide here for more details: downloads.ti.com/.../

    Section 8.9 specifically explains the usage of this feature.

    Also refer to this blog explaining how to use this capability to perform cyclic redundancy checking using linker-generated CRC tables:
    e2e.ti.com/.../from-the-experts-perform-cyclic-redundancy-checking-using-linker-generated-crc-tables

    This includes a video demonstrating the operation. It is specific to a C2000 MCU, but can be easily adapted for the TMS570 MCUs. I will also look to create an example specific for TMS570 MCUs. Hope this helps in the mean time.

    Regards,
    Sunil
  • Hi Sunil,

    I think you've got me wrong. I want to use the HW CRC unit of the TMS570 for data consistency checking, so I have to calculate the CRC on the PC before and append it to the data, so that the TMS570 can check the data.
    For that use case, pycrc seems to be a very goot tool, thanks for that suggestion. You told me that you already got the same results with pycrc, so I just need to know which parameters I have to set for pycrc to match the result TMS570 HW CRC routine.

    Regards,
    Jens
  • Hi Jens,

    I had to redo the experiment to recollect the specific requirements to verify the signature. You need to swap the upper and lower 32-bit values in the input string before input to the CRC module. So in your case, pass the value 0x74B91F3E8DF8A32C as input. See below code:

    int main(void)
    {
    /* USER CODE BEGIN (3) */
    
        uint64 crcSign, crcSign2 = 0;
    
        crcModConfig_t crcParam;
    
        uint64_t dataPattern = 0x74B91F3E8DF8A32C;
    
        crcParam.crc_channel = CRC_CH1;    // CRC channel 0
        crcParam.mode = CRC_FULL_CPU;      // Full CPU mode operation
        crcParam.data_length = 1;          // Single 64-bit word to be analyzed
        crcParam.src_data_pat = &dataPattern;
    
        crcInit();
        crcSignGen(crcREG1, &crcParam);
    
        crcSign = crcGetPSASig(crcREG1, CRC_CH1);
    
        crcSign2 = ((uint64)(crcREG1->PSA_SIGREGH1) << 32U) | (uint64)(crcREG1->PSA_SIGREGL1);
    
        while(1);
    
    /* USER CODE END */
    
        return 0;
    }
    

    The crcGetPSASig reorders the upper and lower 32 bits of the CRC signature, which is not required.

    With this code, I get the following results:

    pycrc gives the same result with the 64-bit input value passed as follows:

  • Hi Sunil,

    thanks for your test, the result is very surprising to me. I always used the generated code, because I have to calculate the CRC of binary data, not of an ASCII string or text file. If I do the test in your way, I get the same result. But why does the code generated by pycrc with exactly the same parameters not come to the same result? I'm really confused.

    Best regards,

    Jens

  • Hi Jens,

    Your CRC test value is defined as:
    uint64 crc_test_value = 0x8DF8A32C74B91F3E;

    The TMS570 implementation has a peculiarity in that the upper and lower 32 bits need to be swapped before calling the SL_CRC_Calculate() function. For example, setup the CRC test value as 0x74B91F3E8DF8A32C to get the same CRC value as the pycrc routine.

    result_crc_safe_ti_lib = SL_CRC_Calculate(&crc_test_value, 1U);

    Regards,
    Sunil
  • Hi Sunil,

    thank you very much, that was the right hint. I either did not swap the input words or swapped them for both routines. For performance reasons I chose the straight version without swapping for the HW CRC calculation and will swap the words in the external tool.

    If it may help someone else, this is my final test with the matching checksums:

    #define CRC_CTRL0     (*(volatile uint32 *)0xFE000000U)
    #define CRC_CTRL2     (*(volatile uint32 *)0xFE000010U)
    #define CRC_SIGREG    (*(volatile uint64 *)0xFE000060U)
    
    /* Function from SafeTI Diagnostic Library (sl_misc.c) */
    /*SAFETYMCUSW 61 D MR: 8.10,8.11 <APPROVED> Comment_1*/
    uint64 SL_CRC_Calculate (uint64* startAddr, const uint32 count64)
    {
      register uint32 count = 0u; /* volatile in order to prevent from being optimised */
      register uint64* pAddress = startAddr;
    
      CRC_CTRL0 |= 0x00000001U; /* Reset the CRC Module */
      CRC_CTRL0 &= 0xFFFFFFFEU;
      CRC_CTRL2 |= 0x00000003U; /* Configure to Full CPU Mode */
    
      /*SAFETYMCUSW 134 S MR: 12.2 <APPROVED> Comment_5*/
      /*SAFETYMCUSW 134 S MR: 12.2 <APPROVED> Comment_5*/
      for (count=0u; count < count64; count++) {
        /*SAFETYMCUSW 45 D MR:21.1 <APPROVED> Comment_2*/
        /*SAFETYMCUSW 93 S MR: 6.1,6.2,10.1,10.2,10.3,10.4 <APPROVED> "LDRA Tool issue" */
        CRC_SIGREG = (uint64)(*pAddress);
        /*SAFETYMCUSW 45 D MR:21.1 <APPROVED> Comment_2*/
        /*SAFETYMCUSW 567 S MR:17.1,17.4 <APPROVED> "Pointer increment needed" */
        pAddress++;
      }
        return(CRC_SIGREG);
    }
    
    #define CRC_START_ADDRESS   0
    #define CRC_MEM_SIZE        0x80000
    
    static inline uint64 SwapWords64( uint64 Data_u64 )
    {
      return ((uint64)((uint32)Data_u64) << 32U) | (uint64)(Data_u64 >> 32U);
    }
    
    void crc_test(void)
    {
      uint64 ResultCrcHw_u64;
      uint64 ResultCrcSw_u64;
    
      uint64* pAddress = (uint64*)CRC_START_ADDRESS;
      uint64 DataSwapped_u64;
      uint32 i;
    
      /* HW calculation */
      ResultCrcHw_u64 = SL_CRC_Calculate((uint64*)CRC_START_ADDRESS, CRC_MEM_SIZE);
    
      /* SW calculation */
      ResultCrcSw_u64 = crc_init();
      for (i = 0; i < CRC_MEM_SIZE; i++)
      {
        DataSwapped_u64 = SwapWords64(*pAddress);
        ResultCrcSw_u64 = crc_update(ResultCrcSw_u64, (unsigned char *)&DataSwapped_u64, 8);
        pAddress++;
      }
      ResultCrcSw_u64 = crc_finalize(ResultCrcSw_u64);
      ResultCrcSw_u64 = SwapWords64(ResultCrcSw_u64);
    
      if (ResultCrcHw_u64 == ResultCrcSw_u64)
      {
        while(1);
      }
      else
      {
        while(1);
      }
    }

    Regards,

    Jens