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.

CRC Algorithm

Other Parts Discussed in Thread: HALCOGEN

Hello,

I am looking for a way to generate a CRC from data using the same algorithm as the hardware CRC engine in the TMS570. As I understand it the polynomial is defined as x^64 + x^4 + x^3 + x + 1 which appears to be a standard ISO CRC64 algorithm.

There are several CRC implementation algorithms on the internet that purport to generate a CRC64 from a byte stream using this polynomial but I can't match what the TMS570 CRC engine is generating. Most of the examples I have seen use a table-driven approach and I understand that there may be an endianess issue but even allowing for that the answers don't match.

Do you have any source code (preferably in C or C++ and if possible using an efficient table driven approach) that you can share to generate the same CRC as the hardware engine?

Thanks,

Richard

  • I have implemented the algorithm as described on page 1630 of the TRM but it is **horribly** inefficient. At least it gives the same answer as the hardware CRC engine but there must be a better way!

    This is compiled in MSVC 2008. The comments reflect the HDL code in the TRM. crc_t is a typedef defined as follows:

    typedef unsigned __int64 crc_t;

    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;

    }

    Regards,

    Richard

  • Richard,

    Which TRM are you refering here ?

    Were you able to generate right CRC with the above C code ?

    Best Regards,

    Pratip

  • Hi Pratip,

    I am referring to the TMS570LS Series Technical Reference Manual (SPNU489A) dated June 2010.

    The code does generate the right CRC but requires 63 * 64 = 4032 iterations of the inner loop for each 64 bit word of data.

    For the TMS570 CRC engine to be of practical use a method is required to precalculate the CRC.

    I was hoping that somebody might have come up with a more efficient implementation that they would be prepared to share with the community.

    Regards,

    Richard

  • Richard,

    If you are looking to do this for static contents you could possibly do this offline, i.e. do it once on the CPU with a program different from your application, save the values and add them to your application and just reuse during runtime.

    For dynamic contents, I can't think of a better option.

    Regards,

    Abhishek

  • Hi Abhishek,

    This one has been open now for nearly 9 months so maybe the algorithm that I listed in an earlier post is the best (only) way to do this.

    I will close this post and mark my earlier message with the algorithm as the verified answer.

    Regards,

    Richard

  • Sure Richard. Sounds reasonable

  • I know this is a year late but hopefully some people find it helpful

    The pycrc project supports this algorithm:

    http://www.tty1.net/pycrc/index_en.html

    Running it with the command:

    pycrc.py --width 64 --poly 0x000000000000001b --reflect-in False --xor-in 0x0000000000000000 --reflect-out False --xor-out 0x0000000000000000

    matches the output of the CRCs generated by the TMS570 hardware unit. I have not compared the generated c code from pycrc with the solution recommended here so I can not vouch for it being more efficient, but it is handy to have another solution to check your code against. 

  • Thanks for sharing.

  • Data Source:
    uint32_t dwInputVal[0xC0] =
    {
    0xC67E816B,
    0x4BFBE2FB,
    0x54F6BDDF,
    0x7C1CE187,
    0x01BF31DE,
    0x56720F47,
    0x67668759,
    0xAA883C59,
    0xEA56137B,
    0xD285A1D8,
    0x3C54552F,
    0x37AE655B,
    0xDA027998,
    0xCCE31A76,
    0x8E5FD999,
    0x8F1F3F36,
    0xEE43784D,
    0x0DFABEA6,
    0xDAE4868E,
    0xDC296D4E,
    0xFF56E170,
    0x20FB8FB1,
    0x580590C5,
    0x09DC53CD,
    0xAA3B4899,
    0x52D3529D,
    0x069FEAB5,
    0xC2061398,
    0x49B2011E,
    0xAC328831,
    0x9C524695,
    0x71368F57,
    0xF6391D16,
    0xFA8874F5,
    0x987C175C,
    0x41BB6D71,
    0x8E0F7059,
    0xC7011B2F,
    0x333D91C0,
    0x1DA50D0D,
    0xAB338D7E,
    0x5E8F3EE6,
    0x6874A63A,
    0xB1C39311,
    0xA864C7DB,
    0xCAE060E1,
    0xF3BF0900,
    0x67A2E325,
    0xA0213187,
    0xD562C5A8,
    0x4F7E2E09,
    0x6B949FB0,
    0x6DA99E5A,
    0x0B467080,
    0xB6CF470C,
    0xA6A52AD8,
    0xACFBA0EB,
    0xB7792472,
    0x23924880,
    0xC5A6A785,
    0xB7D78C90,
    0xE4AB6344,
    0x5266E39C,
    0x3325F95E
    };
    
    
    
    Base On:TMS570LS3137 (TRM 's Literature Number:SPNU499)
    Result:(Full CPU Mode): CRC0_Test[2] = {0x30ADF95E, 0x604CC4EB}
    
    Code below:
    void main(void)
    {
    /* USER CODE BEGIN (3) */
    	double *crc_reg = (double *)0xfe000060;
    	double *data = (double *)&CRC_Pattern[0];
    
    	uint16_t i=0;
    	/** - configuring crc  */
    	crcInit();
    
    	/** - Setup the Channel mode */
       	crcREG->CTRL2=0x00000000;
    	crcREG->CTRL2 |= (CRC_FULL_CPU);
    
    	for(i=0;i<32;i++)
    	{
    	   *crc_reg = *data++;
    	}
    
    	CRC0_Test[0]=crcREG->PSA_SECSIGREGL1;
    	CRC0_Test[1]=crcREG->PSA_SECSIGREGH1;
    
    
        	while(1);
    
    /* USER CODE END */
    }
    
    Your Algorithm(Init CrcVal = 0): CrcVal(result) =  0x166E6EEDE4FEC60E
    
    Code below:
    	U64 CrcVal = 0;
    	for(i=0;i<32;i++)
    	{
    
    		CrcVal = crc_update_word(CrcVal,*(U64 *)&(dwInputVal[i]));
    		i++;
    
    	}
     Why does result inconsistent??
  • Hi Jason,

    There are some problems with your code - firstly you should not define crc_reg or data as double. These should be uint64_t (typedef to unsigned long long).

    Secondly be aware that even though the processor is big endian, the CRC registers are arranged as low byte, high byte. This means that you need to swap the top 32 bits with the bottom 32 bits before doing the conversion and with the result (or do this at the PC end).

    As with all problems like this, I would strongly recommend that you start with one value and make sure you get the right answer from that rather than from a long array of values.

    Finally, note that S. Donnan pointed out a more elegant algorithm previously in this chain.

    Regards,
    Richard

    P.S. If you want prompt attention from the TI guys you would be better to start a new thread because this one is already categorised as answered.

  • Of course when I said low byte, high byte I meant low word, high word!

  • Thanks for you pointed  out my progblems。I tryed ,finally  successed. It's problem of  big Endian(TMS570)and PC(little Endian).

  • Donnan,

    I couldn't get any expected result with pycrc.

    The CRC value calculated in TMS570 gives 0x000002f9ae1a415b, but pycrc gives 0xe4ffbea588933790.

    Could you share the test method and its result??

    Thanks & Regards,

    SH.

  • I have attached a rough main.c and a python script that will communicate with the USB evaluation board for the TMS570 to test the CRC functionality. You will have to set up SCI1 for it work. It does not test a bad CRC but modifying the script to generate a bad CRC is very easy. 

    Some notes:

    • As mentioned before: you must swap the upper and lower word when writing to the CRC_SIGREG
    • I append zeros to data when the length is not a multiple of 64bits
    • The output crc from pycrc is an integer. To guarantee the proper length we create a string and use the format specifiers to get leading zeroes. Then we use binascii to convert the string to binary for the serial port.
    • Binary data printed out to the screen is always converted to a hex string 
    • The python script is written to run on Linux. Though it should be obvious what to change for Windows (random numbers, serial port spec)

    The output when I run the script on my machine with the devboard attached and running the main.c with the standard HalCoGen generated code is:

    $ python crc_test.py
    ------ Start Test ------
    Sending Length: 8
    Sending Data: 0102030405060708
    Sending CRC: 1B362D6C775A41D8
    Test Passed

    ------ Start Test ------
    Added padding for CRC calculation: 7 bytes
    Sending Length: 9
    Sending Data: 466f6f42617242617a
    Sending CRC: 556640B2CA69B5E3
    Test Passed

    ------ Start Test ------
    Added padding for CRC calculation: 1 bytes
    Sending Length: 239
    Sending Data: 0fe4b21636796e0b67c548e665d5c09aa77828230dd564aeb233f71a66a986fd585de33aa0d1bfd731026a4decd31ea2bae1b566d763bf802f87ac65fc9ce3ef8ca320b5477cd7b9811c4154458c7196d64278720ff38376d9b1833855c43b6dab868f5819b41f7b9f2b1a0e99036bd9cdd6fa022e00ce118b0209485881bb08b33f1a6d98434b7c755c33aee901a8e5d87e9df331de112a3134bfde20afad31a12fdb1b5d5e302d30416795eb9febdc6d7ff6803ddad6b4e3d6b7ecb7cd797cf1afcf254bf64b4839b96d9c4502c314c9ab56c054cca1fbe4c6aa1545280d6c68b8b6188d49a2af199c3508a39755
    Sending CRC: DD2C3A21C0CADDFC
    Test Passed

    8802.crc_test.zip

    Hope this helps

  • Excellent, it works!! thank you so much.

    zero padding and swap was the key.

    Thank you for your help..

    Regards,

    SH.

  • Hello,

    I am working with the TMS570LS31x/21x and I just found out that I need to swap 32 HIGH and LOW bits before writing "PSA Signature Register" and when reading from "PSA Sector Signature Register".

    This is a HUGE performace issue and it is really hard to believe that the registers are in the wrong order.

    But also more important, in case I am using DMA transfer to calculate the CRC and that I am calculating the CRC of flash it is not possible to swap the values at all!!

    What is the solution that TI is providing for those cases?

    Also, note that halcogen tool is generating a wrong crc example source code, as values are not swapped when written nor read. This must be fixed as well.

    Regards,

    Francis.

    p.s.: also compiler is generating the wrong crc, see my post 

    http://e2e.ti.com/support/microcontrollers/hercules/f/312/t/321430.aspx

  • Hello Francis,

    Actually you don't need to SWAP the WORDS when writing to CRC Register. Instead for the OFFLINE Calculation of CRC Signature, you need to SWAP the WORDS and everything will be fine. Think of these as NAMES of REGISTERS. It doesn't matter whether you call them LOW or HIGH. Usually offline CRC computation is performed on PC [Intel], where it is naturally SWAPPED  because Intel is LE and TMS570 [Hercules] family is BE format.

    Hope it is clear now.
    Thank you.
    Regards
    Pashan

  • Pashan,

    You are correct that the offline calculation could be word swapped to improve online performance. However there must be a WORD SWAP not a BYTE SWAP so just using a little-endian platform will not automatically solve your swapping issues.

  • Hello Pashan,

    What I mean is that maybe I do not have access to the OFFLINE calculation because this is done by a another company.

    "Usually offline CRC computation is performed on PC [Intel], where it is naturally SWAPPED  because Intel is LE and TMS570 [Hercules] family is BE format." As also another user said, this is wrong, as swap is done for two 32 bits not per byte.

  • Francisco,

    While we are now way off topic from the original question I had a thought over lunch which might enable you to use DMA.

    You could chain three DMA operations together to get the data in the correct order and then into the CRC unit.

    1. Copy the even words to a buffer starting at offset 0x4 (1 word in) and incrementing the address by 0x8.
    2. Copy the odd words to the same buffer starting at offset 0x0 and incrementing the address by 0x8.
    3. Copy the buffer into the CRC unit in 64-bit chunks.

    Since you probably don't have enough RAM to keep the entire flash memory in the scratchpad at once you will have to run through these operations multiple times. It's definitely not ideal but perhaps it will be helpful for you.

    Good luck,

    -Stu

    EDIT: Replaced "scratchpad" with "buffer" because it might be confusing for non-english speakers.

  • Francisco,

    It seems as though you are expecting a BE8 solution.  The BE TMS570 is BE32, also known as word invariant big endian.  This is done for legacy compatibility to earlier ARM solutions in which the only BE mode supported is BE32.  IBM also used same format for many years.

    Regards,

    Karl

  • Hello Stu,

    Thanks for you answer. We thought about that and in case we need we would implement it.

    Best Regards,

    Francis.