

View previous topic :: View next topic 
Author 
Message 
opAmp
Joined: 09 Aug 2022 Posts: 4 Location: Norway

CRC32 with builtin hardware on dsPIC33E 
Posted: Tue Aug 09, 2022 8:39 pm 


Hi,
I have a problem calculating CRC32 using the hardwarebased CRC functions on a dsPIC33E. I attempt to calculate the CRC32 on the ASCII string "abc", using this generator polynomial: 0xEDB88320
The result should be 0x352441C2  this can be verified here:
https://www.scadacore.com/tools/programmingcalculators/onlinechecksumcalculator/
I have also tried with C code from the following web page to calculate the CRC32 in software, and I get the same result 0x352441C2:
http://home.thep.lu.se/~bjorn/crc/
I even implemented CRC32 in JavaScript, and I got the same result 0x352441C2.
Here is my problematic implementation in PCD v5.109:
Code:  unsigned int8 Data[16];
unsigned int8 Length;
unsigned int32 result32;
Length = sprintf(Data, "abc");
setup_crc(32, 31, 30, 29, 27, 26, 24, 23, 21, 20, 19, 15, 9, 8, 5);
crc_init(0);
result32 = crc_calc32(Data, Length, 8);
fprintf(PC, "getenv(\"CRC\") returns %u, length of string \"%s\" is %u.\r\n", getenv("CRC"), Data, Length);
fprintf(PC, "HW CRC32 result from \"abc\" is 0x%08X (expect 0x352441C2)\r\n", result32);

Result on the console:
Quote:  getenv("CRC") returns 2, length of string "abc" is 3.
HW CRC32 result from "abc" is 0x6B4B33E0 (expect 0x352441C2) 
If I instead initialize with crc_init(0xFFFFFFFF); the result is:
Quote:  getenv("CRC") returns 2, length of string "abc" is 3.
HW CRC32 result from "abc" is 0xCA0BE10B (expect 0x352441C2) 
As you can see, the code is not producing the expected result whether i initialize with 0 or 0xFFFFFFFF.
What am I doing wrong? Any help would be greatly appreciated!
I just want to be able to calculate CRC32 in hardware of a string of bytes, using the builtin functions of the compiler.
Thanks in advance,
Erik 


Ttelmah
Joined: 11 Mar 2010 Posts: 18225


Posted: Wed Aug 10, 2022 10:04 am 


Your number sequence for the CRC setup does not look right.
0xEDB88320
Should be:
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
These are not the factors you are loading in your setup... 


opAmp
Joined: 09 Aug 2022 Posts: 4 Location: Norway


Posted: Wed Aug 10, 2022 11:28 am 


Thank you for your suggestion Ttelmah, that is highly appreciated! :D
I now tried to use this setup:
setup_crc(32, 26, 23, 22, 16, 12, 11, 10, 8, 7, 5, 4, 2);
Unfortunately, I still get the wrong results. As usual, I try with crc_init(0xFFFFFFFF) and crc_init(0) since I am not sure which of them is the correct one to use.
I do not understand how this polynomial relates to 0xEDB88320. However, if I add two more coefficients at the end, like this:
setup_crc(32, 26, 23, 22, 16, 12, 11, 10, 8, 7, 5, 4, 2, 1, 0);
...then that polynomial is the reverse of 0xEDB88320, i.e. 0x04C11DB7, but with the extra 32nd coefficient in the beginning (making it 0x104C11DB7).
That did not work either. I still have not been able to make the code produce the correct CRC32 result for the string "abc".
Any other suggestions? 


opAmp
Joined: 09 Aug 2022 Posts: 4 Location: Norway


Posted: Wed Aug 10, 2022 7:52 pm 


Wow, I am SO impressed!
I just received an excellent response from Richard at CCS Support. This fully solved my problem.
Here is the email from Richard:
Quote:  The problem is the polynomial you're using is the reversed CRC32 polynomial. Which the PIC's hardware can't do because that polynomial has the least significant bit set as 0, and the PIC's hardware generator always has the least significant bit of the polynomial set as 1.
What you need to is use the normal CRC32 polynomial 0x04C11DB7 to do the calculation. To get the reversed CRC32 result it also requires that the module be initialized to 0xFFFFFFFF, the input data be reflected, which the CRC peripheral can do, the result to be reflected and the result to be XOR'd by 0xFFFFFFFF.
For example the following code will get you the same result as the online calculator you're looking at:
Code:  //Function to reflect the output
unsigned int32 ReflectInt32(unsigned int32 Value) {
unsigned int16 i;
unsigned int32 Result = 0;
for(i=0;i<32;i++)
{
if(bit_test(Value, i))
shift_left(&Result, 4, 1);
else
shift_left(&Result, 4, 0);
}
return(Result);
}
//Code in main() to do the CRC calculation
unsigned int8 Data[16];
unsigned int8 Length;
unsigned int32 result32;
Length = sprintf(Data, "abc");
setup_crc(CRC_LITTLE_ENDIAN, 32, 26, 23, 22, 16, 12, 11, 10, 8, 7, 5, 4, 2, 1, 0);
crc_init(0xFFFFFFFF);
result32 = ReflectInt32(crc_calc32(Data, Length, 8)) ^ 0xFFFFFFFF;
fprintf(PC, "getenv(\"CRC\") returns %u, length of string \"%s\" is %u.\r\n", getenv("CRC"), Data, Length);
fprintf(PC, "HW CRC32 result from \"abc\" is 0x%08X (expect 0x352441C2)\r\n", result32); 
I also tested it with a couple other strings to verify that it was giving the same result as online calculator.
Richard
CCS Support 
Based on this help, I have now made a little function that does everything for me. It looks like this:
Code:  unsigned int32 crc32(const void *data, int n_bytes)
{
unsigned int32 result = 0;
unsigned int32 value;
setup_crc(CRC_LITTLE_ENDIAN, 32,26,23,22,16,12,11,10,8,7,5,4,2,1,0);
crc_init(0xFFFFFFFF);
value = crc_calc32(data, n_bytes, 8);
for(unsigned int16 k=0; k<32; k++)
{
if(bit_test(value, k))
shift_left(&result, 4, 1);
else
shift_left(&result, 4, 0);
}
return ~result;
} 
Thank you again, Ttelmah, for your help. You were right, the polynomial was not correctly specified.
Case closed.
Erik
PS: Another CRC calculator webpage:
https://crccalc.com/?crc=abc&method=crc32&datatype=ascii&outtype=0 


Ttelmah
Joined: 11 Mar 2010 Posts: 18225


Posted: Wed Aug 10, 2022 11:41 pm 


Brilliant. Well done Richard.
Handling reverse polynomials, was a thing I had to do years ago with CRC16.
Hadn't looked at these for CRC32. Eeek!. 


Ttelmah
Joined: 11 Mar 2010 Posts: 18225



opAmp
Joined: 09 Aug 2022 Posts: 4 Location: Norway


Posted: Tue Aug 16, 2022 7:47 am 


Thank you Ttelmah!
That website explains why I was banging my head against a brick wall when trying to make it work without understanding what I was doing.
So, in summary...
If I understand correctly, for the most popular polynomial (which can be in the normal form 0x04C11DB7 or in the reversed form 0xEDB88320) there are 32 permutations of the various ways to calculate the CRC, and only four of these being valid, meaning that the results are correct/standardized CRC32 values.
Out of these four standardized ways, only two of them lead to the result that I was looking for: 0x352441C2. The other two, which is another form of CRC32, gives a different result (not 0x352441C2).
Still there are 28 other ways which produce nonstandardized garbage output. I am sure I touched upon most of these when I was hopelessly fiddling with the various parameters
All of the above is for the most popular CRC32 polynomial (0x04C11DB7 / 0xEDB88320). But there are several other popular polynomials (e.g. CRC32C, CRC32K and CRC32Q) in use as well.
Yeah... :D
(I miss the days when we were just XORing some bytes to make a simple checksum, haha! ) 


Ttelmah
Joined: 11 Mar 2010 Posts: 18225


Posted: Tue Aug 16, 2022 8:04 am 


Yes, or the old actual 'checksum' (add and just use the low bits of the
result).... 




You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum

Powered by phpBB © 2001, 2005 phpBB Group
