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.
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 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,
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 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